Skip to content

Commit f51cfbe

Browse files
committed
[flang] Add nsw flag to do-variable increment with a new option
This patch adds nsw flag to the increment of do-variables when a new option is enabled. NOTE 11.10 in the Fortran 2018 standard says they never overflow. See also the discussion in 74709 and discourse post.
1 parent 6eb9e21 commit f51cfbe

File tree

20 files changed

+659
-23
lines changed

20 files changed

+659
-23
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6539,6 +6539,10 @@ def flang_deprecated_no_hlfir : Flag<["-"], "flang-deprecated-no-hlfir">,
65396539
Flags<[HelpHidden]>, Visibility<[FlangOption, FC1Option]>,
65406540
HelpText<"Do not use HLFIR lowering (deprecated)">;
65416541

6542+
def flang_experimental_integer_overflow : Flag<["-"], "flang-experimental-integer-overflow">,
6543+
Flags<[HelpHidden]>, Visibility<[FlangOption, FC1Option]>,
6544+
HelpText<"Add nsw flag to internal operations such as do-variable increment (experimental)">;
6545+
65426546
//===----------------------------------------------------------------------===//
65436547
// FLangOption + CoreOption + NoXarchOption
65446548
//===----------------------------------------------------------------------===//

clang/lib/Driver/ToolChains/Flang.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ void Flang::addCodegenOptions(const ArgList &Args,
139139

140140
Args.addAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir,
141141
options::OPT_flang_deprecated_no_hlfir,
142+
options::OPT_flang_experimental_integer_overflow,
142143
options::OPT_fno_ppc_native_vec_elem_order,
143144
options::OPT_fppc_native_vec_elem_order});
144145
}

flang/include/flang/Lower/LoweringOptions.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,9 @@ ENUM_LOWERINGOPT(NoPPCNativeVecElemOrder, unsigned, 1, 0)
3434
/// On by default.
3535
ENUM_LOWERINGOPT(Underscoring, unsigned, 1, 1)
3636

37+
/// If true, add nsw flags to arithmetic operations for integer.
38+
/// Off by default.
39+
ENUM_LOWERINGOPT(NoSignedWrap, unsigned, 1, 0)
40+
3741
#undef LOWERINGOPT
3842
#undef ENUM_LOWERINGOPT

flang/include/flang/Optimizer/Transforms/Passes.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ namespace fir {
5454
std::unique_ptr<mlir::Pass> createAffineDemotionPass();
5555
std::unique_ptr<mlir::Pass>
5656
createArrayValueCopyPass(fir::ArrayValueCopyOptions options = {});
57+
std::unique_ptr<mlir::Pass> createCFGConversionPassWithNSW();
5758
std::unique_ptr<mlir::Pass> createExternalNameConversionPass();
5859
std::unique_ptr<mlir::Pass>
5960
createExternalNameConversionPass(bool appendUnderscore);
@@ -89,7 +90,8 @@ createFunctionAttrPass(FunctionAttrTypes &functionAttr, bool noInfsFPMath,
8990
bool noSignedZerosFPMath, bool unsafeFPMath);
9091

9192
void populateCfgConversionRewrites(mlir::RewritePatternSet &patterns,
92-
bool forceLoopToExecuteOnce = false);
93+
bool forceLoopToExecuteOnce = false,
94+
bool setNSW = false);
9395

9496
// declarative passes
9597
#define GEN_PASS_REGISTRATION

flang/include/flang/Optimizer/Transforms/Passes.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,10 @@ def CFGConversion : Pass<"cfg-conversion"> {
151151
let options = [
152152
Option<"forceLoopToExecuteOnce", "always-execute-loop-body", "bool",
153153
/*default=*/"false",
154-
"force the body of a loop to execute at least once">
154+
"force the body of a loop to execute at least once">,
155+
Option<"setNSW", "set-nsw", "bool",
156+
/*default=*/"false",
157+
"set nsw on loop variable increment">
155158
];
156159
}
157160

flang/include/flang/Tools/CLOptions.inc

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,14 @@ static void addCanonicalizerPassWithoutRegionSimplification(
148148
pm.addPass(mlir::createCanonicalizerPass(config));
149149
}
150150

151-
inline void addCfgConversionPass(mlir::PassManager &pm) {
152-
addNestedPassToAllTopLevelOperationsConditionally(
153-
pm, disableCfgConversion, fir::createCFGConversion);
151+
inline void addCfgConversionPass(
152+
mlir::PassManager &pm, const MLIRToLLVMPassPipelineConfig &config) {
153+
if (config.NoSignedWrap)
154+
addNestedPassToAllTopLevelOperationsConditionally(
155+
pm, disableCfgConversion, fir::createCFGConversionPassWithNSW);
156+
else
157+
addNestedPassToAllTopLevelOperationsConditionally(
158+
pm, disableCfgConversion, fir::createCFGConversion);
154159
}
155160

156161
inline void addAVC(
@@ -290,7 +295,7 @@ inline void createDefaultFIROptimizerPassPipeline(
290295
pm.addPass(fir::createAliasTagsPass());
291296

292297
// convert control flow to CFG form
293-
fir::addCfgConversionPass(pm);
298+
fir::addCfgConversionPass(pm, pc);
294299
pm.addPass(mlir::createConvertSCFToCFPass());
295300

296301
pm.addPass(mlir::createCanonicalizerPass(config));

flang/include/flang/Tools/CrossToolHelpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
122122
bool NoSignedZerosFPMath =
123123
false; ///< Set no-signed-zeros-fp-math attribute for functions.
124124
bool UnsafeFPMath = false; ///< Set unsafe-fp-math attribute for functions.
125+
bool NoSignedWrap = false; ///< Add nsw flag to numeric operations.
125126
};
126127

127128
struct OffloadModuleOpts {

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,12 @@ bool CompilerInvocation::createFromArgs(
12031203
invoc.loweringOpts.setNoPPCNativeVecElemOrder(true);
12041204
}
12051205

1206+
// -flang-experimental-integer-overflow
1207+
if (args.hasArg(
1208+
clang::driver::options::OPT_flang_experimental_integer_overflow)) {
1209+
invoc.loweringOpts.setNoSignedWrap(true);
1210+
}
1211+
12061212
// Preserve all the remark options requested, i.e. -Rpass, -Rpass-missed or
12071213
// -Rpass-analysis. This will be used later when processing and outputting the
12081214
// remarks generated by LLVM in ExecuteCompilerInvocation.cpp.

flang/lib/Frontend/FrontendActions.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,9 @@ void CodeGenAction::generateLLVMIR() {
809809
config.VScaleMax = vsr->second;
810810
}
811811

812+
if (ci.getInvocation().getLoweringOpts().getNoSignedWrap())
813+
config.NoSignedWrap = true;
814+
812815
// Create the pass pipeline
813816
fir::createMLIRToLLVMPassPipeline(pm, config, getCurrentFile());
814817
(void)mlir::applyPassManagerCLOptions(pm);

flang/lib/Lower/Bridge.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,6 +2007,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
20072007
void genFIRIncrementLoopEnd(IncrementLoopNestInfo &incrementLoopNestInfo) {
20082008
assert(!incrementLoopNestInfo.empty() && "empty loop nest");
20092009
mlir::Location loc = toLocation();
2010+
mlir::arith::IntegerOverflowFlags flags{};
2011+
if (getLoweringOptions().getNoSignedWrap())
2012+
flags = bitEnumSet(flags, mlir::arith::IntegerOverflowFlags::nsw);
2013+
auto iofAttr = mlir::arith::IntegerOverflowFlagsAttr::get(
2014+
builder->getContext(), flags);
20102015
for (auto it = incrementLoopNestInfo.rbegin(),
20112016
rend = incrementLoopNestInfo.rend();
20122017
it != rend; ++it) {
@@ -2021,15 +2026,16 @@ class FirConverter : public Fortran::lower::AbstractConverter {
20212026
builder->setInsertionPointToEnd(info.doLoop.getBody());
20222027
llvm::SmallVector<mlir::Value, 2> results;
20232028
results.push_back(builder->create<mlir::arith::AddIOp>(
2024-
loc, info.doLoop.getInductionVar(), info.doLoop.getStep()));
2029+
loc, info.doLoop.getInductionVar(), info.doLoop.getStep(),
2030+
iofAttr));
20252031
// Step loopVariable to help optimizations such as vectorization.
20262032
// Induction variable elimination will clean up as necessary.
20272033
mlir::Value step = builder->createConvert(
20282034
loc, info.getLoopVariableType(), info.doLoop.getStep());
20292035
mlir::Value loopVar =
20302036
builder->create<fir::LoadOp>(loc, info.loopVariable);
20312037
results.push_back(
2032-
builder->create<mlir::arith::AddIOp>(loc, loopVar, step));
2038+
builder->create<mlir::arith::AddIOp>(loc, loopVar, step, iofAttr));
20332039
builder->create<fir::ResultOp>(loc, results);
20342040
builder->setInsertionPointAfter(info.doLoop);
20352041
// The loop control variable may be used after the loop.
@@ -2054,7 +2060,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
20542060
if (info.hasRealControl)
20552061
value = builder->create<mlir::arith::AddFOp>(loc, value, step);
20562062
else
2057-
value = builder->create<mlir::arith::AddIOp>(loc, value, step);
2063+
value = builder->create<mlir::arith::AddIOp>(loc, value, step, iofAttr);
20582064
builder->create<fir::StoreOp>(loc, value, info.loopVariable);
20592065

20602066
genBranch(info.headerBlock);

0 commit comments

Comments
 (0)