mirror of
https://github.com/intel/llvm.git
synced 2026-01-17 06:40:01 +08:00
Special handling for GNU_args_size call frame instruction.
Summary: GNU_args_size is a special kind of CFI that tells runtime to adjust %rsp when control is passed to a landing pad. It is used for annotating call instructions that pass (extra) parameters on the stack and there's a corresponding landing pad. It is also special in a way that its value is not handled by DW_CFA_remember_state/DW_CFA_restore_state instruction sequence that we utilize to restore the state after block re-ordering. This diff adds association of call instructions with GNU_args_size value when it's used. If the function does not use GNU_args_size, there is no overhead. Otherwise, we regenerate GNU_args_size instruction during code emission, i.e. after all optimizations and block-reordering. (cherry picked from FBD3201322)
This commit is contained in:
@@ -213,6 +213,9 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation,
|
||||
else
|
||||
OS << '0';
|
||||
OS << "; action: " << Action;
|
||||
auto GnuArgsSize = BC.MIA->getGnuArgsSize(Instruction);
|
||||
if (GnuArgsSize >= 0)
|
||||
OS << "; GNU_args_size = " << GnuArgsSize;
|
||||
}
|
||||
}
|
||||
if (opts::PrintDebugInfo && LineTable) {
|
||||
@@ -825,6 +828,9 @@ bool BinaryFunction::buildCFG() {
|
||||
// Update the state.
|
||||
CurrentState = State::CFG;
|
||||
|
||||
// Annotate invoke instructions with GNU_args_size data.
|
||||
propagateGnuArgsSizeInfo();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -939,15 +945,13 @@ void BinaryFunction::annotateCFIState() {
|
||||
++HighestState;
|
||||
if (CFI->getOperation() == MCCFIInstruction::OpRememberState) {
|
||||
StateStack.push(State);
|
||||
continue;
|
||||
}
|
||||
if (CFI->getOperation() == MCCFIInstruction::OpRestoreState) {
|
||||
} else if (CFI->getOperation() == MCCFIInstruction::OpRestoreState) {
|
||||
assert(!StateStack.empty() && "Corrupt CFI stack");
|
||||
State = StateStack.top();
|
||||
StateStack.pop();
|
||||
continue;
|
||||
} else if (CFI->getOperation() != MCCFIInstruction::OpGnuArgsSize) {
|
||||
State = HighestState;
|
||||
}
|
||||
State = HighestState;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -995,8 +999,12 @@ bool BinaryFunction::fixCFIState() {
|
||||
}
|
||||
|
||||
for (auto CFI : NewCFIs) {
|
||||
InsertIt = addCFIPseudo(InBB, InsertIt, CFI);
|
||||
++InsertIt;
|
||||
// Ignore GNU_args_size instructions.
|
||||
if (FrameInstructions[CFI].getOperation() !=
|
||||
MCCFIInstruction::OpGnuArgsSize) {
|
||||
InsertIt = addCFIPseudo(InBB, InsertIt, CFI);
|
||||
++InsertIt;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1658,5 +1666,45 @@ void BinaryFunction::splitFunction() {
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryFunction::propagateGnuArgsSizeInfo() {
|
||||
assert(CurrentState == State::CFG && "unexpected function state");
|
||||
|
||||
if (!hasEHRanges() || !usesGnuArgsSize())
|
||||
return;
|
||||
|
||||
// The current value of DW_CFA_GNU_args_size affects all following
|
||||
// invoke instructions untill the next CFI overrides it.
|
||||
// It is important to iterate basic blocks in the original order when
|
||||
// assigning the value.
|
||||
uint64_t CurrentGnuArgsSize = 0;
|
||||
for (auto &BB : BasicBlocks) {
|
||||
for (auto II = BB.begin(); II != BB.end(); ) {
|
||||
auto &Instr = *II;
|
||||
if (BC.MIA->isCFI(Instr)) {
|
||||
auto CFI = getCFIFor(Instr);
|
||||
if (CFI->getOperation() == MCCFIInstruction::OpGnuArgsSize) {
|
||||
CurrentGnuArgsSize = CFI->getOffset();
|
||||
// Delete DW_CFA_GNU_args_size instructions and only regenerate
|
||||
// during the final code emission. The information is embedded
|
||||
// inside call instructions.
|
||||
II = BB.Instructions.erase(II);
|
||||
} else {
|
||||
++II;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (BC.MIA->isInvoke(Instr)) {
|
||||
// Add the value of GNU_args_size as an extra operand if landing pad
|
||||
// is non-emptry.
|
||||
if (BC.MIA->getEHInfo(Instr).first) {
|
||||
Instr.addOperand(MCOperand::createImm(CurrentGnuArgsSize));
|
||||
}
|
||||
}
|
||||
++II;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace bolt
|
||||
} // namespace llvm
|
||||
|
||||
Reference in New Issue
Block a user