[flang-commits] [flang] 2ab1c6d - [flang] Add lowering of move_alloc to IntrinsicCall

David Truby via flang-commits flang-commits at lists.llvm.org
Fri Jan 20 07:12:33 PST 2023


Author: David Truby
Date: 2023-01-20T15:12:25Z
New Revision: 2ab1c6d375b97307ebadf8131589c3abb1b11eb0

URL: https://github.com/llvm/llvm-project/commit/2ab1c6d375b97307ebadf8131589c3abb1b11eb0
DIFF: https://github.com/llvm/llvm-project/commit/2ab1c6d375b97307ebadf8131589c3abb1b11eb0.diff

LOG: [flang] Add lowering of move_alloc to IntrinsicCall

This patch relies on D141286 for the runtime implementation of
move_alloc.

Reviewed By: jeanPerier

Differential Revision: https://reviews.llvm.org/D141616

Added: 
    flang/include/flang/Optimizer/Builder/Runtime/Allocatable.h
    flang/lib/Optimizer/Builder/Runtime/Allocatable.cpp
    flang/test/Lower/Intrinsics/move_alloc.f90
    flang/unittests/Optimizer/Builder/Runtime/Allocatable.cpp
    flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp

Modified: 
    flang/lib/Lower/IntrinsicCall.cpp
    flang/lib/Optimizer/Builder/CMakeLists.txt
    flang/unittests/Optimizer/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Builder/Runtime/Allocatable.h b/flang/include/flang/Optimizer/Builder/Runtime/Allocatable.h
new file mode 100644
index 0000000000000..0013afee9fd0f
--- /dev/null
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Allocatable.h
@@ -0,0 +1,33 @@
+//===-- Allocatable.h - generate Allocatable runtime API calls---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_BUILDER_RUNTIME_ALLOCATABLE_H
+#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_ALLOCATABLE_H
+
+namespace mlir {
+class Value;
+class Location;
+} // namespace mlir
+
+namespace fir {
+class FirOpBuilder;
+}
+
+namespace fir::runtime {
+
+/// Generate runtime call to assign \p sourceBox to \p destBox.
+/// \p destBox must be a fir.ref<fir.box<T>> and \p sourceBox a fir.box<T>.
+/// \p destBox Fortran descriptor may be modified if destBox is an allocatable
+/// according to Fortran allocatable assignment rules, otherwise it is not
+/// modified.
+mlir::Value genMoveAlloc(fir::FirOpBuilder &builder, mlir::Location loc,
+                         mlir::Value to, mlir::Value from, mlir::Value hasStat,
+                         mlir::Value errMsg);
+
+} // namespace fir::runtime
+#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_ALLOCATABLE_H

diff  --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp
index 7d3d4d113bd35..055e9260b8e95 100644
--- a/flang/lib/Lower/IntrinsicCall.cpp
+++ b/flang/lib/Lower/IntrinsicCall.cpp
@@ -19,10 +19,12 @@
 #include "flang/Lower/Runtime.h"
 #include "flang/Lower/StatementContext.h"
 #include "flang/Lower/SymbolMap.h"
+#include "flang/Optimizer/Builder/BoxValue.h"
 #include "flang/Optimizer/Builder/Character.h"
 #include "flang/Optimizer/Builder/Complex.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Builder/MutableBox.h"
+#include "flang/Optimizer/Builder/Runtime/Allocatable.h"
 #include "flang/Optimizer/Builder/Runtime/Character.h"
 #include "flang/Optimizer/Builder/Runtime/Command.h"
 #include "flang/Optimizer/Builder/Runtime/Derived.h"
@@ -267,6 +269,7 @@ struct IntrinsicLibrary {
   fir::ExtendedValue genMinval(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
   mlir::Value genMod(mlir::Type, llvm::ArrayRef<mlir::Value>);
   mlir::Value genModulo(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  void genMoveAlloc(llvm::ArrayRef<fir::ExtendedValue>);
   void genMvbits(llvm::ArrayRef<fir::ExtendedValue>);
   mlir::Value genNearest(mlir::Type, llvm::ArrayRef<mlir::Value>);
   mlir::Value genNint(mlir::Type, llvm::ArrayRef<mlir::Value>);
@@ -695,6 +698,13 @@ static constexpr IntrinsicHandler handlers[]{
      /*isElemental=*/false},
     {"mod", &I::genMod},
     {"modulo", &I::genModulo},
+    {"move_alloc",
+     &I::genMoveAlloc,
+     {{{"from", asInquired},
+       {"to", asInquired},
+       {"status", asAddr, handleDynamicOptional},
+       {"errMsg", asBox, handleDynamicOptional}}},
+     /*isElemental=*/false},
     {"mvbits",
      &I::genMvbits,
      {{{"from", asValue},
@@ -3900,6 +3910,46 @@ mlir::Value IntrinsicLibrary::genModulo(mlir::Type resultType,
                                                remainder);
 }
 
+void IntrinsicLibrary::genMoveAlloc(llvm::ArrayRef<fir::ExtendedValue> args) {
+  assert(args.size() == 4);
+
+  const fir::ExtendedValue &from = args[0];
+  const fir::ExtendedValue &to = args[1];
+  const fir::ExtendedValue &status = args[2];
+  const fir::ExtendedValue &errMsg = args[3];
+
+  mlir::Type boxNoneTy = fir::BoxType::get(builder.getNoneType());
+  mlir::Value errBox =
+      isStaticallyPresent(errMsg)
+          ? fir::getBase(errMsg)
+          : builder.create<fir::AbsentOp>(loc, boxNoneTy).getResult();
+
+  const fir::MutableBoxValue *fromBox = from.getBoxOf<fir::MutableBoxValue>();
+  const fir::MutableBoxValue *toBox = to.getBoxOf<fir::MutableBoxValue>();
+
+  assert(fromBox && toBox && "move_alloc parameters must be mutable arrays");
+
+  mlir::Value fromAddr = fir::factory::getMutableIRBox(builder, loc, *fromBox);
+  mlir::Value toAddr = fir::factory::getMutableIRBox(builder, loc, *toBox);
+
+  mlir::Value hasStat = builder.createBool(loc, isStaticallyPresent(status));
+
+  mlir::Value stat = fir::runtime::genMoveAlloc(builder, loc, toAddr, fromAddr,
+                                                hasStat, errBox);
+
+  fir::factory::syncMutableBoxFromIRBox(builder, loc, *fromBox);
+  fir::factory::syncMutableBoxFromIRBox(builder, loc, *toBox);
+
+  if (isStaticallyPresent(status)) {
+    mlir::Value statAddr = fir::getBase(status);
+    mlir::Value statIsPresentAtRuntime =
+        builder.genIsNotNullAddr(loc, statAddr);
+    builder.genIfThen(loc, statIsPresentAtRuntime)
+        .genThen([&]() { builder.createStoreWithConvert(loc, stat, statAddr); })
+        .end();
+  }
+}
+
 // MVBITS
 void IntrinsicLibrary::genMvbits(llvm::ArrayRef<fir::ExtendedValue> args) {
   // A conformant MVBITS(FROM,FROMPOS,LEN,TO,TOPOS) call satisfies:

diff  --git a/flang/lib/Optimizer/Builder/CMakeLists.txt b/flang/lib/Optimizer/Builder/CMakeLists.txt
index 2ace58a974f15..b429d66c10e07 100644
--- a/flang/lib/Optimizer/Builder/CMakeLists.txt
+++ b/flang/lib/Optimizer/Builder/CMakeLists.txt
@@ -9,6 +9,7 @@ add_flang_library(FIRBuilder
   HLFIRTools.cpp
   LowLevelIntrinsics.cpp
   MutableBox.cpp
+  Runtime/Allocatable.cpp
   Runtime/Assign.cpp
   Runtime/Character.cpp
   Runtime/Command.cpp

diff  --git a/flang/lib/Optimizer/Builder/Runtime/Allocatable.cpp b/flang/lib/Optimizer/Builder/Runtime/Allocatable.cpp
new file mode 100644
index 0000000000000..675faf123e35e
--- /dev/null
+++ b/flang/lib/Optimizer/Builder/Runtime/Allocatable.cpp
@@ -0,0 +1,30 @@
+//===-- Allocatable.cpp -- generate allocatable runtime API calls----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Builder/Runtime/Allocatable.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
+#include "flang/Runtime/allocatable.h"
+
+using namespace Fortran::runtime;
+
+mlir::Value fir::runtime::genMoveAlloc(fir::FirOpBuilder &builder,
+                                       mlir::Location loc, mlir::Value to,
+                                       mlir::Value from, mlir::Value hasStat,
+                                       mlir::Value errMsg) {
+  mlir::func::FuncOp func{
+      fir::runtime::getRuntimeFunc<mkRTKey(MoveAlloc)>(loc, builder)};
+  mlir::FunctionType fTy{func.getFunctionType()};
+  mlir::Value sourceFile{fir::factory::locationToFilename(builder, loc)};
+  mlir::Value sourceLine{
+      fir::factory::locationToLineNo(builder, loc, fTy.getInput(5))};
+  llvm::SmallVector<mlir::Value> args{fir::runtime::createArguments(
+      builder, loc, fTy, to, from, hasStat, errMsg, sourceFile, sourceLine)};
+
+  return builder.create<fir::CallOp>(loc, func, args).getResult(0);
+}

diff  --git a/flang/test/Lower/Intrinsics/move_alloc.f90 b/flang/test/Lower/Intrinsics/move_alloc.f90
new file mode 100644
index 0000000000000..6618150ec415c
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/move_alloc.f90
@@ -0,0 +1,63 @@
+  ! RUN: bbc -emit-fir %s -o - | FileCheck  %s
+  ! RUN: flang-new -fc1 -emit-fir %s -o - | FileCheck %s
+
+! CHECK-LABEL: to_from_only
+subroutine to_from_only
+  ! CHECK: %[[a1:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>>
+  ! CHECK: %[[b1:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>>
+  integer, allocatable :: from(:), to(:)
+  allocate(from(20))
+  ! CHECK: %[[errMsg:.*]] = fir.absent !fir.box<none>
+  ! CHECK: %[[false:.*]] = arith.constant false
+  ! CHECK-DAG: %[[a2:.*]] = fir.convert %[[a1]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
+  ! CHECK-DAG: %[[b2:.*]] = fir.convert %[[b1]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
+  call move_alloc(from, to)
+  ! CHECK: fir.call @_FortranAMoveAlloc(%[[b2]], %[[a2]], %[[false]], %[[errMsg]], %{{.*}}, %{{.*}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.ref<!fir.box<none>>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
+  ! CHECK-DAG:  %[[a3:.*]] = fir.load %[[a1:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+  ! CHECK-DAG:  %[[a4:.*]] = fir.box_addr %[[a3]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+  ! CHECK-DAG:  %[[b3:.*]] = fir.load %[[b1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+  ! CHECK-DAG:  %[[b4:.*]] = fir.box_addr %[[b3:.*]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+end subroutine to_from_only
+
+! CHECK-LABEL: to_from_stat
+subroutine to_from_stat
+  ! CHECK-DAG: %[[a1:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>>
+  ! CHECK-DAG: %[[b1:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>>
+  integer, allocatable :: from(:), to(:)
+  ! CHECK-DAG: %[[stat1:.*]] = fir.alloca i32
+  integer :: stat
+  allocate(from(20))
+  ! CHECK: %[[errMsg:.*]] = fir.absent !fir.box<none>
+  ! CHECK: %[[true:.*]] = arith.constant true
+  ! CHECK-DAG: %[[a2:.*]] = fir.convert %[[a1]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
+  ! CHECK-DAG: %[[b2:.*]] = fir.convert %[[b1]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
+  call move_alloc(from, to, stat)
+  ! CHECK: %[[stat:.*]] = fir.call @_FortranAMoveAlloc(%[[b2]], %[[a2]], %[[true]], %[[errMsg]], %{{.*}}, %{{.*}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.ref<!fir.box<none>>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
+  ! CHECK-DAG:  %[[a3:.*]] = fir.load %[[a1:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+  ! CHECK-DAG:  %[[a4:.*]] = fir.box_addr %[[a3]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+  ! CHECK-DAG:  %[[b3:.*]] = fir.load %[[b1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+  ! CHECK-DAG:  %[[b4:.*]] = fir.box_addr %[[b3:.*]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+end subroutine to_from_stat
+
+! CHECK-LABEL: to_from_stat_errmsg
+subroutine to_from_stat_errmsg
+  ! CHECK-DAG: %[[errMsg1:.*]] = fir.alloca !fir.char<1,64>
+  ! CHECK-DAG: %[[a1:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>>
+  ! CHECK-DAG: %[[b1:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>>
+  integer, allocatable :: from(:), to(:)
+  ! CHECK-DAG: %[[stat1:.*]] = fir.alloca i32
+  integer :: stat
+  character :: errMsg*64
+  allocate(from(20))
+  ! CHECK: %[[errMsg2:.*]] = fir.embox %[[errMsg1]] : (!fir.ref<!fir.char<1,64>>) -> !fir.box<!fir.char<1,64>>
+  ! CHECK: %[[true:.*]] = arith.constant true
+  ! CHECK-DAG: %[[errMsg3:.*]] = fir.convert %[[errMsg2]] : (!fir.box<!fir.char<1,64>>) -> !fir.box<none>
+  ! CHECK-DAG: %[[a2:.*]] = fir.convert %[[a1]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
+  ! CHECK-DAG: %[[b2:.*]] = fir.convert %[[b1]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
+  call move_alloc(from, to, stat, errMsg)
+  ! CHECK: %[[stat:.*]] = fir.call @_FortranAMoveAlloc(%[[b2]], %[[a2]], %[[true]], %[[errMsg3]], %{{.*}}, %{{.*}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.ref<!fir.box<none>>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
+  ! CHECK-DAG:  %[[a3:.*]] = fir.load %[[a1:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+  ! CHECK-DAG:  %[[a4:.*]] = fir.box_addr %[[a3]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+  ! CHECK-DAG:  %[[b3:.*]] = fir.load %[[b1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+  ! CHECK-DAG:  %[[b4:.*]] = fir.box_addr %[[b3:.*]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>) -> !fir.heap<!fir.array<?xi32>>
+end subroutine to_from_stat_errmsg

diff  --git a/flang/unittests/Optimizer/Builder/Runtime/Allocatable.cpp b/flang/unittests/Optimizer/Builder/Runtime/Allocatable.cpp
new file mode 100644
index 0000000000000..e69de29bb2d1d

diff  --git a/flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp b/flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp
new file mode 100644
index 0000000000000..20dd80dc8f8a1
--- /dev/null
+++ b/flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp
@@ -0,0 +1,26 @@
+//===- AllocatableTest.cpp -- allocatable runtime builder unit tests ------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Builder/Runtime/Allocatable.h"
+#include "RuntimeCallTestBase.h"
+#include "gtest/gtest.h"
+#include "flang/Runtime/descriptor.h"
+
+using namespace Fortran::runtime;
+
+TEST_F(RuntimeCallTest, genMoveAlloc) {
+  mlir::Location loc = firBuilder->getUnknownLoc();
+  mlir::Type seqTy =
+      fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty);
+  mlir::Value from = firBuilder->create<fir::UndefOp>(loc, seqTy);
+  mlir::Value to = firBuilder->create<fir::UndefOp>(loc, seqTy);
+  mlir::Value errMsg = firBuilder->create<fir::UndefOp>(loc, seqTy);
+  mlir::Value hasStat = firBuilder->createBool(loc, false);
+  fir::runtime::genMoveAlloc(*firBuilder, loc, to, from, hasStat, errMsg);
+  checkCallOpFromResultBox(to, "_FortranAMoveAlloc", 4);
+}

diff  --git a/flang/unittests/Optimizer/CMakeLists.txt b/flang/unittests/Optimizer/CMakeLists.txt
index b2a8c189ada3f..76555fe7bccbf 100644
--- a/flang/unittests/Optimizer/CMakeLists.txt
+++ b/flang/unittests/Optimizer/CMakeLists.txt
@@ -16,6 +16,7 @@ add_flang_unittest(FlangOptimizerTests
   Builder/DoLoopHelperTest.cpp
   Builder/FIRBuilderTest.cpp
   Builder/HLFIRToolsTest.cpp
+  Builder/Runtime/AllocatableTest.cpp
   Builder/Runtime/AssignTest.cpp
   Builder/Runtime/CommandTest.cpp
   Builder/Runtime/CharacterTest.cpp
@@ -31,7 +32,12 @@ add_flang_unittest(FlangOptimizerTests
   InternalNamesTest.cpp
   KindMappingTest.cpp
   RTBuilder.cpp
-)
+DEPENDS
+  FIRDialect
+  FIRSupport
+  HLFIRDialect
+  ${dialect_libs})
+
 target_link_libraries(FlangOptimizerTests
   PRIVATE
   ${LIBS})


        


More information about the flang-commits mailing list