llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangir
Author: Adam Smith (adams381)
<details>
<summary>Changes</summary>
Complex division returns a wrong imaginary part. CIR declares `__divsc3` as
returning `{ float, float }` where classic CodeGen coerces the return to `<2
x float>`, so the caller reads the two halves out of two registers while the
callee packs both into one. Dividing 3+4i by 1+2i gives 2.2 and 4.0 instead of
2.2 and -0.4, with no diagnostic. The helper call is synthesized by
LoweringPrepare, which runs after the calling-convention pass, so it is never
classified.
Expanding `cir.complex.mul` and `cir.complex.div` in their own pass, scheduled
before CallConvLowering, is enough to fix it and leaves the rest of the
lowering-prepare work where it is. Only the float helpers change shape, since
double and long double already returned a record that matched classic.
Assisted-by: Cursor / claude-opus-5
---
Patch is 36.46 KiB, truncated to 20.00 KiB below, full version:
https://github.com/llvm/llvm-project/pull/216498.diff
8 Files Affected:
- (modified) clang/include/clang/CIR/Dialect/Passes.h (+2)
- (modified) clang/include/clang/CIR/Dialect/Passes.td (+19)
- (modified) clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp (+79-27)
- (modified) clang/lib/CIR/Lowering/CIRPasses.cpp (+6)
- (modified) clang/test/CIR/CodeGen/complex-compound-assignment.cpp (+28-8)
- (added) clang/test/CIR/CodeGen/complex-libcall-abi-global-init.cpp (+30)
- (added) clang/test/CIR/CodeGen/complex-libcall-abi.c (+76)
- (modified) clang/test/CIR/CodeGen/complex-mul-div.cpp (+22-7)
``````````diff
diff --git a/clang/include/clang/CIR/Dialect/Passes.h
b/clang/include/clang/CIR/Dialect/Passes.h
index 674f2180c27ab..c668607dced34 100644
--- a/clang/include/clang/CIR/Dialect/Passes.h
+++ b/clang/include/clang/CIR/Dialect/Passes.h
@@ -42,6 +42,8 @@ std::unique_ptr<Pass> createCallConvLoweringPass(
std::unique_ptr<Pass> createHoistAllocasPass();
std::unique_ptr<Pass> createLoweringPreparePass();
std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx);
+std::unique_ptr<Pass> createComplexLoweringPass();
+std::unique_ptr<Pass> createComplexLoweringPass(clang::ASTContext *astCtx);
std::unique_ptr<Pass> createGotoSolverPass();
std::unique_ptr<Pass> createIdiomRecognizerPass();
std::unique_ptr<Pass> createLibOptPass();
diff --git a/clang/include/clang/CIR/Dialect/Passes.td
b/clang/include/clang/CIR/Dialect/Passes.td
index b983cfe59112a..c0a79d6fde66c 100644
--- a/clang/include/clang/CIR/Dialect/Passes.td
+++ b/clang/include/clang/CIR/Dialect/Passes.td
@@ -184,6 +184,25 @@ def LoweringPrepare : Pass<"cir-lowering-prepare"> {
let dependentDialects = ["cir::CIRDialect"];
}
+def ComplexLowering : Pass<"cir-complex-lowering", "mlir::ModuleOp"> {
+ let summary = "Expand complex multiplication and division";
+ let description = [{
+ This pass replaces `cir.complex.mul` and `cir.complex.div` with the
+ arithmetic each one expands to, which for the full complex range is a call
+ to a runtime helper such as `__mulsc3` or `__divsc3`.
+
+ It runs before the calling-convention pass rather than alongside the rest
+ of the lowering-prepare work, because a call created after that pass has
+ run never gets its return type coerced, which places the real and
+ imaginary halves of the result in the wrong registers.
+
+ Only these two operations need the earlier position, so `cir.complex.conj`
+ and the complex casts are still expanded by `cir-lowering-prepare`.
+ }];
+ let constructor = "mlir::createComplexLoweringPass()";
+ let dependentDialects = ["cir::CIRDialect"];
+}
+
def IdiomRecognizer : Pass<"cir-idiom-recognizer", "mlir::ModuleOp"> {
let summary = "Raise calls to C/C++ libraries to CIR operations";
let description = [{
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 28ba14962cc7b..a71aba6c1460f 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -44,6 +44,7 @@ using namespace mlir;
using namespace cir;
namespace mlir {
+#define GEN_PASS_DEF_COMPLEXLOWERING
#define GEN_PASS_DEF_LOWERINGPREPARE
#include "clang/CIR/Dialect/Passes.h.inc"
} // namespace mlir
@@ -88,8 +89,6 @@ struct LoweringPreparePass
void runOnOp(mlir::Operation *op);
void lowerCastOp(cir::CastOp op);
void lowerComplexConjOp(cir::ComplexConjOp op);
- void lowerComplexDivOp(cir::ComplexDivOp op);
- void lowerComplexMulOp(cir::ComplexMulOp op);
void lowerGetGlobalOp(cir::GetGlobalOp op);
void lowerGlobalOp(cir::GlobalOp op);
void lowerThreeWayCmpOp(cir::CmpThreeWayOp op);
@@ -505,6 +504,26 @@ struct LoweringPreparePass
void setASTContext(clang::ASTContext *c) { astCtx = c; }
};
+/// Expand `cir.complex.mul` and `cir.complex.div`. See the pass description
+/// in Passes.td for why this cannot run with the rest of LoweringPrepare.
+struct ComplexLoweringPass
+ : public impl::ComplexLoweringBase<ComplexLoweringPass> {
+ ComplexLoweringPass() = default;
+
+ void runOnOperation() override;
+
+ void lowerComplexDivOp(cir::ComplexDivOp op);
+ void lowerComplexMulOp(cir::ComplexMulOp op);
+
+ void setASTContext(clang::ASTContext *c) { astCtx = c; }
+
+ /// Read by the promoted-range division path, which asks the target for the
+ /// semantics of a higher-precision element type.
+ clang::ASTContext *astCtx = nullptr;
+
+ mlir::ModuleOp mlirModule;
+};
+
} // namespace
cir::GlobalOp LoweringPreparePass::getOrCreateRuntimeVariable(
@@ -525,9 +544,13 @@ cir::GlobalOp
LoweringPreparePass::getOrCreateRuntimeVariable(
return g;
}
-cir::FuncOp LoweringPreparePass::buildRuntimeFunction(
- mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
- cir::FuncType type, cir::GlobalLinkageKind linkage) {
+/// Declare `name` in `mlirModule` if it is not already declared there, and
+/// return the declaration. Free-standing so that ComplexLoweringPass can
+/// reach it without a LoweringPreparePass instance.
+static cir::FuncOp buildRuntimeFunction(
+ mlir::OpBuilder &builder, mlir::ModuleOp mlirModule, llvm::StringRef name,
+ mlir::Location loc, cir::FuncType type,
+ cir::GlobalLinkageKind linkage = cir::GlobalLinkageKind::ExternalLinkage) {
cir::FuncOp f =
dyn_cast_or_null<FuncOp>(SymbolTable::lookupNearestSymbolFrom(
mlirModule, StringAttr::get(mlirModule->getContext(), name)));
if (!f) {
@@ -542,6 +565,12 @@ cir::FuncOp LoweringPreparePass::buildRuntimeFunction(
return f;
}
+cir::FuncOp LoweringPreparePass::buildRuntimeFunction(
+ mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc,
+ cir::FuncType type, cir::GlobalLinkageKind linkage) {
+ return ::buildRuntimeFunction(builder, mlirModule, name, loc, type, linkage);
+}
+
static mlir::Value lowerScalarToComplexCast(mlir::MLIRContext &ctx,
cir::CastOp op) {
cir::CIRBaseBuilderTy builder(ctx);
@@ -628,7 +657,7 @@ void LoweringPreparePass::lowerCastOp(cir::CastOp op) {
}
static mlir::Value buildComplexBinOpLibCall(
- LoweringPreparePass &pass, CIRBaseBuilderTy &builder,
+ mlir::ModuleOp mlirModule, CIRBaseBuilderTy &builder,
llvm::StringRef (*libFuncNameGetter)(llvm::APFloat::Semantics),
mlir::Location loc, cir::ComplexType ty, mlir::Value lhsReal,
mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag) {
@@ -646,8 +675,9 @@ static mlir::Value buildComplexBinOpLibCall(
cir::FuncOp libFunc;
{
mlir::OpBuilder::InsertionGuard ipGuard{builder};
- builder.setInsertionPointToStart(pass.mlirModule.getBody());
- libFunc = pass.buildRuntimeFunction(builder, libFuncName, loc, libFuncTy);
+ builder.setInsertionPointToStart(mlirModule.getBody());
+ libFunc =
+ buildRuntimeFunction(builder, mlirModule, libFuncName, loc, libFuncTy);
}
cir::CallOp call =
@@ -864,7 +894,7 @@ static mlir::Type
higherPrecisionElementTypeForComplexArithmetic(
}
static mlir::Value
-lowerComplexDiv(LoweringPreparePass &pass, CIRBaseBuilderTy &builder,
+lowerComplexDiv(mlir::ModuleOp mlirModule, CIRBaseBuilderTy &builder,
mlir::Location loc, cir::ComplexDivOp op, mlir::Value lhsReal,
mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag,
mlir::MLIRContext &mlirCx, clang::ASTContext &cc) {
@@ -876,9 +906,9 @@ lowerComplexDiv(LoweringPreparePass &pass, CIRBaseBuilderTy
&builder,
rhsReal, rhsImag);
if (range == cir::ComplexRangeKind::Full)
- return buildComplexBinOpLibCall(pass, builder, &getComplexDivLibCallName,
- loc, complexTy, lhsReal, lhsImag,
rhsReal,
- rhsImag);
+ return buildComplexBinOpLibCall(mlirModule, builder,
+ &getComplexDivLibCallName, loc,
complexTy,
+ lhsReal, lhsImag, rhsReal, rhsImag);
if (range == cir::ComplexRangeKind::Promoted) {
mlir::Type originalElementType = complexTy.getElementType();
@@ -918,7 +948,7 @@ lowerComplexDiv(LoweringPreparePass &pass, CIRBaseBuilderTy
&builder,
rhsImag);
}
-void LoweringPreparePass::lowerComplexDivOp(cir::ComplexDivOp op) {
+void ComplexLoweringPass::lowerComplexDivOp(cir::ComplexDivOp op) {
cir::CIRBaseBuilderTy builder(getContext());
builder.setInsertionPointAfter(op);
mlir::Location loc = op.getLoc();
@@ -930,7 +960,7 @@ void
LoweringPreparePass::lowerComplexDivOp(cir::ComplexDivOp op) {
mlir::Value rhsImag = builder.createComplexImag(loc, rhs);
mlir::Value loweredResult =
- lowerComplexDiv(*this, builder, loc, op, lhsReal, lhsImag, rhsReal,
+ lowerComplexDiv(mlirModule, builder, loc, op, lhsReal, lhsImag, rhsReal,
rhsImag, getContext(), *astCtx);
op.replaceAllUsesWith(loweredResult);
op.erase();
@@ -956,7 +986,7 @@ getComplexMulLibCallName(llvm::APFloat::Semantics
semantics) {
}
}
-static mlir::Value lowerComplexMul(LoweringPreparePass &pass,
+static mlir::Value lowerComplexMul(mlir::ModuleOp mlirModule,
CIRBaseBuilderTy &builder,
mlir::Location loc, cir::ComplexMulOp op,
mlir::Value lhsReal, mlir::Value lhsImag,
@@ -1004,8 +1034,8 @@ static mlir::Value lowerComplexMul(LoweringPreparePass
&pass,
builder, loc, resultRealAndImagAreNaN,
[&](mlir::OpBuilder &, mlir::Location) {
mlir::Value libCallResult = buildComplexBinOpLibCall(
- pass, builder, &getComplexMulLibCallName, loc, complexTy,
- lhsReal, lhsImag, rhsReal, rhsImag);
+ mlirModule, builder, &getComplexMulLibCallName, loc,
+ complexTy, lhsReal, lhsImag, rhsReal, rhsImag);
builder.createYield(loc, libCallResult);
},
[&](mlir::OpBuilder &, mlir::Location) {
@@ -1014,7 +1044,7 @@ static mlir::Value lowerComplexMul(LoweringPreparePass
&pass,
.getResult();
}
-void LoweringPreparePass::lowerComplexMulOp(cir::ComplexMulOp op) {
+void ComplexLoweringPass::lowerComplexMulOp(cir::ComplexMulOp op) {
cir::CIRBaseBuilderTy builder(getContext());
builder.setInsertionPointAfter(op);
mlir::Location loc = op.getLoc();
@@ -1024,12 +1054,28 @@ void
LoweringPreparePass::lowerComplexMulOp(cir::ComplexMulOp op) {
mlir::Value lhsImag = builder.createComplexImag(loc, lhs);
mlir::Value rhsReal = builder.createComplexReal(loc, rhs);
mlir::Value rhsImag = builder.createComplexImag(loc, rhs);
- mlir::Value loweredResult = lowerComplexMul(*this, builder, loc, op, lhsReal,
- lhsImag, rhsReal, rhsImag);
+ mlir::Value loweredResult = lowerComplexMul(
+ mlirModule, builder, loc, op, lhsReal, lhsImag, rhsReal, rhsImag);
op.replaceAllUsesWith(loweredResult);
op.erase();
}
+void ComplexLoweringPass::runOnOperation() {
+ mlirModule = cast<mlir::ModuleOp>(getOperation());
+
+ llvm::SmallVector<mlir::Operation *> opsToTransform;
+ mlirModule->walk([&](mlir::Operation *op) {
+ if (mlir::isa<cir::ComplexMulOp, cir::ComplexDivOp>(op))
+ opsToTransform.push_back(op);
+ });
+
+ for (mlir::Operation *o : opsToTransform)
+ if (auto complexDiv = mlir::dyn_cast<cir::ComplexDivOp>(o))
+ lowerComplexDivOp(complexDiv);
+ else
+ lowerComplexMulOp(mlir::cast<cir::ComplexMulOp>(o));
+}
+
void LoweringPreparePass::lowerComplexConjOp(cir::ComplexConjOp op) {
mlir::Location loc = op.getLoc();
CIRBaseBuilderTy builder(getContext());
@@ -2297,10 +2343,6 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
lowerCastOp(cast);
} else if (auto complexConj = mlir::dyn_cast<cir::ComplexConjOp>(op)) {
lowerComplexConjOp(complexConj);
- } else if (auto complexDiv = mlir::dyn_cast<cir::ComplexDivOp>(op)) {
- lowerComplexDivOp(complexDiv);
- } else if (auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op)) {
- lowerComplexMulOp(complexMul);
} else if (auto glob = mlir::dyn_cast<cir::GlobalOp>(op)) {
lowerGlobalOp(glob);
if (auto regAttr = glob->getAttrOfType<CUDAVarRegistrationInfoAttr>(
@@ -2936,9 +2978,8 @@ void LoweringPreparePass::runOnOperation() {
op->walk([&](mlir::Operation *op) {
if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
- cir::ComplexConjOp, cir::ComplexMulOp, cir::ComplexDivOp,
- cir::DynamicCastOp, cir::FuncOp, cir::CallOp,
- cir::GetGlobalOp, cir::GlobalOp, cir::StoreOp,
+ cir::ComplexConjOp, cir::DynamicCastOp, cir::FuncOp,
+ cir::CallOp, cir::GetGlobalOp, cir::GlobalOp, cir::StoreOp,
cir::CmpThreeWayOp, cir::LocalInitOp, cir::StdOpInterface>(
op))
opsToTransform.push_back(op);
@@ -2965,3 +3006,14 @@ mlir::createLoweringPreparePass(clang::ASTContext
*astCtx) {
pass->setASTContext(astCtx);
return std::move(pass);
}
+
+std::unique_ptr<Pass> mlir::createComplexLoweringPass() {
+ return std::make_unique<ComplexLoweringPass>();
+}
+
+std::unique_ptr<Pass>
+mlir::createComplexLoweringPass(clang::ASTContext *astCtx) {
+ auto pass = std::make_unique<ComplexLoweringPass>();
+ pass->setASTContext(astCtx);
+ return std::move(pass);
+}
diff --git a/clang/lib/CIR/Lowering/CIRPasses.cpp
b/clang/lib/CIR/Lowering/CIRPasses.cpp
index 1d1fdaf42aaa4..1d1501e3719ee 100644
--- a/clang/lib/CIR/Lowering/CIRPasses.cpp
+++ b/clang/lib/CIR/Lowering/CIRPasses.cpp
@@ -106,6 +106,12 @@ runCIRToCIRPasses(mlir::ModuleOp theModule,
mlir::MLIRContext &mlirContext,
pm.addPass(mlir::createTargetLoweringPass());
pm.addPass(mlir::createCXXABILoweringPass());
+ // Complex multiplication and division synthesize calls to runtime helpers
+ // such as __mulsc3 and __divsc3, so they must be expanded before
+ // CallConvLowering classifies calls. The rest of the lowering-prepare work
+ // stays after it.
+ pm.addPass(mlir::createComplexLoweringPass(&astContext));
+
if (enableCallConvLowering) {
// CallConvLowering rewrites signatures and call sites using the
classifier,
// so it must run after CXXABILowering has lowered C++ ABI types to plain
diff --git a/clang/test/CIR/CodeGen/complex-compound-assignment.cpp
b/clang/test/CIR/CodeGen/complex-compound-assignment.cpp
index 8e58c51c570a9..e56717f064fa6 100644
--- a/clang/test/CIR/CodeGen/complex-compound-assignment.cpp
+++ b/clang/test/CIR/CodeGen/complex-compound-assignment.cpp
@@ -415,7 +415,10 @@ void foo7() {
// CIR: %[[CONST_FALSE:.*]] = cir.const #false
// CIR: %[[SELECT_CONDITION:.*]] = cir.select if %[[IS_C_REAL_NAN]] then
%[[IS_C_IMAG_NAN]] else %[[CONST_FALSE]] : (!cir.bool, !cir.bool, !cir.bool) ->
!cir.bool
// CIR: %[[RESULT:.*]] = cir.ternary(%[[SELECT_CONDITION]], true {
-// CIR: %[[LIBC_COMPLEX:.*]] = cir.call @__mulsc3(%[[B_REAL]], %[[B_IMAG]],
%[[A_REAL]], %[[A_IMAG]]) : (!cir.float, !cir.float, !cir.float, !cir.float) ->
!cir.complex<!cir.float>
+// CIR: %[[LIBC_COERCED:.*]] = cir.call @__mulsc3(%[[B_REAL]], %[[B_IMAG]],
%[[A_REAL]], %[[A_IMAG]]) : (!cir.float, !cir.float, !cir.float, !cir.float) ->
!cir.vector<2 x !cir.float>
+// CIR: cir.store %[[LIBC_COERCED]], %[[COERCE_SLOT:.*]] : !cir.vector<2 x
!cir.float>, !cir.ptr<!cir.vector<2 x !cir.float>>
+// CIR: %[[COERCE_PTR:.*]] = cir.cast bitcast %[[COERCE_SLOT]] :
!cir.ptr<!cir.vector<2 x !cir.float>> -> !cir.ptr<!cir.complex<!cir.float>>
+// CIR: %[[LIBC_COMPLEX:.*]] = cir.load %[[COERCE_PTR]] :
!cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
// CIR: cir.yield %[[LIBC_COMPLEX]] : !cir.complex<!cir.float>
// CIR: }, false {
// CIR: cir.yield %[[COMPLEX]] : !cir.complex<!cir.float>
@@ -443,7 +446,9 @@ void foo7() {
// LLVM: %[[SELECT_CONDITION:.*]] = and i1 %[[IS_C_REAL_NAN]],
%[[IS_C_IMAG_NAN]]
// LLVM: br i1 %[[SELECT_CONDITION]], label %[[THEN_LABEL:.*]], label
%[[ELSE_LABEL:.*]]
// LLVM: [[THEN_LABEL]]:
-// LLVM: %[[LIBC_COMPLEX:.*]] = call { float, float } @__mulsc3(float
%[[B_REAL]], float %[[B_IMAG]], float %[[A_REAL]], float %[[A_IMAG]])
+// LLVM: %[[LIBC_COERCED:.*]] = call <2 x float> @__mulsc3(float %[[B_REAL]],
float %[[B_IMAG]], float %[[A_REAL]], float %[[A_IMAG]])
+// LLVM: store <2 x float> %[[LIBC_COERCED]], ptr %[[COERCE_SLOT:.*]], align 8
+// LLVM: %[[LIBC_COMPLEX:.*]] = load { float, float }, ptr %[[COERCE_SLOT]],
align 4
// LLVM: br label %[[PHI_BRANCH:.*]]
// LLVM: [[ELSE_LABEL]]:
// LLVM: br label %[[PHI_BRANCH:]]
@@ -548,7 +553,10 @@ void foo10() {
// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] :
!cir.complex<!cir.float> -> !cir.float
// CIR: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] :
!cir.complex<!cir.float> -> !cir.float
// CIR: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] :
!cir.complex<!cir.float> -> !cir.float
-// CIR: %[[RESULT:.*]] = cir.call @__divsc3(%[[A_REAL]], %[[A_IMAG]],
%[[B_REAL]], %[[B_IMAG]]) : (!cir.float, !cir.float, !cir.float, !cir.float) ->
!cir.complex<!cir.float>
+// CIR: %[[COERCED:.*]] = cir.call @__divsc3(%[[A_REAL]], %[[A_IMAG]],
%[[B_REAL]], %[[B_IMAG]]) : (!cir.float, !cir.float, !cir.float, !cir.float) ->
!cir.vector<2 x !cir.float>
+// CIR: cir.store %[[COERCED]], %[[COERCE_SLOT:.*]] : !cir.vector<2 x
!cir.float>, !cir.ptr<!cir.vector<2 x !cir.float>>
+// CIR: %[[COERCE_PTR:.*]] = cir.cast bitcast %[[COERCE_SLOT]] :
!cir.ptr<!cir.vector<2 x !cir.float>> -> !cir.ptr<!cir.complex<!cir.float>>
+// CIR: %[[RESULT:.*]] = cir.load %[[COERCE_PTR]] :
!cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
// CIR: cir.store{{.*}} %[[RESULT]], %[[A_ADDR]] : !cir.complex<!cir.float>,
!cir.ptr<!cir.complex<!cir.float>>
// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, align 4
@@ -559,7 +567,9 @@ void foo10() {
// LLVM: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1
// LLVM: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0
// LLVM: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1
-// LLVM: %[[RESULT:.*]] = call { float, float } @__divsc3(float %[[A_REAL]],
float %[[A_IMAG]], float %[[B_REAL]], float %[[B_IMAG]])
+// LLVM: %[[COERCED:.*]] = call <2 x float> @__divsc3(float %[[A_REAL]], float
%[[A_IMAG]], float %[[B_REAL]], float %[[B_IMAG]])
+// LLVM: store <2 x float> %[[COERCED]], ptr %[[COERCE_SLOT:.*]], align 8
+// LLVM: %[[RESULT:.*]] = load { float, float }, ptr %[[COERCE_SLOT]], align 4
// LLVM: store { float, float } %[[RESULT]], ptr %[[A_ADDR]], align 4
// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4
@@ -725,7 +735,10 @@ void foo13() {
// CIR: %[[A_IMAG_F32:.*]] = cir.complex.imag %[[A_COMPLEX_F32]] :
!cir.complex<!cir.float> -> !cir.float
// CIR: %[[B_REAL_F32:.*]] = cir.complex.real %[[B_COMPLEX_F32]] :
!cir.complex<!cir.float> -> !cir.float
// CIR: %[[B_IMAG_F32:.*]] = cir.complex.imag %[[B_COMPLEX_F32]] :
!cir.complex<!cir.float> -> !cir.float
-// CIR: %[[DIV_A_B:.*]] = cir.call @__divsc3(%[[A_REAL_F32]], %[[A_IMAG_F32]],
%[[B_REAL_F32]], %[[B_IMAG_F32]]) : (!cir.float, !cir.float, !cir.float,
!cir.float) -> !cir.complex<!cir.float>
+// CIR: %[[DIV_A_B_COERCED:.*]] = cir.call @__divsc3(%[[A_REAL_F32]],
%[[A_IMAG_F32]], %[[B_REAL_F32]], %[[B_IMAG_F32]]) : (!cir.float, !cir.float,
!cir.float, !cir.float) -> !cir.vector<2 x !cir.float>
+// CIR: cir.store %[[DIV_A_B_COERCED]], %[[SLOT_AB:.*]] : !cir.vector<2 x
!cir.float>, !cir.ptr<!cir.vector<2 x !cir.float>>
+// CIR: %[[SLOT_AB_PTR:.*]] = cir.cast bitcast %[[SLOT_AB]] :
!cir.ptr<!cir.vector<2 x !cir.float>> -> !cir.ptr<!cir.complex<!cir.float>>
+// CIR: %[[DIV_A_B:.*]] = cir.load %[[SLOT_AB_PTR]] :
!cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
// CIR: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] :
!cir.ptr<!cir.complex<!cir.f16>>, !cir.complex<!cir.f16>
// CIR: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.f16>
-> !cir.f16
// CIR: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.f16>
-> !cir.f16
@@ -736,7 +749,10 @@ void foo13() {
// CIR: %[[B_IMAG_F32:.*]] = cir.complex.imag %[[B_COMPLEX_F32]] :
!cir.complex<!cir.float> -> !cir.float
// CIR: %[[DIV_AB_REAL:.*]] = cir.complex.real %[[DIV_A_B]] :
!cir.complex<!cir.float> -> !cir.float
// CIR: %[[DIV_AB_IMAG:.*]] = cir.complex.imag %[[DIV_A_B]] :
!cir.complex<!cir.float> -> !cir.float
-// CIR: %[[RESULT:.*]] = cir.call @__divsc3(%[[B_REAL_F32]], %[[B_IMAG_F32]],
%[[DIV_AB_REAL]], %[[DIV_AB_IMAG]]) : (!cir.float, !cir.float, !cir.float,
!cir.float) -> !cir.complex<!cir.float>
+// CIR: %[[RESULT_COERCED:.*]] = cir.call @__divsc3(%[[B_REAL_F32]],
%[[B_IMAG_F32]], %[[DIV_AB_REAL]], %[[DIV_AB_IMAG]]) : (!cir.float, !cir.float,
!cir.float, !cir.float) -> !cir.vector<2 x !cir.float>
+// CIR: cir.store %[[RESULT_COERCED]], %[[SLOT_R:.*]] : !cir....
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/216498
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits