diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 083e4f18b284..6dd4f7e8b419 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -274,6 +274,40 @@ def FPAttr : CIR_Attr<"FP", "fp", [TypedAttrInterface]> { }]; } +//===----------------------------------------------------------------------===// +// ComplexAttr +//===----------------------------------------------------------------------===// + +def ComplexAttr : CIR_Attr<"Complex", "complex", [TypedAttrInterface]> { + let summary = "An attribute that contains a constant complex value"; + let description = [{ + The `#cir.complex` attribute contains a constant value of complex number + type. The `real` parameter gives the real part of the complex number and the + `imag` parameter gives the imaginary part of the complex number. + + The `real` and `imag` parameter must be either an IntAttr or an FPAttr that + contains values of the same CIR type. + }]; + + let parameters = (ins + AttributeSelfTypeParameter<"", "mlir::cir::ComplexType">:$type, + "mlir::TypedAttr":$real, "mlir::TypedAttr":$imag); + + let builders = [ + AttrBuilderWithInferredContext<(ins "mlir::cir::ComplexType":$type, + "mlir::TypedAttr":$real, + "mlir::TypedAttr":$imag), [{ + return $_get(type.getContext(), type, real, imag); + }]>, + ]; + + let genVerifyDecl = 1; + + let assemblyFormat = [{ + `<` qualified($real) `,` qualified($imag) `>` + }]; +} + //===----------------------------------------------------------------------===// // ConstPointerAttr //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td index df5dbe9872a6..fc87df7c86a2 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td @@ -27,6 +27,8 @@ def CIR_Dialect : Dialect { let useDefaultAttributePrinterParser = 0; let useDefaultTypePrinterParser = 0; + let hasConstantMaterializer = 1; + let extraClassDeclaration = [{ // Names of CIR parameter attributes. diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index f7db355f38d3..e39f7c2f778b 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1217,6 +1217,7 @@ def ComplexCreateOp : CIR_Op<"complex.create", [Pure, SameTypeOperands]> { }]; let hasVerifier = 1; + let hasFolder = 1; } //===----------------------------------------------------------------------===// @@ -1245,6 +1246,7 @@ def ComplexRealOp : CIR_Op<"complex.real", [Pure]> { }]; let hasVerifier = 1; + let hasFolder = 1; } def ComplexImagOp : CIR_Op<"complex.imag", [Pure]> { @@ -1269,6 +1271,7 @@ def ComplexImagOp : CIR_Op<"complex.imag", [Pure]> { }]; let hasVerifier = 1; + let hasFolder = 1; } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp index 9f18103d51c9..21e0fc74a614 100644 --- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp @@ -362,6 +362,26 @@ LogicalResult cir::FPAttr::verify(function_ref emitError, return success(); } +//===----------------------------------------------------------------------===// +// ComplexAttr definitions +//===----------------------------------------------------------------------===// + +LogicalResult ComplexAttr::verify(function_ref emitError, + mlir::cir::ComplexType type, + mlir::TypedAttr real, mlir::TypedAttr imag) { + auto elemTy = type.getElementTy(); + if (real.getType() != elemTy) { + emitError() << "type of the real part does not match the complex type"; + return failure(); + } + if (imag.getType() != elemTy) { + emitError() << "type of the imaginary part does not match the complex type"; + return failure(); + } + + return success(); +} + //===----------------------------------------------------------------------===// // CmpThreeWayInfoAttr definitions //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 00021bfb0ef5..933b848951a0 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -124,6 +124,14 @@ void cir::CIRDialect::initialize() { addInterfaces(); } +Operation *cir::CIRDialect::materializeConstant(mlir::OpBuilder &builder, + mlir::Attribute value, + mlir::Type type, + mlir::Location loc) { + return builder.create( + loc, type, mlir::cast(value)); +} + //===----------------------------------------------------------------------===// // Helpers //===----------------------------------------------------------------------===// @@ -344,7 +352,8 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType, return success(); } - if (mlir::isa(attrType)) { + if (mlir::isa( + attrType)) { auto at = cast(attrType); if (at.getType() != opType) { return op->emitOpError("result type (") @@ -638,6 +647,26 @@ LogicalResult ComplexCreateOp::verify() { return success(); } +OpFoldResult ComplexCreateOp::fold(FoldAdaptor adaptor) { + auto real = adaptor.getReal(); + auto imag = adaptor.getImag(); + + if (!real || !imag) + return nullptr; + + // When both of real and imag are constants, we can fold the operation into an + // `cir.const #cir.complex` operation. + + auto realAttr = mlir::cast(real); + auto imagAttr = mlir::cast(imag); + assert(realAttr.getType() == imagAttr.getType() && + "real part and imag part should be of the same type"); + + auto complexTy = + mlir::cir::ComplexType::get(getContext(), realAttr.getType()); + return mlir::cir::ComplexAttr::get(complexTy, realAttr, imagAttr); +} + //===----------------------------------------------------------------------===// // ComplexRealOp and ComplexImagOp //===----------------------------------------------------------------------===// @@ -650,6 +679,14 @@ LogicalResult ComplexRealOp::verify() { return success(); } +OpFoldResult ComplexRealOp::fold(FoldAdaptor adaptor) { + auto input = + mlir::cast_if_present(adaptor.getOperand()); + if (input) + return input.getReal(); + return nullptr; +} + LogicalResult ComplexImagOp::verify() { if (getType() != getOperand().getType().getElementTy()) { emitOpError() << "cir.complex.imag result type does not match operand type"; @@ -658,6 +695,14 @@ LogicalResult ComplexImagOp::verify() { return success(); } +OpFoldResult ComplexImagOp::fold(FoldAdaptor adaptor) { + auto input = + mlir::cast_if_present(adaptor.getOperand()); + if (input) + return input.getImag(); + return nullptr; +} + //===----------------------------------------------------------------------===// // ComplexRealPtrOp and ComplexImagPtrOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp b/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp index 4ce9d4a83c8b..e88c2ce9a04e 100644 --- a/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp @@ -146,7 +146,8 @@ void CIRSimplifyPass::runOnOperation() { getOperation()->walk([&](Operation *op) { // CastOp here is to perform a manual `fold` in // applyOpPatternsAndFold - if (isa(op)) + if (isa(op)) ops.push_back(op); }); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index bc2ee77ea6eb..377dd104d684 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1179,6 +1179,30 @@ class CIRConstantLowering attr = rewriter.getFloatAttr( typeConverter->convertType(op.getType()), mlir::cast(op.getValue()).getValue()); + } else if (auto complexTy = + mlir::dyn_cast(op.getType())) { + auto complexAttr = mlir::cast(op.getValue()); + auto complexElemTy = complexTy.getElementTy(); + auto complexElemLLVMTy = typeConverter->convertType(complexElemTy); + + mlir::Attribute components[2]; + if (mlir::isa(complexElemTy)) { + components[0] = rewriter.getIntegerAttr( + complexElemLLVMTy, + mlir::cast(complexAttr.getReal()).getValue()); + components[1] = rewriter.getIntegerAttr( + complexElemLLVMTy, + mlir::cast(complexAttr.getImag()).getValue()); + } else { + components[0] = rewriter.getFloatAttr( + complexElemLLVMTy, + mlir::cast(complexAttr.getReal()).getValue()); + components[1] = rewriter.getFloatAttr( + complexElemLLVMTy, + mlir::cast(complexAttr.getImag()).getValue()); + } + + attr = rewriter.getArrayAttr(components); } else if (mlir::isa(op.getType())) { // Optimize with dedicated LLVM op for null pointers. if (mlir::isa(op.getValue())) { diff --git a/clang/test/CIR/CodeGen/complex.c b/clang/test/CIR/CodeGen/complex.c index 3dd02118ea6a..a1cab1070aca 100644 --- a/clang/test/CIR/CodeGen/complex.c +++ b/clang/test/CIR/CodeGen/complex.c @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -o %t.cir %s -// RUN: FileCheck --input-file=%t.cir --check-prefixes=C,CHECK %s -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -fclangir -emit-cir -o %t.cir %s -// RUN: FileCheck --input-file=%t.cir --check-prefixes=CPP,CHECK %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-simplify -o %t.cir %s 2>&1 | FileCheck --check-prefix=CHECK-BEFORE %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-simplify -o %t.cir %s 2>&1 | FileCheck --check-prefix=CHECK-BEFORE %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-simplify -o %t.cir %s 2>&1 | FileCheck --check-prefix=CHECK-AFTER %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-simplify -o %t.cir %s 2>&1 | FileCheck --check-prefix=CHECK-AFTER %s // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -o %t.ll %s // RUN: FileCheck --input-file=%t.ll --check-prefixes=LLVM %s @@ -16,15 +16,19 @@ void list_init() { int _Complex c2 = {1, 2}; } -// C: cir.func no_proto @list_init() -// CPP: cir.func @_Z9list_initv() -// CHECK: %[[#REAL:]] = cir.const #cir.fp<1.000000e+00> : !cir.double -// CHECK-NEXT: %[[#IMAG:]] = cir.const #cir.fp<2.000000e+00> : !cir.double -// CHECK-NEXT: %{{.+}} = cir.complex.create %[[#REAL]], %[[#IMAG]] : !cir.double -> !cir.complex -// CHECK: %[[#REAL:]] = cir.const #cir.int<1> : !s32i -// CHECK-NEXT: %[[#IMAG:]] = cir.const #cir.int<2> : !s32i -// CHECK-NEXT: %{{.+}} = cir.complex.create %[[#REAL]], %[[#IMAG]] : !s32i -> !cir.complex -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %[[#REAL:]] = cir.const #cir.fp<1.000000e+00> : !cir.double +// CHECK-BEFORE-NEXT: %[[#IMAG:]] = cir.const #cir.fp<2.000000e+00> : !cir.double +// CHECK-BEFORE-NEXT: %{{.+}} = cir.complex.create %[[#REAL]], %[[#IMAG]] : !cir.double -> !cir.complex +// CHECK-BEFORE: %[[#REAL:]] = cir.const #cir.int<1> : !s32i +// CHECK-BEFORE-NEXT: %[[#IMAG:]] = cir.const #cir.int<2> : !s32i +// CHECK-BEFORE-NEXT: %{{.+}} = cir.complex.create %[[#REAL]], %[[#IMAG]] : !s32i -> !cir.complex +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %{{.+}} = cir.const #cir.complex<#cir.fp<1.000000e+00> : !cir.double, #cir.fp<2.000000e+00> : !cir.double> : !cir.complex +// CHECK-AFTER: %{{.+}} = cir.const #cir.complex<#cir.int<1> : !s32i, #cir.int<2> : !s32i> : !cir.complex +// CHECK-AFTER: } // LLVM: define dso_local void @list_init() // LLVM: store { double, double } { double 1.000000e+00, double 2.000000e+00 }, ptr %{{.+}}, align 8 @@ -34,13 +38,19 @@ void list_init_2(double r, double i) { double _Complex c1 = {r, i}; } -// C: cir.func @list_init_2 -// CPP: cir.func @_Z11list_init_2dd -// CHECK: %[[#R:]] = cir.load %{{.+}} : !cir.ptr, !cir.double -// CHECK-NEXT: %[[#I:]] = cir.load %{{.+}} : !cir.ptr, !cir.double -// CHECK-NEXT: %[[#C:]] = cir.complex.create %[[#R]], %[[#I]] : !cir.double -> !cir.complex -// CHECK-NEXT: cir.store %[[#C]], %{{.+}} : !cir.complex, !cir.ptr> -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %[[#R:]] = cir.load %{{.+}} : !cir.ptr, !cir.double +// CHECK-BEFORE-NEXT: %[[#I:]] = cir.load %{{.+}} : !cir.ptr, !cir.double +// CHECK-BEFORE-NEXT: %[[#C:]] = cir.complex.create %[[#R]], %[[#I]] : !cir.double -> !cir.complex +// CHECK-BEFORE-NEXT: cir.store %[[#C]], %{{.+}} : !cir.complex, !cir.ptr> +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %[[#R:]] = cir.load %{{.+}} : !cir.ptr, !cir.double +// CHECK-AFTER-NEXT: %[[#I:]] = cir.load %{{.+}} : !cir.ptr, !cir.double +// CHECK-AFTER-NEXT: %[[#C:]] = cir.complex.create %[[#R]], %[[#I]] : !cir.double -> !cir.complex +// CHECK-AFTER-NEXT: cir.store %[[#C]], %{{.+}} : !cir.complex, !cir.ptr> +// CHECK-AFTER: } // LLVM: define dso_local void @list_init_2(double %{{.+}}, double %{{.+}}) // LLVM: %[[#A:]] = insertvalue { double, double } undef, double %{{.+}}, 0 @@ -52,10 +62,13 @@ void builtin_init(double r, double i) { double _Complex c = __builtin_complex(r, i); } -// C: cir.func @builtin_init -// CPP: cir.func @_Z12builtin_initdd -// CHECK: %{{.+}} = cir.complex.create %{{.+}}, %{{.+}} : !cir.double -> !cir.complex -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %{{.+}} = cir.complex.create %{{.+}}, %{{.+}} : !cir.double -> !cir.complex +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %{{.+}} = cir.complex.create %{{.+}}, %{{.+}} : !cir.double -> !cir.complex +// CHECK-AFTER: } // LLVM: define dso_local void @builtin_init // LLVM: %[[#A:]] = insertvalue { double, double } undef, double %{{.+}}, 0 @@ -68,15 +81,19 @@ void imag_literal() { ci = 3i; } -// C: cir.func no_proto @imag_literal() -// CPP: cir.func @_Z12imag_literalv() -// CHECK: %[[#REAL:]] = cir.const #cir.fp<0.000000e+00> : !cir.double -// CHECK-NEXT: %[[#IMAG:]] = cir.const #cir.fp<3.000000e+00> : !cir.double -// CHECK-NEXT: %{{.+}} = cir.complex.create %[[#REAL]], %[[#IMAG]] : !cir.double -> !cir.complex -// CHECK: %[[#REAL:]] = cir.const #cir.int<0> : !s32i -// CHECK-NEXT: %[[#IMAG:]] = cir.const #cir.int<3> : !s32i -// CHECK-NEXT: %{{.+}} = cir.complex.create %[[#REAL]], %[[#IMAG]] : !s32i -> !cir.complex -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %[[#REAL:]] = cir.const #cir.fp<0.000000e+00> : !cir.double +// CHECK-BEFORE-NEXT: %[[#IMAG:]] = cir.const #cir.fp<3.000000e+00> : !cir.double +// CHECK-BEFORE-NEXT: %{{.+}} = cir.complex.create %[[#REAL]], %[[#IMAG]] : !cir.double -> !cir.complex +// CHECK-BEFORE: %[[#REAL:]] = cir.const #cir.int<0> : !s32i +// CHECK-BEFORE-NEXT: %[[#IMAG:]] = cir.const #cir.int<3> : !s32i +// CHECK-BEFORE-NEXT: %{{.+}} = cir.complex.create %[[#REAL]], %[[#IMAG]] : !s32i -> !cir.complex +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %{{.+}} = cir.const #cir.complex<#cir.fp<0.000000e+00> : !cir.double, #cir.fp<3.000000e+00> : !cir.double> : !cir.complex +// CHECK-AFTER: %{{.+}} = cir.const #cir.complex<#cir.int<0> : !s32i, #cir.int<3> : !s32i> : !cir.complex +// CHECK-AFTER: } // LLVM: define dso_local void @imag_literal() // LLVM: store { double, double } { double 0.000000e+00, double 3.000000e+00 }, ptr @c, align 8 @@ -88,17 +105,27 @@ void load_store() { ci = ci2; } -// C: cir.func no_proto @load_store() -// CPP: cir.func @_Z10load_storev() -// CHECK-NEXT: %[[#C2_PTR:]] = cir.get_global @c2 : !cir.ptr> -// CHECK-NEXT: %[[#C2:]] = cir.load %[[#C2_PTR]] : !cir.ptr>, !cir.complex -// CHECK-NEXT: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> -// CHECK-NEXT: cir.store %[[#C2]], %[[#C_PTR]] : !cir.complex, !cir.ptr> -// CHECK-NEXT: %[[#CI2_PTR:]] = cir.get_global @ci2 : !cir.ptr> -// CHECK-NEXT: %[[#CI2:]] = cir.load %[[#CI2_PTR]] : !cir.ptr>, !cir.complex -// CHECK-NEXT: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> -// CHECK-NEXT: cir.store %[[#CI2]], %[[#CI_PTR]] : !cir.complex, !cir.ptr> -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE-NEXT: %[[#C2_PTR:]] = cir.get_global @c2 : !cir.ptr> +// CHECK-BEFORE-NEXT: %[[#C2:]] = cir.load %[[#C2_PTR]] : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> +// CHECK-BEFORE-NEXT: cir.store %[[#C2]], %[[#C_PTR]] : !cir.complex, !cir.ptr> +// CHECK-BEFORE-NEXT: %[[#CI2_PTR:]] = cir.get_global @ci2 : !cir.ptr> +// CHECK-BEFORE-NEXT: %[[#CI2:]] = cir.load %[[#CI2_PTR]] : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> +// CHECK-BEFORE-NEXT: cir.store %[[#CI2]], %[[#CI_PTR]] : !cir.complex, !cir.ptr> +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER-NEXT: %[[#C2_PTR:]] = cir.get_global @c2 : !cir.ptr> +// CHECK-AFTER-NEXT: %[[#C2:]] = cir.load %[[#C2_PTR]] : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> +// CHECK-AFTER-NEXT: cir.store %[[#C2]], %[[#C_PTR]] : !cir.complex, !cir.ptr> +// CHECK-AFTER-NEXT: %[[#CI2_PTR:]] = cir.get_global @ci2 : !cir.ptr> +// CHECK-AFTER-NEXT: %[[#CI2:]] = cir.load %[[#CI2_PTR]] : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> +// CHECK-AFTER-NEXT: cir.store %[[#CI2]], %[[#CI_PTR]] : !cir.complex, !cir.ptr> +// CHECK-AFTER: } // LLVM: define dso_local void @load_store() // LLVM: %[[#A:]] = load { double, double }, ptr @c2, align 8 @@ -112,17 +139,27 @@ void load_store_volatile() { vci = vci2; } -// C: cir.func no_proto @load_store_volatile() -// CPP: cir.func @_Z19load_store_volatilev() -// CHECK-NEXT: %[[#VC2_PTR:]] = cir.get_global @vc2 : !cir.ptr> -// CHECK-NEXT: %[[#VC2:]] = cir.load volatile %[[#VC2_PTR]] : !cir.ptr>, !cir.complex -// CHECK-NEXT: %[[#VC_PTR:]] = cir.get_global @vc : !cir.ptr> -// CHECK-NEXT: cir.store volatile %[[#VC2]], %[[#VC_PTR]] : !cir.complex, !cir.ptr> -// CHECK-NEXT: %[[#VCI2_PTR:]] = cir.get_global @vci2 : !cir.ptr> -// CHECK-NEXT: %[[#VCI2:]] = cir.load volatile %[[#VCI2_PTR]] : !cir.ptr>, !cir.complex -// CHECK-NEXT: %[[#VCI_PTR:]] = cir.get_global @vci : !cir.ptr> -// CHECK-NEXT: cir.store volatile %[[#VCI2]], %[[#VCI_PTR]] : !cir.complex, !cir.ptr> -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE-NEXT: %[[#VC2_PTR:]] = cir.get_global @vc2 : !cir.ptr> +// CHECK-BEFORE-NEXT: %[[#VC2:]] = cir.load volatile %[[#VC2_PTR]] : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %[[#VC_PTR:]] = cir.get_global @vc : !cir.ptr> +// CHECK-BEFORE-NEXT: cir.store volatile %[[#VC2]], %[[#VC_PTR]] : !cir.complex, !cir.ptr> +// CHECK-BEFORE-NEXT: %[[#VCI2_PTR:]] = cir.get_global @vci2 : !cir.ptr> +// CHECK-BEFORE-NEXT: %[[#VCI2:]] = cir.load volatile %[[#VCI2_PTR]] : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %[[#VCI_PTR:]] = cir.get_global @vci : !cir.ptr> +// CHECK-BEFORE-NEXT: cir.store volatile %[[#VCI2]], %[[#VCI_PTR]] : !cir.complex, !cir.ptr> +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER-NEXT: %[[#VC2_PTR:]] = cir.get_global @vc2 : !cir.ptr> +// CHECK-AFTER-NEXT: %[[#VC2:]] = cir.load volatile %[[#VC2_PTR]] : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %[[#VC_PTR:]] = cir.get_global @vc : !cir.ptr> +// CHECK-AFTER-NEXT: cir.store volatile %[[#VC2]], %[[#VC_PTR]] : !cir.complex, !cir.ptr> +// CHECK-AFTER-NEXT: %[[#VCI2_PTR:]] = cir.get_global @vci2 : !cir.ptr> +// CHECK-AFTER-NEXT: %[[#VCI2:]] = cir.load volatile %[[#VCI2_PTR]] : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %[[#VCI_PTR:]] = cir.get_global @vci : !cir.ptr> +// CHECK-AFTER-NEXT: cir.store volatile %[[#VCI2]], %[[#VCI_PTR]] : !cir.complex, !cir.ptr> +// CHECK-AFTER: } // LLVM: define dso_local void @load_store_volatile() // LLVM: %[[#A:]] = load volatile { double, double }, ptr @vc2, align 8 @@ -135,12 +172,17 @@ void real() { double r = __builtin_creal(c); } -// C: cir.func no_proto @real() -// CPP: cir.func @_Z4realv() -// CHECK: %[[#A:]] = cir.get_global @c : !cir.ptr> -// CHECK-NEXT: %[[#B:]] = cir.load %[[#A]] : !cir.ptr>, !cir.complex -// CHECK-NEXT: %{{.+}} = cir.complex.real %[[#B]] : !cir.complex -> !cir.double -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %[[#A:]] = cir.get_global @c : !cir.ptr> +// CHECK-BEFORE-NEXT: %[[#B:]] = cir.load %[[#A]] : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %{{.+}} = cir.complex.real %[[#B]] : !cir.complex -> !cir.double +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %[[#A:]] = cir.get_global @c : !cir.ptr> +// CHECK-AFTER-NEXT: %[[#B:]] = cir.load %[[#A]] : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %{{.+}} = cir.complex.real %[[#B]] : !cir.complex -> !cir.double +// CHECK-AFTER: } // LLVM: define dso_local void @real() // LLVM: %[[#A:]] = extractvalue { double, double } %{{.+}}, 0 @@ -151,12 +193,17 @@ void imag() { double i = __builtin_cimag(c); } -// C: cir.func no_proto @imag() -// CPP: cir.func @_Z4imagv() -// CHECK: %[[#A:]] = cir.get_global @c : !cir.ptr> -// CHECK-NEXT: %[[#B:]] = cir.load %[[#A]] : !cir.ptr>, !cir.complex -// CHECK-NEXT: %{{.+}} = cir.complex.imag %[[#B]] : !cir.complex -> !cir.double -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %[[#A:]] = cir.get_global @c : !cir.ptr> +// CHECK-BEFORE-NEXT: %[[#B:]] = cir.load %[[#A]] : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %{{.+}} = cir.complex.imag %[[#B]] : !cir.complex -> !cir.double +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %[[#A:]] = cir.get_global @c : !cir.ptr> +// CHECK-AFTER-NEXT: %[[#B:]] = cir.load %[[#A]] : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %{{.+}} = cir.complex.imag %[[#B]] : !cir.complex -> !cir.double +// CHECK-AFTER: } // LLVM: define dso_local void @imag() // LLVM: %[[#A:]] = extractvalue { double, double } %{{.+}}, 1 @@ -168,13 +215,19 @@ void real_ptr() { int *r2 = &__real__ ci; } -// C: cir.func no_proto @real_ptr() -// CPP: cir.func @_Z8real_ptrv() -// CHECK: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> -// CHECK-NEXT: %{{.+}} = cir.complex.real_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> -// CHECK-NEXT: %{{.+}} = cir.complex.real_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> +// CHECK-BEFORE-NEXT: %{{.+}} = cir.complex.real_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-BEFORE: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> +// CHECK-BEFORE-NEXT: %{{.+}} = cir.complex.real_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> +// CHECK-AFTER-NEXT: %{{.+}} = cir.complex.real_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-AFTER: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> +// CHECK-AFTER-NEXT: %{{.+}} = cir.complex.real_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-AFTER: } // LLVM: define dso_local void @real_ptr() // LLVM: store ptr @c, ptr %{{.+}}, align 8 @@ -186,11 +239,15 @@ void real_ptr_local() { double *r3 = &__real__ c1; } -// C: cir.func no_proto @real_ptr_local() -// CPP: cir.func @_Z14real_ptr_localv() -// CHECK: %[[#C:]] = cir.alloca !cir.complex, !cir.ptr> -// CHECK: %{{.+}} = cir.complex.real_ptr %[[#C]] : !cir.ptr> -> !cir.ptr -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %[[#C:]] = cir.alloca !cir.complex, !cir.ptr> +// CHECK-BEFORE: %{{.+}} = cir.complex.real_ptr %[[#C]] : !cir.ptr> -> !cir.ptr +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %[[#C:]] = cir.alloca !cir.complex, !cir.ptr> +// CHECK-AFTER: %{{.+}} = cir.complex.real_ptr %[[#C]] : !cir.ptr> -> !cir.ptr +// CHECK-AFTER: } // LLVM: define dso_local void @real_ptr_local() // LLVM: store { double, double } { double 1.000000e+00, double 2.000000e+00 }, ptr %{{.+}}, align 8 @@ -202,15 +259,23 @@ void extract_real() { int r2 = __real__ ci; } -// C: cir.func no_proto @extract_real() -// CPP: cir.func @_Z12extract_realv() -// CHECK: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> -// CHECK-NEXT: %[[#REAL_PTR:]] = cir.complex.real_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK-NEXT: %{{.+}} = cir.load %[[#REAL_PTR]] : !cir.ptr, !cir.double -// CHECK: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> -// CHECK-NEXT: %[[#REAL_PTR:]] = cir.complex.real_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK-NEXT: %{{.+}} = cir.load %[[#REAL_PTR]] : !cir.ptr, !s32i -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> +// CHECK-BEFORE-NEXT: %[[#REAL_PTR:]] = cir.complex.real_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-BEFORE-NEXT: %{{.+}} = cir.load %[[#REAL_PTR]] : !cir.ptr, !cir.double +// CHECK-BEFORE: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> +// CHECK-BEFORE-NEXT: %[[#REAL_PTR:]] = cir.complex.real_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-BEFORE-NEXT: %{{.+}} = cir.load %[[#REAL_PTR]] : !cir.ptr, !s32i +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> +// CHECK-AFTER-NEXT: %[[#REAL_PTR:]] = cir.complex.real_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-AFTER-NEXT: %{{.+}} = cir.load %[[#REAL_PTR]] : !cir.ptr, !cir.double +// CHECK-AFTER: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> +// CHECK-AFTER-NEXT: %[[#REAL_PTR:]] = cir.complex.real_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-AFTER-NEXT: %{{.+}} = cir.load %[[#REAL_PTR]] : !cir.ptr, !s32i +// CHECK-AFTER: } // LLVM: define dso_local void @extract_real() // LLVM: %{{.+}} = load double, ptr @c, align 8 @@ -222,13 +287,19 @@ void imag_ptr() { int *i2 = &__imag__ ci; } -// C: cir.func no_proto @imag_ptr() -// CPP: cir.func @_Z8imag_ptrv() -// CHECK: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> -// CHECK-NEXT: %{{.+}} = cir.complex.imag_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> -// CHECK-NEXT: %{{.+}} = cir.complex.imag_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> +// CHECK-BEFORE-NEXT: %{{.+}} = cir.complex.imag_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-BEFORE: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> +// CHECK-BEFORE-NEXT: %{{.+}} = cir.complex.imag_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> +// CHECK-AFTER-NEXT: %{{.+}} = cir.complex.imag_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-AFTER: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> +// CHECK-AFTER-NEXT: %{{.+}} = cir.complex.imag_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-AFTER: } // LLVM: define dso_local void @imag_ptr() // LLVM: store ptr getelementptr inbounds ({ double, double }, ptr @c, i32 0, i32 1), ptr %{{.+}}, align 8 @@ -240,15 +311,23 @@ void extract_imag() { int i2 = __imag__ ci; } -// C: cir.func no_proto @extract_imag() -// CPP: cir.func @_Z12extract_imagv() -// CHECK: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> -// CHECK-NEXT: %[[#IMAG_PTR:]] = cir.complex.imag_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK-NEXT: %{{.+}} = cir.load %[[#IMAG_PTR]] : !cir.ptr, !cir.double -// CHECK: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> -// CHECK-NEXT: %[[#IMAG_PTR:]] = cir.complex.imag_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK-NEXT: %{{.+}} = cir.load %[[#IMAG_PTR]] : !cir.ptr, !s32i -// CHECK: } +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> +// CHECK-BEFORE-NEXT: %[[#IMAG_PTR:]] = cir.complex.imag_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-BEFORE-NEXT: %{{.+}} = cir.load %[[#IMAG_PTR]] : !cir.ptr, !cir.double +// CHECK-BEFORE: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> +// CHECK-BEFORE-NEXT: %[[#IMAG_PTR:]] = cir.complex.imag_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-BEFORE-NEXT: %{{.+}} = cir.load %[[#IMAG_PTR]] : !cir.ptr, !s32i +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> +// CHECK-AFTER-NEXT: %[[#IMAG_PTR:]] = cir.complex.imag_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-AFTER-NEXT: %{{.+}} = cir.load %[[#IMAG_PTR]] : !cir.ptr, !cir.double +// CHECK-AFTER: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> +// CHECK-AFTER-NEXT: %[[#IMAG_PTR:]] = cir.complex.imag_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr +// CHECK-AFTER-NEXT: %{{.+}} = cir.load %[[#IMAG_PTR]] : !cir.ptr, !s32i +// CHECK-AFTER: } // LLVM: define dso_local void @extract_imag() // LLVM: %{{.+}} = load double, ptr getelementptr inbounds ({ double, double }, ptr @c, i32 0, i32 1), align 8 diff --git a/clang/test/CIR/Lowering/complex.cir b/clang/test/CIR/Lowering/complex.cir new file mode 100644 index 000000000000..91ded659997d --- /dev/null +++ b/clang/test/CIR/Lowering/complex.cir @@ -0,0 +1,15 @@ +// RUN: cir-translate -cir-to-llvmir -o %t.ll %s +// RUN: FileCheck --input-file %t.ll -check-prefix=LLVM %s + +!s32i = !cir.int + +module { + cir.func @complex_const() -> !cir.complex { + %0 = cir.const #cir.complex<#cir.int<1> : !s32i, #cir.int<2> : !s32i> : !cir.complex + cir.return %0 : !cir.complex + } + + // LLVM-LABEL: define { i32, i32 } @complex_const() + // LLVM-NEXT: ret { i32, i32 } { i32 1, i32 2 } + // LLVM-NEXT: } +} diff --git a/clang/test/CIR/Transforms/complex-fold.cir b/clang/test/CIR/Transforms/complex-fold.cir new file mode 100644 index 000000000000..34f6b67e1dc4 --- /dev/null +++ b/clang/test/CIR/Transforms/complex-fold.cir @@ -0,0 +1,44 @@ +// RUN: cir-opt --canonicalize -o %t.cir %s +// RUN: FileCheck --input-file %t.cir %s + +!s32i = !cir.int + +module { + cir.func @complex_create_fold() -> !cir.complex { + %0 = cir.const #cir.int<1> : !s32i + %1 = cir.const #cir.int<2> : !s32i + %2 = cir.complex.create %0, %1 : !s32i -> !cir.complex + cir.return %2 : !cir.complex + } + + // CHECK-LABEL: cir.func @complex_create_fold() -> !cir.complex { + // CHECK-NEXT: %[[#A:]] = cir.const #cir.complex<#cir.int<1> : !s32i, #cir.int<2> : !s32i> : !cir.complex + // CHECK-NEXT: cir.return %[[#A]] : !cir.complex + // CHECK-NEXT: } + + cir.func @fold_complex_real() -> !s32i { + %0 = cir.const #cir.int<1> : !s32i + %1 = cir.const #cir.int<2> : !s32i + %2 = cir.complex.create %0, %1 : !s32i -> !cir.complex + %3 = cir.complex.real %2 : !cir.complex -> !s32i + cir.return %3 : !s32i + } + + // CHECK-LABEL: cir.func @fold_complex_real() -> !s32i { + // CHECK-NEXT: %[[#A:]] = cir.const #cir.int<1> : !s32i + // CHECK-NEXT: cir.return %[[#A]] : !s32i + // CHECK-NEXT: } + + cir.func @fold_complex_imag() -> !s32i { + %0 = cir.const #cir.int<1> : !s32i + %1 = cir.const #cir.int<2> : !s32i + %2 = cir.complex.create %0, %1 : !s32i -> !cir.complex + %3 = cir.complex.imag %2 : !cir.complex -> !s32i + cir.return %3 : !s32i + } + + // CHECK-LABEL: cir.func @fold_complex_imag() -> !s32i { + // CHECK-NEXT: %[[#A:]] = cir.const #cir.int<2> : !s32i + // CHECK-NEXT: cir.return %[[#A]] : !s32i + // CHECK-NEXT: } +}