From 8fc31d0c3e1797fa6887ac8831c2e0eaadfb64fa Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Sat, 12 Jul 2025 00:56:36 +0200 Subject: [PATCH] [CIR] Upstream ComplexImagPtrOp for ComplexType --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 30 +++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenBuilder.h | 15 ++++++++++ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 10 +++---- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 21 +++++++++++-- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 18 +++++++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 10 +++++++ clang/test/CIR/CodeGen/complex.cpp | 14 +++++++++ 7 files changed, 110 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 99fcb322a42d5..aac803247bc22 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2642,6 +2642,36 @@ def ComplexRealPtrOp : CIR_Op<"complex.real_ptr", [Pure]> { let hasVerifier = 1; } +//===----------------------------------------------------------------------===// +// ComplexImagPtrOp +//===----------------------------------------------------------------------===// + +def ComplexImagPtrOp : CIR_Op<"complex.imag_ptr", [Pure]> { + let summary = "Derive a pointer to the imaginary part of a complex value"; + let description = [{ + `cir.complex.imag_ptr` operation takes a pointer operand that points to a + complex value of type `!cir.complex` and yields a pointer to the imaginary + part of the operand. + + Example: + + ```mlir + %1 = cir.complex.imag_ptr %0 : !cir.ptr> + -> !cir.ptr + ``` + }]; + + let results = (outs CIR_PtrToIntOrFloatType:$result); + let arguments = (ins CIR_PtrToComplexType:$operand); + + let assemblyFormat = [{ + $operand `:` + qualified(type($operand)) `->` qualified(type($result)) attr-dict + }]; + + let hasVerifier = 1; +} + //===----------------------------------------------------------------------===// // ComplexAddOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index d0b6b6918f0e2..5bd53ebc52ab5 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -378,6 +378,21 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { addr.getAlignment()}; } + /// Create a cir.complex.imag_ptr operation that derives a pointer to the + /// imaginary part of the complex value pointed to by the specified pointer + /// value. + mlir::Value createComplexImagPtr(mlir::Location loc, mlir::Value value) { + auto srcPtrTy = mlir::cast(value.getType()); + auto srcComplexTy = mlir::cast(srcPtrTy.getPointee()); + return create( + loc, getPointerTo(srcComplexTy.getElementType()), value); + } + + Address createComplexImagPtr(mlir::Location loc, Address addr) { + return Address{createComplexImagPtr(loc, addr.getPointer()), + addr.getAlignment()}; + } + /// 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/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index b1d6b8047a0ab..51da48d330f55 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -637,11 +637,6 @@ LValue CIRGenFunction::emitUnaryOpLValue(const UnaryOperator *e) { } case UO_Real: case UO_Imag: { - if (op == UO_Imag) { - cgm.errorNYI(e->getSourceRange(), "UnaryOp real/imag"); - return LValue(); - } - LValue lv = emitLValue(e->getSubExpr()); assert(lv.isSimple() && "real/imag on non-ordinary l-value"); @@ -656,7 +651,10 @@ LValue CIRGenFunction::emitUnaryOpLValue(const UnaryOperator *e) { QualType exprTy = getContext().getCanonicalType(e->getSubExpr()->getType()); QualType elemTy = exprTy->castAs()->getElementType(); mlir::Location loc = getLoc(e->getExprLoc()); - Address component = builder.createComplexRealPtr(loc, lv.getAddress()); + Address component = + e->getOpcode() == UO_Real + ? builder.createComplexRealPtr(loc, lv.getAddress()) + : builder.createComplexImagPtr(loc, lv.getAddress()); assert(!cir::MissingFeatures::opTBAA()); LValue elemLV = makeAddrLValue(component, elemTy); elemLV.getQuals().addQualifiers(lv.getQuals()); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 5fe5ac827fff9..f0416b6aba6e4 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -21,6 +21,7 @@ #include "clang/CIR/Dialect/IR/CIROpsDialect.cpp.inc" #include "clang/CIR/Dialect/IR/CIROpsEnums.cpp.inc" #include "clang/CIR/MissingFeatures.h" +#include "llvm/Support/LogicalResult.h" #include @@ -2108,13 +2109,29 @@ LogicalResult cir::ComplexRealPtrOp::verify() { mlir::cast(operandPtrTy.getPointee()); if (resultPointeeTy != operandPointeeTy.getElementType()) { - emitOpError() << ": result type does not match operand type"; - return failure(); + return emitOpError() << ": result type does not match operand type"; } return success(); } +//===----------------------------------------------------------------------===// +// ComplexImagPtrOp +//===----------------------------------------------------------------------===// + +LogicalResult cir::ComplexImagPtrOp::verify() { + mlir::Type resultPointeeTy = getType().getPointee(); + cir::PointerType operandPtrTy = getOperand().getType(); + auto operandPointeeTy = + mlir::cast(operandPtrTy.getPointee()); + + if (resultPointeeTy != operandPointeeTy.getElementType()) { + return emitOpError() + << "cir.complex.imag_ptr result type does not match operand type"; + } + return success(); +} + //===----------------------------------------------------------------------===// // TableGen'd op method definitions //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 3446265769a2c..338dbbcc2be36 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2051,6 +2051,7 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMComplexAddOpLowering, CIRToLLVMComplexCreateOpLowering, CIRToLLVMComplexImagOpLowering, + CIRToLLVMComplexImagPtrOpLowering, CIRToLLVMComplexRealOpLowering, CIRToLLVMComplexRealPtrOpLowering, CIRToLLVMConstantOpLowering, @@ -2527,6 +2528,23 @@ mlir::LogicalResult CIRToLLVMSetBitfieldOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMComplexImagPtrOpLowering::matchAndRewrite( + cir::ComplexImagPtrOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + cir::PointerType operandTy = op.getOperand().getType(); + mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType()); + mlir::Type elementLLVMTy = + getTypeConverter()->convertType(operandTy.getPointee()); + + mlir::LLVM::GEPArg gepIndices[2] = {{0}, {1}}; + mlir::LLVM::GEPNoWrapFlags inboundsNuw = + mlir::LLVM::GEPNoWrapFlags::inbounds | mlir::LLVM::GEPNoWrapFlags::nuw; + rewriter.replaceOpWithNewOp( + op, resultLLVMTy, elementLLVMTy, adaptor.getOperand(), gepIndices, + inboundsNuw); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMComplexRealPtrOpLowering::matchAndRewrite( cir::ComplexRealPtrOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index ed158eb7289dd..1e461f200942c 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -513,6 +513,16 @@ class CIRToLLVMComplexImagOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMComplexImagPtrOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::ComplexImagPtrOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMComplexRealPtrOpLowering : public mlir::OpConversionPattern { public: diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index 88df771e6f272..0a7765fcc730d 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -230,6 +230,20 @@ void foo10() { // OGCG: %[[COMPLEX:.*]] = alloca { double, double }, align 8 // OGCG: %[[REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 0 +void foo11() { + double _Complex c; + double *imagPtr = &__imag__ c; +} + +// CIR: %[[COMPLEX:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["c"] +// CIR: %[[IMAG_PTR:.*]] = cir.complex.imag_ptr %[[COMPLEX]] : !cir.ptr> -> !cir.ptr + +// LLVM: %[[COMPLEX:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: %[[IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 1 + +// OGCG: %[[COMPLEX:.*]] = alloca { double, double }, align 8 +// OGCG: %[[IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 1 + void foo12() { double _Complex c; double imag = __imag__ c;