Skip to content

Commit

Permalink
[flang] Lower optionals in GET_COMMAND_ARGUMENT and GET_ENVIRONMENT_V…
Browse files Browse the repository at this point in the history
…ARIABLE

Handle dynamic optional argument in GET_COMMAND_ARGUMENT and GET_ENVIRONMENT_VARIABLE
(previously compiled but caused segfaults). The previous code
handled static presence/absence aspects, but not when an absent dummy optional was
passed to one of the optional intrinsic arguments.

Simplify the runtime call lowering to simply lower the runtime call without
dealing with optionality there. This keeps the optional handling logic in
IntrinsicCall.cpp.

Note that the new code will generate some extra "if (not null addr )/then/else"
when the actual arguments are always there at runtime. That makes the implementation
a lot simpler/safer, and I think it is OK for now (I do not expect these runtime
function to be called in hot loop nests).

Differential Revision: https://reviews.llvm.org/D123388
  • Loading branch information
jeanPerier committed Apr 11, 2022
1 parent 9cfa899 commit 189cb7d
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 241 deletions.
5 changes: 5 additions & 0 deletions flang/include/flang/Optimizer/Builder/FIRBuilder.h
Expand Up @@ -247,6 +247,11 @@ class FirOpBuilder : public mlir::OpBuilder {
mlir::Value createConvert(mlir::Location loc, mlir::Type toTy,
mlir::Value val);

/// Create a fir.store of \p val into \p addr. A lazy conversion
/// of \p val to the element type of \p addr is created if needed.
void createStoreWithConvert(mlir::Location loc, mlir::Value val,
mlir::Value addr);

/// Create a new FuncOp. If the function may have already been created, use
/// `addNamedFunction` instead.
mlir::FuncOp createFunction(mlir::Location loc, llvm::StringRef name,
Expand Down
46 changes: 29 additions & 17 deletions flang/include/flang/Optimizer/Builder/Runtime/Command.h
Expand Up @@ -23,23 +23,35 @@ 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);

/// Generate call to GET_ENVIRONMENT_VARIABLE intrinsic runtime routine.
/// Note that GET_ENVIRONMENT_ARGUMENT intrinsic is split between 2 functions in
/// implementation; EnvVariableValue and EnvVariableLength. So we handle each
/// seperately.
void genGetEnvironmentVariable(fir::FirOpBuilder &, mlir::Location,
mlir::Value number, mlir::Value value,
mlir::Value length, mlir::Value status,
mlir::Value trimName, mlir::Value errmsg);
/// Generate a call to ArgumentValue runtime function which implements
/// the part of GET_COMMAND_ARGUMENT related to VALUE, ERRMSG, and STATUS.
/// \p value and \p errmsg must be fir.box that can be absent (but not null
/// mlir values). The status value is returned.
mlir::Value genArgumentValue(fir::FirOpBuilder &, mlir::Location,
mlir::Value number, mlir::Value value,
mlir::Value errmsg);

/// Generate a call to ArgumentLength runtime function which implements
/// the part of GET_COMMAND_ARGUMENT related to LENGTH.
/// It returns the length of the \p number command arguments.
mlir::Value genArgumentLength(fir::FirOpBuilder &, mlir::Location,
mlir::Value number);

/// Generate a call to EnvVariableValue runtime function which implements
/// the part of GET_ENVIRONMENT_ARGUMENT related to VALUE, ERRMSG, and STATUS.
/// \p value and \p errmsg must be fir.box that can be absent (but not null
/// mlir values). The status value is returned. \p name must be a fir.box.
/// and \p trimName a boolean value.
mlir::Value genEnvVariableValue(fir::FirOpBuilder &, mlir::Location,
mlir::Value name, mlir::Value value,
mlir::Value trimName, mlir::Value errmsg);

/// Generate a call to EnvVariableLength runtime function which implements
/// the part of GET_ENVIRONMENT_ARGUMENT related to LENGTH.
/// It returns the length of the \p number command arguments.
/// \p name must be a fir.box and \p trimName a boolean value.
mlir::Value genEnvVariableLength(fir::FirOpBuilder &, mlir::Location,
mlir::Value name, mlir::Value trimName);

} // namespace fir::runtime
#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_COMMAND_H
191 changes: 105 additions & 86 deletions flang/lib/Lower/IntrinsicCall.cpp
Expand Up @@ -737,19 +737,19 @@ static constexpr IntrinsicHandler handlers[]{
{"get_command_argument",
&I::genGetCommandArgument,
{{{"number", asValue},
{"value", asAddr},
{"value", asBox, handleDynamicOptional},
{"length", asAddr},
{"status", asAddr},
{"errmsg", asAddr}}},
{"errmsg", asBox, handleDynamicOptional}}},
/*isElemental=*/false},
{"get_environment_variable",
&I::genGetEnvironmentVariable,
{{{"name", asValue},
{"value", asAddr},
{{{"name", asBox},
{"value", asBox, handleDynamicOptional},
{"length", asAddr},
{"status", asAddr},
{"trim_name", asValue},
{"errmsg", asAddr}}},
{"trim_name", asAddr},
{"errmsg", asBox, handleDynamicOptional}}},
/*isElemental=*/false},
{"iachar", &I::genIchar},
{"iand", &I::genIand},
Expand Down Expand Up @@ -2399,100 +2399,119 @@ mlir::Value IntrinsicLibrary::genFraction(mlir::Type resultType,
void IntrinsicLibrary::genGetCommandArgument(
llvm::ArrayRef<fir::ExtendedValue> args) {
assert(args.size() == 5);

auto processCharBox = [&](llvm::Optional<fir::CharBoxValue> arg,
mlir::Value &value) -> void {
if (arg.hasValue()) {
value = builder.createBox(loc, *arg);
} else {
value = builder
.create<fir::AbsentOp>(
loc, fir::BoxType::get(builder.getNoneType()))
.getResult();
}
};

// Handle NUMBER argument
mlir::Value number = fir::getBase(args[0]);
const fir::ExtendedValue &value = args[1];
const fir::ExtendedValue &length = args[2];
const fir::ExtendedValue &status = args[3];
const fir::ExtendedValue &errmsg = args[4];

if (!number)
fir::emitFatalError(loc, "expected NUMBER parameter");

// Handle optional VALUE argument
mlir::Value value;
llvm::Optional<fir::CharBoxValue> valBox;
if (const fir::CharBoxValue *charBox = args[1].getCharBox())
valBox = *charBox;
processCharBox(valBox, value);

// Handle optional LENGTH argument
mlir::Value length = fir::getBase(args[2]);

// Handle optional STATUS argument
mlir::Value status = fir::getBase(args[3]);

// Handle optional ERRMSG argument
mlir::Value errmsg;
llvm::Optional<fir::CharBoxValue> errmsgBox;
if (const fir::CharBoxValue *charBox = args[4].getCharBox())
errmsgBox = *charBox;
processCharBox(errmsgBox, errmsg);

fir::runtime::genGetCommandArgument(builder, loc, number, value, length,
status, errmsg);
if (isStaticallyPresent(value) || isStaticallyPresent(status) ||
isStaticallyPresent(errmsg)) {
mlir::Type boxNoneTy = fir::BoxType::get(builder.getNoneType());
mlir::Value valBox =
isStaticallyPresent(value)
? fir::getBase(value)
: builder.create<fir::AbsentOp>(loc, boxNoneTy).getResult();
mlir::Value errBox =
isStaticallyPresent(errmsg)
? fir::getBase(errmsg)
: builder.create<fir::AbsentOp>(loc, boxNoneTy).getResult();
mlir::Value stat =
fir::runtime::genArgumentValue(builder, loc, number, valBox, errBox);
if (isStaticallyPresent(status)) {
mlir::Value statAddr = fir::getBase(status);
mlir::Value statIsPresentAtRuntime = builder.genIsNotNull(loc, statAddr);
builder.genIfThen(loc, statIsPresentAtRuntime)
.genThen(
[&]() { builder.createStoreWithConvert(loc, stat, statAddr); })
.end();
}
}
if (isStaticallyPresent(length)) {
mlir::Value lenAddr = fir::getBase(length);
mlir::Value lenIsPresentAtRuntime = builder.genIsNotNull(loc, lenAddr);
builder.genIfThen(loc, lenIsPresentAtRuntime)
.genThen([&]() {
mlir::Value len =
fir::runtime::genArgumentLength(builder, loc, number);
builder.createStoreWithConvert(loc, len, lenAddr);
})
.end();
}
}

// GET_ENVIRONMENT_VARIABLE
void IntrinsicLibrary::genGetEnvironmentVariable(
llvm::ArrayRef<fir::ExtendedValue> args) {
assert(args.size() == 6);
mlir::Value name = fir::getBase(args[0]);
const fir::ExtendedValue &value = args[1];
const fir::ExtendedValue &length = args[2];
const fir::ExtendedValue &status = args[3];
const fir::ExtendedValue &trimName = args[4];
const fir::ExtendedValue &errmsg = args[5];

auto processCharBox = [&](llvm::Optional<fir::CharBoxValue> arg,
mlir::Value &value) -> void {
if (arg.hasValue()) {
value = builder.createBox(loc, *arg);
} else {
value = builder
.create<fir::AbsentOp>(
loc, fir::BoxType::get(builder.getNoneType()))
.getResult();
}
};

// Handle NAME argument
mlir::Value name;
if (const fir::CharBoxValue *charBox = args[0].getCharBox()) {
llvm::Optional<fir::CharBoxValue> nameBox = *charBox;
assert(nameBox.hasValue());
name = builder.createBox(loc, *nameBox);
// Handle optional TRIM_NAME argument
mlir::Value trim;
if (isStaticallyAbsent(trimName)) {
trim = builder.createBool(loc, true);
} else {
mlir::Type i1Ty = builder.getI1Type();
mlir::Value trimNameAddr = fir::getBase(trimName);
mlir::Value trimNameIsPresentAtRuntime =
builder.genIsNotNull(loc, trimNameAddr);
trim = builder
.genIfOp(loc, {i1Ty}, trimNameIsPresentAtRuntime,
/*withElseRegion=*/true)
.genThen([&]() {
auto trimLoad = builder.create<fir::LoadOp>(loc, trimNameAddr);
mlir::Value cast = builder.createConvert(loc, i1Ty, trimLoad);
builder.create<fir::ResultOp>(loc, cast);
})
.genElse([&]() {
mlir::Value trueVal = builder.createBool(loc, true);
builder.create<fir::ResultOp>(loc, trueVal);
})
.getResults()[0];
}

// Handle optional VALUE argument
mlir::Value value;
llvm::Optional<fir::CharBoxValue> valBox;
if (const fir::CharBoxValue *charBox = args[1].getCharBox())
valBox = *charBox;
processCharBox(valBox, value);

// Handle optional LENGTH argument
mlir::Value length = fir::getBase(args[2]);

// Handle optional STATUS argument
mlir::Value status = fir::getBase(args[3]);
if (isStaticallyPresent(value) || isStaticallyPresent(status) ||
isStaticallyPresent(errmsg)) {
mlir::Type boxNoneTy = fir::BoxType::get(builder.getNoneType());
mlir::Value valBox =
isStaticallyPresent(value)
? fir::getBase(value)
: builder.create<fir::AbsentOp>(loc, boxNoneTy).getResult();
mlir::Value errBox =
isStaticallyPresent(errmsg)
? fir::getBase(errmsg)
: builder.create<fir::AbsentOp>(loc, boxNoneTy).getResult();
mlir::Value stat = fir::runtime::genEnvVariableValue(builder, loc, name,
valBox, trim, errBox);
if (isStaticallyPresent(status)) {
mlir::Value statAddr = fir::getBase(status);
mlir::Value statIsPresentAtRuntime = builder.genIsNotNull(loc, statAddr);
builder.genIfThen(loc, statIsPresentAtRuntime)
.genThen(
[&]() { builder.createStoreWithConvert(loc, stat, statAddr); })
.end();
}
}

// Handle optional TRIM_NAME argument
mlir::Value trim_name = isStaticallyAbsent(args[4])
? builder.createBool(loc, true)
: fir::getBase(args[4]);

// Handle optional ERRMSG argument
mlir::Value errmsg;
llvm::Optional<fir::CharBoxValue> errmsgBox;
if (const fir::CharBoxValue *charBox = args[5].getCharBox())
errmsgBox = *charBox;
processCharBox(errmsgBox, errmsg);

fir::runtime::genGetEnvironmentVariable(builder, loc, name, value, length,
status, trim_name, errmsg);
if (isStaticallyPresent(length)) {
mlir::Value lenAddr = fir::getBase(length);
mlir::Value lenIsPresentAtRuntime = builder.genIsNotNull(loc, lenAddr);
builder.genIfThen(loc, lenIsPresentAtRuntime)
.genThen([&]() {
mlir::Value len =
fir::runtime::genEnvVariableLength(builder, loc, name, trim);
builder.createStoreWithConvert(loc, len, lenAddr);
})
.end();
}
}

// IAND
Expand Down
8 changes: 8 additions & 0 deletions flang/lib/Optimizer/Builder/FIRBuilder.cpp
Expand Up @@ -334,6 +334,14 @@ mlir::Value fir::FirOpBuilder::createConvert(mlir::Location loc,
return val;
}

void fir::FirOpBuilder::createStoreWithConvert(mlir::Location loc,
mlir::Value val,
mlir::Value addr) {
mlir::Value cast =
createConvert(loc, fir::unwrapRefType(addr.getType()), val);
create<fir::StoreOp>(loc, cast, addr);
}

fir::StringLitOp fir::FirOpBuilder::createStringLitOp(mlir::Location loc,
llvm::StringRef data) {
auto type = fir::CharacterType::get(getContext(), 1, data.size());
Expand Down

0 comments on commit 189cb7d

Please sign in to comment.