[flang-commits] [flang] [flang] Implement lowering for the PAUSE statement (Fixes #166821) (PR #167115)

via flang-commits flang-commits at lists.llvm.org
Fri Nov 28 23:28:47 PST 2025


https://github.com/sathvikreddy853 updated https://github.com/llvm/llvm-project/pull/167115

>From faf6544603b16652369d28a3af4e97d00c58b95a Mon Sep 17 00:00:00 2001
From: Sathvik Reddy <sathvikreddy853 at gmail.com>
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 <integer>
  - 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<mkRTKey(PauseStatement)>(loc, builder);
-  fir::CallOp::create(builder, loc, callee, mlir::ValueRange{});
+  Fortran::lower::StatementContext stmtCtx;
+  llvm::SmallVector<mlir::Value> 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<mkRTKey(PauseStatementText)>(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<mkRTKey(PauseStatement)>(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<mkRTKey(PauseStatement)>(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<mlir::OpTrait::IsTerminator>();
+  };
+  if (blockIsUnterminated())
+    genUnreachable(builder, loc);
 }
 
 void Fortran::lower::genPointerAssociate(fir::FirOpBuilder &builder,

>From 8914d5ef9356b1601a6f7799d66af65138c3b268 Mon Sep 17 00:00:00 2001
From: Sathvik Reddy <sathvikreddy853 at gmail.com>
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<mlir::Value> 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<mkRTKey(PauseStatementText)>(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<mkRTKey(PauseStatement)>(loc, builder);
-          calleeType = callee.getFunctionType();
-          mlir::Value cast =
-              builder.createConvert(loc, calleeType.getInput(0), x);
-          operands.push_back(cast);
+           callee = fir::runtime::getRuntimeFunc<mkRTKey(PauseStatement)>(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<mkRTKey(PauseStatement)>(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<mlir::OpTrait::IsTerminator>();
-  };
-  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 <adityanath5002 at gmail.com>
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<!fir.char<1,5>>
+  ! CHECK-DAG: %[[buff:.*]] = fir.convert %[[lit]] : (!fir.ref<!fir.char<1,5>>) -> !fir.ref<i8>
+  ! 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 <sathvikreddy853 at gmail.com>
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<mkRTKey(PauseStatement)>(loc, builder);
+           callee = fir::runtime::getRuntimeFunc<mkRTKey(PauseStatementInt)>(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 <sathvikreddy853 at gmail.com>
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<mkRTKey(PauseStatementText)>(loc, builder);
+          callee = fir::runtime::getRuntimeFunc<mkRTKey(PauseStatementText)>(
+              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<mkRTKey(PauseStatementInt)>(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<mkRTKey(PauseStatementInt)>(
+              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<mkRTKey(PauseStatement)>(loc, builder);
+    callee =
+        fir::runtime::getRuntimeFunc<mkRTKey(PauseStatement)>(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<!fir.char<1,5>>
   ! CHECK-DAG: %[[buff:.*]] = fir.convert %[[lit]] : (!fir.ref<!fir.char<1,5>>) -> !fir.ref<i8>
@@ -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 <sathvikreddy853 at gmail.com>
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<!fir.char<1,5>>
-  ! CHECK-DAG: %[[buff:.*]] = fir.convert %[[lit]] : (!fir.ref<!fir.char<1,5>>) -> !fir.ref<i8>
+  ! CHECK-DAG: %[[addr:.*]] = fir.address_of(@_QQ{{.*}}) : !fir.ref<!fir.char<1,5>>
+  ! CHECK-DAG: %[[str:.*]]:2 = hlfir.declare %[[addr]] typeparams %[[five]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQ{{.*}}"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
+  ! CHECK-DAG: %[[buff:.*]] = fir.convert %[[str]]#0 : (!fir.ref<!fir.char<1,5>>) -> !fir.ref<i8>
   ! 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



More information about the flang-commits mailing list