-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[CIR] Upstream unary not for ComplexType #148857
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang Author: Amr Hesham (AmrDeveloper) ChangesUpstream unary not for ComplexType Full diff: https://github.com/llvm/llvm-project/pull/148857.diff 5 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 277c278fd38b7..25baf278bba38 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -129,6 +129,22 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
cir::BoolAttr getTrueAttr() { return getCIRBoolAttr(true); }
cir::BoolAttr getFalseAttr() { return getCIRBoolAttr(false); }
+ mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
+ mlir::Value imag) {
+ auto resultComplexTy = cir::ComplexType::get(real.getType());
+ return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
+ }
+
+ mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
+ auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
+ return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);
+ }
+
+ mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
+ auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
+ return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
+ }
+
mlir::Value createNot(mlir::Value value) {
return create<cir::UnaryOp>(value.getLoc(), value.getType(),
cir::UnaryOpKind::Not, value);
@@ -169,6 +185,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return create<cir::ContinueOp>(loc);
}
+ mlir::Value createUnaryOp(mlir::Location loc, cir::UnaryOpKind kind,
+ mlir::Value operand) {
+ return create<cir::UnaryOp>(loc, kind, operand);
+ }
+
mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {
return cir::ConstPtrAttr::get(type, getI64IntegerAttr(value));
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 5bd53ebc52ab5..f855bdad2d7c3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -348,22 +348,6 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), align);
}
- mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
- mlir::Value imag) {
- auto resultComplexTy = cir::ComplexType::get(real.getType());
- return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
- }
-
- mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
- auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
- return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);
- }
-
- mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
- auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
- return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
- }
-
/// Create a cir.complex.real_ptr operation that derives a pointer to the real
/// part of the complex value pointed to by the specified pointer value.
mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index 3273d9000771a..6663f5ea1e758 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -57,6 +57,7 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
mlir::Value
VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e);
mlir::Value VisitUnaryDeref(const Expr *e);
+ mlir::Value VisitUnaryNot(const UnaryOperator *e);
struct BinOpInfo {
mlir::Location loc;
@@ -338,6 +339,11 @@ mlir::Value ComplexExprEmitter::VisitUnaryDeref(const Expr *e) {
return emitLoadOfLValue(e);
}
+mlir::Value ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *e) {
+ mlir::Value op = Visit(e->getSubExpr());
+ return builder.createNot(op);
+}
+
mlir::Value ComplexExprEmitter::emitPromoted(const Expr *e,
QualType promotionTy) {
e = e->IgnoreParens();
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 5493b86a0a321..788817006baa5 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -8,7 +8,9 @@
#include "PassDetail.h"
#include "clang/AST/ASTContext.h"
+#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/Dialect/Passes.h"
#include <memory>
@@ -22,15 +24,68 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
void runOnOperation() override;
void runOnOp(Operation *op);
+ void lowerUnaryOp(UnaryOp op);
};
} // namespace
-void LoweringPreparePass::runOnOp(Operation *op) {}
+void LoweringPreparePass::lowerUnaryOp(UnaryOp op) {
+ mlir::Type ty = op.getType();
+ if (!mlir::isa<cir::ComplexType>(ty))
+ return;
+
+ mlir::Location loc = op.getLoc();
+ cir::UnaryOpKind opKind = op.getKind();
+
+ CIRBaseBuilderTy builder(getContext());
+ builder.setInsertionPointAfter(op);
+
+ mlir::Value operand = op.getInput();
+ mlir::Value operandReal = builder.createComplexReal(loc, operand);
+ mlir::Value operandImag = builder.createComplexImag(loc, operand);
+
+ mlir::Value resultReal;
+ mlir::Value resultImag;
+
+ switch (opKind) {
+ case cir::UnaryOpKind::Inc:
+ case cir::UnaryOpKind::Dec:
+ llvm_unreachable("Complex unary Inc/Dec NYI");
+ break;
+
+ case cir::UnaryOpKind::Plus:
+ case cir::UnaryOpKind::Minus:
+ llvm_unreachable("Complex unary Plus/Minus NYI");
+ break;
+
+ case cir::UnaryOpKind::Not:
+ resultReal = operandReal;
+ resultImag =
+ builder.createUnaryOp(loc, cir::UnaryOpKind::Minus, operandImag);
+ break;
+ }
+
+ auto result = builder.createComplexCreate(loc, resultReal, resultImag);
+ op.replaceAllUsesWith(result);
+ op.erase();
+}
+
+void LoweringPreparePass::runOnOp(Operation *op) {
+ if (auto unary = dyn_cast<UnaryOp>(op)) {
+ lowerUnaryOp(unary);
+ }
+}
void LoweringPreparePass::runOnOperation() {
+ mlir::Operation *op = getOperation();
+
llvm::SmallVector<Operation *> opsToTransform;
+ op->walk([&](Operation *op) {
+ if (isa<UnaryOp>(op))
+ opsToTransform.push_back(op);
+ });
+
for (auto *o : opsToTransform)
runOnOp(o);
}
diff --git a/clang/test/CIR/CodeGen/complex-unary.cpp b/clang/test/CIR/CodeGen/complex-unary.cpp
new file mode 100644
index 0000000000000..463c4dde47ed6
--- /dev/null
+++ b/clang/test/CIR/CodeGen/complex-unary.cpp
@@ -0,0 +1,48 @@
+// 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
+// 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
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+void foo() {
+ int _Complex a;
+ int _Complex b = ~a;
+}
+
+// CIR-BEFORE: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
+// CIR-BEFORE: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]
+// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR-BEFORE: %[[COMPLEX_NOT:.*]] = cir.unary(not, %[[TMP]]) : !cir.complex<!s32i>, !cir.complex<!s32i>
+// CIR-BEFORE: cir.store{{.*}} %[[COMPLEX_NOT]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+
+// CIR-AFTER: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
+// CIR-AFTER: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]
+// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %[[TMP]] : !cir.complex<!s32i> -> !s32i
+// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %[[TMP]] : !cir.complex<!s32i> -> !s32i
+// CIR-AFTER: %[[IMAG_MINUS:.*]] = cir.unary(minus, %[[IMAG]]) : !s32i, !s32i
+// CIR-AFTER: %[[RESULT_VAL:.*]] = cir.complex.create %[[REAL]], %[[IMAG_MINUS]] : !s32i -> !cir.complex<!s32i>
+// CIR-AFTER: cir.store{{.*}} %[[RESULT_VAL]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+
+// LLVM: %[[COMPLEX:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[RESULT:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[TMP:.*]] = load { i32, i32 }, ptr %[[COMPLEX]], align 4
+// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %[[TMP]], 0
+// LLVM: %[[IMAG:.*]] = extractvalue { i32, i32 } %[[TMP]], 1
+// LLVM: %[[IMAG_MINUS:.*]] = sub i32 0, %[[IMAG]]
+// LLVM: %[[RESULT_TMP:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[REAL]], 0
+// LLVM: %[[RESULT_VAL:.*]] = insertvalue { i32, i32 } %[[RESULT_TMP]], i32 %[[IMAG_MINUS]], 1
+// LLVM: store { i32, i32 } %[[RESULT_VAL]], ptr %[[RESULT]], align 4
+
+// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[RESULT:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0
+// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4
+// OGCG: %[[A_IMAG_MINUS:.*]] = sub i32 0, %[[A_IMAG]]
+// OGCG: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESULT]], i32 0, i32 0
+// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESULT]], i32 0, i32 1
+// OGCG: store i32 %[[A_REAL]], ptr %[[RESULT_REAL_PTR]], align 4
+// OGCG: store i32 %[[A_IMAG_MINUS]], ptr %[[RESULT_IMAG_PTR]], align 4
|
@llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) ChangesUpstream unary not for ComplexType Full diff: https://github.com/llvm/llvm-project/pull/148857.diff 5 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index 277c278fd38b7..25baf278bba38 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -129,6 +129,22 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
cir::BoolAttr getTrueAttr() { return getCIRBoolAttr(true); }
cir::BoolAttr getFalseAttr() { return getCIRBoolAttr(false); }
+ mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
+ mlir::Value imag) {
+ auto resultComplexTy = cir::ComplexType::get(real.getType());
+ return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
+ }
+
+ mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
+ auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
+ return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);
+ }
+
+ mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
+ auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
+ return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
+ }
+
mlir::Value createNot(mlir::Value value) {
return create<cir::UnaryOp>(value.getLoc(), value.getType(),
cir::UnaryOpKind::Not, value);
@@ -169,6 +185,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return create<cir::ContinueOp>(loc);
}
+ mlir::Value createUnaryOp(mlir::Location loc, cir::UnaryOpKind kind,
+ mlir::Value operand) {
+ return create<cir::UnaryOp>(loc, kind, operand);
+ }
+
mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {
return cir::ConstPtrAttr::get(type, getI64IntegerAttr(value));
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 5bd53ebc52ab5..f855bdad2d7c3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -348,22 +348,6 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return CIRBaseBuilderTy::createStore(loc, val, dst.getPointer(), align);
}
- mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
- mlir::Value imag) {
- auto resultComplexTy = cir::ComplexType::get(real.getType());
- return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
- }
-
- mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
- auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
- return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);
- }
-
- mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
- auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
- return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
- }
-
/// Create a cir.complex.real_ptr operation that derives a pointer to the real
/// part of the complex value pointed to by the specified pointer value.
mlir::Value createComplexRealPtr(mlir::Location loc, mlir::Value value) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
index 3273d9000771a..6663f5ea1e758 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -57,6 +57,7 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
mlir::Value
VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e);
mlir::Value VisitUnaryDeref(const Expr *e);
+ mlir::Value VisitUnaryNot(const UnaryOperator *e);
struct BinOpInfo {
mlir::Location loc;
@@ -338,6 +339,11 @@ mlir::Value ComplexExprEmitter::VisitUnaryDeref(const Expr *e) {
return emitLoadOfLValue(e);
}
+mlir::Value ComplexExprEmitter::VisitUnaryNot(const UnaryOperator *e) {
+ mlir::Value op = Visit(e->getSubExpr());
+ return builder.createNot(op);
+}
+
mlir::Value ComplexExprEmitter::emitPromoted(const Expr *e,
QualType promotionTy) {
e = e->IgnoreParens();
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 5493b86a0a321..788817006baa5 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -8,7 +8,9 @@
#include "PassDetail.h"
#include "clang/AST/ASTContext.h"
+#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/Dialect/Passes.h"
#include <memory>
@@ -22,15 +24,68 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
void runOnOperation() override;
void runOnOp(Operation *op);
+ void lowerUnaryOp(UnaryOp op);
};
} // namespace
-void LoweringPreparePass::runOnOp(Operation *op) {}
+void LoweringPreparePass::lowerUnaryOp(UnaryOp op) {
+ mlir::Type ty = op.getType();
+ if (!mlir::isa<cir::ComplexType>(ty))
+ return;
+
+ mlir::Location loc = op.getLoc();
+ cir::UnaryOpKind opKind = op.getKind();
+
+ CIRBaseBuilderTy builder(getContext());
+ builder.setInsertionPointAfter(op);
+
+ mlir::Value operand = op.getInput();
+ mlir::Value operandReal = builder.createComplexReal(loc, operand);
+ mlir::Value operandImag = builder.createComplexImag(loc, operand);
+
+ mlir::Value resultReal;
+ mlir::Value resultImag;
+
+ switch (opKind) {
+ case cir::UnaryOpKind::Inc:
+ case cir::UnaryOpKind::Dec:
+ llvm_unreachable("Complex unary Inc/Dec NYI");
+ break;
+
+ case cir::UnaryOpKind::Plus:
+ case cir::UnaryOpKind::Minus:
+ llvm_unreachable("Complex unary Plus/Minus NYI");
+ break;
+
+ case cir::UnaryOpKind::Not:
+ resultReal = operandReal;
+ resultImag =
+ builder.createUnaryOp(loc, cir::UnaryOpKind::Minus, operandImag);
+ break;
+ }
+
+ auto result = builder.createComplexCreate(loc, resultReal, resultImag);
+ op.replaceAllUsesWith(result);
+ op.erase();
+}
+
+void LoweringPreparePass::runOnOp(Operation *op) {
+ if (auto unary = dyn_cast<UnaryOp>(op)) {
+ lowerUnaryOp(unary);
+ }
+}
void LoweringPreparePass::runOnOperation() {
+ mlir::Operation *op = getOperation();
+
llvm::SmallVector<Operation *> opsToTransform;
+ op->walk([&](Operation *op) {
+ if (isa<UnaryOp>(op))
+ opsToTransform.push_back(op);
+ });
+
for (auto *o : opsToTransform)
runOnOp(o);
}
diff --git a/clang/test/CIR/CodeGen/complex-unary.cpp b/clang/test/CIR/CodeGen/complex-unary.cpp
new file mode 100644
index 0000000000000..463c4dde47ed6
--- /dev/null
+++ b/clang/test/CIR/CodeGen/complex-unary.cpp
@@ -0,0 +1,48 @@
+// 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
+// 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
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+void foo() {
+ int _Complex a;
+ int _Complex b = ~a;
+}
+
+// CIR-BEFORE: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
+// CIR-BEFORE: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]
+// CIR-BEFORE: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR-BEFORE: %[[COMPLEX_NOT:.*]] = cir.unary(not, %[[TMP]]) : !cir.complex<!s32i>, !cir.complex<!s32i>
+// CIR-BEFORE: cir.store{{.*}} %[[COMPLEX_NOT]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+
+// CIR-AFTER: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["a"]
+// CIR-AFTER: %[[RESULT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["b", init]
+// CIR-AFTER: %[[TMP:.*]] = cir.load{{.*}} %[[COMPLEX]] : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i>
+// CIR-AFTER: %[[REAL:.*]] = cir.complex.real %[[TMP]] : !cir.complex<!s32i> -> !s32i
+// CIR-AFTER: %[[IMAG:.*]] = cir.complex.imag %[[TMP]] : !cir.complex<!s32i> -> !s32i
+// CIR-AFTER: %[[IMAG_MINUS:.*]] = cir.unary(minus, %[[IMAG]]) : !s32i, !s32i
+// CIR-AFTER: %[[RESULT_VAL:.*]] = cir.complex.create %[[REAL]], %[[IMAG_MINUS]] : !s32i -> !cir.complex<!s32i>
+// CIR-AFTER: cir.store{{.*}} %[[RESULT_VAL]], %[[RESULT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+
+// LLVM: %[[COMPLEX:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[RESULT:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[TMP:.*]] = load { i32, i32 }, ptr %[[COMPLEX]], align 4
+// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %[[TMP]], 0
+// LLVM: %[[IMAG:.*]] = extractvalue { i32, i32 } %[[TMP]], 1
+// LLVM: %[[IMAG_MINUS:.*]] = sub i32 0, %[[IMAG]]
+// LLVM: %[[RESULT_TMP:.*]] = insertvalue { i32, i32 } {{.*}}, i32 %[[REAL]], 0
+// LLVM: %[[RESULT_VAL:.*]] = insertvalue { i32, i32 } %[[RESULT_TMP]], i32 %[[IMAG_MINUS]], 1
+// LLVM: store { i32, i32 } %[[RESULT_VAL]], ptr %[[RESULT]], align 4
+
+// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[RESULT:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0
+// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4
+// OGCG: %[[A_IMAG_MINUS:.*]] = sub i32 0, %[[A_IMAG]]
+// OGCG: %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESULT]], i32 0, i32 0
+// OGCG: %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[RESULT]], i32 0, i32 1
+// OGCG: store i32 %[[A_REAL]], ptr %[[RESULT_REAL_PTR]], align 4
+// OGCG: store i32 %[[A_IMAG_MINUS]], ptr %[[RESULT_IMAG_PTR]], align 4
|
}; | ||
|
||
} // namespace | ||
|
||
void LoweringPreparePass::runOnOp(Operation *op) {} | ||
void LoweringPreparePass::lowerUnaryOp(UnaryOp op) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void LoweringPreparePass::lowerUnaryOp(UnaryOp op) { | |
void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { |
op.erase(); | ||
} | ||
|
||
void LoweringPreparePass::runOnOp(Operation *op) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void LoweringPreparePass::runOnOp(Operation *op) { | |
void LoweringPreparePass::runOnOp(mlir::Operation *op) { |
if (auto unary = dyn_cast<UnaryOp>(op)) { | ||
lowerUnaryOp(unary); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (auto unary = dyn_cast<UnaryOp>(op)) { | |
lowerUnaryOp(unary); | |
} | |
if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) | |
lowerUnaryOp(unary); |
llvm::SmallVector<Operation *> opsToTransform; | ||
|
||
op->walk([&](Operation *op) { | ||
if (isa<UnaryOp>(op)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (isa<UnaryOp>(op)) | |
if (mlir::isa<cir::UnaryOp>(op)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm, with one nit about the test
// LLVM: %[[TMP:.*]] = load { i32, i32 }, ptr %[[COMPLEX]], align 4 | ||
// LLVM: %[[REAL:.*]] = extractvalue { i32, i32 } %[[TMP]], 0 | ||
// LLVM: %[[IMAG:.*]] = extractvalue { i32, i32 } %[[TMP]], 1 | ||
// LLVM: %[[IMAG_MINUS:.*]] = sub i32 0, %[[IMAG]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a test case for float _Complex
(or even just replace this one)? For floating point types, we should get an fneg
rather than fsub 0, i
here. It's a subtle but important difference.
Upstream unary not for ComplexType
#141365