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