[LLVM] Add HasFakeUses to MachineFunction (#110097)
Following the addition of the llvm.fake.use intrinsic and corresponding
MIR instruction, two further changes are planned: to add an
-fextend-lifetimes flag to Clang that emits these intrinsics, and to
have -Og enable this flag by default. Currently, some logic for handling
fake uses is gated by the optdebug attribute, which is intended to be
switched on by -fextend-lifetimes (and by extension -Og later on).
However, the decision was made that a general optdebug attribute should
be incompatible with other opt_ attributes (e.g. optsize, optnone),
since they all express different intents for how to optimize the
program. We would still like to allow -fextend-lifetimes with optsize
however (i.e. -Os -fextend-lifetimes should be legal), since it may be a
useful configuration and there is no technical reason to not allow it.
This patch resolves this by tracking MachineFunctions that have fake
uses, allowing us to run passes that interact with them and skip passes
that clash with them.
diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index ab8dc44..c5bf697 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -734,6 +734,7 @@
std::optional<bool> NoPHIs;
std::optional<bool> IsSSA;
std::optional<bool> NoVRegs;
+ std::optional<bool> HasFakeUses;
bool CallsEHReturn = false;
bool CallsUnwindInit = false;
@@ -780,6 +781,7 @@
YamlIO.mapOptional("noPhis", MF.NoPHIs, std::optional<bool>());
YamlIO.mapOptional("isSSA", MF.IsSSA, std::optional<bool>());
YamlIO.mapOptional("noVRegs", MF.NoVRegs, std::optional<bool>());
+ YamlIO.mapOptional("hasFakeUses", MF.HasFakeUses, std::optional<bool>());
YamlIO.mapOptional("callsEHReturn", MF.CallsEHReturn, false);
YamlIO.mapOptional("callsUnwindInit", MF.CallsUnwindInit, false);
diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h
index 997960f..49a1fc1 100644
--- a/llvm/include/llvm/CodeGen/MachineFunction.h
+++ b/llvm/include/llvm/CodeGen/MachineFunction.h
@@ -187,6 +187,7 @@
TiedOpsRewritten,
FailsVerification,
TracksDebugUserValues,
+ HasFakeUses,
LastProperty = TracksDebugUserValues,
};
@@ -376,6 +377,7 @@
bool HasEHCatchret = false;
bool HasEHScopes = false;
bool HasEHFunclets = false;
+ bool HasFakeUses = false;
bool IsOutlined = false;
/// BBID to assign to the next basic block of this function.
@@ -1195,6 +1197,9 @@
bool hasEHFunclets() const { return HasEHFunclets; }
void setHasEHFunclets(bool V) { HasEHFunclets = V; }
+ bool hasFakeUses() const { return HasFakeUses; }
+ void setHasFakeUses(bool V) { HasFakeUses = V; }
+
bool isOutlined() const { return IsOutlined; }
void setIsOutlined(bool V) { IsOutlined = V; }
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 40360b0..932287d 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -2201,6 +2201,7 @@
for (auto VReg : getOrCreateVRegs(*Arg))
VRegs.push_back(VReg);
MIRBuilder.buildInstr(TargetOpcode::FAKE_USE, {}, VRegs);
+ MF->setHasFakeUses(true);
return true;
}
case Intrinsic::dbg_declare: {
diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index 997c428..30b1a71 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -380,6 +380,7 @@
bool HasPHI = false;
bool HasInlineAsm = false;
+ bool HasFakeUses = false;
bool AllTiedOpsRewritten = true, HasTiedOps = false;
for (const MachineBasicBlock &MBB : MF) {
for (const MachineInstr &MI : MBB) {
@@ -387,6 +388,8 @@
HasPHI = true;
if (MI.isInlineAsm())
HasInlineAsm = true;
+ if (MI.isFakeUse())
+ HasFakeUses = true;
for (unsigned I = 0; I < MI.getNumOperands(); ++I) {
const MachineOperand &MO = MI.getOperand(I);
if (!MO.isReg() || !MO.getReg())
@@ -441,6 +444,16 @@
" has explicit property NoVRegs, but contains virtual registers");
}
+ // For hasFakeUses we follow similar logic to the ComputedPropertyHelper,
+ // except for caring about the inverse case only, i.e. when the property is
+ // explicitly set to false and Fake Uses are present; having HasFakeUses=true
+ // on a function without fake uses is harmless.
+ if (YamlMF.HasFakeUses && !*YamlMF.HasFakeUses && HasFakeUses)
+ return error(
+ MF.getName() +
+ " has explicit property hasFakeUses=false, but contains fake uses");
+ MF.setHasFakeUses(YamlMF.HasFakeUses.value_or(HasFakeUses));
+
return false;
}
diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp
index cf6122b..d52c1d8 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -207,6 +207,7 @@
YamlMF.HasEHCatchret = MF.hasEHCatchret();
YamlMF.HasEHScopes = MF.hasEHScopes();
YamlMF.HasEHFunclets = MF.hasEHFunclets();
+ YamlMF.HasFakeUses = MF.hasFakeUses();
YamlMF.IsOutlined = MF.isOutlined();
YamlMF.UseDebugInstrRef = MF.useDebugInstrRef();
diff --git a/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp b/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
index 232181a..ef7a586 100644
--- a/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
+++ b/llvm/lib/CodeGen/RemoveLoadsIntoFakeUses.cpp
@@ -74,10 +74,8 @@
"Remove Loads Into Fake Uses", false, false)
bool RemoveLoadsIntoFakeUses::runOnMachineFunction(MachineFunction &MF) {
- // Only `optdebug` functions should contain FAKE_USEs, so don't try to run
- // this for other functions.
- if (!MF.getFunction().hasFnAttribute(Attribute::OptimizeForDebugging) ||
- skipFunction(MF.getFunction()))
+ // Only run this for functions that have fake uses.
+ if (!MF.hasFakeUses() || skipFunction(MF.getFunction()))
return false;
bool AnyChanges = false;
diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
index 8405ba9..6a6bc19 100644
--- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
@@ -31,6 +31,7 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
@@ -200,12 +201,22 @@
}
}
}
- // Look for calls to the @llvm.va_start intrinsic. We can omit some
- // prologue boilerplate for variadic functions that don't examine their
- // arguments.
if (const auto *II = dyn_cast<IntrinsicInst>(&I)) {
- if (II->getIntrinsicID() == Intrinsic::vastart)
+ switch (II->getIntrinsicID()) {
+ case Intrinsic::vastart:
+ // Look for calls to the @llvm.va_start intrinsic. We can omit
+ // some prologue boilerplate for variadic functions that don't
+ // examine their arguments.
MF->getFrameInfo().setHasVAStart(true);
+ break;
+ case Intrinsic::fake_use:
+ // Look for llvm.fake.uses, so that we can remove loads into fake
+ // uses later if necessary.
+ MF->setHasFakeUses(true);
+ break;
+ default:
+ break;
+ }
}
// If we have a musttail call in a variadic function, we need to ensure
diff --git a/llvm/test/CodeGen/MIR/Generic/machine-function-hasfakeuses-conflict.mir b/llvm/test/CodeGen/MIR/Generic/machine-function-hasfakeuses-conflict.mir
new file mode 100644
index 0000000..56175bd
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/Generic/machine-function-hasfakeuses-conflict.mir
@@ -0,0 +1,14 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+
+# Test that computed properties are not conflicting with explicitly set
+# properties
+
+---
+# CHECK: error: {{.*}}: TestHasFakeUsesOverrideConflict has explicit property hasFakeUses=false, but contains fake uses
+name: TestHasFakeUsesOverrideConflict
+hasFakeUses: false
+body: |
+ bb.0:
+ %0:_(s32) = G_IMPLICIT_DEF
+ FAKE_USE %0
+...
diff --git a/llvm/test/CodeGen/MIR/Generic/machine-function-optionally-computed-properties.mir b/llvm/test/CodeGen/MIR/Generic/machine-function-optionally-computed-properties.mir
index 858bbc8..8ac6b2e 100644
--- a/llvm/test/CodeGen/MIR/Generic/machine-function-optionally-computed-properties.mir
+++ b/llvm/test/CodeGen/MIR/Generic/machine-function-optionally-computed-properties.mir
@@ -62,3 +62,23 @@
name: TestNoVRegsOverrideTrue
noVRegs: true
...
+---
+# CHECK-LABEL: name: TestHasFakeUses
+# CHECK: hasFakeUses: false
+# CHECK: ...
+name: TestHasFakeUses
+...
+---
+# CHECK-LABEL: name: TestHasFakeUsesOverride
+# CHECK: hasFakeUses: false
+# CHECK: ...
+name: TestHasFakeUsesOverride
+hasFakeUses: false
+...
+---
+# CHECK-LABEL: name: TestHasFakeUsesOverrideTrue
+# CHECK: hasFakeUses: true
+# CHECK: ...
+name: TestHasFakeUsesOverrideTrue
+hasFakeUses: true
+...
diff --git a/llvm/test/tools/llvm-reduce/mir/preserve-func-info.mir b/llvm/test/tools/llvm-reduce/mir/preserve-func-info.mir
index f735dfd..cbddf89 100644
--- a/llvm/test/tools/llvm-reduce/mir/preserve-func-info.mir
+++ b/llvm/test/tools/llvm-reduce/mir/preserve-func-info.mir
@@ -17,6 +17,7 @@
# RESULT-NEXT: noPhis: false
# RESULT-NEXT: isSSA: false
# RESULT-NEXT: noVRegs: false
+# RESULT-NEXT: hasFakeUses: true
# RESULT-NEXT: callsEHReturn: true
# RESULT-NEXT: callsUnwindInit: true
# RESULT-NEXT: hasEHCatchret: true
@@ -47,6 +48,7 @@
noPhis: false
isSSA: false
noVRegs: false
+hasFakeUses: true
failsVerification: true
tracksDebugUserValues: true
callsEHReturn: true
diff --git a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
index 5409b6d..5f6a22c 100644
--- a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
+++ b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
@@ -403,6 +403,7 @@
DstMF->setHasEHCatchret(SrcMF->hasEHCatchret());
DstMF->setHasEHScopes(SrcMF->hasEHScopes());
DstMF->setHasEHFunclets(SrcMF->hasEHFunclets());
+ DstMF->setHasFakeUses(SrcMF->hasFakeUses());
DstMF->setIsOutlined(SrcMF->isOutlined());
if (!SrcMF->getLandingPads().empty() ||