brintos

brintos / llvm-project-archived public Read only

0
0
Text · 29.6 KiB · 10a7ddf Raw
731 lines · cpp
1//===- FIRBuilderTest.cpp -- FIRBuilder unit tests ------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "flang/Optimizer/Builder/FIRBuilder.h"10#include "gtest/gtest.h"11#include "flang/Optimizer/Builder/BoxValue.h"12#include "flang/Optimizer/Dialect/Support/KindMapping.h"13#include "flang/Optimizer/Support/InitFIR.h"14 15using namespace mlir;16 17struct FIRBuilderTest : public testing::Test {18public:19  void SetUp() override {20    fir::support::loadDialects(context);21 22    llvm::ArrayRef<fir::KindTy> defs;23    fir::KindMapping kindMap(&context, defs);24    mlir::OpBuilder builder(&context);25    auto loc = builder.getUnknownLoc();26 27    // Set up a Module with a dummy function operation inside.28    // Set the insertion point in the function entry block.29    moduleOp = mlir::ModuleOp::create(builder, loc);30    builder.setInsertionPointToStart(moduleOp->getBody());31    mlir::func::FuncOp func = mlir::func::FuncOp::create(32        builder, loc, "func1", builder.getFunctionType({}, {}));33    auto *entryBlock = func.addEntryBlock();34    builder.setInsertionPointToStart(entryBlock);35 36    firBuilder = std::make_unique<fir::FirOpBuilder>(builder, kindMap);37  }38 39  fir::FirOpBuilder &getBuilder() { return *firBuilder; }40 41  mlir::MLIRContext context;42  mlir::OwningOpRef<mlir::ModuleOp> moduleOp;43  std::unique_ptr<fir::FirOpBuilder> firBuilder;44};45 46static arith::CmpIOp createCondition(fir::FirOpBuilder &builder) {47  auto loc = builder.getUnknownLoc();48  auto zero1 = builder.createIntegerConstant(loc, builder.getIndexType(), 0);49  auto zero2 = builder.createIntegerConstant(loc, builder.getIndexType(), 0);50  return arith::CmpIOp::create(51      builder, loc, arith::CmpIPredicate::eq, zero1, zero2);52}53 54static void checkIntegerConstant(mlir::Value value, mlir::Type ty, int64_t v) {55  EXPECT_TRUE(mlir::isa<mlir::arith::ConstantOp>(value.getDefiningOp()));56  auto cstOp = dyn_cast<mlir::arith::ConstantOp>(value.getDefiningOp());57  EXPECT_EQ(ty, cstOp.getType());58  auto valueAttr = mlir::dyn_cast_or_null<IntegerAttr>(cstOp.getValue());59  EXPECT_EQ(v, valueAttr.getInt());60}61 62//===----------------------------------------------------------------------===//63// IfBuilder tests64//===----------------------------------------------------------------------===//65 66TEST_F(FIRBuilderTest, genIfThen) {67  auto builder = getBuilder();68  auto loc = builder.getUnknownLoc();69  auto cdt = createCondition(builder);70  auto ifBuilder = builder.genIfThen(loc, cdt);71  EXPECT_FALSE(ifBuilder.getIfOp().getThenRegion().empty());72  EXPECT_TRUE(ifBuilder.getIfOp().getElseRegion().empty());73}74 75TEST_F(FIRBuilderTest, genIfThenElse) {76  auto builder = getBuilder();77  auto loc = builder.getUnknownLoc();78  auto cdt = createCondition(builder);79  auto ifBuilder = builder.genIfThenElse(loc, cdt);80  EXPECT_FALSE(ifBuilder.getIfOp().getThenRegion().empty());81  EXPECT_FALSE(ifBuilder.getIfOp().getElseRegion().empty());82}83 84TEST_F(FIRBuilderTest, genIfWithThen) {85  auto builder = getBuilder();86  auto loc = builder.getUnknownLoc();87  auto cdt = createCondition(builder);88  auto ifBuilder = builder.genIfOp(loc, {}, cdt, false);89  EXPECT_FALSE(ifBuilder.getIfOp().getThenRegion().empty());90  EXPECT_TRUE(ifBuilder.getIfOp().getElseRegion().empty());91}92 93TEST_F(FIRBuilderTest, genIfWithThenAndElse) {94  auto builder = getBuilder();95  auto loc = builder.getUnknownLoc();96  auto cdt = createCondition(builder);97  auto ifBuilder = builder.genIfOp(loc, {}, cdt, true);98  EXPECT_FALSE(ifBuilder.getIfOp().getThenRegion().empty());99  EXPECT_FALSE(ifBuilder.getIfOp().getElseRegion().empty());100}101 102//===----------------------------------------------------------------------===//103// Helper functions tests104//===----------------------------------------------------------------------===//105 106TEST_F(FIRBuilderTest, genIsNotNullAddr) {107  auto builder = getBuilder();108  auto loc = builder.getUnknownLoc();109  auto dummyValue =110      builder.createIntegerConstant(loc, builder.getIndexType(), 0);111  auto res = builder.genIsNotNullAddr(loc, dummyValue);112  EXPECT_TRUE(mlir::isa<arith::CmpIOp>(res.getDefiningOp()));113  auto cmpOp = dyn_cast<arith::CmpIOp>(res.getDefiningOp());114  EXPECT_EQ(arith::CmpIPredicate::ne, cmpOp.getPredicate());115}116 117TEST_F(FIRBuilderTest, genIsNullAddr) {118  auto builder = getBuilder();119  auto loc = builder.getUnknownLoc();120  auto dummyValue =121      builder.createIntegerConstant(loc, builder.getIndexType(), 0);122  auto res = builder.genIsNullAddr(loc, dummyValue);123  EXPECT_TRUE(mlir::isa<arith::CmpIOp>(res.getDefiningOp()));124  auto cmpOp = dyn_cast<arith::CmpIOp>(res.getDefiningOp());125  EXPECT_EQ(arith::CmpIPredicate::eq, cmpOp.getPredicate());126}127 128TEST_F(FIRBuilderTest, createZeroConstant) {129  auto builder = getBuilder();130  auto loc = builder.getUnknownLoc();131 132  auto cst = builder.createNullConstant(loc);133  EXPECT_TRUE(mlir::isa<fir::ZeroOp>(cst.getDefiningOp()));134  auto zeroOp = dyn_cast<fir::ZeroOp>(cst.getDefiningOp());135  EXPECT_EQ(fir::ReferenceType::get(builder.getNoneType()),136      zeroOp.getResult().getType());137  auto idxTy = builder.getIndexType();138 139  cst = builder.createNullConstant(loc, idxTy);140  EXPECT_TRUE(mlir::isa<fir::ZeroOp>(cst.getDefiningOp()));141  zeroOp = dyn_cast<fir::ZeroOp>(cst.getDefiningOp());142  EXPECT_EQ(builder.getIndexType(), zeroOp.getResult().getType());143}144 145TEST_F(FIRBuilderTest, createRealZeroConstant) {146  auto builder = getBuilder();147  auto ctx = builder.getContext();148  auto loc = builder.getUnknownLoc();149  auto realTy = mlir::Float64Type::get(ctx);150  auto cst = builder.createRealZeroConstant(loc, realTy);151  EXPECT_TRUE(mlir::isa<arith::ConstantOp>(cst.getDefiningOp()));152  auto cstOp = dyn_cast<arith::ConstantOp>(cst.getDefiningOp());153  EXPECT_EQ(realTy, cstOp.getType());154  EXPECT_EQ(155      0u, mlir::cast<FloatAttr>(cstOp.getValue()).getValue().convertToDouble());156}157 158TEST_F(FIRBuilderTest, createBool) {159  auto builder = getBuilder();160  auto loc = builder.getUnknownLoc();161  auto b = builder.createBool(loc, false);162  checkIntegerConstant(b, builder.getIntegerType(1), 0);163}164 165TEST_F(FIRBuilderTest, getVarLenSeqTy) {166  auto builder = getBuilder();167  auto ty = builder.getVarLenSeqTy(builder.getI64Type());168  EXPECT_TRUE(mlir::isa<fir::SequenceType>(ty));169  fir::SequenceType seqTy = mlir::dyn_cast<fir::SequenceType>(ty);170  EXPECT_EQ(1u, seqTy.getDimension());171  EXPECT_TRUE(fir::unwrapSequenceType(ty).isInteger(64));172}173 174TEST_F(FIRBuilderTest, getNamedFunction) {175  auto builder = getBuilder();176  auto func2 = builder.getNamedFunction("func2");177  EXPECT_EQ(nullptr, func2);178  auto loc = builder.getUnknownLoc();179  func2 = builder.createFunction(loc, "func2", builder.getFunctionType({}, {}));180  auto func2query = builder.getNamedFunction("func2");181  EXPECT_EQ(func2, func2query);182}183 184TEST_F(FIRBuilderTest, createGlobal1) {185  auto builder = getBuilder();186  auto loc = builder.getUnknownLoc();187  auto i64Type = IntegerType::get(builder.getContext(), 64);188  auto global = builder.createGlobal(189      loc, i64Type, "global1", builder.createInternalLinkage(), {}, true);190  EXPECT_TRUE(mlir::isa<fir::GlobalOp>(global));191  EXPECT_EQ("global1", global.getSymName());192  EXPECT_TRUE(global.getConstant().has_value());193  EXPECT_EQ(i64Type, global.getType());194  EXPECT_TRUE(global.getLinkName().has_value());195  EXPECT_EQ(196      builder.createInternalLinkage().getValue(), global.getLinkName().value());197  EXPECT_FALSE(global.getInitVal().has_value());198 199  auto g1 = builder.getNamedGlobal("global1");200  EXPECT_EQ(global, g1);201  auto g2 = builder.getNamedGlobal("global7");202  EXPECT_EQ(nullptr, g2);203  auto g3 = builder.getNamedGlobal("");204  EXPECT_EQ(nullptr, g3);205}206 207TEST_F(FIRBuilderTest, createGlobal2) {208  auto builder = getBuilder();209  auto loc = builder.getUnknownLoc();210  auto i32Type = IntegerType::get(builder.getContext(), 32);211  auto attr = builder.getIntegerAttr(i32Type, 16);212  auto global = builder.createGlobal(213      loc, i32Type, "global2", builder.createLinkOnceLinkage(), attr, false);214  EXPECT_TRUE(mlir::isa<fir::GlobalOp>(global));215  EXPECT_EQ("global2", global.getSymName());216  EXPECT_FALSE(global.getConstant().has_value());217  EXPECT_EQ(i32Type, global.getType());218  EXPECT_TRUE(global.getInitVal().has_value());219  EXPECT_TRUE(mlir::isa<mlir::IntegerAttr>(global.getInitVal().value()));220  EXPECT_EQ(16,221      mlir::cast<mlir::IntegerAttr>(global.getInitVal().value()).getValue());222  EXPECT_TRUE(global.getLinkName().has_value());223  EXPECT_EQ(224      builder.createLinkOnceLinkage().getValue(), global.getLinkName().value());225}226 227TEST_F(FIRBuilderTest, uniqueCFIdent) {228  auto str1 = fir::factory::uniqueCGIdent("", "func1");229  EXPECT_EQ("_QQX66756E6331", str1);230  str1 = fir::factory::uniqueCGIdent("", "");231  EXPECT_EQ("_QQX", str1);232  str1 = fir::factory::uniqueCGIdent("pr", "func1");233  EXPECT_EQ("_QQprX66756E6331", str1);234  str1 = fir::factory::uniqueCGIdent(235      "", "longnamemorethan32characterneedshashing");236  EXPECT_EQ("_QQXc22a886b2f30ea8c064ef1178377fc31", str1);237  str1 = fir::factory::uniqueCGIdent(238      "pr", "longnamemorethan32characterneedshashing");239  EXPECT_EQ("_QQprXc22a886b2f30ea8c064ef1178377fc31", str1);240}241 242TEST_F(FIRBuilderTest, locationToLineNo) {243  auto builder = getBuilder();244  auto loc = mlir::FileLineColLoc::get(builder.getStringAttr("file1"), 10, 5);245  mlir::Value line =246      fir::factory::locationToLineNo(builder, loc, builder.getI64Type());247  checkIntegerConstant(line, builder.getI64Type(), 10);248  line = fir::factory::locationToLineNo(249      builder, builder.getUnknownLoc(), builder.getI64Type());250  checkIntegerConstant(line, builder.getI64Type(), 0);251}252 253TEST_F(FIRBuilderTest, hasDynamicSize) {254  auto builder = getBuilder();255  auto type = fir::CharacterType::get(builder.getContext(), 1, 16);256  EXPECT_FALSE(fir::hasDynamicSize(type));257  EXPECT_TRUE(fir::SequenceType::getUnknownExtent());258  auto seqTy = builder.getVarLenSeqTy(builder.getI64Type(), 10);259  EXPECT_TRUE(fir::hasDynamicSize(seqTy));260  EXPECT_FALSE(fir::hasDynamicSize(builder.getI64Type()));261}262 263TEST_F(FIRBuilderTest, locationToFilename) {264  auto builder = getBuilder();265  auto loc =266      mlir::FileLineColLoc::get(builder.getStringAttr("file1.f90"), 10, 5);267  mlir::Value locToFile = fir::factory::locationToFilename(builder, loc);268  auto addrOp = dyn_cast<fir::AddrOfOp>(locToFile.getDefiningOp());269  auto symbol = addrOp.getSymbol().getRootReference().getValue();270  auto global = builder.getNamedGlobal(symbol);271  auto stringLitOps = global.getRegion().front().getOps<fir::StringLitOp>();272  EXPECT_TRUE(llvm::hasSingleElement(stringLitOps));273  for (auto stringLit : stringLitOps) {274    EXPECT_EQ(275        10, mlir::cast<mlir::IntegerAttr>(stringLit.getSize()).getValue());276    EXPECT_TRUE(mlir::isa<StringAttr>(stringLit.getValue()));277    EXPECT_EQ(0,278        strcmp("file1.f90\0",279            mlir::dyn_cast<StringAttr>(stringLit.getValue())280                .getValue()281                .str()282                .c_str()));283  }284}285 286TEST_F(FIRBuilderTest, createStringLitOp) {287  auto builder = getBuilder();288  llvm::StringRef data("mystringlitdata");289  auto loc = builder.getUnknownLoc();290  auto op = builder.createStringLitOp(loc, data);291  EXPECT_EQ(15, mlir::cast<mlir::IntegerAttr>(op.getSize()).getValue());292  EXPECT_TRUE(mlir::isa<StringAttr>(op.getValue()));293  EXPECT_EQ(data, mlir::dyn_cast<StringAttr>(op.getValue()).getValue());294}295 296TEST_F(FIRBuilderTest, createStringLiteral) {297  auto builder = getBuilder();298  auto loc = builder.getUnknownLoc();299  llvm::StringRef strValue("onestringliteral");300  auto strLit = fir::factory::createStringLiteral(builder, loc, strValue);301  EXPECT_EQ(0u, strLit.rank());302  EXPECT_TRUE(strLit.getCharBox() != nullptr);303  auto *charBox = strLit.getCharBox();304  EXPECT_FALSE(fir::isArray(*charBox));305  checkIntegerConstant(charBox->getLen(), builder.getCharacterLengthType(), 16);306  auto generalGetLen = fir::getLen(strLit);307  checkIntegerConstant(generalGetLen, builder.getCharacterLengthType(), 16);308  auto addr = charBox->getBuffer();309  EXPECT_TRUE(mlir::isa<fir::AddrOfOp>(addr.getDefiningOp()));310  auto addrOp = dyn_cast<fir::AddrOfOp>(addr.getDefiningOp());311  auto symbol = addrOp.getSymbol().getRootReference().getValue();312  auto global = builder.getNamedGlobal(symbol);313  EXPECT_EQ(314      builder.createLinkOnceLinkage().getValue(), global.getLinkName().value());315  EXPECT_EQ(fir::CharacterType::get(builder.getContext(), 1, strValue.size()),316      global.getType());317 318  auto stringLitOps = global.getRegion().front().getOps<fir::StringLitOp>();319  EXPECT_TRUE(llvm::hasSingleElement(stringLitOps));320  for (auto stringLit : stringLitOps) {321    EXPECT_EQ(322        16, mlir::cast<mlir::IntegerAttr>(stringLit.getSize()).getValue());323    EXPECT_TRUE(mlir::isa<StringAttr>(stringLit.getValue()));324    EXPECT_EQ(325        strValue, mlir::dyn_cast<StringAttr>(stringLit.getValue()).getValue());326  }327}328 329TEST_F(FIRBuilderTest, allocateLocal) {330  auto builder = getBuilder();331  auto loc = builder.getUnknownLoc();332  llvm::StringRef varName = "var1";333  auto var = builder.allocateLocal(334      loc, builder.getI64Type(), "", varName, {}, {}, false);335  EXPECT_TRUE(mlir::isa<fir::AllocaOp>(var.getDefiningOp()));336  auto allocaOp = dyn_cast<fir::AllocaOp>(var.getDefiningOp());337  EXPECT_EQ(builder.getI64Type(), allocaOp.getInType());338  EXPECT_TRUE(allocaOp.getBindcName().has_value());339  EXPECT_EQ(varName, allocaOp.getBindcName().value());340  EXPECT_FALSE(allocaOp.getUniqName().has_value());341  EXPECT_FALSE(allocaOp.getPinned());342  EXPECT_EQ(0u, allocaOp.getTypeparams().size());343  EXPECT_EQ(0u, allocaOp.getShape().size());344}345 346static void checkShapeOp(mlir::Value shape, mlir::Value c10, mlir::Value c100) {347  EXPECT_TRUE(mlir::isa<fir::ShapeOp>(shape.getDefiningOp()));348  fir::ShapeOp op = dyn_cast<fir::ShapeOp>(shape.getDefiningOp());349  auto shapeTy = mlir::dyn_cast<fir::ShapeType>(op.getType());350  EXPECT_EQ(2u, shapeTy.getRank());351  EXPECT_EQ(2u, op.getExtents().size());352  EXPECT_EQ(c10, op.getExtents()[0]);353  EXPECT_EQ(c100, op.getExtents()[1]);354}355 356TEST_F(FIRBuilderTest, genShapeWithExtents) {357  auto builder = getBuilder();358  auto loc = builder.getUnknownLoc();359  auto c10 = builder.createIntegerConstant(loc, builder.getI64Type(), 10);360  auto c100 = builder.createIntegerConstant(loc, builder.getI64Type(), 100);361  llvm::SmallVector<mlir::Value> extents = {c10, c100};362  auto shape = builder.genShape(loc, extents);363  checkShapeOp(shape, c10, c100);364}365 366TEST_F(FIRBuilderTest, genShapeWithExtentsAndShapeShift) {367  auto builder = getBuilder();368  auto loc = builder.getUnknownLoc();369  auto c10 = builder.createIntegerConstant(loc, builder.getI64Type(), 10);370  auto c100 = builder.createIntegerConstant(loc, builder.getI64Type(), 100);371  auto c1 = builder.createIntegerConstant(loc, builder.getI64Type(), 100);372  llvm::SmallVector<mlir::Value> shifts = {c1, c1};373  llvm::SmallVector<mlir::Value> extents = {c10, c100};374  auto shape = builder.genShape(loc, shifts, extents);375  EXPECT_TRUE(mlir::isa<fir::ShapeShiftOp>(shape.getDefiningOp()));376  fir::ShapeShiftOp op = dyn_cast<fir::ShapeShiftOp>(shape.getDefiningOp());377  auto shapeTy = mlir::dyn_cast<fir::ShapeShiftType>(op.getType());378  EXPECT_EQ(2u, shapeTy.getRank());379  EXPECT_EQ(2u, op.getExtents().size());380  EXPECT_EQ(2u, op.getOrigins().size());381}382 383TEST_F(FIRBuilderTest, genShapeWithAbstractArrayBox) {384  auto builder = getBuilder();385  auto loc = builder.getUnknownLoc();386  auto c10 = builder.createIntegerConstant(loc, builder.getI64Type(), 10);387  auto c100 = builder.createIntegerConstant(loc, builder.getI64Type(), 100);388  llvm::SmallVector<mlir::Value> extents = {c10, c100};389  fir::AbstractArrayBox aab(extents, {});390  EXPECT_TRUE(aab.lboundsAllOne());391  auto shape = builder.genShape(loc, aab);392  checkShapeOp(shape, c10, c100);393}394 395TEST_F(FIRBuilderTest, readCharLen) {396  auto builder = getBuilder();397  auto loc = builder.getUnknownLoc();398  llvm::StringRef strValue("length");399  auto strLit = fir::factory::createStringLiteral(builder, loc, strValue);400  auto len = fir::factory::readCharLen(builder, loc, strLit);401  EXPECT_EQ(strLit.getCharBox()->getLen(), len);402}403 404TEST_F(FIRBuilderTest, getExtents) {405  auto builder = getBuilder();406  auto loc = builder.getUnknownLoc();407  llvm::StringRef strValue("length");408  auto strLit = fir::factory::createStringLiteral(builder, loc, strValue);409  auto ext = fir::factory::getExtents(loc, builder, strLit);410  EXPECT_EQ(0u, ext.size());411  auto c10 = builder.createIntegerConstant(loc, builder.getI64Type(), 10);412  auto c100 = builder.createIntegerConstant(loc, builder.getI64Type(), 100);413  llvm::SmallVector<mlir::Value> extents = {c10, c100};414  fir::SequenceType::Shape shape(2, fir::SequenceType::getUnknownExtent());415  auto arrayTy = fir::SequenceType::get(shape, builder.getI64Type());416  mlir::Value array = fir::UndefOp::create(builder, loc, arrayTy);417  fir::ArrayBoxValue aab(array, extents, {});418  fir::ExtendedValue ex(aab);419  auto readExtents = fir::factory::getExtents(loc, builder, ex);420  EXPECT_EQ(2u, readExtents.size());421}422 423TEST_F(FIRBuilderTest, createZeroValue) {424  auto builder = getBuilder();425  auto loc = builder.getUnknownLoc();426 427  mlir::Type i64Ty = mlir::IntegerType::get(builder.getContext(), 64);428  mlir::Value zeroInt = fir::factory::createZeroValue(builder, loc, i64Ty);429  EXPECT_TRUE(zeroInt.getType() == i64Ty);430  auto cst =431      mlir::dyn_cast_or_null<mlir::arith::ConstantOp>(zeroInt.getDefiningOp());432  EXPECT_TRUE(cst);433  auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>(cst.getValue());434  EXPECT_TRUE(intAttr && intAttr.getInt() == 0);435 436  mlir::Type f32Ty = mlir::Float32Type::get(builder.getContext());437  mlir::Value zeroFloat = fir::factory::createZeroValue(builder, loc, f32Ty);438  EXPECT_TRUE(zeroFloat.getType() == f32Ty);439  auto cst2 = mlir::dyn_cast_or_null<mlir::arith::ConstantOp>(440      zeroFloat.getDefiningOp());441  EXPECT_TRUE(cst2);442  auto floatAttr = mlir::dyn_cast<mlir::FloatAttr>(cst2.getValue());443  EXPECT_TRUE(floatAttr && floatAttr.getValueAsDouble() == 0.);444 445  mlir::Type boolTy = mlir::IntegerType::get(builder.getContext(), 1);446  mlir::Value flaseBool = fir::factory::createZeroValue(builder, loc, boolTy);447  EXPECT_TRUE(flaseBool.getType() == boolTy);448  auto cst3 = mlir::dyn_cast_or_null<mlir::arith::ConstantOp>(449      flaseBool.getDefiningOp());450  EXPECT_TRUE(cst3);451  auto intAttr2 = mlir::dyn_cast<mlir::IntegerAttr>(cst.getValue());452  EXPECT_TRUE(intAttr2 && intAttr2.getInt() == 0);453}454 455TEST_F(FIRBuilderTest, getBaseTypeOf) {456  auto builder = getBuilder();457  auto loc = builder.getUnknownLoc();458 459  auto makeExv = [&](mlir::Type elementType, mlir::Type arrayType)460      -> std::tuple<llvm::SmallVector<fir::ExtendedValue, 4>,461          llvm::SmallVector<fir::ExtendedValue, 4>> {462    auto ptrTyArray = fir::PointerType::get(arrayType);463    auto ptrTyScalar = fir::PointerType::get(elementType);464    auto ptrBoxTyArray = fir::BoxType::get(ptrTyArray);465    auto ptrBoxTyScalar = fir::BoxType::get(ptrTyScalar);466    auto boxRefTyArray = fir::ReferenceType::get(ptrBoxTyArray);467    auto boxRefTyScalar = fir::ReferenceType::get(ptrBoxTyScalar);468    auto boxTyArray = fir::BoxType::get(arrayType);469    auto boxTyScalar = fir::BoxType::get(elementType);470 471    auto ptrValArray = fir::UndefOp::create(builder, loc, ptrTyArray);472    auto ptrValScalar = fir::UndefOp::create(builder, loc, ptrTyScalar);473    auto boxRefValArray = fir::UndefOp::create(builder, loc, boxRefTyArray);474    auto boxRefValScalar = fir::UndefOp::create(builder, loc, boxRefTyScalar);475    auto boxValArray = fir::UndefOp::create(builder, loc, boxTyArray);476    auto boxValScalar = fir::UndefOp::create(builder, loc, boxTyScalar);477 478    llvm::SmallVector<fir::ExtendedValue, 4> scalars;479    scalars.emplace_back(fir::UnboxedValue(ptrValScalar));480    scalars.emplace_back(fir::BoxValue(boxValScalar));481    scalars.emplace_back(482        fir::MutableBoxValue(boxRefValScalar, mlir::ValueRange(), {}));483 484    llvm::SmallVector<fir::ExtendedValue, 4> arrays;485    auto extent = fir::UndefOp::create(builder, loc, builder.getIndexType());486    llvm::SmallVector<mlir::Value> extents(487        mlir::dyn_cast<fir::SequenceType>(arrayType).getDimension(),488        extent.getResult());489    arrays.emplace_back(fir::ArrayBoxValue(ptrValArray, extents));490    arrays.emplace_back(fir::BoxValue(boxValArray));491    arrays.emplace_back(492        fir::MutableBoxValue(boxRefValArray, mlir::ValueRange(), {}));493    return {scalars, arrays};494  };495 496  auto f32Ty = mlir::Float32Type::get(builder.getContext());497  mlir::Type f32SeqTy = builder.getVarLenSeqTy(f32Ty);498  auto [f32Scalars, f32Arrays] = makeExv(f32Ty, f32SeqTy);499  for (const auto &scalar : f32Scalars) {500    EXPECT_EQ(fir::getBaseTypeOf(scalar), f32Ty);501    EXPECT_EQ(fir::getElementTypeOf(scalar), f32Ty);502    EXPECT_FALSE(fir::isDerivedWithLenParameters(scalar));503  }504  for (const auto &array : f32Arrays) {505    EXPECT_EQ(fir::getBaseTypeOf(array), f32SeqTy);506    EXPECT_EQ(fir::getElementTypeOf(array), f32Ty);507    EXPECT_FALSE(fir::isDerivedWithLenParameters(array));508  }509 510  auto derivedWithLengthTy =511      fir::RecordType::get(builder.getContext(), "derived_test");512 513  llvm::SmallVector<std::pair<std::string, mlir::Type>> parameters;514  llvm::SmallVector<std::pair<std::string, mlir::Type>> components;515  parameters.emplace_back("p1", builder.getI64Type());516  components.emplace_back("c1", f32Ty);517  derivedWithLengthTy.finalize(parameters, components);518  mlir::Type derivedWithLengthSeqTy =519      builder.getVarLenSeqTy(derivedWithLengthTy);520  auto [derivedWithLengthScalars, derivedWithLengthArrays] =521      makeExv(derivedWithLengthTy, derivedWithLengthSeqTy);522  for (const auto &scalar : derivedWithLengthScalars) {523    EXPECT_EQ(fir::getBaseTypeOf(scalar), derivedWithLengthTy);524    EXPECT_EQ(fir::getElementTypeOf(scalar), derivedWithLengthTy);525    EXPECT_TRUE(fir::isDerivedWithLenParameters(scalar));526  }527  for (const auto &array : derivedWithLengthArrays) {528    EXPECT_EQ(fir::getBaseTypeOf(array), derivedWithLengthSeqTy);529    EXPECT_EQ(fir::getElementTypeOf(array), derivedWithLengthTy);530    EXPECT_TRUE(fir::isDerivedWithLenParameters(array));531  }532}533 534TEST_F(FIRBuilderTest, genArithFastMath) {535  auto builder = getBuilder();536  auto ctx = builder.getContext();537  auto loc = builder.getUnknownLoc();538 539  auto realTy = mlir::Float32Type::get(ctx);540  auto arg = fir::UndefOp::create(builder, loc, realTy);541 542  // Test that FastMathFlags is 'none' by default.543  mlir::Operation *op1 = mlir::arith::AddFOp::create(builder, loc, arg, arg);544  auto op1_fmi =545      mlir::dyn_cast_or_null<mlir::arith::ArithFastMathInterface>(op1);546  EXPECT_TRUE(op1_fmi);547  auto op1_fmf = op1_fmi.getFastMathFlagsAttr().getValue();548  EXPECT_EQ(op1_fmf, arith::FastMathFlags::none);549 550  // Test that the builder is copied properly.551  fir::FirOpBuilder builder_copy(builder);552 553  arith::FastMathFlags FMF1 =554      arith::FastMathFlags::contract | arith::FastMathFlags::reassoc;555  builder.setFastMathFlags(FMF1);556  arith::FastMathFlags FMF2 =557      arith::FastMathFlags::nnan | arith::FastMathFlags::ninf;558  builder_copy.setFastMathFlags(FMF2);559 560  // Modifying FastMathFlags for the copy must not affect the original builder.561  mlir::Operation *op2 = mlir::arith::AddFOp::create(builder, loc, arg, arg);562  auto op2_fmi =563      mlir::dyn_cast_or_null<mlir::arith::ArithFastMathInterface>(op2);564  EXPECT_TRUE(op2_fmi);565  auto op2_fmf = op2_fmi.getFastMathFlagsAttr().getValue();566  EXPECT_EQ(op2_fmf, FMF1);567 568  // Modifying FastMathFlags for the original builder must not affect the copy.569  mlir::Operation *op3 =570      mlir::arith::AddFOp::create(builder_copy, loc, arg, arg);571  auto op3_fmi =572      mlir::dyn_cast_or_null<mlir::arith::ArithFastMathInterface>(op3);573  EXPECT_TRUE(op3_fmi);574  auto op3_fmf = op3_fmi.getFastMathFlagsAttr().getValue();575  EXPECT_EQ(op3_fmf, FMF2);576 577  // Test that the builder copy inherits FastMathFlags from the original.578  fir::FirOpBuilder builder_copy2(builder);579 580  mlir::Operation *op4 =581      mlir::arith::AddFOp::create(builder_copy2, loc, arg, arg);582  auto op4_fmi =583      mlir::dyn_cast_or_null<mlir::arith::ArithFastMathInterface>(op4);584  EXPECT_TRUE(op4_fmi);585  auto op4_fmf = op4_fmi.getFastMathFlagsAttr().getValue();586  EXPECT_EQ(op4_fmf, FMF1);587}588 589TEST_F(FIRBuilderTest, genArithIntegerOverflow) {590  auto builder = getBuilder();591  auto ctx = builder.getContext();592  auto loc = builder.getUnknownLoc();593 594  auto intTy = IntegerType::get(ctx, 32);595  auto arg = fir::UndefOp::create(builder, loc, intTy);596 597  // Test that IntegerOverflowFlags is 'none' by default.598  mlir::Operation *op1 = mlir::arith::AddIOp::create(builder, loc, arg, arg);599  auto op1_iofi =600      mlir::dyn_cast_or_null<mlir::arith::ArithIntegerOverflowFlagsInterface>(601          op1);602  EXPECT_TRUE(op1_iofi);603  auto op1_ioff = op1_iofi.getOverflowAttr().getValue();604  EXPECT_EQ(op1_ioff, arith::IntegerOverflowFlags::none);605 606  // Test that the builder is copied properly.607  fir::FirOpBuilder builder_copy(builder);608 609  arith::IntegerOverflowFlags nsw = arith::IntegerOverflowFlags::nsw;610  builder.setIntegerOverflowFlags(nsw);611  arith::IntegerOverflowFlags nuw = arith::IntegerOverflowFlags::nuw;612  builder_copy.setIntegerOverflowFlags(nuw);613 614  // Modifying IntegerOverflowFlags for the copy must not affect the original615  // builder.616  mlir::Operation *op2 = mlir::arith::AddIOp::create(builder, loc, arg, arg);617  auto op2_iofi =618      mlir::dyn_cast_or_null<mlir::arith::ArithIntegerOverflowFlagsInterface>(619          op2);620  EXPECT_TRUE(op2_iofi);621  auto op2_ioff = op2_iofi.getOverflowAttr().getValue();622  EXPECT_EQ(op2_ioff, nsw);623 624  // Modifying IntegerOverflowFlags for the original builder must not affect the625  // copy.626  mlir::Operation *op3 =627      mlir::arith::AddIOp::create(builder_copy, loc, arg, arg);628  auto op3_iofi =629      mlir::dyn_cast_or_null<mlir::arith::ArithIntegerOverflowFlagsInterface>(630          op3);631  EXPECT_TRUE(op3_iofi);632  auto op3_ioff = op3_iofi.getOverflowAttr().getValue();633  EXPECT_EQ(op3_ioff, nuw);634 635  // Test that the builder copy inherits IntegerOverflowFlags from the original.636  fir::FirOpBuilder builder_copy2(builder);637 638  mlir::Operation *op4 =639      mlir::arith::AddIOp::create(builder_copy2, loc, arg, arg);640  auto op4_iofi =641      mlir::dyn_cast_or_null<mlir::arith::ArithIntegerOverflowFlagsInterface>(642          op4);643  EXPECT_TRUE(op4_iofi);644  auto op4_ioff = op4_iofi.getOverflowAttr().getValue();645  EXPECT_EQ(op4_ioff, nsw);646}647 648TEST_F(FIRBuilderTest, getDescriptorWithNewBaseAddress) {649  auto builder = getBuilder();650  auto loc = builder.getUnknownLoc();651 652  // Build an input fir.box for a 1-D array of i64 with constant extent 10.653  auto i64Ty = builder.getI64Type();654  auto seqTy = fir::SequenceType::get({10}, i64Ty);655  auto refArrTy = fir::ReferenceType::get(seqTy);656  auto ptrTy = fir::PointerType::get(seqTy);657  auto boxTy = fir::BoxType::get(ptrTy);658  // Create an undef box descriptor value (descriptor contents are unspecified).659  mlir::Value inputBox = fir::UndefOp::create(builder, loc, boxTy);660 661  // New base address (same element type and properties).662  mlir::Value addr2 = fir::UndefOp::create(builder, loc, refArrTy);663 664  mlir::Value newBox = fir::factory::getDescriptorWithNewBaseAddress(665      builder, loc, inputBox, addr2);666 667  // The returned descriptor must have the same type as the input box.668  EXPECT_EQ(newBox.getType(), inputBox.getType());669 670  // It must be constructed by an embox using the new base address.671  ASSERT_TRUE(llvm::isa_and_nonnull<fir::EmboxOp>(newBox.getDefiningOp()));672  auto embox = llvm::dyn_cast<fir::EmboxOp>(newBox.getDefiningOp());673  EXPECT_EQ(embox.getMemref(), addr2);674 675  // The shape should be derived from the input box; expect a fir.shape with one676  // extent that comes from a fir.box_dims reading from the original input box.677  mlir::Value shape = embox.getShape();678  ASSERT_TRUE(shape);679  ASSERT_TRUE(llvm::isa_and_nonnull<fir::ShapeShiftOp>(shape.getDefiningOp()));680  auto shapeOp = llvm::dyn_cast<fir::ShapeShiftOp>(shape.getDefiningOp());681  ASSERT_EQ(shapeOp.getExtents().size(), 1u);682  mlir::Value extent0 = shapeOp.getExtents()[0];683  ASSERT_TRUE(llvm::isa_and_nonnull<fir::BoxDimsOp>(extent0.getDefiningOp()));684  auto dimOp = llvm::dyn_cast<fir::BoxDimsOp>(extent0.getDefiningOp());685  EXPECT_EQ(dimOp.getVal(), inputBox);686 687  // Also verify the origin comes from a BoxDims on the same input box.688  ASSERT_EQ(shapeOp.getOrigins().size(), 1u);689  mlir::Value origin0 = shapeOp.getOrigins()[0];690  ASSERT_TRUE(llvm::isa_and_nonnull<fir::BoxDimsOp>(origin0.getDefiningOp()));691  auto lbOp = llvm::dyn_cast<fir::BoxDimsOp>(origin0.getDefiningOp());692  EXPECT_EQ(lbOp.getVal(), inputBox);693}694 695TEST_F(FIRBuilderTest, getDescriptorWithNewBaseAddress_PolymorphicScalar) {696  auto builder = getBuilder();697  auto loc = builder.getUnknownLoc();698 699  // Build a polymorphic scalar: fir.class<ptr<!fir.type<rec>>>.700  auto recTy = fir::RecordType::get(builder.getContext(), "poly_rec");701  auto ptrRecTy = fir::PointerType::get(recTy);702  auto classTy = fir::ClassType::get(ptrRecTy);703 704  // Input descriptor is an undefined fir.class value.705  mlir::Value inputBox = fir::UndefOp::create(builder, loc, classTy);706 707  // New base address of the same element type (reference to the record).708  auto refRecTy = fir::ReferenceType::get(recTy);709  mlir::Value newAddr = fir::UndefOp::create(builder, loc, refRecTy);710 711  mlir::Value newBox = fir::factory::getDescriptorWithNewBaseAddress(712      builder, loc, inputBox, newAddr);713 714  // Same descriptor type must be preserved.715  EXPECT_EQ(newBox.getType(), inputBox.getType());716 717  // Must be an embox using the new base address and carrying the original box718  // as mold.719  ASSERT_TRUE(llvm::isa_and_nonnull<fir::EmboxOp>(newBox.getDefiningOp()));720  auto embox = llvm::dyn_cast<fir::EmboxOp>(newBox.getDefiningOp());721  EXPECT_EQ(embox.getMemref(), newAddr);722 723  // Polymorphic scalar should have no shape operand.724  mlir::Value shape = embox.getShape();725  EXPECT_TRUE(shape == nullptr);726 727  // The type descriptor/mold must be the original input box.728  mlir::Value tdesc = embox.getSourceBox();729  EXPECT_EQ(tdesc, inputBox);730}731