diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Command.h b/flang/include/flang/Optimizer/Builder/Runtime/Command.h --- a/flang/include/flang/Optimizer/Builder/Runtime/Command.h +++ b/flang/include/flang/Optimizer/Builder/Runtime/Command.h @@ -16,12 +16,21 @@ namespace fir { class FirOpBuilder; -} +} // namespace fir namespace fir::runtime { /// Generate call to COMMAND_ARGUMENT_COUNT intrinsic runtime routine. mlir::Value genCommandArgumentCount(fir::FirOpBuilder &, mlir::Location); +/// Generate call to GET_COMMAND_ARGUMENT intrinsic runtime routine. +/// Note that GET_COMMAND_ARGUMENT intrinsic is split between 2 functions in +/// implementation; ArgumentValue and ArgumentLength. So we handle each +/// seperately. +void genGetCommandArgument(fir::FirOpBuilder &, mlir::Location, + mlir::Value number, mlir::Value value, + mlir::Value length, mlir::Value status, + mlir::Value errmsg); + } // namespace fir::runtime #endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_COMMAND_H diff --git a/flang/lib/Optimizer/Builder/Runtime/Command.cpp b/flang/lib/Optimizer/Builder/Runtime/Command.cpp --- a/flang/lib/Optimizer/Builder/Runtime/Command.cpp +++ b/flang/lib/Optimizer/Builder/Runtime/Command.cpp @@ -19,3 +19,52 @@ fir::runtime::getRuntimeFunc(loc, builder); return builder.create(loc, argumentCountFunc).getResult(0); } + +void fir::runtime::genGetCommandArgument(fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value number, + mlir::Value value, mlir::Value length, + mlir::Value status, + mlir::Value errmsg) { + auto argumentValueFunc = + fir::runtime::getRuntimeFunc(loc, builder); + auto argumentLengthFunc = + fir::runtime::getRuntimeFunc(loc, builder); + + auto isPresent = [&](mlir::Value val) -> bool { + return !mlir::isa_and_nonnull(val.getDefiningOp()); + }; + + mlir::Value valueResult; + // Run `ArgumentValue` intrisc only if we have either "value", "status" or + // "errmsg" `ArgumentValue` "requires" existing values for its arguments + // "value" and "errmsg". So in the case they aren't given, but the user has + // requested "status", we have to assign "absent" values to them before + // calling `ArgumentValue`. This happens in IntrinsicCall.cpp. For this reason + // we need extra indirection with `isPresent` for testing whether "value" or + // "errmsg" is present. + if (isPresent(value) || status || isPresent(errmsg)) { + llvm::SmallVector args = fir::runtime::createArguments( + builder, loc, argumentValueFunc.getType(), number, value, errmsg); + valueResult = + builder.create(loc, argumentValueFunc, args).getResult(0); + } + + // Only save result of ArgumentValue if "status" parameter has been given + if (status) { + const mlir::Value statusLoaded = builder.create(loc, status); + mlir::Value resultCast = + builder.createConvert(loc, statusLoaded.getType(), valueResult); + builder.create(loc, resultCast, status); + } + + if (length) { + llvm::SmallVector args = fir::runtime::createArguments( + builder, loc, argumentLengthFunc.getType(), number); + mlir::Value result = + builder.create(loc, argumentLengthFunc, args).getResult(0); + const mlir::Value valueLoaded = builder.create(loc, length); + mlir::Value resultCast = + builder.createConvert(loc, valueLoaded.getType(), result); + builder.create(loc, resultCast, length); + } +} diff --git a/flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp b/flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp --- a/flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp +++ b/flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp @@ -16,3 +16,21 @@ checkCallOp(result.getDefiningOp(), "_FortranAArgumentCount", /*nbArgs=*/0, /*addLocArgs=*/false); } + +TEST_F(RuntimeCallTest, genGetCommandArgument) { + mlir::Location loc = firBuilder->getUnknownLoc(); + mlir::Type intTy = firBuilder->getDefaultIntegerType(); + mlir::Type charTy = fir::BoxType::get(firBuilder->getNoneType()); + mlir::Value number = firBuilder->create(loc, intTy); + mlir::Value value = firBuilder->create(loc, charTy); + mlir::Value length = firBuilder->create(loc, intTy); + mlir::Value status = firBuilder->create(loc, intTy); + mlir::Value errmsg = firBuilder->create(loc, charTy); + fir::runtime::genGetCommandArgument( + *firBuilder, loc, number, value, length, status, errmsg); + checkCallOpFromResultBox( + value, "_FortranAArgumentValue", /*nbArgs=*/3, /*addLocArgs=*/false); + mlir::Block *block = firBuilder->getBlock(); + EXPECT_TRUE(block) << "Failed to retrieve the block!"; + checkBlockForCallOp(block, "_FortranAArgumentLength", /*nbArgs=*/1); +}