Skip to content

Commit 3d08ade

Browse files
authored
[ExtendLifetimes] Implement llvm.fake.use to extend variable lifetimes (#86149)
This patch is part of a set of patches that add an `-fextend-lifetimes` flag to clang, which extends the lifetimes of local variables and parameters for improved debuggability. In addition to that flag, the patch series adds a pragma to selectively disable `-fextend-lifetimes`, and an `-fextend-this-ptr` flag which functions as `-fextend-lifetimes` for this pointers only. All changes and tests in these patches were written by Wolfgang Pieb (@wolfy1961), while Stephen Tozer (@SLTozer) has handled review and merging. The extend lifetimes flag is intended to eventually be set on by `-Og`, as discussed in the RFC here: https://discourse.llvm.org/t/rfc-redefine-og-o1-and-add-a-new-level-of-og/72850 This patch implements a new intrinsic instruction in LLVM, `llvm.fake.use` in IR and `FAKE_USE` in MIR, that takes a single operand and has no effect other than "using" its operand, to ensure that its operand remains live until after the fake use. This patch does not emit fake uses anywhere; the next patch in this sequence causes them to be emitted from the clang frontend, such that for each variable (or this) a fake.use operand is inserted at the end of that variable's scope, using that variable's value. This patch covers everything post-frontend, which is largely just the basic plumbing for a new intrinsic/instruction, along with a few steps to preserve the fake uses through optimizations (such as moving them ahead of a tail call or translating them through SROA). Co-authored-by: Stephen Tozer <[email protected]>
1 parent e5e38dd commit 3d08ade

File tree

76 files changed

+1609
-38
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+1609
-38
lines changed

llvm/docs/LangRef.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29477,6 +29477,42 @@ execution, but is unknown at compile time.
2947729477
If the result value does not fit in the result type, then the result is
2947829478
a :ref:`poison value <poisonvalues>`.
2947929479

29480+
.. _llvm_fake_use:
29481+
29482+
'``llvm.fake.use``' Intrinsic
29483+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29484+
29485+
Syntax:
29486+
"""""""
29487+
29488+
::
29489+
29490+
declare void @llvm.fake.use(...)
29491+
29492+
Overview:
29493+
"""""""""
29494+
29495+
The ``llvm.fake.use`` intrinsic is a no-op. It takes a single
29496+
value as an operand and is treated as a use of that operand, to force the
29497+
optimizer to preserve that value prior to the fake use. This is used for
29498+
extending the lifetimes of variables, where this intrinsic placed at the end of
29499+
a variable's scope helps prevent that variable from being optimized out.
29500+
29501+
Arguments:
29502+
""""""""""
29503+
29504+
The ``llvm.fake.use`` intrinsic takes one argument, which may be any
29505+
function-local SSA value. Note that the signature is variadic so that the
29506+
intrinsic can take any type of argument, but passing more than one argument will
29507+
result in an error.
29508+
29509+
Semantics:
29510+
""""""""""
29511+
29512+
This intrinsic does nothing, but optimizers must consider it a use of its single
29513+
operand and should try to preserve the intrinsic and its position in the
29514+
function.
29515+
2948029516

2948129517
Stack Map Intrinsics
2948229518
--------------------

llvm/include/llvm/Analysis/PtrUseVisitor.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,12 @@ class PtrUseVisitor : protected InstVisitor<DerivedT>,
278278
default:
279279
return Base::visitIntrinsicInst(II);
280280

281+
// We escape pointers used by a fake_use to prevent SROA from transforming
282+
// them.
283+
case Intrinsic::fake_use:
284+
PI.setEscaped(&II);
285+
return;
286+
281287
case Intrinsic::lifetime_start:
282288
case Intrinsic::lifetime_end:
283289
return; // No-op intrinsics.

llvm/include/llvm/CodeGen/ISDOpcodes.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,11 @@ enum NodeType {
13721372
LIFETIME_START,
13731373
LIFETIME_END,
13741374

1375+
/// FAKE_USE represents a use of the operand but does not do anything.
1376+
/// Its purpose is the extension of the operand's lifetime mainly for
1377+
/// debugging purposes.
1378+
FAKE_USE,
1379+
13751380
/// GC_TRANSITION_START/GC_TRANSITION_END - These operators mark the
13761381
/// beginning and end of GC transition sequence, and carry arbitrary
13771382
/// information that target might need for lowering. The first operand is

llvm/include/llvm/CodeGen/MachineInstr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,6 +1435,8 @@ class MachineInstr
14351435
return getOpcode() == TargetOpcode::EXTRACT_SUBREG;
14361436
}
14371437

1438+
bool isFakeUse() const { return getOpcode() == TargetOpcode::FAKE_USE; }
1439+
14381440
/// Return true if the instruction behaves like a copy.
14391441
/// This does not include native copy instructions.
14401442
bool isCopyLike() const {

llvm/include/llvm/CodeGen/Passes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,9 @@ namespace llvm {
440440
// metadata after llvm SanitizerBinaryMetadata pass.
441441
extern char &MachineSanitizerBinaryMetadataID;
442442

443+
/// RemoveLoadsIntoFakeUses pass.
444+
extern char &RemoveLoadsIntoFakeUsesID;
445+
443446
/// RemoveRedundantDebugValues pass.
444447
extern char &RemoveRedundantDebugValuesID;
445448

llvm/include/llvm/CodeGen/SelectionDAGISel.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ class SelectionDAGISel {
463463
void Select_READ_REGISTER(SDNode *Op);
464464
void Select_WRITE_REGISTER(SDNode *Op);
465465
void Select_UNDEF(SDNode *N);
466+
void Select_FAKE_USE(SDNode *N);
466467
void CannotYetSelect(SDNode *N);
467468

468469
void Select_FREEZE(SDNode *N);

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,6 +1835,9 @@ def int_is_constant : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty],
18351835
[IntrNoMem, IntrWillReturn, IntrConvergent],
18361836
"llvm.is.constant">;
18371837

1838+
// Introduce a use of the argument without generating any code.
1839+
def int_fake_use : Intrinsic<[], [llvm_vararg_ty]>;
1840+
18381841
// Intrinsic to mask out bits of a pointer.
18391842
// First argument must be pointer or vector of pointer. This is checked by the
18401843
// verifier.

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ void initializeRegionOnlyViewerPass(PassRegistry &);
264264
void initializeRegionPrinterPass(PassRegistry &);
265265
void initializeRegionViewerPass(PassRegistry &);
266266
void initializeRegisterCoalescerPass(PassRegistry &);
267+
void initializeRemoveLoadsIntoFakeUsesPass(PassRegistry &);
267268
void initializeRemoveRedundantDebugValuesPass(PassRegistry &);
268269
void initializeRenameIndependentSubregsPass(PassRegistry &);
269270
void initializeReplaceWithVeclibLegacyPass(PassRegistry &);

llvm/include/llvm/Passes/MachinePassRegistry.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ DUMMY_MACHINE_FUNCTION_PASS("reg-usage-propagation", RegUsageInfoPropagationPass
250250
DUMMY_MACHINE_FUNCTION_PASS("regalloc", RegAllocPass)
251251
DUMMY_MACHINE_FUNCTION_PASS("regallocscoringpass", RegAllocScoringPass)
252252
DUMMY_MACHINE_FUNCTION_PASS("regbankselect", RegBankSelectPass)
253+
DUMMY_MACHINE_FUNCTION_PASS("remove-loads-into-fake-uses", RemoveLoadsIntoFakeUsesPass)
253254
DUMMY_MACHINE_FUNCTION_PASS("removeredundantdebugvalues", RemoveRedundantDebugValuesPass)
254255
DUMMY_MACHINE_FUNCTION_PASS("rename-independent-subregs", RenameIndependentSubregsPass)
255256
DUMMY_MACHINE_FUNCTION_PASS("reset-machine-function", ResetMachineFunctionPass)

llvm/include/llvm/Support/TargetOpcodes.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@ HANDLE_TARGET_OPCODE(PATCHABLE_TYPED_EVENT_CALL)
217217

218218
HANDLE_TARGET_OPCODE(ICALL_BRANCH_FUNNEL)
219219

220+
/// Represents a use of the operand but generates no code.
221+
HANDLE_TARGET_OPCODE(FAKE_USE)
222+
220223
// This is a fence with the singlethread scope. It represents a compiler memory
221224
// barrier, but does not correspond to any generated instruction.
222225
HANDLE_TARGET_OPCODE(MEMBARRIER)

0 commit comments

Comments
 (0)