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 `&lt;2 
x float&gt;`, 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

Reply via email to