llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) <details> <summary>Changes</summary> This change adds support for the create op for ComplexType with folder and support for empty init list https://github.com/llvm/llvm-project/issues/141365 --- 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: - (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+32) - (modified) clang/include/clang/CIR/Dialect/IR/CIRTypes.td (+2-1) - (modified) clang/include/clang/CIR/MissingFeatures.h (-1) - (modified) clang/lib/CIR/CodeGen/CIRGenBuilder.h (+6) - (modified) clang/lib/CIR/CodeGen/CIRGenDecl.cpp (+9-3) - (modified) clang/lib/CIR/CodeGen/CIRGenExpr.cpp (+11) - (added) clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp (+81) - (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+9) - (modified) clang/lib/CIR/CodeGen/CMakeLists.txt (+1) - (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+28) - (modified) clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp (+1-2) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+46-2) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h (+10) - (modified) clang/test/CIR/CodeGen/complex.cpp (+56) - (added) clang/test/CIR/Transforms/complex-create-fold.cir (+30) ``````````diff 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] `````````` </details> https://github.com/llvm/llvm-project/pull/143192 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits