diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 17279f0a9985a..f90784c99602c 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2414,4 +2414,33 @@ 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; +} + #endif // CLANG_CIR_DIALECT_IR_CIROPS_TD diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 3f7ea5bccb6d5..df3f4d65610a6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -379,6 +379,20 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { return Address{createRealPtr(loc, addr.getPointer()), 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 createImagPtr(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 createImagPtr(mlir::Location loc, Address addr) { + return Address{createImagPtr(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 a682586562e04..8e3d9ab620621 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -541,11 +541,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"); @@ -560,7 +555,9 @@ 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.createRealPtr(loc, lv.getAddress()); + Address component = op == UO_Real + ? builder.createRealPtr(loc, lv.getAddress()) + : builder.createImagPtr(loc, lv.getAddress()); LValue elemLV = makeAddrLValue(component, elemTy); elemLV.getQuals().addQualifiers(lv.getQuals()); return elemLV; diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 99ae4dd59120a..40488f6af5676 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -1794,6 +1794,25 @@ LogicalResult cir::ComplexRealPtrOp::verify() { 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()) { + emitOpError() + << "cir.complex.imag_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 c11992a4bdc61..35f334e3c8e78 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1837,7 +1837,8 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMVecShuffleDynamicOpLowering, CIRToLLVMVecTernaryOpLowering, CIRToLLVMComplexCreateOpLowering, - CIRToLLVMComplexRealPtrOpLowering + CIRToLLVMComplexRealPtrOpLowering, + CIRToLLVMComplexImagPtrOpLowering // clang-format on >(converter, patterns.getContext()); @@ -2158,6 +2159,23 @@ mlir::LogicalResult CIRToLLVMComplexRealPtrOpLowering::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(); +} + std::unique_ptr createConvertCIRToLLVMPass() { return std::make_unique(); } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index caee3e9cd6980..531cd42f1e270 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -428,6 +428,16 @@ class CIRToLLVMComplexRealPtrOpLowering 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; +}; + } // namespace direct } // namespace cir diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index 182673a69be90..4bccf65cceb13 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -189,3 +189,17 @@ 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