Skip to content

Commit e3a6c2e

Browse files
committed
[CIR] Upstream __imag__ for ComplexType
1 parent 77941eb commit e3a6c2e

File tree

9 files changed

+177
-3
lines changed

9 files changed

+177
-3
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2424,6 +2424,35 @@ def ComplexCreateOp : CIR_Op<"complex.create", [Pure, SameTypeOperands]> {
24242424
let hasFolder = 1;
24252425
}
24262426

2427+
//===----------------------------------------------------------------------===//
2428+
// ComplexImagOp
2429+
//===----------------------------------------------------------------------===//
2430+
2431+
def ComplexImagOp : CIR_Op<"complex.imag", [Pure]> {
2432+
let summary = "Extract the imaginary part of a complex value";
2433+
let description = [{
2434+
`cir.complex.imag` operation takes an operand of `!cir.complex` type and
2435+
yields the imaginary part of it.
2436+
2437+
Example:
2438+
2439+
```mlir
2440+
%1 = cir.complex.imag %0 : !cir.complex<!cir.float> -> !cir.float
2441+
```
2442+
}];
2443+
2444+
let results = (outs CIR_AnyIntOrFloatType:$result);
2445+
let arguments = (ins CIR_ComplexType:$operand);
2446+
2447+
let assemblyFormat = [{
2448+
$operand `:` qualified(type($operand)) `->` qualified(type($result))
2449+
attr-dict
2450+
}];
2451+
2452+
let hasVerifier = 1;
2453+
let hasFolder = 1;
2454+
}
2455+
24272456
//===----------------------------------------------------------------------===//
24282457
// Assume Operations
24292458
//===----------------------------------------------------------------------===//

clang/lib/CIR/CodeGen/CIRGenBuilder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,11 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
366366
return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
367367
}
368368

369+
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
370+
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
371+
return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
372+
}
373+
369374
/// Create a cir.ptr_stride operation to get access to an array element.
370375
/// \p idx is the index of the element to access, \p shouldDecay is true if
371376
/// the result should decay to a pointer to the element type.

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
603603

604604
mlir::Value VisitUnaryLNot(const UnaryOperator *e);
605605

606+
mlir::Value VisitUnaryImag(const UnaryOperator *e);
607+
606608
mlir::Value VisitCXXThisExpr(CXXThisExpr *te) { return cgf.loadCXXThis(); }
607609

608610
/// Emit a conversion from the specified type to the specified destination
@@ -1891,6 +1893,27 @@ mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *e) {
18911893
return maybePromoteBoolResult(boolVal, cgf.convertType(e->getType()));
18921894
}
18931895

1896+
mlir::Value ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *e) {
1897+
// TODO(cir): handle scalar promotion.
1898+
Expr *op = e->getSubExpr();
1899+
if (op->getType()->isAnyComplexType()) {
1900+
// If it's an l-value, load through the appropriate subobject l-value.
1901+
// Note that we have to ask E because Op might be an l-value that
1902+
// this won't work for, e.g. an Obj-C property.
1903+
if (e->isGLValue()) {
1904+
mlir::Location loc = cgf.getLoc(e->getExprLoc());
1905+
mlir::Value complex = cgf.emitComplexExpr(op);
1906+
return cgf.builder.createComplexImag(loc, complex);
1907+
}
1908+
1909+
// Otherwise, calculate and project.
1910+
cgf.cgm.errorNYI(e->getSourceRange(),
1911+
"VisitUnaryImag calculate and project");
1912+
}
1913+
1914+
return Visit(op);
1915+
}
1916+
18941917
/// Return the size or alignment of the type of argument of the sizeof
18951918
/// expression as an integer.
18961919
mlir::Value ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1933,6 +1933,24 @@ OpFoldResult cir::ComplexCreateOp::fold(FoldAdaptor adaptor) {
19331933
return cir::ConstComplexAttr::get(realAttr, imagAttr);
19341934
}
19351935

1936+
//===----------------------------------------------------------------------===//
1937+
// ComplexImagOp
1938+
//===----------------------------------------------------------------------===//
1939+
1940+
LogicalResult cir::ComplexImagOp::verify() {
1941+
if (getType() != getOperand().getType().getElementType()) {
1942+
emitOpError() << "cir.complex.imag result type does not match operand type";
1943+
return failure();
1944+
}
1945+
return success();
1946+
}
1947+
1948+
OpFoldResult cir::ComplexImagOp::fold(FoldAdaptor adaptor) {
1949+
auto complex =
1950+
mlir::cast_if_present<cir::ConstComplexAttr>(adaptor.getOperand());
1951+
return complex ? complex.getImag() : nullptr;
1952+
}
1953+
19361954
//===----------------------------------------------------------------------===//
19371955
// TableGen'd op method definitions
19381956
//===----------------------------------------------------------------------===//

clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ void CIRCanonicalizePass::runOnOperation() {
141141
// Many operations are here to perform a manual `fold` in
142142
// applyOpPatternsGreedily.
143143
if (isa<BrOp, BrCondOp, CastOp, ScopeOp, SwitchOp, SelectOp, UnaryOp,
144-
ComplexCreateOp, VecCmpOp, VecCreateOp, VecExtractOp, VecShuffleOp,
145-
VecShuffleDynamicOp, VecTernaryOp>(op))
144+
ComplexCreateOp, ComplexImagOp, VecCmpOp, VecCreateOp, VecExtractOp,
145+
VecShuffleOp, VecShuffleDynamicOp, VecTernaryOp>(op))
146146
ops.push_back(op);
147147
});
148148

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1886,7 +1886,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
18861886
CIRToLLVMVecShuffleOpLowering,
18871887
CIRToLLVMVecShuffleDynamicOpLowering,
18881888
CIRToLLVMVecTernaryOpLowering,
1889-
CIRToLLVMComplexCreateOpLowering
1889+
CIRToLLVMComplexCreateOpLowering,
1890+
CIRToLLVMComplexImagOpLowering
18901891
// clang-format on
18911892
>(converter, patterns.getContext());
18921893

@@ -2190,6 +2191,15 @@ mlir::LogicalResult CIRToLLVMComplexCreateOpLowering::matchAndRewrite(
21902191
return mlir::success();
21912192
}
21922193

2194+
mlir::LogicalResult CIRToLLVMComplexImagOpLowering::matchAndRewrite(
2195+
cir::ComplexImagOp op, OpAdaptor adaptor,
2196+
mlir::ConversionPatternRewriter &rewriter) const {
2197+
mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());
2198+
rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
2199+
op, resultLLVMTy, adaptor.getOperand(), llvm::ArrayRef<std::int64_t>{1});
2200+
return mlir::success();
2201+
}
2202+
21932203
std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
21942204
return std::make_unique<ConvertCIRToLLVMPass>();
21952205
}

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,16 @@ class CIRToLLVMComplexCreateOpLowering
433433
mlir::ConversionPatternRewriter &) const override;
434434
};
435435

436+
class CIRToLLVMComplexImagOpLowering
437+
: public mlir::OpConversionPattern<cir::ComplexImagOp> {
438+
public:
439+
using mlir::OpConversionPattern<cir::ComplexImagOp>::OpConversionPattern;
440+
441+
mlir::LogicalResult
442+
matchAndRewrite(cir::ComplexImagOp op, OpAdaptor,
443+
mlir::ConversionPatternRewriter &) const override;
444+
};
445+
436446
} // namespace direct
437447
} // namespace cir
438448

clang/test/CIR/CodeGen/complex.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,29 @@ void foo9(double a, double b) {
216216
// OGCG: store double %[[TMP_A]], ptr %[[C_REAL_PTR]], align 8
217217
// OGCG: store double %[[TMP_B]], ptr %[[C_IMAG_PTR]], align 8
218218

219+
void foo13() {
220+
double _Complex c;
221+
double imag = __imag__ c;
222+
}
223+
224+
// CIR: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["c"]
225+
// CIR: %[[INIT:.*]] = cir.alloca !cir.double, !cir.ptr<!cir.double>, ["imag", init]
226+
// CIR: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double>
227+
// CIR: %[[IMAG:.*]] = cir.complex.imag %[[TMP]] : !cir.complex<!cir.double> -> !cir.double
228+
// CIR: cir.store{{.*}} %[[IMAG]], %[[INIT]] : !cir.double, !cir.ptr<!cir.double>
229+
230+
// LLVM: %[[COMPLEX:.*]] = alloca { double, double }, i64 1, align 8
231+
// LLVM: %[[INIT:.*]] = alloca double, i64 1, align 8
232+
// LLVM: %[[TMP:.*]] = load { double, double }, ptr %[[COMPLEX]], align 8
233+
// LLVM: %[[IMAG:.*]] = extractvalue { double, double } %[[TMP]], 1
234+
// LLVM: store double %[[IMAG]], ptr %[[INIT]], align 8
235+
236+
// OGCG: %[[COMPLEX:.*]] = alloca { double, double }, align 8
237+
// OGCG: %[[INIT:.*]] = alloca double, align 8
238+
// OGCG: %[[IMAG:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 1
239+
// OGCG: %[[TMP:.*]] = load double, ptr %[[IMAG]], align 8
240+
// OGCG: store double %[[TMP]], ptr %[[INIT]], align 8
241+
219242
void foo14() {
220243
int _Complex c = 2i;
221244
}
@@ -256,3 +279,36 @@ void foo15() {
256279
// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 1
257280
// OGCG: store i32 %[[A_REAL]], ptr %[[B_REAL_PTR]], align 4
258281
// OGCG: store i32 %[[A_IMAG]], ptr %[[B_IMAG_PTR]], align 4
282+
283+
int foo16(int _Complex a, int _Complex b) {
284+
return __imag__ a + __imag__ b;
285+
}
286+
287+
// CIR: %[[RET:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
288+
// CIR: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
289+
// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[COMPLEX_A]] : !cir.complex<!s32i> -> !s32i
290+
// CIR: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
291+
// CIR: %[[B_IMAG:.*]] = cir.complex.imag %[[COMPLEX_B]] : !cir.complex<!s32i> -> !s32i
292+
// CIR: %[[ADD:.*]] = cir.binop(add, %[[A_IMAG]], %[[B_IMAG]]) nsw : !s32i
293+
// CIR: cir.store %[[ADD]], %[[RET]] : !s32i, !cir.ptr<!s32i>
294+
// CIR: %[[TMP:.*]] = cir.load %[[RET]] : !cir.ptr<!s32i>, !s32i
295+
// CIR: cir.return %[[TMP]] : !s32i
296+
297+
// LLVM: %[[RET:.*]] = alloca i32, i64 1, align 4
298+
// LLVM: %[[COMPLEX_A:.*]] = load { i32, i32 }, ptr {{.*}}, align 4
299+
// LLVM: %[[A_IMAG:.*]] = extractvalue { i32, i32 } %[[COMPLEX_A]], 1
300+
// LLVM: %[[COMPLEX_B:.*]] = load { i32, i32 }, ptr {{.*}}, align 4
301+
// LLVM: %[[B_IMAG:.*]] = extractvalue { i32, i32 } %[[COMPLEX_B]], 1
302+
// LLVM: %[[ADD:.*]] = add nsw i32 %[[A_IMAG]], %[[B_IMAG]]
303+
// LLVM: store i32 %[[ADD]], ptr %[[RET]], align 4
304+
// LLVM: %[[TMP:.*]] = load i32, ptr %[[RET]], align 4
305+
// LLVM: ret i32 %[[TMP]]
306+
307+
// OGCG: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, align 4
308+
// OGCG: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, align 4
309+
// OGCG: %[[A_IMAG:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 1
310+
// OGCG: %[[TMP_A:.*]] = load i32, ptr %[[A_IMAG]], align 4
311+
// OGCG: %[[B_IMAG:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 1
312+
// OGCG: %[[TMP_B:.*]] = load i32, ptr %[[B_IMAG]], align 4
313+
// OGCG: %[[ADD:.*]] = add nsw i32 %[[TMP_A]], %[[TMP_B]]
314+
// OGCG: ret i32 %[[ADD]]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: cir-opt %s -cir-canonicalize -o - | FileCheck %s
2+
3+
!s32i = !cir.int<s, 32>
4+
5+
module {
6+
cir.func @fold_complex_imag_test() -> !s32i {
7+
%0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
8+
%2 = cir.const #cir.const_complex<#cir.int<1> : !s32i, #cir.int<2> : !s32i> : !cir.complex<!s32i>
9+
%4 = cir.complex.imag %2 : !cir.complex<!s32i> -> !s32i
10+
cir.store %4, %0 : !s32i, !cir.ptr<!s32i>
11+
%5 = cir.load %0 : !cir.ptr<!s32i>, !s32i
12+
cir.return %5 : !s32i
13+
}
14+
15+
// CHECK: cir.func @fold_complex_imag_test() -> !s32i {
16+
// CHECK: %[[RET:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
17+
// CHECK: %[[IMAG:.*]] = cir.const #cir.int<2> : !s32i
18+
// CHECK: cir.store %[[IMAG]], %[[RET]] : !s32i, !cir.ptr<!s32i>
19+
// CHECK: %[[TMP:.]] = cir.load %[[RET]] : !cir.ptr<!s32i>, !s32i
20+
// CHECK: cir.return %[[TMP]] : !s32i
21+
// CHECK: }
22+
23+
}

0 commit comments

Comments
 (0)