[flang-commits] [flang] a5fb402 - [flang] add hlfir::FortranEntity class
Jean Perier via flang-commits
flang-commits at lists.llvm.org
Fri Oct 21 04:21:25 PDT 2022
Author: Jean Perier
Date: 2022-10-21T13:20:36+02:00
New Revision: a5fb4028386ebafec289285fae484ce007bdc986
URL: https://github.com/llvm/llvm-project/commit/a5fb4028386ebafec289285fae484ce007bdc986
DIFF: https://github.com/llvm/llvm-project/commit/a5fb4028386ebafec289285fae484ce007bdc986.diff
LOG: [flang] add hlfir::FortranEntity class
Add hlfir::FortranEntity class and a first helper to convert it to
fir::ExtendedValue.
The hlfir::FortranEntity will be the core class of the new expression
lowering. It is conceptually very similar to what fir::ExtendedValue
is today, except that it is wrapping single mlir::Value: it holds the
SSA value for a lowered Fortran variable or expression value.
Differential Revision: https://reviews.llvm.org/D136428
Added:
flang/include/flang/Optimizer/Builder/HLFIRTools.h
flang/lib/Optimizer/Builder/HLFIRTools.cpp
flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp
Modified:
flang/lib/Optimizer/Builder/CMakeLists.txt
flang/unittests/Optimizer/CMakeLists.txt
Removed:
################################################################################
diff --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h
new file mode 100644
index 0000000000000..568806a3a30cb
--- /dev/null
+++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h
@@ -0,0 +1,90 @@
+//===-- HLFIRTools.h -- HLFIR tools -----------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H
+#define FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H
+
+#include "flang/Optimizer/Builder/BoxValue.h"
+#include "flang/Optimizer/Dialect/FortranVariableInterface.h"
+#include "flang/Optimizer/HLFIR/HLFIRDialect.h"
+
+namespace fir {
+class FirOpBuilder;
+}
+
+namespace hlfir {
+
+/// Is this an SSA value type for the value of a Fortran expression?
+inline bool isFortranValueType(mlir::Type type) {
+ return type.isa<hlfir::ExprType>() || fir::isa_trivial(type);
+}
+
+/// Is this the value of a Fortran expression in an SSA value form?
+inline bool isFortranValue(mlir::Value value) {
+ return isFortranValueType(value.getType());
+}
+
+/// Is this a Fortran variable?
+/// Note that by "variable", it must be understood that the mlir::Value is
+/// a memory value of a storage that can be reason about as a Fortran object
+/// (its bounds, shape, and type parameters, if any, are retrievable).
+/// This does not imply that the mlir::Value points to a variable from the
+/// original source or can be legally defined: temporaries created to store
+/// expression values are considered to be variables, and so are PARAMETERs
+/// global constant address.
+inline bool isFortranVariable(mlir::Value value) {
+ return value.getDefiningOp<fir::FortranVariableOpInterface>();
+}
+
+/// Is this a Fortran variable or expression value?
+inline bool isFortranEntity(mlir::Value value) {
+ return isFortranValue(value) || isFortranVariable(value);
+}
+
+/// Wrapper over an mlir::Value that can be viewed as a Fortran entity.
+/// This provides some Fortran specific helpers as well as a guarantee
+/// in the compiler source that a certain mlir::Value must be a Fortran
+/// entity.
+class FortranEntity : public mlir::Value {
+public:
+ explicit FortranEntity(mlir::Value value) : mlir::Value(value) {
+ assert(isFortranEntity(value) &&
+ "must be a value representing a Fortran value or variable");
+ }
+ FortranEntity(fir::FortranVariableOpInterface variable)
+ : mlir::Value(variable.getBase()) {}
+ bool isValue() const { return isFortranValue(*this); }
+ bool isVariable() const { return !isValue(); }
+ fir::FortranVariableOpInterface getIfVariable() const {
+ return this->getDefiningOp<fir::FortranVariableOpInterface>();
+ }
+ mlir::Value getBase() const { return *this; }
+};
+
+/// Functions to translate hlfir::FortranEntity to fir::ExtendedValue.
+/// For Fortran arrays, character, and derived type values, this require
+/// allocating a storage since these can only be represented in memory in FIR.
+/// In that case, a cleanup function is provided to generate the finalization
+/// code after the end of the fir::ExtendedValue use.
+using CleanupFunction = std::function<void()>;
+std::pair<fir::ExtendedValue, llvm::Optional<CleanupFunction>>
+translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &builder,
+ FortranEntity entity);
+
+/// Function to translate FortranVariableOpInterface to fir::ExtendedValue.
+/// It does not generate any IR, and is a simple packaging operation.
+fir::ExtendedValue
+translateToExtendedValue(fir::FortranVariableOpInterface fortranVariable);
+
+} // namespace hlfir
+
+#endif // FORTRAN_OPTIMIZER_BUILDER_HLFIRTOOLS_H
diff --git a/flang/lib/Optimizer/Builder/CMakeLists.txt b/flang/lib/Optimizer/Builder/CMakeLists.txt
index 5f59ed37632d1..bd12fc234d905 100644
--- a/flang/lib/Optimizer/Builder/CMakeLists.txt
+++ b/flang/lib/Optimizer/Builder/CMakeLists.txt
@@ -6,6 +6,7 @@ add_flang_library(FIRBuilder
Complex.cpp
DoLoopHelper.cpp
FIRBuilder.cpp
+ HLFIRTools.cpp
LowLevelIntrinsics.cpp
MutableBox.cpp
Runtime/Assign.cpp
diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
new file mode 100644
index 0000000000000..fe14a714900d7
--- /dev/null
+++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
@@ -0,0 +1,99 @@
+//===-- HLFIRTools.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Tools to manipulate HLFIR variable and expressions
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/Todo.h"
+
+// Return explicit extents. If the base is a fir.box, this won't read it to
+// return the extents and will instead return an empty vector.
+static llvm::SmallVector<mlir::Value>
+getExplicitExtents(fir::FortranVariableOpInterface var) {
+ llvm::SmallVector<mlir::Value> result;
+ if (mlir::Value shape = var.getShape()) {
+ auto *shapeOp = shape.getDefiningOp();
+ if (auto s = mlir::dyn_cast_or_null<fir::ShapeOp>(shapeOp)) {
+ auto e = s.getExtents();
+ result.append(e.begin(), e.end());
+ } else if (auto s = mlir::dyn_cast_or_null<fir::ShapeShiftOp>(shapeOp)) {
+ auto e = s.getExtents();
+ result.append(e.begin(), e.end());
+ } else if (mlir::dyn_cast_or_null<fir::ShiftOp>(shapeOp)) {
+ return {};
+ } else {
+ TODO(var->getLoc(), "read fir.shape to get extents");
+ }
+ }
+ return result;
+}
+
+// Return explicit lower bounds. For pointers and allocatables, this will not
+// read the lower bounds and instead return an empty vector.
+static llvm::SmallVector<mlir::Value>
+getExplicitLbounds(fir::FortranVariableOpInterface var) {
+ llvm::SmallVector<mlir::Value> result;
+ if (mlir::Value shape = var.getShape()) {
+ auto *shapeOp = shape.getDefiningOp();
+ if (auto s = mlir::dyn_cast_or_null<fir::ShapeOp>(shapeOp)) {
+ return {};
+ } else if (auto s = mlir::dyn_cast_or_null<fir::ShapeShiftOp>(shapeOp)) {
+ auto e = s.getOrigins();
+ result.append(e.begin(), e.end());
+ } else if (auto s = mlir::dyn_cast_or_null<fir::ShiftOp>(shapeOp)) {
+ auto e = s.getOrigins();
+ result.append(e.begin(), e.end());
+ } else {
+ TODO(var->getLoc(), "read fir.shape to get lower bounds");
+ }
+ }
+ return result;
+}
+
+static llvm::SmallVector<mlir::Value>
+getExplicitTypeParams(fir::FortranVariableOpInterface var) {
+ llvm::SmallVector<mlir::Value> res;
+ mlir::OperandRange range = var.getExplicitTypeParams();
+ res.append(range.begin(), range.end());
+ return res;
+}
+
+std::pair<fir::ExtendedValue, llvm::Optional<hlfir::CleanupFunction>>
+hlfir::translateToExtendedValue(mlir::Location loc, fir::FirOpBuilder &,
+ hlfir::FortranEntity entity) {
+ if (auto variable = entity.getIfVariable())
+ return {hlfir::translateToExtendedValue(variable), {}};
+ if (entity.getType().isa<hlfir::ExprType>())
+ TODO(loc, "hlfir.expr to fir::ExtendedValue"); // use hlfir.associate
+ return {{static_cast<mlir::Value>(entity)}, {}};
+}
+
+fir::ExtendedValue
+hlfir::translateToExtendedValue(fir::FortranVariableOpInterface variable) {
+ if (variable.isPointer() || variable.isAllocatable())
+ TODO(variable->getLoc(), "pointer or allocatable "
+ "FortranVariableOpInterface to extendedValue");
+ if (variable.getBase().getType().isa<fir::BaseBoxType>())
+ return fir::BoxValue(variable.getBase(), getExplicitLbounds(variable),
+ getExplicitTypeParams(variable),
+ getExplicitExtents(variable));
+ if (variable.isCharacter()) {
+ if (variable.isArray())
+ return fir::CharArrayBoxValue(
+ variable.getBase(), variable.getExplicitCharLen(),
+ getExplicitExtents(variable), getExplicitLbounds(variable));
+ return fir::CharBoxValue(variable.getBase(), variable.getExplicitCharLen());
+ }
+ if (variable.isArray())
+ return fir::ArrayBoxValue(variable.getBase(), getExplicitExtents(variable),
+ getExplicitLbounds(variable));
+ return variable.getBase();
+}
diff --git a/flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp b/flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp
new file mode 100644
index 0000000000000..ce3d1208c4dc6
--- /dev/null
+++ b/flang/unittests/Optimizer/Builder/HLFIRToolsTest.cpp
@@ -0,0 +1,218 @@
+//===- HLFIRToolsTest.cpp -- HLFIR tools 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/HLFIRTools.h"
+#include "gtest/gtest.h"
+#include "flang/Optimizer/Builder/BoxValue.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Support/InitFIR.h"
+#include "flang/Optimizer/Support/KindMapping.h"
+
+struct HLFIRToolsTest : public testing::Test {
+public:
+ void SetUp() override {
+ fir::support::loadDialects(context);
+
+ llvm::ArrayRef<fir::KindTy> defs;
+ fir::KindMapping kindMap(&context, defs);
+ mlir::OpBuilder builder(&context);
+ auto loc = builder.getUnknownLoc();
+
+ // Set up a Module with a dummy function operation inside.
+ // Set the insertion point in the function entry block.
+ mlir::ModuleOp mod = builder.create<mlir::ModuleOp>(loc);
+ mlir::func::FuncOp func = mlir::func::FuncOp::create(
+ loc, "func1", builder.getFunctionType(llvm::None, llvm::None));
+ auto *entryBlock = func.addEntryBlock();
+ mod.push_back(mod);
+ builder.setInsertionPointToStart(entryBlock);
+
+ firBuilder = std::make_unique<fir::FirOpBuilder>(mod, kindMap);
+ }
+
+ mlir::Value createDeclare(fir::ExtendedValue exv) {
+ mlir::Value addr = fir::getBase(exv);
+ mlir::Location loc = getLoc();
+ mlir::Value shape;
+ if (exv.rank() > 0)
+ shape = firBuilder->createShape(loc, exv);
+ llvm::SmallVector<mlir::Value> typeParams;
+ exv.match(
+ [&](const fir::CharBoxValue &x) {
+ typeParams.emplace_back(x.getLen());
+ },
+ [&](const fir::CharArrayBoxValue &x) {
+ typeParams.emplace_back(x.getLen());
+ },
+ [&](const fir::BoxValue &x) {
+ typeParams.append(x.getExplicitParameters().begin(),
+ x.getExplicitParameters().end());
+ },
+ [&](const fir::MutableBoxValue &x) {
+ typeParams.append(
+ x.nonDeferredLenParams().begin(), x.nonDeferredLenParams().end());
+ },
+ [](const auto &) {});
+ auto name =
+ mlir::StringAttr::get(&context, "x" + std::to_string(varCounter++));
+ return firBuilder->create<fir::DeclareOp>(loc, addr.getType(), addr, shape,
+ typeParams, name,
+ /*fortran_attrs=*/fir::FortranVariableFlagsAttr{});
+ }
+
+ mlir::Value createConstant(std::int64_t cst) {
+ mlir::Type indexType = firBuilder->getIndexType();
+ return firBuilder->create<mlir::arith::ConstantOp>(
+ getLoc(), indexType, firBuilder->getIntegerAttr(indexType, cst));
+ }
+
+ mlir::Location getLoc() { return firBuilder->getUnknownLoc(); }
+ fir::FirOpBuilder &getBuilder() { return *firBuilder; }
+
+ int varCounter = 0;
+ mlir::MLIRContext context;
+ std::unique_ptr<fir::FirOpBuilder> firBuilder;
+};
+
+TEST_F(HLFIRToolsTest, testScalarRoundTrip) {
+ auto &builder = getBuilder();
+ mlir::Location loc = getLoc();
+ mlir::Type f32Type = mlir::FloatType::getF32(&context);
+ mlir::Type scalarf32Type = builder.getRefType(f32Type);
+ mlir::Value scalarf32Addr = builder.create<fir::UndefOp>(loc, scalarf32Type);
+ fir::ExtendedValue scalarf32{scalarf32Addr};
+ hlfir::FortranEntity scalarf32Entity(createDeclare(scalarf32));
+ auto [scalarf32Result, cleanup] =
+ hlfir::translateToExtendedValue(loc, builder, scalarf32Entity);
+ auto *unboxed = scalarf32Result.getUnboxed();
+ EXPECT_FALSE(cleanup.has_value());
+ ASSERT_NE(unboxed, nullptr);
+ EXPECT_TRUE(*unboxed == scalarf32Entity.getBase());
+ EXPECT_TRUE(scalarf32Entity.isVariable());
+ EXPECT_FALSE(scalarf32Entity.isValue());
+}
+
+TEST_F(HLFIRToolsTest, testArrayRoundTrip) {
+ auto &builder = getBuilder();
+ mlir::Location loc = getLoc();
+ llvm::SmallVector<mlir::Value> extents{
+ createConstant(20), createConstant(30)};
+ llvm::SmallVector<mlir::Value> lbounds{
+ createConstant(-1), createConstant(-2)};
+
+ mlir::Type f32Type = mlir::FloatType::getF32(&context);
+ mlir::Type seqf32Type = builder.getVarLenSeqTy(f32Type, 2);
+ mlir::Type arrayf32Type = builder.getRefType(seqf32Type);
+ mlir::Value arrayf32Addr = builder.create<fir::UndefOp>(loc, arrayf32Type);
+ fir::ArrayBoxValue arrayf32{arrayf32Addr, extents, lbounds};
+ hlfir::FortranEntity arrayf32Entity(createDeclare(arrayf32));
+ auto [arrayf32Result, cleanup] =
+ hlfir::translateToExtendedValue(loc, builder, arrayf32Entity);
+ auto *res = arrayf32Result.getBoxOf<fir::ArrayBoxValue>();
+ EXPECT_FALSE(cleanup.has_value());
+ ASSERT_NE(res, nullptr);
+ // gtest has a terrible time printing mlir::Value in case of failing
+ // EXPECT_EQ(mlir::Value, mlir::Value). So use EXPECT_TRUE instead.
+ EXPECT_TRUE(fir::getBase(*res) == arrayf32Entity.getBase());
+ ASSERT_EQ(res->getExtents().size(), arrayf32.getExtents().size());
+ for (unsigned i = 0; i < arrayf32.getExtents().size(); ++i)
+ EXPECT_TRUE(res->getExtents()[i] == arrayf32.getExtents()[i]);
+ ASSERT_EQ(res->getLBounds().size(), arrayf32.getLBounds().size());
+ for (unsigned i = 0; i < arrayf32.getLBounds().size(); ++i)
+ EXPECT_TRUE(res->getLBounds()[i] == arrayf32.getLBounds()[i]);
+ EXPECT_TRUE(arrayf32Entity.isVariable());
+ EXPECT_FALSE(arrayf32Entity.isValue());
+}
+
+TEST_F(HLFIRToolsTest, testScalarCharRoundTrip) {
+ auto &builder = getBuilder();
+ mlir::Location loc = getLoc();
+ mlir::Value len = createConstant(42);
+ mlir::Type charType = fir::CharacterType::getUnknownLen(&context, 1);
+ mlir::Type scalarCharType = builder.getRefType(charType);
+ mlir::Value scalarCharAddr =
+ builder.create<fir::UndefOp>(loc, scalarCharType);
+ fir::CharBoxValue scalarChar{scalarCharAddr, len};
+ hlfir::FortranEntity scalarCharEntity(createDeclare(scalarChar));
+ auto [scalarCharResult, cleanup] =
+ hlfir::translateToExtendedValue(loc, builder, scalarCharEntity);
+ auto *res = scalarCharResult.getBoxOf<fir::CharBoxValue>();
+ EXPECT_FALSE(cleanup.has_value());
+ ASSERT_NE(res, nullptr);
+ EXPECT_TRUE(fir::getBase(*res) == scalarCharEntity.getBase());
+ EXPECT_TRUE(res->getLen() == scalarChar.getLen());
+ EXPECT_TRUE(scalarCharEntity.isVariable());
+ EXPECT_FALSE(scalarCharEntity.isValue());
+}
+
+TEST_F(HLFIRToolsTest, testArrayCharRoundTrip) {
+ auto &builder = getBuilder();
+ mlir::Location loc = getLoc();
+ llvm::SmallVector<mlir::Value> extents{
+ createConstant(20), createConstant(30)};
+ llvm::SmallVector<mlir::Value> lbounds{
+ createConstant(-1), createConstant(-2)};
+ mlir::Value len = createConstant(42);
+ mlir::Type charType = fir::CharacterType::getUnknownLen(&context, 1);
+ mlir::Type seqCharType = builder.getVarLenSeqTy(charType, 2);
+ mlir::Type arrayCharType = builder.getRefType(seqCharType);
+ mlir::Value arrayCharAddr = builder.create<fir::UndefOp>(loc, arrayCharType);
+ fir::CharArrayBoxValue arrayChar{arrayCharAddr, len, extents, lbounds};
+ hlfir::FortranEntity arrayCharEntity(createDeclare(arrayChar));
+ auto [arrayCharResult, cleanup] =
+ hlfir::translateToExtendedValue(loc, builder, arrayCharEntity);
+ auto *res = arrayCharResult.getBoxOf<fir::CharArrayBoxValue>();
+ EXPECT_FALSE(cleanup.has_value());
+ ASSERT_NE(res, nullptr);
+ // gtest has a terrible time printing mlir::Value in case of failing
+ // EXPECT_EQ(mlir::Value, mlir::Value). So use EXPECT_TRUE instead.
+ EXPECT_TRUE(fir::getBase(*res) == arrayCharEntity.getBase());
+ EXPECT_TRUE(res->getLen() == arrayChar.getLen());
+ ASSERT_EQ(res->getExtents().size(), arrayChar.getExtents().size());
+ for (unsigned i = 0; i < arrayChar.getExtents().size(); ++i)
+ EXPECT_TRUE(res->getExtents()[i] == arrayChar.getExtents()[i]);
+ ASSERT_EQ(res->getLBounds().size(), arrayChar.getLBounds().size());
+ for (unsigned i = 0; i < arrayChar.getLBounds().size(); ++i)
+ EXPECT_TRUE(res->getLBounds()[i] == arrayChar.getLBounds()[i]);
+ EXPECT_TRUE(arrayCharEntity.isVariable());
+ EXPECT_FALSE(arrayCharEntity.isValue());
+}
+
+TEST_F(HLFIRToolsTest, testArrayCharBoxRoundTrip) {
+ auto &builder = getBuilder();
+ mlir::Location loc = getLoc();
+ llvm::SmallVector<mlir::Value> lbounds{
+ createConstant(-1), createConstant(-2)};
+ mlir::Value len = createConstant(42);
+ mlir::Type charType = fir::CharacterType::getUnknownLen(&context, 1);
+ mlir::Type seqCharType = builder.getVarLenSeqTy(charType, 2);
+ mlir::Type arrayCharBoxType = fir::BoxType::get(seqCharType);
+ mlir::Value arrayCharAddr =
+ builder.create<fir::UndefOp>(loc, arrayCharBoxType);
+ llvm::SmallVector<mlir::Value> explicitTypeParams{len};
+ fir::BoxValue arrayChar{arrayCharAddr, lbounds, explicitTypeParams};
+ hlfir::FortranEntity arrayCharEntity(createDeclare(arrayChar));
+ auto [arrayCharResult, cleanup] =
+ hlfir::translateToExtendedValue(loc, builder, arrayCharEntity);
+ auto *res = arrayCharResult.getBoxOf<fir::BoxValue>();
+ EXPECT_FALSE(cleanup.has_value());
+ ASSERT_NE(res, nullptr);
+ // gtest has a terrible time printing mlir::Value in case of failing
+ // EXPECT_EQ(mlir::Value, mlir::Value). So use EXPECT_TRUE instead.
+ EXPECT_TRUE(fir::getBase(*res) == arrayCharEntity.getBase());
+ ASSERT_EQ(res->getExplicitParameters().size(),
+ arrayChar.getExplicitParameters().size());
+ for (unsigned i = 0; i < arrayChar.getExplicitParameters().size(); ++i)
+ EXPECT_TRUE(res->getExplicitParameters()[i] ==
+ arrayChar.getExplicitParameters()[i]);
+ ASSERT_EQ(res->getLBounds().size(), arrayChar.getLBounds().size());
+ for (unsigned i = 0; i < arrayChar.getLBounds().size(); ++i)
+ EXPECT_TRUE(res->getLBounds()[i] == arrayChar.getLBounds()[i]);
+ EXPECT_TRUE(arrayCharEntity.isVariable());
+ EXPECT_FALSE(arrayCharEntity.isValue());
+}
diff --git a/flang/unittests/Optimizer/CMakeLists.txt b/flang/unittests/Optimizer/CMakeLists.txt
index c3cc04e86ce2d..e3693ab4d8862 100644
--- a/flang/unittests/Optimizer/CMakeLists.txt
+++ b/flang/unittests/Optimizer/CMakeLists.txt
@@ -14,6 +14,7 @@ add_flang_unittest(FlangOptimizerTests
Builder/ComplexTest.cpp
Builder/DoLoopHelperTest.cpp
Builder/FIRBuilderTest.cpp
+ Builder/HLFIRToolsTest.cpp
Builder/Runtime/AssignTest.cpp
Builder/Runtime/CommandTest.cpp
Builder/Runtime/CharacterTest.cpp
More information about the flang-commits
mailing list