Skip to content

Commit bd0f9dd

Browse files
authored
[CIR] Upstream unary not for ComplexType (#148857)
Upstream unary not for ComplexType #141365
1 parent fdec9fd commit bd0f9dd

File tree

5 files changed

+175
-20
lines changed

5 files changed

+175
-20
lines changed

clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,22 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
129129
cir::BoolAttr getTrueAttr() { return getCIRBoolAttr(true); }
130130
cir::BoolAttr getFalseAttr() { return getCIRBoolAttr(false); }
131131

132+
mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
133+
mlir::Value imag) {
134+
auto resultComplexTy = cir::ComplexType::get(real.getType());
135+
return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
136+
}
137+
138+
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
139+
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
140+
return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);
141+
}
142+
143+
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
144+
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
145+
return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
146+
}
147+
132148
mlir::Value createNot(mlir::Value value) {
133149
return create<cir::UnaryOp>(value.getLoc(), value.getType(),
134150
cir::UnaryOpKind::Not, value);
@@ -169,6 +185,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
169185
return create<cir::ContinueOp>(loc);
170186
}
171187

188+
mlir::Value createUnaryOp(mlir::Location loc, cir::UnaryOpKind kind,
189+
mlir::Value operand) {
190+
return create<cir::UnaryOp>(loc, kind, operand);
191+
}
192+
172193
mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {
173194
return cir::ConstPtrAttr::get(type, getI64IntegerAttr(value));
174195
}

clang/lib/CIR/CodeGen/CIRGenBuilder.h

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -348,22 +348,6 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
348348
return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), align);
349349
}
350350

351-
mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
352-
mlir::Value imag) {
353-
auto resultComplexTy = cir::ComplexType::get(real.getType());
354-
return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
355-
}
356-
357-
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
358-
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
359-
return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);
360-
}
361-
362-
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
363-
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
364-
return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
365-
}
366-
367351
/// Create a cir.complex.real_ptr operation that derives a pointer to the real
368352
/// part of the complex value pointed to by the specified pointer value.
369353
mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {

clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
5757
mlir::Value
5858
VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e);
5959
mlir::Value VisitUnaryDeref(const Expr *e);
60+
mlir::Value VisitUnaryNot(const UnaryOperator *e);
6061

6162
struct BinOpInfo {
6263
mlir::Location loc;
@@ -338,6 +339,11 @@ mlir::Value ComplexExprEmitter::VisitUnaryDeref(const Expr *e) {
338339
return emitLoadOfLValue(e);
339340
}
340341

342+
mlir::Value ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *e) {
343+
mlir::Value op = Visit(e->getSubExpr());
344+
return builder.createNot(op);
345+
}
346+
341347
mlir::Value ComplexExprEmitter::emitPromoted(const Expr *e,
342348
QualType promotionTy) {
343349
e = e->IgnoreParens();

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

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
#include "PassDetail.h"
1010
#include "clang/AST/ASTContext.h"
11+
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
1112
#include "clang/CIR/Dialect/IR/CIRDialect.h"
13+
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
1214
#include "clang/CIR/Dialect/Passes.h"
1315

1416
#include <memory>
@@ -21,17 +23,69 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
2123
LoweringPreparePass() = default;
2224
void runOnOperation() override;
2325

24-
void runOnOp(Operation *op);
26+
void runOnOp(mlir::Operation *op);
27+
void lowerUnaryOp(cir::UnaryOp op);
2528
};
2629

2730
} // namespace
2831

29-
void LoweringPreparePass::runOnOp(Operation *op) {}
32+
void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) {
33+
mlir::Type ty = op.getType();
34+
if (!mlir::isa<cir::ComplexType>(ty))
35+
return;
36+
37+
mlir::Location loc = op.getLoc();
38+
cir::UnaryOpKind opKind = op.getKind();
39+
40+
CIRBaseBuilderTy builder(getContext());
41+
builder.setInsertionPointAfter(op);
42+
43+
mlir::Value operand = op.getInput();
44+
mlir::Value operandReal = builder.createComplexReal(loc, operand);
45+
mlir::Value operandImag = builder.createComplexImag(loc, operand);
46+
47+
mlir::Value resultReal;
48+
mlir::Value resultImag;
49+
50+
switch (opKind) {
51+
case cir::UnaryOpKind::Inc:
52+
case cir::UnaryOpKind::Dec:
53+
llvm_unreachable("Complex unary Inc/Dec NYI");
54+
break;
55+
56+
case cir::UnaryOpKind::Plus:
57+
case cir::UnaryOpKind::Minus:
58+
llvm_unreachable("Complex unary Plus/Minus NYI");
59+
break;
60+
61+
case cir::UnaryOpKind::Not:
62+
resultReal = operandReal;
63+
resultImag =
64+
builder.createUnaryOp(loc, cir::UnaryOpKind::Minus, operandImag);
65+
break;
66+
}
67+
68+
mlir::Value result = builder.createComplexCreate(loc, resultReal, resultImag);
69+
op.replaceAllUsesWith(result);
70+
op.erase();
71+
}
72+
73+
void LoweringPreparePass::runOnOp(mlir::Operation *op) {
74+
if (auto unary = dyn_cast<cir::UnaryOp>(op))
75+
lowerUnaryOp(unary);
76+
}
3077

3178
void LoweringPreparePass::runOnOperation() {
32-
llvm::SmallVector<Operation *> opsToTransform;
79+
mlir::Operation *op = getOperation();
80+
81+
llvm::SmallVector<mlir::Operation *> opsToTransform;
82+
83+
op->walk([&](mlir::Operation *op) {
84+
if (mlir::isa<cir::UnaryOp>(op))
85+
opsToTransform.push_back(op);
86+
});
3387

34-
for (auto *o : opsToTransform)
88+
for (mlir::Operation *o : opsToTransform)
3589
runOnOp(o);
3690
}
3791

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE %s
2+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare -o %t.cir %s 2>&1 | FileCheck --check-prefixes=CIR-AFTER %s
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
5+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
7+
8+
void foo() {
9+
int _Complex a;
10+
int _Complex b = ~a;
11+
}
12+
13+
// CIR-BEFORE: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
14+
// CIR-BEFORE: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]
15+
// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
16+
// CIR-BEFORE: %[[COMPLEX_NOT:.*]] = cir.unary(not, %[[TMP]]) : !cir.complex<!s32i>, !cir.complex<!s32i>
17+
// CIR-BEFORE: cir.store{{.*}} %[[COMPLEX_NOT]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
18+
19+
// CIR-AFTER: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
20+
// CIR-AFTER: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]
21+
// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
22+
// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %[[TMP]] : !cir.complex<!s32i> -> !s32i
23+
// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %[[TMP]] : !cir.complex<!s32i> -> !s32i
24+
// CIR-AFTER: %[[IMAG_MINUS:.*]] = cir.unary(minus, %[[IMAG]]) : !s32i, !s32i
25+
// CIR-AFTER: %[[RESULT_VAL:.*]] = cir.complex.create %[[REAL]], %[[IMAG_MINUS]] : !s32i -> !cir.complex<!s32i>
26+
// CIR-AFTER: cir.store{{.*}} %[[RESULT_VAL]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
27+
28+
// LLVM: %[[COMPLEX:.*]] = alloca { i32, i32 }, i64 1, align 4
29+
// LLVM: %[[RESULT:.*]] = alloca { i32, i32 }, i64 1, align 4
30+
// LLVM: %[[TMP:.*]] = load { i32, i32 }, ptr %[[COMPLEX]], align 4
31+
// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %[[TMP]], 0
32+
// LLVM: %[[IMAG:.*]] = extractvalue { i32, i32 } %[[TMP]], 1
33+
// LLVM: %[[IMAG_MINUS:.*]] = sub i32 0, %[[IMAG]]
34+
// LLVM: %[[RESULT_TMP:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[REAL]], 0
35+
// LLVM: %[[RESULT_VAL:.*]] = insertvalue { i32, i32 } %[[RESULT_TMP]], i32 %[[IMAG_MINUS]], 1
36+
// LLVM: store { i32, i32 } %[[RESULT_VAL]], ptr %[[RESULT]], align 4
37+
38+
// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4
39+
// OGCG: %[[RESULT:.*]] = alloca { i32, i32 }, align 4
40+
// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0
41+
// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4
42+
// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1
43+
// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4
44+
// OGCG: %[[A_IMAG_MINUS:.*]] = sub i32 0, %[[A_IMAG]]
45+
// OGCG: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESULT]], i32 0, i32 0
46+
// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESULT]], i32 0, i32 1
47+
// OGCG: store i32 %[[A_REAL]], ptr %[[RESULT_REAL_PTR]], align 4
48+
// OGCG: store i32 %[[A_IMAG_MINUS]], ptr %[[RESULT_IMAG_PTR]], align 4
49+
50+
void foo2() {
51+
float _Complex a;
52+
float _Complex b = ~a;
53+
}
54+
55+
// CIR-BEFORE: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
56+
// CIR-BEFORE: %[[RESULT:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b", init]
57+
// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
58+
// CIR-BEFORE: %[[COMPLEX_NOT:.*]] = cir.unary(not, %[[TMP]]) : !cir.complex<!cir.float>, !cir.complex<!cir.float>
59+
// CIR-BEFORE: cir.store{{.*}} %[[COMPLEX_NOT]], %[[RESULT]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
60+
61+
// CIR-AFTER: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
62+
// CIR-AFTER: %[[RESULT:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b", init]
63+
// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
64+
// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %[[TMP]] : !cir.complex<!cir.float> -> !cir.float
65+
// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %[[TMP]] : !cir.complex<!cir.float> -> !cir.float
66+
// CIR-AFTER: %[[IMAG_MINUS:.*]] = cir.unary(minus, %[[IMAG]]) : !cir.float, !cir.float
67+
// CIR-AFTER: %[[RESULT_VAL:.*]] = cir.complex.create %[[REAL]], %[[IMAG_MINUS]] : !cir.float -> !cir.complex<!cir.float>
68+
// CIR-AFTER: cir.store{{.*}} %[[RESULT_VAL]], %[[RESULT]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
69+
70+
// LLVM: %[[COMPLEX:.*]] = alloca { float, float }, i64 1, align 4
71+
// LLVM: %[[RESULT:.*]] = alloca { float, float }, i64 1, align 4
72+
// LLVM: %[[TMP:.*]] = load { float, float }, ptr %[[COMPLEX]], align 4
73+
// LLVM: %[[REAL:.*]] = extractvalue { float, float } %[[TMP]], 0
74+
// LLVM: %[[IMAG:.*]] = extractvalue { float, float } %[[TMP]], 1
75+
// LLVM: %[[IMAG_MINUS:.*]] = fneg float %[[IMAG]]
76+
// LLVM: %[[RESULT_TMP:.*]] = insertvalue { float, float } {{.*}}, float %[[REAL]], 0
77+
// LLVM: %[[RESULT_VAL:.*]] = insertvalue { float, float } %[[RESULT_TMP]], float %[[IMAG_MINUS]], 1
78+
// LLVM: store { float, float } %[[RESULT_VAL]], ptr %[[RESULT]], align 4
79+
80+
// OGCG: %[[COMPLEX:.*]] = alloca { float, float }, align 4
81+
// OGCG: %[[RESULT:.*]] = alloca { float, float }, align 4
82+
// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX]], i32 0, i32 0
83+
// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4
84+
// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX]], i32 0, i32 1
85+
// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4
86+
// OGCG: %[[A_IMAG_MINUS:.*]] = fneg float %[[A_IMAG]]
87+
// OGCG: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RESULT]], i32 0, i32 0
88+
// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[RESULT]], i32 0, i32 1
89+
// OGCG: store float %[[A_REAL]], ptr %[[RESULT_REAL_PTR]], align 4
90+
// OGCG: store float %[[A_IMAG_MINUS]], ptr %[[RESULT_IMAG_PTR]], align 4

0 commit comments

Comments
 (0)