From 1543f10164d64c28951ae4fff396f58877c43f74 Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Mon, 7 Jul 2025 20:52:33 +0200 Subject: [PATCH 1/2] [CIR] Upstream ComplexRealPtrOp for ComplexType --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 30 +++++++++++++++++++ .../CIR/Dialect/IR/CIRTypeConstraints.td | 24 +++++++++++++++ clang/lib/CIR/CodeGen/CIRGenBuilder.h | 14 +++++++++ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 25 ++++++++++++++-- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 18 +++++++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 18 +++++++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 30 ++++++++++++------- clang/test/CIR/CodeGen/complex.cpp | 16 +++++++++- clang/test/CIR/IR/invalid-complex.cir | 12 ++++++++ 9 files changed, 174 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index d5cdb5aa91251..99fcb322a42d5 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2612,6 +2612,36 @@ def ComplexImagOp : CIR_Op<"complex.imag", [Pure]> { let hasFolder = 1; } +//===----------------------------------------------------------------------===// +// ComplexRealPtrOp +//===----------------------------------------------------------------------===// + +def ComplexRealPtrOp : CIR_Op<"complex.real_ptr", [Pure]> { + let summary = "Derive a pointer to the real part of a complex value"; + let description = [{ + `cir.complex.real_ptr` operation takes a pointer operand that points to a + complex value of type `!cir.complex` and yields a pointer to the real part + of the operand. + + Example: + + ```mlir + %1 = cir.complex.real_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/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td index bcd516e27cc76..2bf77583465a6 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td @@ -159,6 +159,12 @@ def CIR_AnyIntOrFloatType : AnyTypeOf<[CIR_AnyFloatType, CIR_AnyIntType], let cppFunctionName = "isAnyIntegerOrFloatingPointType"; } +//===----------------------------------------------------------------------===// +// Complex Type predicates +//===----------------------------------------------------------------------===// + +def CIR_AnyComplexType : CIR_TypeBase<"::cir::ComplexType", "complex type">; + //===----------------------------------------------------------------------===// // Pointer Type predicates //===----------------------------------------------------------------------===// @@ -180,6 +186,17 @@ class CIR_PtrToPtrTo : CIR_ConfinedType], "pointer to pointer to " # summary>; +// Pointee type constraint bases +class CIR_PointeePred : SubstLeaves<"$_self", + "::mlir::cast<::cir::PointerType>($_self).getPointee()", pred>; + +class CIR_PtrToAnyOf types, string summary = ""> +: CIR_ConfinedType)>], + !if(!empty(summary), + "pointer to " # CIR_TypeSummaries.value, + summary)>; + // Void pointer type constraints def CIR_VoidPtrType : CIR_PtrTo<"::cir::VoidType", "void type">, @@ -192,6 +209,13 @@ def CIR_PtrToVoidPtrType "$_builder.getType<" # cppType # ">(" "cir::VoidType::get($_builder.getContext())))">; +class CIR_PtrToType : CIR_PtrToAnyOf<[type]>; + +// Pointer to type constraints +def CIR_PtrToIntOrFloatType : CIR_PtrToType; + +def CIR_PtrToComplexType : CIR_PtrToType; + //===----------------------------------------------------------------------===// // Vector Type predicates //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index d95ea36a5e0d0..d0b6b6918f0e2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -364,6 +364,20 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { return create(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) { + auto srcPtrTy = mlir::cast(value.getType()); + auto srcComplexTy = mlir::cast(srcPtrTy.getPointee()); + return create( + loc, getPointerTo(srcComplexTy.getElementType()), value); + } + + Address createComplexRealPtr(mlir::Location loc, Address addr) { + return Address{createComplexRealPtr(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 6d2dfb9269b5e..cc32072631017 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -637,8 +637,29 @@ LValue CIRGenFunction::emitUnaryOpLValue(const UnaryOperator *e) { } case UO_Real: case UO_Imag: { - cgm.errorNYI(e->getSourceRange(), "UnaryOp real/imag"); - return LValue(); + 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"); + + // __real is valid on scalars. This is a faster way of testing that. + // __imag can only produce an rvalue on scalars. + if (e->getOpcode() == UO_Real && + !mlir::isa(lv.getAddress().getElementType())) { + assert(e->getSubExpr()->getType()->isArithmeticType()); + return lv; + } + + 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()); + LValue elemLV = makeAddrLValue(component, elemTy); + elemLV.getQuals().addQualifiers(lv.getQuals()); + return elemLV; } case UO_PreInc: case UO_PreDec: { diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 9e7615bdd7a7f..5fe5ac827fff9 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2097,6 +2097,24 @@ OpFoldResult cir::ComplexImagOp::fold(FoldAdaptor adaptor) { return complex ? complex.getImag() : nullptr; } +//===----------------------------------------------------------------------===// +// ComplexRealPtrOp +//===----------------------------------------------------------------------===// + +LogicalResult cir::ComplexRealPtrOp::verify() { + mlir::Type resultPointeeTy = getType().getPointee(); + cir::PointerType operandPtrTy = getOperand().getType(); + auto operandPointeeTy = + mlir::cast(operandPtrTy.getPointee()); + + if (resultPointeeTy != operandPointeeTy.getElementType()) { + emitOpError() << ": result type does not match operand type"; + return failure(); + } + + 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 813be0cf1cfb7..3446265769a2c 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2052,6 +2052,7 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMComplexCreateOpLowering, CIRToLLVMComplexImagOpLowering, CIRToLLVMComplexRealOpLowering, + CIRToLLVMComplexRealPtrOpLowering, CIRToLLVMConstantOpLowering, CIRToLLVMExpectOpLowering, CIRToLLVMFuncOpLowering, @@ -2526,6 +2527,23 @@ mlir::LogicalResult CIRToLLVMSetBitfieldOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMComplexRealPtrOpLowering::matchAndRewrite( + cir::ComplexRealPtrOp 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, 0}; + 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 CIRToLLVMGetBitfieldOpLowering::matchAndRewrite( cir::GetBitfieldOp 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 9fd0de353d9eb..ed158eb7289dd 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -513,6 +513,26 @@ class CIRToLLVMComplexImagOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMComplexRealPtrOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::ComplexRealPtrOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + +class CIRToLLVMComplexAddOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::ComplexAddOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMSetBitfieldOpLowering : public mlir::OpConversionPattern { public: @@ -533,16 +553,6 @@ class CIRToLLVMGetBitfieldOpLowering mlir::ConversionPatternRewriter &) const override; }; -class CIRToLLVMComplexAddOpLowering - : public mlir::OpConversionPattern { -public: - using mlir::OpConversionPattern::OpConversionPattern; - - mlir::LogicalResult - matchAndRewrite(cir::ComplexAddOp 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 6e7e889df146f..c00da5472fa9f 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -216,6 +216,20 @@ void foo9(double a, double b) { // OGCG: store double %[[TMP_A]], ptr %[[C_REAL_PTR]], align 8 // OGCG: store double %[[TMP_B]], ptr %[[C_IMAG_PTR]], align 8 +void foo10() { + double _Complex c; + double *realPtr = &__real__ c; +} + +// CIR: %[[COMPLEX:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["c"] +// CIR: %[[REAL_PTR:.*]] = cir.complex.real_ptr %[[COMPLEX]] : !cir.ptr> -> !cir.ptr + +// LLVM: %[[COMPLEX:.*]] = alloca { double, double }, i64 1, align 8 +// LLVM: %[[REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 0 + +// OGCG: %[[COMPLEX:.*]] = alloca { double, double }, align 8 +// OGCG: %[[REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX]], i32 0, i32 0 + void foo12() { double _Complex c; double imag = __imag__ c; @@ -751,4 +765,4 @@ void foo29() { // OGCG: %[[INIT_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[INIT]], i32 0, i32 0 // OGCG: %[[INIT_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[INIT]], i32 0, i32 1 // OGCG: store i32 0, ptr %[[INIT_REAL_PTR]], align 4 -// OGCG: store i32 0, ptr %[[INIT_IMAG_PTR]], align 4 \ No newline at end of file +// OGCG: store i32 0, ptr %[[INIT_IMAG_PTR]], align 4 diff --git a/clang/test/CIR/IR/invalid-complex.cir b/clang/test/CIR/IR/invalid-complex.cir index 2414809f7dbca..3a11b631a2ac7 100644 --- a/clang/test/CIR/IR/invalid-complex.cir +++ b/clang/test/CIR/IR/invalid-complex.cir @@ -45,3 +45,15 @@ module { cir.return } } + + +// ----- + +module { + cir.func @complex_real_ptr_invalid_result_type() -> !cir.double { + %0 = cir.alloca !cir.complex, !cir.ptr>, ["c"] + // expected-error @below {{result type does not match operand type}} + %1 = cir.complex.real_ptr %0 : !cir.ptr> -> !cir.ptr + cir.return + } +} From d1818136e15ab7c566138ab7637042290b70c473 Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Thu, 10 Jul 2025 18:33:54 +0200 Subject: [PATCH 2/2] Add MissingFeatures --- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index cc32072631017..b1d6b8047a0ab 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -657,6 +657,7 @@ LValue CIRGenFunction::emitUnaryOpLValue(const UnaryOperator *e) { QualType elemTy = exprTy->castAs()->getElementType(); mlir::Location loc = getLoc(e->getExprLoc()); Address component = builder.createComplexRealPtr(loc, lv.getAddress()); + assert(!cir::MissingFeatures::opTBAA()); LValue elemLV = makeAddrLValue(component, elemTy); elemLV.getQuals().addQualifiers(lv.getQuals()); return elemLV;