[flang-commits] [flang] 2384e84 - [flang] Restore stack after allocas created by TargetRewrite.
Slava Zakharin via flang-commits
flang-commits at lists.llvm.org
Wed Apr 26 10:33:39 PDT 2023
Author: Slava Zakharin
Date: 2023-04-26T10:33:00-07:00
New Revision: 2384e84bbbfd8d713fd2e1ffcc7d3d89dc1a0f16
URL: https://github.com/llvm/llvm-project/commit/2384e84bbbfd8d713fd2e1ffcc7d3d89dc1a0f16
DIFF: https://github.com/llvm/llvm-project/commit/2384e84bbbfd8d713fd2e1ffcc7d3d89dc1a0f16.diff
LOG: [flang] Restore stack after allocas created by TargetRewrite.
This resolves issues with running out of stack on examples like
https://fortran-lang.discourse.group/t/modern-fortran-sample-code/2019/18
reported by @clementval.
When target rewrite creates alloca(s) around a call, we need to insert
stacksave/stackrestore to free the allocated stack. Better performant
code may be achieved by placing the alloca(s) outside of loops,
but the placement has to behave correctly with regards to OpenMP/OpenACC/etc.
dialect operations that have special representation for "private"
objects. This is a concervative fix for correctness issue.
Differential Revision: https://reviews.llvm.org/D149222
Added:
Modified:
flang/include/flang/Optimizer/CodeGen/CGPasses.td
flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
flang/test/Fir/target-rewrite-complex16.fir
flang/test/Fir/target.fir
Removed:
################################################################################
diff --git a/flang/include/flang/Optimizer/CodeGen/CGPasses.td b/flang/include/flang/Optimizer/CodeGen/CGPasses.td
index c215cb647849d..0014298a27a22 100644
--- a/flang/include/flang/Optimizer/CodeGen/CGPasses.td
+++ b/flang/include/flang/Optimizer/CodeGen/CGPasses.td
@@ -53,7 +53,7 @@ def TargetRewritePass : Pass<"target-rewrite", "mlir::ModuleOp"> {
representations that may
diff er based on the target machine.
}];
let constructor = "::fir::createFirTargetRewritePass()";
- let dependentDialects = [ "fir::FIROpsDialect" ];
+ let dependentDialects = [ "fir::FIROpsDialect", "mlir::func::FuncDialect" ];
let options = [
Option<"forcedTargetTriple", "target", "std::string", /*default=*/"",
"Override module's target triple.">,
diff --git a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
index 813e32eeced97..b38c64cc790b2 100644
--- a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
+++ b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
@@ -91,6 +91,13 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
mod.getContext(), fir::getTargetTriple(mod), fir::getKindMapping(mod));
setMembers(specifics.get(), &rewriter);
+ // We may need to call stacksave/stackrestore later, so
+ // create the FuncOps beforehand.
+ fir::FirOpBuilder builder(rewriter, fir::getKindMapping(mod));
+ builder.setInsertionPointToStart(mod.getBody());
+ stackSaveFn = fir::factory::getLlvmStackSave(builder);
+ stackRestoreFn = fir::factory::getLlvmStackRestore(builder);
+
// Perform type conversion on signatures and call sites.
if (mlir::failed(convertTypes(mod))) {
mlir::emitError(mlir::UnknownLoc::get(&context),
@@ -121,7 +128,8 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
template <typename A, typename B, typename C>
std::optional<std::function<mlir::Value(mlir::Operation *)>>
rewriteCallComplexResultType(mlir::Location loc, A ty, B &newResTys,
- B &newInTys, C &newOpers) {
+ B &newInTys, C &newOpers,
+ mlir::Value &savedStackPtr) {
if (noComplexConversion) {
newResTys.push_back(ty);
return std::nullopt;
@@ -134,6 +142,11 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
auto attr = std::get<fir::CodeGenSpecifics::Attributes>(m[0]);
if (attr.isSRet()) {
assert(fir::isa_ref_type(resTy) && "must be a memory reference type");
+ // Save the stack pointer, if it has not been saved for this call yet.
+ // We will need to restore it after the call, because the alloca
+ // needs to be deallocated.
+ if (!savedStackPtr)
+ savedStackPtr = genStackSave(loc);
mlir::Value stack =
rewriter->create<fir::AllocaOp>(loc, fir::dyn_cast_ptrEleTy(resTy));
newInTys.push_back(resTy);
@@ -145,7 +158,10 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
};
}
newResTys.push_back(resTy);
- return [=](mlir::Operation *call) -> mlir::Value {
+ return [=, &savedStackPtr](mlir::Operation *call) -> mlir::Value {
+ // We are going to generate an alloca, so save the stack pointer.
+ if (!savedStackPtr)
+ savedStackPtr = genStackSave(loc);
auto mem = rewriter->create<fir::AllocaOp>(loc, resTy);
rewriter->create<fir::StoreOp>(loc, call->getResult(0), mem);
auto memTy = fir::ReferenceType::get(ty);
@@ -156,7 +172,7 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
template <typename A, typename B, typename C>
void rewriteCallComplexInputType(A ty, mlir::Value oper, B &newInTys,
- C &newOpers) {
+ C &newOpers, mlir::Value &savedStackPtr) {
if (noComplexConversion) {
newInTys.push_back(ty);
newOpers.push_back(oper);
@@ -173,6 +189,9 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
auto resTy = std::get<mlir::Type>(m[0]);
auto attr = std::get<fir::CodeGenSpecifics::Attributes>(m[0]);
auto oldRefTy = fir::ReferenceType::get(ty);
+ // We are going to generate an alloca, so save the stack pointer.
+ if (!savedStackPtr)
+ savedStackPtr = genStackSave(loc);
if (attr.isByVal()) {
auto mem = rewriter->create<fir::AllocaOp>(loc, ty);
rewriter->create<fir::StoreOp>(loc, oper, mem);
@@ -210,6 +229,7 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
llvm::SmallVector<mlir::Type> newResTys;
llvm::SmallVector<mlir::Type> newInTys;
llvm::SmallVector<mlir::Value> newOpers;
+ mlir::Value savedStackPtr = nullptr;
// If the call is indirect, the first argument must still be the function
// to call.
@@ -231,11 +251,11 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
llvm::TypeSwitch<mlir::Type>(ty)
.template Case<fir::ComplexType>([&](fir::ComplexType cmplx) {
wrap = rewriteCallComplexResultType(loc, cmplx, newResTys, newInTys,
- newOpers);
+ newOpers, savedStackPtr);
})
.template Case<mlir::ComplexType>([&](mlir::ComplexType cmplx) {
wrap = rewriteCallComplexResultType(loc, cmplx, newResTys, newInTys,
- newOpers);
+ newOpers, savedStackPtr);
})
.Default([&](mlir::Type ty) { newResTys.push_back(ty); });
} else if (fnTy.getResults().size() > 1) {
@@ -290,10 +310,12 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
}
})
.template Case<fir::ComplexType>([&](fir::ComplexType cmplx) {
- rewriteCallComplexInputType(cmplx, oper, newInTys, newOpers);
+ rewriteCallComplexInputType(cmplx, oper, newInTys, newOpers,
+ savedStackPtr);
})
.template Case<mlir::ComplexType>([&](mlir::ComplexType cmplx) {
- rewriteCallComplexInputType(cmplx, oper, newInTys, newOpers);
+ rewriteCallComplexInputType(cmplx, oper, newInTys, newOpers,
+ savedStackPtr);
})
.template Case<mlir::TupleType>([&](mlir::TupleType tuple) {
if (fir::isCharacterProcedureTuple(tuple)) {
@@ -343,6 +365,8 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
}
newInTys.insert(newInTys.end(), trailingInTys.begin(), trailingInTys.end());
newOpers.insert(newOpers.end(), trailingOpers.begin(), trailingOpers.end());
+
+ llvm::SmallVector<mlir::Value, 1> newCallResults;
if constexpr (std::is_same_v<std::decay_t<A>, fir::CallOp>) {
fir::CallOp newCall;
if (callOp.getCallee()) {
@@ -357,18 +381,40 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
}
LLVM_DEBUG(llvm::dbgs() << "replacing call with " << newCall << '\n');
if (wrap)
- replaceOp(callOp, (*wrap)(newCall.getOperation()));
+ newCallResults.push_back((*wrap)(newCall.getOperation()));
else
- replaceOp(callOp, newCall.getResults());
+ newCallResults.append(newCall.result_begin(), newCall.result_end());
} else {
fir::DispatchOp dispatchOp = rewriter->create<A>(
loc, newResTys, rewriter->getStringAttr(callOp.getMethod()),
callOp.getOperands()[0], newOpers,
rewriter->getI32IntegerAttr(*callOp.getPassArgPos() + passArgShift));
if (wrap)
- replaceOp(callOp, (*wrap)(dispatchOp.getOperation()));
+ newCallResults.push_back((*wrap)(dispatchOp.getOperation()));
else
- replaceOp(callOp, dispatchOp.getResults());
+ newCallResults.append(dispatchOp.result_begin(),
+ dispatchOp.result_end());
+ }
+
+ if (newCallResults.size() <= 1) {
+ if (savedStackPtr) {
+ if (newCallResults.size() == 1) {
+ // We assume that all the allocas are inserted before
+ // the operation that defines the new call result.
+ rewriter->setInsertionPointAfterValue(newCallResults[0]);
+ } else {
+ // If the call does not have results, then insert
+ // stack restore after the original call operation.
+ rewriter->setInsertionPointAfter(callOp);
+ }
+ genStackRestore(loc, savedStackPtr);
+ }
+ replaceOp(callOp, newCallResults);
+ } else {
+ // The TODO is duplicated here to make sure this part
+ // handles the stackrestore insertion properly, if
+ // we add support for multiple call results.
+ TODO(loc, "multiple results not supported yet");
}
}
@@ -974,8 +1020,22 @@ class TargetRewrite : public fir::impl::TargetRewritePassBase<TargetRewrite> {
inline void clearMembers() { setMembers(nullptr, nullptr); }
+ // Inserts a call to llvm.stacksave at the current insertion
+ // point and the given location. Returns the call's result Value.
+ inline mlir::Value genStackSave(mlir::Location loc) {
+ return rewriter->create<fir::CallOp>(loc, stackSaveFn).getResult(0);
+ }
+
+ // Inserts a call to llvm.stackrestore at the current insertion
+ // point and the given location and argument.
+ inline void genStackRestore(mlir::Location loc, mlir::Value sp) {
+ rewriter->create<fir::CallOp>(loc, stackRestoreFn, mlir::ValueRange{sp});
+ }
+
fir::CodeGenSpecifics *specifics = nullptr;
mlir::OpBuilder *rewriter = nullptr;
+ mlir::func::FuncOp stackSaveFn = nullptr;
+ mlir::func::FuncOp stackRestoreFn = nullptr;
}; // namespace
} // namespace
diff --git a/flang/test/Fir/target-rewrite-complex16.fir b/flang/test/Fir/target-rewrite-complex16.fir
index 2627af41c9b8e..0903075ad223f 100644
--- a/flang/test/Fir/target-rewrite-complex16.fir
+++ b/flang/test/Fir/target-rewrite-complex16.fir
@@ -63,57 +63,65 @@ func.func @addrof() {
// CHECK: func.func private @paramcomplex16(!fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval = tuple<!fir.real<16>, !fir.real<16>>})
// CHECK-LABEL: func.func @callcomplex16() {
-// CHECK: %[[VAL_0:.*]] = fir.alloca tuple<!fir.real<16>, !fir.real<16>>
-// CHECK: fir.call @returncomplex16(%[[VAL_0]]) : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> ()
-// CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> !fir.ref<!fir.complex<16>>
-// CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.complex<16>>
-// CHECK: %[[VAL_3:.*]] = fir.alloca !fir.complex<16>
-// CHECK: fir.store %[[VAL_2]] to %[[VAL_3]] : !fir.ref<!fir.complex<16>>
-// CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<!fir.complex<16>>) -> !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>
-// CHECK: fir.call @paramcomplex16(%[[VAL_4]]) : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> ()
+// CHECK: %[[VAL_0:.*]] = fir.call @llvm.stacksave() : () -> !fir.ref<i8>
+// CHECK: %[[VAL_1:.*]] = fir.alloca tuple<!fir.real<16>, !fir.real<16>>
+// CHECK: fir.call @returncomplex16(%[[VAL_1]]) : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> ()
+// CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> !fir.ref<!fir.complex<16>>
+// CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.complex<16>>
+// CHECK: fir.call @llvm.stackrestore(%[[VAL_0]]) : (!fir.ref<i8>) -> ()
+// CHECK: %[[VAL_4:.*]] = fir.call @llvm.stacksave() : () -> !fir.ref<i8>
+// CHECK: %[[VAL_5:.*]] = fir.alloca !fir.complex<16>
+// CHECK: fir.store %[[VAL_3]] to %[[VAL_5]] : !fir.ref<!fir.complex<16>>
+// CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (!fir.ref<!fir.complex<16>>) -> !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>
+// CHECK: fir.call @paramcomplex16(%[[VAL_6]]) : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> ()
+// CHECK: fir.call @llvm.stackrestore(%[[VAL_4]]) : (!fir.ref<i8>) -> ()
// CHECK: return
// CHECK: }
// CHECK: func.func private @calleemultipleparamscomplex16(!fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval = tuple<!fir.real<16>, !fir.real<16>>}, !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval = tuple<!fir.real<16>, !fir.real<16>>}, !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval = tuple<!fir.real<16>, !fir.real<16>>})
// CHECK-LABEL: func.func @multipleparamscomplex16(
-// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval = tuple<!fir.real<16>, !fir.real<16>>}, %[[VAL_1:.*]]: !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval = tuple<!fir.real<16>, !fir.real<16>>}, %[[VAL_2:.*]]: !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval = tuple<!fir.real<16>, !fir.real<16>>}) {
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval = tuple<!fir.real<16>, !fir.real<16>>}, %[[VAL_1:.*]]: !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval = tuple<!fir.real<16>, !fir.real<16>>}, %[[VAL_2:.*]]: !fir.ref<tuple<!fir.real<16>, !fir.real<16>>> {llvm.align = 16 : i32, llvm.byval = tuple<!fir.real<16>, !fir.real<16>>}) {
// CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> !fir.ref<!fir.complex<16>>
// CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]] : !fir.ref<!fir.complex<16>>
// CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> !fir.ref<!fir.complex<16>>
// CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_5]] : !fir.ref<!fir.complex<16>>
// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> !fir.ref<!fir.complex<16>>
// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_7]] : !fir.ref<!fir.complex<16>>
-// CHECK: %[[VAL_9:.*]] = fir.alloca !fir.complex<16>
-// CHECK: fir.store %[[VAL_8]] to %[[VAL_9]] : !fir.ref<!fir.complex<16>>
-// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (!fir.ref<!fir.complex<16>>) -> !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>
-// CHECK: %[[VAL_11:.*]] = fir.alloca !fir.complex<16>
-// CHECK: fir.store %[[VAL_6]] to %[[VAL_11]] : !fir.ref<!fir.complex<16>>
-// CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.ref<!fir.complex<16>>) -> !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>
-// CHECK: %[[VAL_13:.*]] = fir.alloca !fir.complex<16>
-// CHECK: fir.store %[[VAL_4]] to %[[VAL_13]] : !fir.ref<!fir.complex<16>>
-// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (!fir.ref<!fir.complex<16>>) -> !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>
-// CHECK: fir.call @calleemultipleparamscomplex16(%[[VAL_10]], %[[VAL_12]], %[[VAL_14]]) : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>, !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>, !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> ()
+// CHECK: %[[VAL_9:.*]] = fir.call @llvm.stacksave() : () -> !fir.ref<i8>
+// CHECK: %[[VAL_10:.*]] = fir.alloca !fir.complex<16>
+// CHECK: fir.store %[[VAL_8]] to %[[VAL_10]] : !fir.ref<!fir.complex<16>>
+// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (!fir.ref<!fir.complex<16>>) -> !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>
+// CHECK: %[[VAL_12:.*]] = fir.alloca !fir.complex<16>
+// CHECK: fir.store %[[VAL_6]] to %[[VAL_12]] : !fir.ref<!fir.complex<16>>
+// CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_12]] : (!fir.ref<!fir.complex<16>>) -> !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>
+// CHECK: %[[VAL_14:.*]] = fir.alloca !fir.complex<16>
+// CHECK: fir.store %[[VAL_4]] to %[[VAL_14]] : !fir.ref<!fir.complex<16>>
+// CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (!fir.ref<!fir.complex<16>>) -> !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>
+// CHECK: fir.call @calleemultipleparamscomplex16(%[[VAL_11]], %[[VAL_13]], %[[VAL_15]]) : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>, !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>, !fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> ()
+// CHECK: fir.call @llvm.stackrestore(%[[VAL_9]]) : (!fir.ref<i8>) -> ()
// CHECK: return
// CHECK: }
// CHECK-LABEL: func.func private @mlircomplexf128(
-// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<f128, f128>> {llvm.align = 16 : i32, llvm.sret = tuple<f128, f128>}, %[[VAL_1:.*]]: !fir.ref<tuple<f128, f128>> {llvm.align = 16 : i32, llvm.byval = tuple<f128, f128>}, %[[VAL_2:.*]]: !fir.ref<tuple<f128, f128>> {llvm.align = 16 : i32, llvm.byval = tuple<f128, f128>}) {
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<tuple<f128, f128>> {llvm.align = 16 : i32, llvm.sret = tuple<f128, f128>}, %[[VAL_1:.*]]: !fir.ref<tuple<f128, f128>> {llvm.align = 16 : i32, llvm.byval = tuple<f128, f128>}, %[[VAL_2:.*]]: !fir.ref<tuple<f128, f128>> {llvm.align = 16 : i32, llvm.byval = tuple<f128, f128>}) {
// CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<tuple<f128, f128>>) -> !fir.ref<complex<f128>>
// CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]] : !fir.ref<complex<f128>>
// CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<tuple<f128, f128>>) -> !fir.ref<complex<f128>>
// CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_5]] : !fir.ref<complex<f128>>
-// CHECK: %[[VAL_7:.*]] = fir.alloca tuple<f128, f128>
-// CHECK: %[[VAL_8:.*]] = fir.alloca complex<f128>
-// CHECK: fir.store %[[VAL_6]] to %[[VAL_8]] : !fir.ref<complex<f128>>
-// CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.ref<complex<f128>>) -> !fir.ref<tuple<f128, f128>>
-// CHECK: %[[VAL_10:.*]] = fir.alloca complex<f128>
-// CHECK: fir.store %[[VAL_4]] to %[[VAL_10]] : !fir.ref<complex<f128>>
-// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (!fir.ref<complex<f128>>) -> !fir.ref<tuple<f128, f128>>
-// CHECK: fir.call @mlircomplexf128(%[[VAL_7]], %[[VAL_9]], %[[VAL_11]]) : (!fir.ref<tuple<f128, f128>>, !fir.ref<tuple<f128, f128>>, !fir.ref<tuple<f128, f128>>) -> ()
-// CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<tuple<f128, f128>>) -> !fir.ref<complex<f128>>
-// CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_12]] : !fir.ref<complex<f128>>
-// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<f128, f128>>) -> !fir.ref<complex<f128>>
-// CHECK: fir.store %[[VAL_13]] to %[[VAL_14]] : !fir.ref<complex<f128>>
+// CHECK: %[[VAL_7:.*]] = fir.call @llvm.stacksave() : () -> !fir.ref<i8>
+// CHECK: %[[VAL_8:.*]] = fir.alloca tuple<f128, f128>
+// CHECK: %[[VAL_9:.*]] = fir.alloca complex<f128>
+// CHECK: fir.store %[[VAL_6]] to %[[VAL_9]] : !fir.ref<complex<f128>>
+// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (!fir.ref<complex<f128>>) -> !fir.ref<tuple<f128, f128>>
+// CHECK: %[[VAL_11:.*]] = fir.alloca complex<f128>
+// CHECK: fir.store %[[VAL_4]] to %[[VAL_11]] : !fir.ref<complex<f128>>
+// CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.ref<complex<f128>>) -> !fir.ref<tuple<f128, f128>>
+// CHECK: fir.call @mlircomplexf128(%[[VAL_8]], %[[VAL_10]], %[[VAL_12]]) : (!fir.ref<tuple<f128, f128>>, !fir.ref<tuple<f128, f128>>, !fir.ref<tuple<f128, f128>>) -> ()
+// CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_8]] : (!fir.ref<tuple<f128, f128>>) -> !fir.ref<complex<f128>>
+// CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_13]] : !fir.ref<complex<f128>>
+// CHECK: fir.call @llvm.stackrestore(%[[VAL_7]]) : (!fir.ref<i8>) -> ()
+// CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<f128, f128>>) -> !fir.ref<complex<f128>>
+// CHECK: fir.store %[[VAL_14]] to %[[VAL_15]] : !fir.ref<complex<f128>>
// CHECK: return
// CHECK: }
@@ -122,3 +130,5 @@ func.func @addrof() {
// CHECK: %[[VAL_1:.*]] = fir.address_of(@paramcomplex16) : (!fir.ref<tuple<!fir.real<16>, !fir.real<16>>>) -> ()
// CHECK: return
// CHECK: }
+// CHECK: func.func private @llvm.stacksave() -> !fir.ref<i8>
+// CHECK: func.func private @llvm.stackrestore(!fir.ref<i8>)
diff --git a/flang/test/Fir/target.fir b/flang/test/Fir/target.fir
index f6cf0587fcae9..653b100bccbd4 100644
--- a/flang/test/Fir/target.fir
+++ b/flang/test/Fir/target.fir
@@ -87,7 +87,7 @@ func.func @call8() {
// PPC: = call { double, double } @gen8()
%1 = fir.call @gen8() : () -> !fir.complex<8>
// I32: call void @sink8(ptr %
- // X64: call void @sink8(double %4, double %5)
+ // X64: call void @sink8(double %{{[0-9]*}}, double %{{[0-9]*}})
// AARCH64: call void @sink8([2 x double] %
// PPC: call void @sink8(double %{{.*}}, double %{{.*}})
fir.call @sink8(%1) : (!fir.complex<8>) -> ()
More information about the flang-commits
mailing list