https://github.com/AmrDeveloper created https://github.com/llvm/llvm-project/pull/144235
None >From 80571d5272f70d4b273f4277af1bfb064fbe6e89 Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Sat, 14 Jun 2025 21:51:43 +0200 Subject: [PATCH] [CIR] Upstream ComplexRealPtrOp for ComplexType --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 29 +++++++++++++++++++ .../CIR/Dialect/IR/CIRTypeConstraints.td | 24 +++++++++++++++ clang/lib/CIR/CodeGen/CIRGenBuilder.h | 13 +++++++++ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 25 ++++++++++++++-- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 19 ++++++++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 20 ++++++++++++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 10 +++++++ clang/test/CIR/CodeGen/complex.cpp | 13 +++++++++ 8 files changed, 150 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index bd36d228578b7..17279f0a9985a 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2385,4 +2385,33 @@ def ComplexCreateOp : CIR_Op<"complex.create", [Pure, SameTypeOperands]> { 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.complex<!cir.double>> -> !cir.ptr<!cir.double> + ``` + }]; + + 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; +} + #endif // CLANG_CIR_DIALECT_IR_CIROPS_TD diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td index bcd516e27cc76..d59ff62248e1f 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,19 @@ class CIR_PtrToPtrTo<code type, string summary> : CIR_ConfinedType<CIR_AnyPtrType, [CIR_IsPtrToPtrToPred<type>], "pointer to pointer to " # summary>; +// Pointee type constraint bases +class CIR_PointeePred<Pred pred> : SubstLeaves<"$_self", + "::mlir::cast<::cir::PointerType>($_self).getPointee()", pred>; + +class CIR_PtrToAnyOf<list<Type> types, string summary = ""> + : CIR_ConfinedType<CIR_AnyPtrType, + [Or<!foreach(type, types, CIR_PointeePred<type.predicate>)>], + !if(!empty(summary), + "pointer to " # CIR_TypeSummaries<types>.value, + summary)>; + +class CIR_PtrToType<Type type> : CIR_PtrToAnyOf<[type]>; + // Void pointer type constraints def CIR_VoidPtrType : CIR_PtrTo<"::cir::VoidType", "void type">, @@ -192,6 +211,11 @@ def CIR_PtrToVoidPtrType "$_builder.getType<" # cppType # ">(" "cir::VoidType::get($_builder.getContext())))">; +// Pointer to type constraints +def CIR_PtrToIntOrFloatType : CIR_PtrToType<CIR_AnyIntOrFloatType>; + +def CIR_PtrToComplexType : CIR_PtrToType<CIR_AnyComplexType>; + //===----------------------------------------------------------------------===// // Vector Type predicates //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index e38faba83b80c..3f7ea5bccb6d5 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -366,6 +366,19 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag); } + /// 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 createRealPtr(mlir::Location loc, mlir::Value value) { + auto srcPtrTy = mlir::cast<cir::PointerType>(value.getType()); + auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee()); + return create<cir::ComplexRealPtrOp>( + loc, getPointerTo(srcComplexTy.getElementType()), value); + } + + Address createRealPtr(mlir::Location loc, Address addr) { + return Address{createRealPtr(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 2e43f10be132c..a682586562e04 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -541,8 +541,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<cir::ComplexType>(lv.getAddress().getElementType())) { + assert(e->getSubExpr()->getType()->isArithmeticType()); + return lv; + } + + QualType exprTy = getContext().getCanonicalType(e->getSubExpr()->getType()); + QualType elemTy = exprTy->castAs<clang::ComplexType>()->getElementType(); + mlir::Location loc = getLoc(e->getExprLoc()); + Address component = builder.createRealPtr(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 5578d4f5825a9..99ae4dd59120a 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -1775,6 +1775,25 @@ OpFoldResult cir::ComplexCreateOp::fold(FoldAdaptor adaptor) { return cir::ConstComplexAttr::get(realAttr, imagAttr); } +//===----------------------------------------------------------------------===// +// ComplexRealPtrOp +//===----------------------------------------------------------------------===// + +LogicalResult cir::ComplexRealPtrOp::verify() { + mlir::Type resultPointeeTy = getType().getPointee(); + cir::PointerType operandPtrTy = getOperand().getType(); + auto operandPointeeTy = + mlir::cast<cir::ComplexType>(operandPtrTy.getPointee()); + + if (resultPointeeTy != operandPointeeTy.getElementType()) { + emitOpError() + << "cir.complex.real_ptr 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 6a4e4e4a7df3b..c11992a4bdc61 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1836,7 +1836,8 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMVecShuffleOpLowering, CIRToLLVMVecShuffleDynamicOpLowering, CIRToLLVMVecTernaryOpLowering, - CIRToLLVMComplexCreateOpLowering + CIRToLLVMComplexCreateOpLowering, + CIRToLLVMComplexRealPtrOpLowering // clang-format on >(converter, patterns.getContext()); @@ -2140,6 +2141,23 @@ mlir::LogicalResult CIRToLLVMComplexCreateOpLowering::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<mlir::LLVM::GEPOp>( + op, resultLLVMTy, elementLLVMTy, adaptor.getOperand(), gepIndices, + inboundsNuw); + 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 a809818063547..caee3e9cd6980 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -418,6 +418,16 @@ class CIRToLLVMComplexCreateOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMComplexRealPtrOpLowering + : public mlir::OpConversionPattern<cir::ComplexRealPtrOp> { +public: + using mlir::OpConversionPattern<cir::ComplexRealPtrOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::ComplexRealPtrOp 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 d193b9f32efbc..182673a69be90 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -176,3 +176,16 @@ void foo7() { // OGCG: store float %[[TMP_A]], ptr %[[C_REAL_PTR]], align 4 // OGCG: store float 2.000000e+00, ptr %[[C_IMAG_PTR]], align 4 +void foo10() { + double _Complex c; + double *realPtr = &__real__ c; +} + +// CIR: %[[COMPLEX:.*]] = cir.alloca !cir.complex<!cir.double>, !cir.ptr<!cir.complex<!cir.double>>, ["c"] +// CIR: %[[REAL_PTR:.*]] = cir.complex.real_ptr %[[COMPLEX]] : !cir.ptr<!cir.complex<!cir.double>> -> !cir.ptr<!cir.double> + +// 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits