-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[CIR] Upstream CreateOp for ComplexType with folder #143192
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
[CIR] Upstream CreateOp for ComplexType with folder #143192
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) ChangesThis change adds support for the create op for ComplexType with folder and support for empty init list Patch is 22.07 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/143192.diff 15 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index bd847731193ab..5f72545ea020d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2226,4 +2226,36 @@ def VecTernaryOp : CIR_Op<"vec.ternary",
let hasVerifier = 1;
}
+//===----------------------------------------------------------------------===//
+// ComplexCreateOp
+//===----------------------------------------------------------------------===//
+
+def ComplexCreateOp : CIR_Op<"complex.create", [Pure, SameTypeOperands]> {
+ let summary = "Create a complex value from its real and imaginary parts";
+ let description = [{
+ The `cir.complex.create` operation takes two operands that represent the
+ real and imaginary part of a complex number, and yields the complex number.
+
+ ```mlir
+ %0 = cir.const #cir.fp<1.000000e+00> : !cir.double
+ %1 = cir.const #cir.fp<2.000000e+00> : !cir.double
+ %2 = cir.complex.create %0, %1 : !cir.complex<!cir.double>
+ ```
+ }];
+
+ let results = (outs CIR_ComplexType:$result);
+ let arguments = (ins
+ CIR_AnyIntOrFloatType:$real,
+ CIR_AnyIntOrFloatType:$imag
+ );
+
+ let assemblyFormat = [{
+ $real `,` $imag
+ `:` qualified(type($real)) `->` qualified(type($result)) attr-dict
+ }];
+
+ let hasVerifier = 1;
+ let hasFolder = 1;
+}
+
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index fb96976075130..41d7d725a09e0 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -600,7 +600,8 @@ def CIRRecordType : Type<
def CIR_AnyType : AnyTypeOf<[
CIR_VoidType, CIR_BoolType, CIR_ArrayType, CIR_VectorType, CIR_IntType,
- CIR_AnyFloatType, CIR_PointerType, CIR_FuncType, CIR_RecordType
+ CIR_AnyFloatType, CIR_PointerType, CIR_FuncType, CIR_RecordType,
+ CIR_ComplexType
]>;
#endif // MLIR_CIR_DIALECT_CIR_TYPES
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index f1e0c15d41f64..473e4dc7a81a4 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -233,7 +233,6 @@ struct MissingFeatures {
// Future CIR operations
static bool awaitOp() { return false; }
static bool callOp() { return false; }
- static bool complexCreateOp() { return false; }
static bool complexImagOp() { return false; }
static bool complexRealOp() { return false; }
static bool ifOp() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 5f33ae1af35ee..308b51be6c30b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -323,6 +323,12 @@ 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);
+ }
+
/// Create a cir.ptr_stride operation to get access to an array element.
/// \p idx is the index of the element to access, \p shouldDecay is true if
/// the result should decay to a pointer to the element type.
diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index 80b0172090aa3..3e2c96c5aaeaf 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -255,7 +255,13 @@ void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *d,
emitScalarInit(init, getLoc(d->getSourceRange()), lvalue);
return;
case cir::TEK_Complex: {
- cgm.errorNYI(init->getSourceRange(), "emitExprAsInit: complex type");
+ mlir::Value complex = emitComplexExpr(init);
+ if (capturedByInit)
+ cgm.errorNYI(init->getSourceRange(),
+ "emitExprAsInit: complex type captured by init");
+ mlir::Location loc = getLoc(init->getExprLoc());
+ emitStoreOfComplex(loc, complex, lvalue,
+ /*init*/ true);
return;
}
case cir::TEK_Aggregate:
@@ -344,8 +350,8 @@ void CIRGenFunction::emitDecl(const Decl &d) {
// None of these decls require codegen support.
return;
- case Decl::Enum: // enum X;
- case Decl::Record: // struct/union/class X;
+ case Decl::Enum: // enum X;
+ case Decl::Record: // struct/union/class X;
case Decl::CXXRecord: // struct/union/class X; [C++]
case Decl::NamespaceAlias:
case Decl::Using: // using X; [C++]
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 1175fdc0be2cf..a8f927befcb75 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -1495,3 +1495,14 @@ cir::AllocaOp CIRGenFunction::createTempAlloca(mlir::Type ty,
emitAlloca(name.str(), ty, loc, CharUnits(), ip, arraySize)
.getDefiningOp());
}
+
+/// An LValue is a candidate for having its loads and stores be made atomic if
+/// we are operating under /volatile:ms *and* the LValue itself is volatile and
+/// performing such an operation can be performed without a libcall.
+bool CIRGenFunction::isLValueSuitableForInlineAtomic(LValue lv) {
+ if (!cgm.getLangOpts().MSVolatile)
+ return false;
+
+ cgm.errorNYI("LValueSuitableForInlineAtomic LangOpts MSVolatile");
+ return false;
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
new file mode 100644
index 0000000000000..e7eaebac01341
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp
@@ -0,0 +1,81 @@
+#include "CIRGenBuilder.h"
+#include "CIRGenFunction.h"
+
+#include "clang/AST/StmtVisitor.h"
+
+using namespace clang;
+using namespace clang::CIRGen;
+
+namespace {
+class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> {
+ CIRGenFunction &cgf;
+ CIRGenBuilderTy &builder;
+
+public:
+ explicit ComplexExprEmitter(CIRGenFunction &cgf)
+ : cgf(cgf), builder(cgf.getBuilder()) {}
+
+ /// EmitStoreOfComplex - Store the specified real/imag parts into the
+ /// specified value pointer.
+ void emitStoreOfComplex(mlir::Location loc, mlir::Value val, LValue lv,
+ bool isInit);
+
+ mlir::Value VisitInitListExpr(InitListExpr *e);
+};
+
+} // namespace
+
+static const ComplexType *getComplexType(QualType type) {
+ type = type.getCanonicalType();
+ if (const ComplexType *comp = dyn_cast<ComplexType>(type))
+ return comp;
+ return cast<ComplexType>(cast<AtomicType>(type)->getValueType());
+}
+
+void ComplexExprEmitter::emitStoreOfComplex(mlir::Location loc, mlir::Value val,
+ LValue lv, bool isInit) {
+ if (lv.getType()->isAtomicType() ||
+ (!isInit && cgf.isLValueSuitableForInlineAtomic(lv))) {
+ cgf.cgm.errorNYI("StoreOfComplex with Atomic LV");
+ return;
+ }
+
+ const Address destAddr = lv.getAddress();
+ builder.createStore(loc, val, destAddr);
+}
+
+mlir::Value ComplexExprEmitter::VisitInitListExpr(InitListExpr *e) {
+ if (e->getNumInits() == 2) {
+ mlir::Value real = cgf.emitScalarExpr(e->getInit(0));
+ mlir::Value imag = cgf.emitScalarExpr(e->getInit(1));
+ return builder.createComplexCreate(cgf.getLoc(e->getExprLoc()), real, imag);
+ }
+
+ if (e->getNumInits() == 1) {
+ cgf.cgm.errorNYI("Create Complex with InitList with size 1");
+ return {};
+ }
+
+ assert(e->getNumInits() == 0 && "Unexpected number of inits");
+ mlir::Location loc = cgf.getLoc(e->getExprLoc());
+ QualType complexElemTy =
+ e->getType()->castAs<clang::ComplexType>()->getElementType();
+ mlir::Type complexElemLLVMTy = cgf.convertType(complexElemTy);
+ mlir::TypedAttr defaultValue = builder.getZeroInitAttr(complexElemLLVMTy);
+ auto complexTy = cir::ComplexType::get(complexElemLLVMTy);
+ auto complexAttr =
+ cir::ConstComplexAttr::get(complexTy, defaultValue, defaultValue);
+ return builder.create<cir::ConstantOp>(loc, complexAttr);
+}
+
+mlir::Value CIRGenFunction::emitComplexExpr(const Expr *e) {
+ assert(e && getComplexType(e->getType()) &&
+ "Invalid complex expression to emit");
+
+ return ComplexExprEmitter(*this).Visit(const_cast<Expr *>(e));
+}
+
+void CIRGenFunction::emitStoreOfComplex(mlir::Location loc, mlir::Value v,
+ LValue dest, bool isInit) {
+ ComplexExprEmitter(*this).emitStoreOfComplex(loc, v, dest, isInit);
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index ee014adc961be..e17119cf34e98 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -327,6 +327,8 @@ class CIRGenFunction : public CIRGenTypeCache {
PrototypeWrapper(const clang::ObjCMethodDecl *md) : p(md) {}
};
+ bool isLValueSuitableForInlineAtomic(LValue lv);
+
/// An abstract representation of regular/ObjC call/message targets.
class AbstractCallee {
/// The function declaration of the callee.
@@ -763,6 +765,10 @@ class CIRGenFunction : public CIRGenTypeCache {
mlir::LogicalResult emitForStmt(const clang::ForStmt &s);
+ /// Emit the computation of the specified expression of complex type,
+ /// returning the result.
+ mlir::Value emitComplexExpr(const Expr *e);
+
void emitCompoundStmt(const clang::CompoundStmt &s);
void emitCompoundStmtWithoutScope(const clang::CompoundStmt &s);
@@ -849,6 +855,9 @@ class CIRGenFunction : public CIRGenTypeCache {
void emitScalarInit(const clang::Expr *init, mlir::Location loc,
LValue lvalue, bool capturedByInit = false);
+ void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest,
+ bool isInit);
+
void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile,
clang::QualType ty, bool isInit = false,
bool isNontemporal = false);
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt
index 185a0e10547af..63226a313c599 100644
--- a/clang/lib/CIR/CodeGen/CMakeLists.txt
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -16,6 +16,7 @@ add_clang_library(clangCIR
CIRGenDeclOpenACC.cpp
CIRGenExpr.cpp
CIRGenExprAggregate.cpp
+ CIRGenExprComplex.cpp
CIRGenExprConstant.cpp
CIRGenExprScalar.cpp
CIRGenFunction.cpp
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index d7999f59bd021..00e963aa056ba 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1641,6 +1641,34 @@ LogicalResult cir::VecTernaryOp::verify() {
return success();
}
+//===----------------------------------------------------------------------===//
+// ComplexCreateOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::ComplexCreateOp::verify() {
+ if (getType().getElementType() != getReal().getType()) {
+ emitOpError()
+ << "operand type of cir.complex.create does not match its result type";
+ return failure();
+ }
+
+ return success();
+}
+
+OpFoldResult cir::ComplexCreateOp::fold(FoldAdaptor adaptor) {
+ mlir::Attribute real = adaptor.getReal();
+ mlir::Attribute imag = adaptor.getImag();
+ if (!real || !imag)
+ return {};
+
+ // When both of real and imag are constants, we can fold the operation into an
+ // `#cir.const_complex` operation.
+ auto realAttr = mlir::cast<mlir::TypedAttr>(real);
+ auto imagAttr = mlir::cast<mlir::TypedAttr>(imag);
+ auto complexTy = cir::ComplexType::get(realAttr.getType());
+ return cir::ConstComplexAttr::get(complexTy, realAttr, imagAttr);
+}
+
//===----------------------------------------------------------------------===//
// TableGen'd op method definitions
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
index 7d03e374c27e8..7abb9f1ebdb0f 100644
--- a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp
@@ -134,14 +134,13 @@ void CIRCanonicalizePass::runOnOperation() {
getOperation()->walk([&](Operation *op) {
assert(!cir::MissingFeatures::switchOp());
assert(!cir::MissingFeatures::tryOp());
- assert(!cir::MissingFeatures::complexCreateOp());
assert(!cir::MissingFeatures::complexRealOp());
assert(!cir::MissingFeatures::complexImagOp());
assert(!cir::MissingFeatures::callOp());
// CastOp, UnaryOp, VecExtractOp and VecShuffleDynamicOp are here to perform
// a manual `fold` in applyOpPatternsGreedily.
if (isa<BrOp, BrCondOp, CastOp, ScopeOp, SwitchOp, SelectOp, UnaryOp,
- VecExtractOp, VecShuffleDynamicOp>(op))
+ VecExtractOp, VecShuffleDynamicOp, ComplexCreateOp>(op))
ops.push_back(op);
});
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 977c8912c1d11..6ce5b67f5e4f9 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -869,7 +869,32 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite(
rewriter.eraseOp(op);
return mlir::success();
}
- } else {
+ } else if (auto complexTy = mlir::dyn_cast<cir::ComplexType>(op.getType())) {
+ auto complexAttr = mlir::cast<cir::ConstComplexAttr>(op.getValue());
+ mlir::Type complexElemTy = complexTy.getElementType();
+ mlir::Type complexElemLLVMTy = typeConverter->convertType(complexElemTy);
+
+ mlir::Attribute components[2];
+ if (mlir::isa<cir::IntType>(complexElemTy)) {
+ components[0] = rewriter.getIntegerAttr(
+ complexElemLLVMTy,
+ mlir::cast<cir::IntAttr>(complexAttr.getReal()).getValue());
+ components[1] = rewriter.getIntegerAttr(
+ complexElemLLVMTy,
+ mlir::cast<cir::IntAttr>(complexAttr.getImag()).getValue());
+ } else {
+ components[0] = rewriter.getFloatAttr(
+ complexElemLLVMTy,
+ mlir::cast<cir::FPAttr>(complexAttr.getReal()).getValue());
+ components[1] = rewriter.getFloatAttr(
+ complexElemLLVMTy,
+ mlir::cast<cir::FPAttr>(complexAttr.getImag()).getValue());
+ }
+
+ attr = rewriter.getArrayAttr(components);
+ }
+
+ else {
return op.emitError() << "unsupported constant type " << op.getType();
}
@@ -1771,7 +1796,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMVecInsertOpLowering,
CIRToLLVMVecCmpOpLowering,
CIRToLLVMVecShuffleDynamicOpLowering,
- CIRToLLVMVecTernaryOpLowering
+ CIRToLLVMVecTernaryOpLowering,
+ CIRToLLVMComplexCreateOpLowering
// clang-format on
>(converter, patterns.getContext());
@@ -1990,6 +2016,24 @@ mlir::LogicalResult CIRToLLVMVecTernaryOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMComplexCreateOpLowering::matchAndRewrite(
+ cir::ComplexCreateOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ mlir::Type complexLLVMTy =
+ getTypeConverter()->convertType(op.getResult().getType());
+ auto initialComplex =
+ rewriter.create<mlir::LLVM::UndefOp>(op->getLoc(), complexLLVMTy);
+
+ auto realComplex = rewriter.create<mlir::LLVM::InsertValueOp>(
+ op->getLoc(), initialComplex, adaptor.getReal(), 0);
+
+ auto complex = rewriter.create<mlir::LLVM::InsertValueOp>(
+ op->getLoc(), realComplex, adaptor.getImag(), 1);
+
+ rewriter.replaceOp(op, complex);
+ return mlir::success();
+}
+
std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
return std::make_unique<ConvertCIRToLLVMPass>();
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index d1efa4e181a07..b572fb6a9dfe4 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -378,6 +378,16 @@ class CIRToLLVMVecTernaryOpLowering
mlir::ConversionPatternRewriter &) const override;
};
+class CIRToLLVMComplexCreateOpLowering
+ : public mlir::OpConversionPattern<cir::ComplexCreateOp> {
+public:
+ using mlir::OpConversionPattern<cir::ComplexCreateOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::ComplexCreateOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
} // namespace direct
} // namespace cir
diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp
index 6fa7bca3749cf..3702f809b14f6 100644
--- a/clang/test/CIR/CodeGen/complex.cpp
+++ b/clang/test/CIR/CodeGen/complex.cpp
@@ -27,3 +27,59 @@ float _Complex cf2 = { 1.0f, 2.0f };
// OGCG: {{.*}} = global { float, float } zeroinitializer, align 4
// OGCG: {{.*}} = global { i32, i32 } { i32 1, i32 2 }, align 4
// OGCG: {{.*}} = global { float, float } { float 1.000000e+00, float 2.000000e+00 }, align 4
+
+void foo() { int _Complex c = {}; }
+
+// CIR: %[[INIT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["c", init]
+// CIR: %[[COMPLEX:.*]] = cir.const #cir.const_complex<#cir.int<0> : !s32i, #cir.int<0> : !s32i> : !cir.complex<!s32i>
+// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+
+// LLVM: %[[INIT:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: store { i32, i32 } zeroinitializer, ptr %[[INIT]], align 4
+
+// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0
+// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1
+// OGCG: store i32 0, ptr %[[C_REAL_PTR]], align 4
+// OGCG: store i32 0, ptr %[[C_IMAG_PTR]], align 4
+
+void foo2() { int _Complex c = {1, 2}; }
+
+// CIR: %[[INIT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["c", init]
+// CIR: %[[COMPLEX:.*]] = cir.const #cir.const_complex<#cir.int<1> : !s32i, #cir.int<2> : !s32i> : !cir.complex<!s32i>
+// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+
+// LLVM: %[[INIT:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: store { i32, i32 } { i32 1, i32 2 }, ptr %[[INIT]], align 4
+
+// OGCG: %[[COMPLEX:.*]] = alloca { i32, i32 }, align 4
+// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0
+// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1
+// OGCG: store i32 1, ptr %[[C_REAL_PTR]], align 4
+// OGCG: store i32 2, ptr %[[C_IMAG_PTR]], align 4
+
+void foo3() {
+ int a;
+ int b;
+ int _Complex c = {a, b};
+}
+
+// CIR: %[[INIT:.*]] = cir.alloca !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>, ["c", init]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!s32i>
+// CIR: %[[TMP_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!s32i>
+// CIR: %[[COMPLEX:.*]] = cir.complex.create %[[TMP_A]], %[[TMP_B]] : !s32i -> !cir.complex<!s32i>
+// CIR: cir.store{{.*}} %[[COMPLEX]], %[[INIT]] : !cir.complex<!s32i>, !cir.ptr<!cir.complex<!s32i>>
+
+// LLVM: %[[INIT:.*]] = alloca { i32, i32 }, i64 1, align 4
+// LLVM: %[[TMP_A:.*]] = load i32, ptr {{.*}}, align 4
+// LLVM: %[[TMP_B:.*]] = load i32, ptr {{.*}}, align 4
+// LLVM: %[[TMP:.*]] = insertvalue { i32, i32 } undef, i32 %[[TMP_A]], 0
+// LLVM: %[[TMP_2:.*]] = insertvalue { i32, i32 } %[[TMP]], i32 %[[TMP_B]], 1
+// LLVM: store { i32, i32 } %[[TMP_2]], ptr %[[INIT]], align 4
+
+// OGCG: %[[REAL_VAL:.*]] = load i32, ptr {{.*}}, align 4
+// OGCG: %[[IMAG_VAL:.*]] = load i32, ptr {{.*}}, align 4
+// OGCG: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 0
+// OGCG: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX]], i32 0, i32 1
+// OGCG: st...
[truncated]
|
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.
This looks good. Just a request for a couple more test cases.
void foo3() { | ||
int a; | ||
int b; | ||
int _Complex c = {a, b}; |
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
and another for a mixed constant/variable initializer?
```mlir | ||
%0 = cir.const #cir.fp<1.000000e+00> : !cir.double | ||
%1 = cir.const #cir.fp<2.000000e+00> : !cir.double | ||
%2 = cir.complex.create %0, %1 : !cir.complex<!cir.double> |
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.
this does not match assemblyFormat
%2 = cir.complex.create %0, %1 : !cir.complex<!cir.double> | |
%2 = cir.complex.create %0, %1 : !cir.double -> !cir.complex<!cir.double> |
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, some nits
explicit ComplexExprEmitter(CIRGenFunction &cgf) | ||
: cgf(cgf), builder(cgf.getBuilder()) {} | ||
|
||
/// EmitStoreOfComplex - Store the specified real/imag parts into the |
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.
You can remove the "EmitStoreOfComplex - " part, LLVM does not use it anymore.
return {}; | ||
|
||
// When both of real and imag are constants, we can fold the operation into an | ||
// `#cir.const_complex` operation. |
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.
Thanks for adding a folder :)
Backport support for Complex value initialization from the empty InitList. Backported from llvm/llvm-project#143192
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
clang/lib/CIR/CodeGen/CIRGenDecl.cpp
Outdated
"emitExprAsInit: complex type captured by init"); | ||
mlir::Location loc = getLoc(init->getExprLoc()); | ||
emitStoreOfComplex(loc, complex, lvalue, | ||
/*init*/ true); |
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.
/*init*/ true); | |
/*isInit=*/ true); |
} | ||
|
||
assert(e->getNumInits() == 0 && "Unexpected number of inits"); | ||
mlir::Location loc = cgf.getLoc(e->getExprLoc()); |
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.
move this to the start of function and remove duplicit cgf.getLoc
from line 51
mlir::TypedAttr defaultValue = builder.getZeroInitAttr(complexElemLLVMTy); | ||
auto complexTy = cir::ComplexType::get(complexElemLLVMTy); | ||
auto complexAttr = | ||
cir::ConstComplexAttr::get(complexTy, defaultValue, defaultValue); |
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.
It might be worth adding ConstComplexAttr
builder just from 2 values as ComplexType
can be inferred inside of the builder. Resulting in here:
mlir::TypedAttr defaultValue = builder.getZeroInitAttr(complexElemLLVMTy); | |
auto complexTy = cir::ComplexType::get(complexElemLLVMTy); | |
auto complexAttr = | |
cir::ConstComplexAttr::get(complexTy, defaultValue, defaultValue); | |
mlir::TypedAttr defaultValue = builder.getZeroInitAttr(complexElemLLVMTy); | |
auto complexAttr = cir::ConstComplexAttr::get(defaultValue, defaultValue); |
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.
This can be used on multiple other places.
dd58178
to
8d31f9c
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
1f325ea
to
cd9aa41
Compare
cd9aa41
to
95eabbf
Compare
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/186/builds/9883 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/130/builds/13734 Here is the relevant piece of the build log for the reference
|
This change adds support for the create op for ComplexType with folder and support for empty init list llvm#141365
This change adds support for the create op for ComplexType with folder and support for empty init list llvm#141365
This change adds support for the create op for ComplexType with folder and support for empty init list
#141365