diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Ragged.h b/flang/include/flang/Optimizer/Builder/Runtime/Ragged.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Optimizer/Builder/Runtime/Ragged.h @@ -0,0 +1,39 @@ +//===-- Ragged.h ------------------------------------------------*- 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_RAGGED_H +#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RAGGED_H + +namespace mlir { +class Location; +class Value; +class ValueRange; +} // namespace mlir + +namespace fir { +class FirOpBuilder; +} // namespace fir + +namespace fir::runtime { + +/// Generate code to instantiate a section of a ragged array. Calls the runtime +/// to initialize the data buffer. \p header must be a ragged buffer header (on +/// the heap) and will be initialized, if and only if the rank of \p extents is +/// at least 1 and all values in the vector of extents are positive. \p extents +/// must be a vector of Value of type `i64`. \p eleSize is in bytes, not bits. +void genRaggedArrayAllocate(mlir::Location loc, fir::FirOpBuilder &builder, + mlir::Value header, bool asHeaders, + mlir::Value eleSize, mlir::ValueRange extents); + +/// Generate a call to the runtime routine to deallocate a ragged array data +/// structure on the heap. +void genRaggedArrayDeallocate(mlir::Location loc, fir::FirOpBuilder &builder, + mlir::Value header); + +} // namespace fir::runtime +#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RAGGED_H diff --git a/flang/lib/Optimizer/Builder/CMakeLists.txt b/flang/lib/Optimizer/Builder/CMakeLists.txt --- a/flang/lib/Optimizer/Builder/CMakeLists.txt +++ b/flang/lib/Optimizer/Builder/CMakeLists.txt @@ -7,6 +7,7 @@ DoLoopHelper.cpp FIRBuilder.cpp MutableBox.cpp + Runtime/Ragged.cpp Runtime/Reduction.cpp DEPENDS diff --git a/flang/lib/Optimizer/Builder/Runtime/Ragged.cpp b/flang/lib/Optimizer/Builder/Runtime/Ragged.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Optimizer/Builder/Runtime/Ragged.cpp @@ -0,0 +1,66 @@ +//===-- Ragged.cpp --------------------------------------------------------===// +// +// 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/Ragged.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/Runtime/RTBuilder.h" +#include "flang/Runtime/ragged.h" + +using namespace Fortran::runtime; + +void fir::runtime::genRaggedArrayAllocate(mlir::Location loc, + fir::FirOpBuilder &builder, + mlir::Value header, bool asHeaders, + mlir::Value eleSize, + mlir::ValueRange extents) { + auto i32Ty = builder.getIntegerType(32); + auto rank = extents.size(); + auto i64Ty = builder.getIntegerType(64); + auto func = + fir::runtime::getRuntimeFunc(loc, builder); + auto fTy = func.getType(); + auto i1Ty = builder.getIntegerType(1); + fir::SequenceType::Shape shape = { + static_cast(rank)}; + auto extentTy = fir::SequenceType::get(shape, i64Ty); + auto refTy = fir::ReferenceType::get(i64Ty); + auto one = builder.createIntegerConstant(loc, i32Ty, 1); + auto eleTy = fir::unwrapSequenceType(fir::unwrapRefType(header.getType())); + auto ptrTy = builder.getRefType(eleTy.cast().getType(1)); + auto ptr = builder.create(loc, ptrTy, header, one); + auto heap = builder.create(loc, ptr); + auto cmp = builder.genIsNull(loc, heap); + builder.genIfThen(loc, cmp) + .genThen([&]() { + auto asHeadersVal = builder.createIntegerConstant(loc, i1Ty, asHeaders); + auto rankVal = builder.createIntegerConstant(loc, i64Ty, rank); + auto buff = builder.create(loc, extentTy); + // Convert all the extents to i64 and pack them in a buffer on the heap. + for (auto i : llvm::enumerate(extents)) { + auto offset = builder.createIntegerConstant(loc, i32Ty, i.index()); + auto addr = + builder.create(loc, refTy, buff, offset); + auto castVal = builder.createConvert(loc, i64Ty, i.value()); + builder.create(loc, castVal, addr); + } + auto args = fir::runtime::createArguments( + builder, loc, fTy, header, asHeadersVal, rankVal, eleSize, buff); + builder.create(loc, func, args); + }) + .end(); +} + +void fir::runtime::genRaggedArrayDeallocate(mlir::Location loc, + fir::FirOpBuilder &builder, + mlir::Value header) { + auto func = fir::runtime::getRuntimeFunc( + loc, builder); + auto fTy = func.getType(); + auto args = fir::runtime::createArguments(builder, loc, fTy, header); + builder.create(loc, func, args); +} diff --git a/flang/unittests/Optimizer/Builder/Runtime/RaggedTest.cpp b/flang/unittests/Optimizer/Builder/Runtime/RaggedTest.cpp new file mode 100644 --- /dev/null +++ b/flang/unittests/Optimizer/Builder/Runtime/RaggedTest.cpp @@ -0,0 +1,36 @@ +//===- RaggedTest.cpp -- Ragged array runtime function 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/Ragged.h" +#include "RuntimeCallTestBase.h" +#include "gtest/gtest.h" + +TEST_F(RuntimeCallTest, genRaggedArrayAllocateTest) { + auto loc = firBuilder->getUnknownLoc(); + mlir::Type tupleTy = + mlir::TupleType::get(firBuilder->getContext(), {i32Ty, i32Ty}); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), tupleTy); + mlir::Value header = firBuilder->create(loc, seqTy); + mlir::Value eleSize = firBuilder->createIntegerConstant(loc, i32Ty, 1); + mlir::Value extent = firBuilder->createIntegerConstant(loc, i32Ty, 1); + fir::runtime::genRaggedArrayAllocate( + loc, *firBuilder, header, false, eleSize, {extent}); + checkCallOpFromResultBox( + eleSize, "_FortranARaggedArrayAllocate", 5, /*addLocArgs=*/false); +} + +TEST_F(RuntimeCallTest, genRaggedArrayDeallocateTest) { + auto loc = firBuilder->getUnknownLoc(); + mlir::Type seqTy = + fir::SequenceType::get(fir::SequenceType::Shape(1, 10), i32Ty); + mlir::Value header = firBuilder->create(loc, seqTy); + fir::runtime::genRaggedArrayDeallocate(loc, *firBuilder, header); + checkCallOpFromResultBox( + header, "_FortranARaggedArrayDeallocate", 1, /*addLocArgs=*/false); +} diff --git a/flang/unittests/Optimizer/Builder/Runtime/RuntimeCallTestBase.h b/flang/unittests/Optimizer/Builder/Runtime/RuntimeCallTestBase.h --- a/flang/unittests/Optimizer/Builder/Runtime/RuntimeCallTestBase.h +++ b/flang/unittests/Optimizer/Builder/Runtime/RuntimeCallTestBase.h @@ -70,26 +70,28 @@ mlir::Type c16Ty; }; -static void checkCallOp( - mlir::Operation *op, llvm::StringRef fctName, unsigned nbArgs) { +static void checkCallOp(mlir::Operation *op, llvm::StringRef fctName, + unsigned nbArgs, bool addLocArgs = true) { EXPECT_TRUE(mlir::isa(*op)); auto callOp = mlir::dyn_cast(*op); EXPECT_TRUE(callOp.callee().hasValue()); mlir::SymbolRefAttr callee = *callOp.callee(); EXPECT_EQ(fctName, callee.getRootReference().getValue()); // sourceFile and sourceLine are added arguments. - EXPECT_EQ(nbArgs + 2, callOp.args().size()); + if (addLocArgs) + nbArgs += 2; + EXPECT_EQ(nbArgs, callOp.args().size()); } -static void checkCallOpFromResultBox( - mlir::Value result, llvm::StringRef fctName, unsigned nbArgs) { +static void checkCallOpFromResultBox(mlir::Value result, + llvm::StringRef fctName, unsigned nbArgs, bool addLocArgs = true) { EXPECT_TRUE(result.hasOneUse()); for (auto &u : result.getUses()) { if (mlir::isa(*u.getOwner())) { - checkCallOp(u.getOwner(), fctName, nbArgs); + checkCallOp(u.getOwner(), fctName, nbArgs, addLocArgs); } else { auto convOp = mlir::dyn_cast(*u.getOwner()); - checkCallOpFromResultBox(convOp.getResult(), fctName, nbArgs); + checkCallOpFromResultBox(convOp.getResult(), fctName, nbArgs, addLocArgs); } } } diff --git a/flang/unittests/Optimizer/CMakeLists.txt b/flang/unittests/Optimizer/CMakeLists.txt --- a/flang/unittests/Optimizer/CMakeLists.txt +++ b/flang/unittests/Optimizer/CMakeLists.txt @@ -13,6 +13,7 @@ Builder/ComplexTest.cpp Builder/DoLoopHelperTest.cpp Builder/FIRBuilderTest.cpp + Builder/Runtime/RaggedTest.cpp Builder/Runtime/ReductionTest.cpp FIRContextTest.cpp InternalNamesTest.cpp