From faf6544603b16652369d28a3af4e97d00c58b95a Mon Sep 17 00:00:00 2001 From: Sathvik Reddy Date: Sat, 8 Nov 2025 10:53:37 +0530 Subject: [PATCH 1/6] [flang] Lower PAUSE statement with code and message operands This patch adds lowering support for the Fortran PAUSE statement to FIR. It mirrors the STOP statement lowering logic to handle: - PAUSE with no operand - PAUSE - PAUSE 'message' Fixes #166821. --- flang/lib/Lower/Runtime.cpp | 48 +++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/flang/lib/Lower/Runtime.cpp b/flang/lib/Lower/Runtime.cpp index cb555249125f6..d864b027c3183 100644 --- a/flang/lib/Lower/Runtime.cpp +++ b/flang/lib/Lower/Runtime.cpp @@ -263,12 +263,52 @@ void Fortran::lower::genSyncTeamStatement( void Fortran::lower::genPauseStatement( Fortran::lower::AbstractConverter &converter, - const Fortran::parser::PauseStmt &) { + const Fortran::parser::PauseStmt &stmt) { fir::FirOpBuilder &builder = converter.getFirOpBuilder(); mlir::Location loc = converter.getCurrentLocation(); - mlir::func::FuncOp callee = - fir::runtime::getRuntimeFunc(loc, builder); - fir::CallOp::create(builder, loc, callee, mlir::ValueRange{}); + Fortran::lower::StatementContext stmtCtx; + llvm::SmallVector operands; + mlir::func::FuncOp callee; + mlir::FunctionType calleeType; + + if (stmt.v.has_value()) { + const Fortran::parser::StopCode &code = stmt.v.value(); + auto expr = converter.genExprValue(*Fortran::semantics::GetExpr(code), stmtCtx); + LLVM_DEBUG(llvm::dbgs() << "pause expression: "; expr.dump(); llvm::dbgs() << '\n'); + expr.match( + [&](const fir::CharBoxValue &x) { + callee = fir::runtime::getRuntimeFunc(loc, builder); + calleeType = callee.getFunctionType(); + operands.push_back( + builder.createConvert(loc, calleeType.getInput(0), x.getAddr())); + operands.push_back( + builder.createConvert(loc, calleeType.getInput(1), x.getLen())); + }, + [&](fir::UnboxedValue x) { + callee = fir::runtime::getRuntimeFunc(loc, builder); + calleeType = callee.getFunctionType(); + mlir::Value cast = + builder.createConvert(loc, calleeType.getInput(0), x); + operands.push_back(cast); + }, + [&](auto) { + mlir::emitError(loc, "unhandled expression in PAUSE"); + std::exit(1); + }); + } else { + callee = fir::runtime::getRuntimeFunc(loc, builder); + calleeType = callee.getFunctionType(); + } + + fir::CallOp::create(builder, loc, callee, operands); + + auto blockIsUnterminated = [&builder]() { + mlir::Block *currentBlock = builder.getBlock(); + return currentBlock->empty() || + !currentBlock->back().hasTrait(); + }; + if (blockIsUnterminated()) + genUnreachable(builder, loc); } void Fortran::lower::genPointerAssociate(fir::FirOpBuilder &builder, From 8914d5ef9356b1601a6f7799d66af65138c3b268 Mon Sep 17 00:00:00 2001 From: Sathvik Reddy Date: Sat, 8 Nov 2025 14:55:25 +0530 Subject: [PATCH 2/6] [flang] add check for number of inputs and remove unreachable block code --- flang/lib/Lower/Runtime.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/flang/lib/Lower/Runtime.cpp b/flang/lib/Lower/Runtime.cpp index d864b027c3183..48c70f4180de0 100644 --- a/flang/lib/Lower/Runtime.cpp +++ b/flang/lib/Lower/Runtime.cpp @@ -264,32 +264,39 @@ void Fortran::lower::genSyncTeamStatement( void Fortran::lower::genPauseStatement( Fortran::lower::AbstractConverter &converter, const Fortran::parser::PauseStmt &stmt) { + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); mlir::Location loc = converter.getCurrentLocation(); Fortran::lower::StatementContext stmtCtx; + llvm::SmallVector operands; mlir::func::FuncOp callee; mlir::FunctionType calleeType; if (stmt.v.has_value()) { - const Fortran::parser::StopCode &code = stmt.v.value(); + const auto &code = stmt.v.value(); auto expr = converter.genExprValue(*Fortran::semantics::GetExpr(code), stmtCtx); LLVM_DEBUG(llvm::dbgs() << "pause expression: "; expr.dump(); llvm::dbgs() << '\n'); expr.match( + // Character-valued expression -> call PauseStatementText (CHAR, LEN) [&](const fir::CharBoxValue &x) { callee = fir::runtime::getRuntimeFunc(loc, builder); calleeType = callee.getFunctionType(); + operands.push_back( builder.createConvert(loc, calleeType.getInput(0), x.getAddr())); operands.push_back( builder.createConvert(loc, calleeType.getInput(1), x.getLen())); }, + // Numeric/unboxed value -> call PauseStatement which accepts an integer code. [&](fir::UnboxedValue x) { - callee = fir::runtime::getRuntimeFunc(loc, builder); - calleeType = callee.getFunctionType(); - mlir::Value cast = - builder.createConvert(loc, calleeType.getInput(0), x); - operands.push_back(cast); + callee = fir::runtime::getRuntimeFunc(loc, builder); + calleeType = callee.getFunctionType(); + if (calleeType.getNumInputs() >= 1) { + mlir::Value cast = + builder.createConvert(loc, calleeType.getInput(0), x); + operands.push_back(cast); + } }, [&](auto) { mlir::emitError(loc, "unhandled expression in PAUSE"); @@ -299,16 +306,13 @@ void Fortran::lower::genPauseStatement( callee = fir::runtime::getRuntimeFunc(loc, builder); calleeType = callee.getFunctionType(); } - + fir::CallOp::create(builder, loc, callee, operands); - auto blockIsUnterminated = [&builder]() { - mlir::Block *currentBlock = builder.getBlock(); - return currentBlock->empty() || - !currentBlock->back().hasTrait(); - }; - if (blockIsUnterminated()) - genUnreachable(builder, loc); + // NOTE: PAUSE should not unconditionally terminate the current block. + // Unlike STOP, PAUSE does not necessarily abandon control flow, so do not + // subsequent control flow (e.g. GOTO/branches) to be generated. + // insert genUnreachable() here. Leaving the block un-terminated allows } void Fortran::lower::genPointerAssociate(fir::FirOpBuilder &builder, From 99974a0e6306cb90e0085576fd9e0ed98732ac26 Mon Sep 17 00:00:00 2001 From: aditya nath Date: Sat, 8 Nov 2025 15:02:24 +0530 Subject: [PATCH 3/6] [flang] Update pause-statement testcase --- flang/test/Lower/pause-statement.f90 | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/flang/test/Lower/pause-statement.f90 b/flang/test/Lower/pause-statement.f90 index f4c8f6fbc4385..926f81e96cefd 100644 --- a/flang/test/Lower/pause-statement.f90 +++ b/flang/test/Lower/pause-statement.f90 @@ -1,4 +1,4 @@ -! RUN: bbc %s -emit-fir --canonicalize -o - | FileCheck %s +! RUN: bbc %s -emit-fir -hlfir=false --canonicalize -o - | FileCheck %s ! CHECK-LABEL: pause_test subroutine pause_test() @@ -6,3 +6,24 @@ subroutine pause_test() ! CHECK-NEXT: return pause end subroutine + +! CHECK-LABEL: pause_code +subroutine pause_code() + pause 42 + ! CHECK: fir.call @_Fortran{{.*}}PauseStatement + ! CHECK-NEXT: return +end subroutine + +! CHECK-LABEL: pause_msg +subroutine pause_msg() + pause "hello" + ! CHECK-DAG: %[[five:.*]] = arith.constant 5 : index + ! CHECK-DAG: %[[lit:.*]] = fir.address_of(@_QQ{{.*}}) : !fir.ref> + ! CHECK-DAG: %[[buff:.*]] = fir.convert %[[lit]] : (!fir.ref>) -> !fir.ref + ! CHECK-DAG: %[[len:.*]] = fir.convert %[[five]] : (index) -> i64 + ! CHECK: fir.call @_Fortran{{.*}}PauseStatementText(%[[buff]], %[[len]]) + ! CHECK-NEXT: return +end subroutine + +! CHECK-DAG: func private @_Fortran{{.*}}PauseStatement +! CHECK-DAG: func private @_Fortran{{.*}}PauseStatementText \ No newline at end of file From 0e8d546b105bcdddf5aa4b2625cab2ab26763f88 Mon Sep 17 00:00:00 2001 From: Sathvik Reddy Date: Fri, 21 Nov 2025 13:11:50 +0530 Subject: [PATCH 4/6] [flang] Address review feedback --- flang/lib/Lower/Runtime.cpp | 12 +++++------- flang/test/Lower/pause-statement.f90 | 6 +++--- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/flang/lib/Lower/Runtime.cpp b/flang/lib/Lower/Runtime.cpp index 48c70f4180de0..3e57d180c5b81 100644 --- a/flang/lib/Lower/Runtime.cpp +++ b/flang/lib/Lower/Runtime.cpp @@ -276,7 +276,6 @@ void Fortran::lower::genPauseStatement( if (stmt.v.has_value()) { const auto &code = stmt.v.value(); auto expr = converter.genExprValue(*Fortran::semantics::GetExpr(code), stmtCtx); - LLVM_DEBUG(llvm::dbgs() << "pause expression: "; expr.dump(); llvm::dbgs() << '\n'); expr.match( // Character-valued expression -> call PauseStatementText (CHAR, LEN) [&](const fir::CharBoxValue &x) { @@ -290,7 +289,7 @@ void Fortran::lower::genPauseStatement( }, // Numeric/unboxed value -> call PauseStatement which accepts an integer code. [&](fir::UnboxedValue x) { - callee = fir::runtime::getRuntimeFunc(loc, builder); + callee = fir::runtime::getRuntimeFunc(loc, builder); calleeType = callee.getFunctionType(); if (calleeType.getNumInputs() >= 1) { mlir::Value cast = @@ -299,7 +298,8 @@ void Fortran::lower::genPauseStatement( } }, [&](auto) { - mlir::emitError(loc, "unhandled expression in PAUSE"); + fir::emitFatalError(loc, "unhandled expression in PAUSE"); + // mlir::emitError(loc, "unhandled expression in PAUSE"); std::exit(1); }); } else { @@ -309,10 +309,8 @@ void Fortran::lower::genPauseStatement( fir::CallOp::create(builder, loc, callee, operands); - // NOTE: PAUSE should not unconditionally terminate the current block. - // Unlike STOP, PAUSE does not necessarily abandon control flow, so do not - // subsequent control flow (e.g. GOTO/branches) to be generated. - // insert genUnreachable() here. Leaving the block un-terminated allows + // NOTE: PAUSE does not terminate the current block. The program may resume + // and continue normal execution, so we do not emit control-flow terminators. } void Fortran::lower::genPointerAssociate(fir::FirOpBuilder &builder, diff --git a/flang/test/Lower/pause-statement.f90 b/flang/test/Lower/pause-statement.f90 index 926f81e96cefd..8eb0448587cdc 100644 --- a/flang/test/Lower/pause-statement.f90 +++ b/flang/test/Lower/pause-statement.f90 @@ -1,4 +1,4 @@ -! RUN: bbc %s -emit-fir -hlfir=false --canonicalize -o - | FileCheck %s +! RUN: bbc %s -emit-fir --canonicalize -o - | FileCheck %s ! CHECK-LABEL: pause_test subroutine pause_test() @@ -10,7 +10,7 @@ subroutine pause_test() ! CHECK-LABEL: pause_code subroutine pause_code() pause 42 - ! CHECK: fir.call @_Fortran{{.*}}PauseStatement + ! CHECK: fir.call @_Fortran{{.*}}PauseStatementInt ! CHECK-NEXT: return end subroutine @@ -26,4 +26,4 @@ subroutine pause_msg() end subroutine ! CHECK-DAG: func private @_Fortran{{.*}}PauseStatement -! CHECK-DAG: func private @_Fortran{{.*}}PauseStatementText \ No newline at end of file +! CHECK-DAG: func private @_Fortran{{.*}}PauseStatementText From 18b7e8f06ff8c6825f9744c6eaa9100e8ce39ac6 Mon Sep 17 00:00:00 2001 From: Sathvik Reddy Date: Sat, 22 Nov 2025 13:32:57 +0530 Subject: [PATCH 5/6] [flang] Add missing argument to pause_code test and clean up PAUSE lowering --- flang/lib/Lower/Runtime.cpp | 31 ++++++++++++++-------------- flang/test/Lower/pause-statement.f90 | 12 ++++++----- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/flang/lib/Lower/Runtime.cpp b/flang/lib/Lower/Runtime.cpp index 3e57d180c5b81..c64f5db8bdfcb 100644 --- a/flang/lib/Lower/Runtime.cpp +++ b/flang/lib/Lower/Runtime.cpp @@ -264,7 +264,7 @@ void Fortran::lower::genSyncTeamStatement( void Fortran::lower::genPauseStatement( Fortran::lower::AbstractConverter &converter, const Fortran::parser::PauseStmt &stmt) { - + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); mlir::Location loc = converter.getCurrentLocation(); Fortran::lower::StatementContext stmtCtx; @@ -275,11 +275,13 @@ void Fortran::lower::genPauseStatement( if (stmt.v.has_value()) { const auto &code = stmt.v.value(); - auto expr = converter.genExprValue(*Fortran::semantics::GetExpr(code), stmtCtx); + auto expr = + converter.genExprValue(*Fortran::semantics::GetExpr(code), stmtCtx); expr.match( // Character-valued expression -> call PauseStatementText (CHAR, LEN) [&](const fir::CharBoxValue &x) { - callee = fir::runtime::getRuntimeFunc(loc, builder); + callee = fir::runtime::getRuntimeFunc( + loc, builder); calleeType = callee.getFunctionType(); operands.push_back( @@ -287,26 +289,25 @@ void Fortran::lower::genPauseStatement( operands.push_back( builder.createConvert(loc, calleeType.getInput(1), x.getLen())); }, - // Numeric/unboxed value -> call PauseStatement which accepts an integer code. + // Unboxed value -> call PauseStatementInt which accepts an integer. [&](fir::UnboxedValue x) { - callee = fir::runtime::getRuntimeFunc(loc, builder); - calleeType = callee.getFunctionType(); - if (calleeType.getNumInputs() >= 1) { - mlir::Value cast = - builder.createConvert(loc, calleeType.getInput(0), x); - operands.push_back(cast); - } + callee = fir::runtime::getRuntimeFunc( + loc, builder); + calleeType = callee.getFunctionType(); + assert(calleeType.getNumInputs() >= 1); + mlir::Value cast = + builder.createConvert(loc, calleeType.getInput(0), x); + operands.push_back(cast); }, [&](auto) { fir::emitFatalError(loc, "unhandled expression in PAUSE"); - // mlir::emitError(loc, "unhandled expression in PAUSE"); - std::exit(1); }); } else { - callee = fir::runtime::getRuntimeFunc(loc, builder); + callee = + fir::runtime::getRuntimeFunc(loc, builder); calleeType = callee.getFunctionType(); } - + fir::CallOp::create(builder, loc, callee, operands); // NOTE: PAUSE does not terminate the current block. The program may resume diff --git a/flang/test/Lower/pause-statement.f90 b/flang/test/Lower/pause-statement.f90 index 8eb0448587cdc..0a7545167f855 100644 --- a/flang/test/Lower/pause-statement.f90 +++ b/flang/test/Lower/pause-statement.f90 @@ -1,22 +1,23 @@ -! RUN: bbc %s -emit-fir --canonicalize -o - | FileCheck %s +! RUN: bbc %s -emit-fir -hlfir=false --canonicalize -o - | FileCheck %s ! CHECK-LABEL: pause_test subroutine pause_test() + pause ! CHECK: fir.call @_Fortran{{.*}}PauseStatement() ! CHECK-NEXT: return - pause end subroutine ! CHECK-LABEL: pause_code subroutine pause_code() pause 42 - ! CHECK: fir.call @_Fortran{{.*}}PauseStatementInt - ! CHECK-NEXT: return + ! CHECK: %[[c42:.*]] = arith.constant 42 : i32 + ! CHECK: fir.call @_Fortran{{.*}}PauseStatementInt(%[[c42]]) + ! CHECK-NEXT: return end subroutine ! CHECK-LABEL: pause_msg subroutine pause_msg() - pause "hello" + pause 'hello' ! CHECK-DAG: %[[five:.*]] = arith.constant 5 : index ! CHECK-DAG: %[[lit:.*]] = fir.address_of(@_QQ{{.*}}) : !fir.ref> ! CHECK-DAG: %[[buff:.*]] = fir.convert %[[lit]] : (!fir.ref>) -> !fir.ref @@ -26,4 +27,5 @@ subroutine pause_msg() end subroutine ! CHECK-DAG: func private @_Fortran{{.*}}PauseStatement +! CHECK-DAG: func private @_Fortran{{.*}}PauseStatementInt ! CHECK-DAG: func private @_Fortran{{.*}}PauseStatementText From b73c6c77f8a613323edb7f303f527c844b9308e9 Mon Sep 17 00:00:00 2001 From: Sathvik Reddy Date: Tue, 25 Nov 2025 23:00:32 +0530 Subject: [PATCH 6/6] [flang] Fix pause-statement testcase Remove hlfir and add an additional check for hlfir.declare --- flang/test/Lower/pause-statement.f90 | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/flang/test/Lower/pause-statement.f90 b/flang/test/Lower/pause-statement.f90 index 0a7545167f855..465d82449c5bc 100644 --- a/flang/test/Lower/pause-statement.f90 +++ b/flang/test/Lower/pause-statement.f90 @@ -1,9 +1,9 @@ -! RUN: bbc %s -emit-fir -hlfir=false --canonicalize -o - | FileCheck %s +! RUN: bbc %s -emit-fir --canonicalize -o - | FileCheck %s ! CHECK-LABEL: pause_test subroutine pause_test() pause - ! CHECK: fir.call @_Fortran{{.*}}PauseStatement() + ! CHECK: fir.call @_FortranA{{.*}}PauseStatement() ! CHECK-NEXT: return end subroutine @@ -11,21 +11,22 @@ subroutine pause_test() subroutine pause_code() pause 42 ! CHECK: %[[c42:.*]] = arith.constant 42 : i32 - ! CHECK: fir.call @_Fortran{{.*}}PauseStatementInt(%[[c42]]) + ! CHECK: fir.call @_FortranA{{.*}}PauseStatementInt(%[[c42]]) ! CHECK-NEXT: return end subroutine ! CHECK-LABEL: pause_msg subroutine pause_msg() - pause 'hello' + pause "hello" ! CHECK-DAG: %[[five:.*]] = arith.constant 5 : index - ! CHECK-DAG: %[[lit:.*]] = fir.address_of(@_QQ{{.*}}) : !fir.ref> - ! CHECK-DAG: %[[buff:.*]] = fir.convert %[[lit]] : (!fir.ref>) -> !fir.ref + ! CHECK-DAG: %[[addr:.*]] = fir.address_of(@_QQ{{.*}}) : !fir.ref> + ! CHECK-DAG: %[[str:.*]]:2 = hlfir.declare %[[addr]] typeparams %[[five]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QQ{{.*}}"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) + ! CHECK-DAG: %[[buff:.*]] = fir.convert %[[str]]#0 : (!fir.ref>) -> !fir.ref ! CHECK-DAG: %[[len:.*]] = fir.convert %[[five]] : (index) -> i64 - ! CHECK: fir.call @_Fortran{{.*}}PauseStatementText(%[[buff]], %[[len]]) + ! CHECK: fir.call @_FortranA{{.*}}PauseStatementText(%[[buff]], %[[len]]) ! CHECK-NEXT: return end subroutine -! CHECK-DAG: func private @_Fortran{{.*}}PauseStatement -! CHECK-DAG: func private @_Fortran{{.*}}PauseStatementInt -! CHECK-DAG: func private @_Fortran{{.*}}PauseStatementText +! CHECK-DAG: func private @_FortranA{{.*}}PauseStatement +! CHECK-DAG: func private @_FortranA{{.*}}PauseStatementInt +! CHECK-DAG: func private @_FortranA{{.*}}PauseStatementText