Skip to content

Commit 79cbb8e

Browse files
committed
Emit label after calls to fix stackmap offsets.
During codegen stackmaps instructions emit a label when they are encountered. This label is then used to calculate the offset of its location from function entry. Unfortunately, this offset isn't always correct since codegen may insert instructions (e.g. for restoring caller-saved registers) in-between a call and the stackmap instruction. To fix this, we now insert a label immediately after codegenning a call. The following stackmap instruction can then pickup that label to compute the correct offset.
1 parent c861e95 commit 79cbb8e

File tree

5 files changed

+76
-8
lines changed

5 files changed

+76
-8
lines changed

llvm/include/llvm/CodeGen/AsmPrinter.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,12 @@ class AsmPrinter : public MachineFunctionPass {
329329
/// definition in the same module.
330330
MCSymbol *getSymbolPreferLocal(const GlobalValue &GV) const;
331331

332+
/// Maps call instructions to the label emitted just after the call. The label
333+
/// is later used to calculate the correct offset of the call instruction
334+
/// without interference from caller-saved registers which are sometimes
335+
/// emitted inbetween call and stackmap.
336+
MCSymbol *YkLastCallLabel = nullptr;
337+
332338
//===------------------------------------------------------------------===//
333339
// XRay instrumentation implementation.
334340
//===------------------------------------------------------------------===//

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ static cl::opt<bool>
135135

136136
extern bool YkAllocLLVMBBAddrMapSection;
137137
extern bool YkExtendedLLVMBBAddrMapSection;
138+
extern bool YkStackMapOffsetFix;
138139

139140
const char DWARFGroupName[] = "dwarf";
140141
const char DWARFGroupDescription[] = "DWARF Emission";
@@ -1699,6 +1700,9 @@ void AsmPrinter::emitFunctionBody() {
16991700
bool HasAnyRealCode = false;
17001701
int NumInstsInFunction = 0;
17011702

1703+
// Reset YkLastCallLabel so we don't use it across different functions.
1704+
YkLastCallLabel = nullptr;
1705+
17021706
bool CanDoExtraAnalysis = ORE->allowExtraAnalysis(DEBUG_TYPE);
17031707
for (auto &MBB : *MF) {
17041708
// Print a label for the basic block.
@@ -1800,6 +1804,31 @@ void AsmPrinter::emitFunctionBody() {
18001804
}
18011805

18021806
emitInstruction(&MI);
1807+
// Generate labels for function calls so we can record the correct
1808+
// instruction offset. The conditions for generating the label must be
1809+
// the same as the ones for generating the stackmap call in
1810+
// `Transforms/Yk/Stackmaps.cpp`, as otherwise we could end up with
1811+
// wrong offsets (e.g. we create a label here but the corresponding
1812+
// stackmap call was ommitted, and this label is then used for the
1813+
// following stackmap call).
1814+
1815+
// Convoluted way of finding our whether this function call is an
1816+
// intrinsic.
1817+
bool IsIntrinsic = false;
1818+
if (MI.getNumExplicitDefs() < MI.getNumOperands()) {
1819+
IsIntrinsic = MI.getOperand(MI.getNumExplicitDefs()).isIntrinsicID();
1820+
}
1821+
if (YkStackMapOffsetFix && MI.isCall() && !MI.isInlineAsm() &&
1822+
(MI.getOpcode() != TargetOpcode::STACKMAP) &&
1823+
(MI.getOpcode() != TargetOpcode::PATCHPOINT) && !IsIntrinsic) {
1824+
// YKFIXME: We don't need to emit labels (and stackmap calls) for
1825+
// functions that cannot guard fail, e.g. inlined functions, or
1826+
// functions we don't have IR for.
1827+
MCSymbol *MILabel =
1828+
OutStreamer->getContext().createTempSymbol("ykstackcall", true);
1829+
OutStreamer->emitLabel(MILabel);
1830+
YkLastCallLabel = MILabel;
1831+
}
18031832
if (CanDoExtraAnalysis) {
18041833
MCInst MCI;
18051834
MCI.setOpcode(MI.getOpcode());

llvm/lib/Support/Yk.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,10 @@ static cl::opt<bool, true> YkExtendedLLVMBBAddrMapSectionParser(
1818
"yk-extended-llvmbbaddrmap-section",
1919
cl::desc("Use the extended Yk `.llvmbbaddrmap` section format"),
2020
cl::NotHidden, cl::location(YkExtendedLLVMBBAddrMapSection));
21+
22+
bool YkStackMapOffsetFix;
23+
static cl::opt<bool, true> YkStackMapOffsetFixParser(
24+
"yk-stackmap-offset-fix",
25+
cl::desc("Apply a fix to stackmaps that corrects the reported instruction "
26+
"offset in the presence of calls."),
27+
cl::NotHidden, cl::location(YkStackMapOffsetFix));

llvm/lib/Target/X86/X86MCInstLower.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,10 +1422,25 @@ void X86AsmPrinter::LowerPATCHABLE_OP(const MachineInstr &MI,
14221422
void X86AsmPrinter::LowerSTACKMAP(const MachineInstr &MI) {
14231423
SMShadowTracker.emitShadowPadding(*OutStreamer, getSubtargetInfo());
14241424

1425-
auto &Ctx = OutStreamer->getContext();
1426-
MCSymbol *MILabel = Ctx.createTempSymbol();
1427-
OutStreamer->emitLabel(MILabel);
1428-
1425+
// When the stackmap is attached to a function call, caller-saved register
1426+
// loads may be emitted in-between call and stackmap call, thus skewing the
1427+
// reported offset.
1428+
// This makes it impossible to reliably continue at the correct location after
1429+
// deoptimisation has occured. In order to fix this, we insert labels after
1430+
// every call that could lead to a guard failure, and store the last such
1431+
// label inside `YkLastCallLabel`. If `YkLastCallLabel` is set (i.e. the
1432+
// stackmap was inserted after a call) use it to calculate the stackmap
1433+
// offset, otherwise (i.e. the stackmap was inserted before a branch) generate
1434+
// a new label as per ususual.
1435+
MCSymbol *MILabel;
1436+
if (YkLastCallLabel != nullptr) {
1437+
MILabel = YkLastCallLabel;
1438+
YkLastCallLabel = nullptr;
1439+
} else {
1440+
auto &Ctx = OutStreamer->getContext();
1441+
MILabel = Ctx.createTempSymbol();
1442+
OutStreamer->emitLabel(MILabel);
1443+
}
14291444
SM.recordStackMap(*MILabel, MI);
14301445
unsigned NumShadowBytes = MI.getOperand(1).getImm();
14311446
SMShadowTracker.reset(NumShadowBytes);

llvm/lib/Transforms/Yk/StackMaps.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,22 @@ class YkStackmaps : public ModulePass {
5151
continue;
5252
LivenessAnalysis LA(&F);
5353
for (BasicBlock &BB : F)
54-
for (Instruction &I : BB)
55-
if ((isa<CallInst>(I)) ||
56-
((isa<BranchInst>(I)) && (cast<BranchInst>(I).isConditional())) ||
57-
isa<SwitchInst>(I))
54+
for (Instruction &I : BB) {
55+
if (isa<CallInst>(I)) {
56+
CallInst &CI = cast<CallInst>(I);
57+
if (CI.isInlineAsm())
58+
continue;
59+
if (CI.isIndirectCall())
60+
continue;
61+
if (CI.getCalledFunction()->isIntrinsic())
62+
continue;
5863
SMCalls.insert({&I, LA.getLiveVarsBefore(&I)});
64+
} else if ((isa<BranchInst>(I) &&
65+
cast<BranchInst>(I).isConditional()) ||
66+
isa<SwitchInst>(I)) {
67+
SMCalls.insert({&I, LA.getLiveVarsBefore(&I)});
68+
}
69+
}
5970
}
6071

6172
Function *SMFunc = Intrinsic::getDeclaration(&M, SMFuncID);

0 commit comments

Comments
 (0)