[clang] [CIR] Upstream ComplexRealPtrOp for ComplexType (PR #144235)
Amr Hesham via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 7 12:00:11 PDT 2025
https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/144235
>From acab11ee6a8e8041dab689c5518229e358d4f5a1 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Mon, 7 Jul 2025 20:52:33 +0200
Subject: [PATCH] [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 | 10 +++++++
clang/test/CIR/CodeGen/complex.cpp | 16 +++++++++-
clang/test/CIR/IR/invalid-complex.cir | 12 ++++++++
9 files changed, 164 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 6529f1386599c..3c7b8b120af3b 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2521,6 +2521,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.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;
+}
+
//===----------------------------------------------------------------------===//
// Bit Manipulation Operations
//===----------------------------------------------------------------------===//
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<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)>;
+
// 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<Type type> : CIR_PtrToAnyOf<[type]>;
+
+// 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 0b33f6c7d03b7..b09f1baf1d016 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<cir::ComplexImagOp>(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<cir::PointerType>(value.getType());
+ auto srcComplexTy = mlir::cast<cir::ComplexType>(srcPtrTy.getPointee());
+ return create<cir::ComplexRealPtrOp>(
+ 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 68d7f1f5bca48..1defc1d8801bf 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -621,8 +621,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.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 8512b229c2663..68e8434a68b29 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2089,6 +2089,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<cir::ComplexType>(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 5ac42b6a63b09..6d0bf1024043d 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2042,6 +2042,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMComplexCreateOpLowering,
CIRToLLVMComplexImagOpLowering,
CIRToLLVMComplexRealOpLowering,
+ CIRToLLVMComplexRealPtrOpLowering,
CIRToLLVMConstantOpLowering,
CIRToLLVMExpectOpLowering,
CIRToLLVMFuncOpLowering,
@@ -2384,6 +2385,23 @@ mlir::LogicalResult CIRToLLVMComplexImagOpLowering::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();
+}
+
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 d9fb91066317b..36ef67d5b8e0a 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 CIRToLLVMComplexRealPtrOpLowering
+ : public mlir::OpConversionPattern<cir::ComplexRealPtrOp> {
+public:
+ using mlir::OpConversionPattern<cir::ComplexRealPtrOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::ComplexRealPtrOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
class CIRToLLVMGetBitfieldOpLowering
: public mlir::OpConversionPattern<cir::GetBitfieldOp> {
public:
diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp
index 25d81785ef482..2ec2b2c8d9a48 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.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
+
void foo12() {
double _Complex c;
double imag = __imag__ c;
@@ -733,4 +747,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.double>, !cir.ptr<!cir.complex<!cir.double>>, ["c"]
+ // expected-error @below {{result type does not match operand type}}
+ %1 = cir.complex.real_ptr %0 : !cir.ptr<!cir.complex<!cir.double>> -> !cir.ptr<!cir.float>
+ cir.return
+ }
+}
More information about the cfe-commits
mailing list