mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 21:55:39 +08:00
Regenerate exception handling information after optimizations.
Summary: Regenerate exception handling information after optimizations. Use '-print-eh-ranges' to see CFG with updated ranges. (cherry picked from FBD2660982)
This commit is contained in:
@@ -100,14 +100,26 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation,
|
||||
uint64_t Offset{0};
|
||||
|
||||
auto printInstruction = [&](const MCInst &Instruction) {
|
||||
if (BC.MIA->isEHLabel(Instruction)) {
|
||||
OS << " EH_LABEL: "
|
||||
<< cast<MCSymbolRefExpr>(Instruction.getOperand(0).getExpr())->
|
||||
getSymbol()
|
||||
<< '\n';
|
||||
return;
|
||||
}
|
||||
OS << format(" %08" PRIx64 ": ", Offset);
|
||||
BC.InstPrinter->printInst(&Instruction, OS, "", *BC.STI);
|
||||
if (BC.MIA->isCall(Instruction)) {
|
||||
if (BC.MIA->isTailCall(Instruction))
|
||||
OS << " # TAILCALL ";
|
||||
if (Instruction.getNumOperands() > 1) {
|
||||
OS << " # handler: " << Instruction.getOperand(1);
|
||||
OS << "; action: " << Instruction.getOperand(2);
|
||||
OS << " # handler: ";
|
||||
if (Instruction.getOperand(1).isExpr())
|
||||
OS << cast<MCSymbolRefExpr>(Instruction.getOperand(1).getExpr())->
|
||||
getSymbol();
|
||||
else
|
||||
OS << '0';
|
||||
OS << "; action: " << Instruction.getOperand(2).getImm();
|
||||
}
|
||||
}
|
||||
OS << "\n";
|
||||
@@ -190,34 +202,46 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation,
|
||||
OS << '\n';
|
||||
}
|
||||
|
||||
if (FrameInstructions.empty()) {
|
||||
OS << "End of Function \"" << getName() << "\"\n";
|
||||
return;
|
||||
}
|
||||
|
||||
OS << "DWARF CFI Instructions:\n";
|
||||
for (auto &CFIInstr : FrameInstructions) {
|
||||
OS << format(" %08x: ", CFIInstr.first);
|
||||
switch(CFIInstr.second.getOperation()) {
|
||||
case MCCFIInstruction::OpSameValue: OS << "OpSameValue"; break;
|
||||
case MCCFIInstruction::OpRememberState: OS << "OpRememberState"; break;
|
||||
case MCCFIInstruction::OpRestoreState: OS << "OpRestoreState"; break;
|
||||
case MCCFIInstruction::OpOffset: OS << "OpOffset"; break;
|
||||
case MCCFIInstruction::OpDefCfaRegister: OS << "OpDefCfaRegister"; break;
|
||||
case MCCFIInstruction::OpDefCfaOffset: OS << "OpDefCfaOffset"; break;
|
||||
case MCCFIInstruction::OpDefCfa: OS << "OpDefCfa"; break;
|
||||
case MCCFIInstruction::OpRelOffset: OS << "OpRelOffset"; break;
|
||||
case MCCFIInstruction::OpAdjustCfaOffset: OS << "OfAdjustCfaOffset"; break;
|
||||
case MCCFIInstruction::OpEscape: OS << "OpEscape"; break;
|
||||
case MCCFIInstruction::OpRestore: OS << "OpRestore"; break;
|
||||
case MCCFIInstruction::OpUndefined: OS << "OpUndefined"; break;
|
||||
case MCCFIInstruction::OpRegister: OS << "OpRegister"; break;
|
||||
case MCCFIInstruction::OpWindowSave: OS << "OpWindowSave"; break;
|
||||
// Dump new exception ranges for the function.
|
||||
if (!CallSites.empty()) {
|
||||
OS << "EH table:\n";
|
||||
for (auto &CSI : CallSites) {
|
||||
OS << " [" << *CSI.Start << ", " << *CSI.End << ") landing pad : ";
|
||||
if (CSI.LP)
|
||||
OS << *CSI.LP;
|
||||
else
|
||||
OS << "0";
|
||||
OS << ", action : " << CSI.Action << '\n';
|
||||
}
|
||||
OS << "\n";
|
||||
OS << '\n';
|
||||
}
|
||||
|
||||
OS << "End of Function \"" << getName() << "\"\n";
|
||||
if (!FrameInstructions.empty()) {
|
||||
OS << "DWARF CFI Instructions:\n";
|
||||
for (auto &CFIInstr : FrameInstructions) {
|
||||
OS << format(" %08x: ", CFIInstr.first);
|
||||
switch(CFIInstr.second.getOperation()) {
|
||||
case MCCFIInstruction::OpSameValue: OS << "OpSameValue"; break;
|
||||
case MCCFIInstruction::OpRememberState: OS << "OpRememberState"; break;
|
||||
case MCCFIInstruction::OpRestoreState: OS << "OpRestoreState"; break;
|
||||
case MCCFIInstruction::OpOffset: OS << "OpOffset"; break;
|
||||
case MCCFIInstruction::OpDefCfaRegister: OS << "OpDefCfaRegister"; break;
|
||||
case MCCFIInstruction::OpDefCfaOffset: OS << "OpDefCfaOffset"; break;
|
||||
case MCCFIInstruction::OpDefCfa: OS << "OpDefCfa"; break;
|
||||
case MCCFIInstruction::OpRelOffset: OS << "OpRelOffset"; break;
|
||||
case MCCFIInstruction::OpAdjustCfaOffset:OS << "OfAdjustCfaOffset"; break;
|
||||
case MCCFIInstruction::OpEscape: OS << "OpEscape"; break;
|
||||
case MCCFIInstruction::OpRestore: OS << "OpRestore"; break;
|
||||
case MCCFIInstruction::OpUndefined: OS << "OpUndefined"; break;
|
||||
case MCCFIInstruction::OpRegister: OS << "OpRegister"; break;
|
||||
case MCCFIInstruction::OpWindowSave: OS << "OpWindowSave"; break;
|
||||
}
|
||||
OS << '\n';
|
||||
}
|
||||
OS << '\n';
|
||||
}
|
||||
|
||||
OS << "End of Function \"" << getName() << "\"\n\n";
|
||||
}
|
||||
|
||||
bool BinaryFunction::disassemble(ArrayRef<uint8_t> FunctionData) {
|
||||
|
||||
@@ -182,6 +182,15 @@ private:
|
||||
using CFIInstrMapType = std::multimap<uint32_t, MCCFIInstruction>;
|
||||
CFIInstrMapType FrameInstructions;
|
||||
|
||||
/// Exception handling ranges.
|
||||
struct CallSite {
|
||||
const MCSymbol *Start;
|
||||
const MCSymbol *End;
|
||||
const MCSymbol *LP;
|
||||
uint64_t Action;
|
||||
};
|
||||
std::vector<CallSite> CallSites;
|
||||
|
||||
// Blocks are kept sorted in the layout order. If we need to change the
|
||||
// layout (if BasicBlocksLayout stores a different order than BasicBlocks),
|
||||
// the terminating instructions need to be modified.
|
||||
@@ -469,6 +478,9 @@ public:
|
||||
/// Process LSDA information for the function.
|
||||
void parseLSDA(ArrayRef<uint8_t> LSDAData, uint64_t LSDAAddress);
|
||||
|
||||
/// Update exception handling ranges for the function.
|
||||
void updateEHRanges();
|
||||
|
||||
virtual ~BinaryFunction() {}
|
||||
};
|
||||
|
||||
|
||||
@@ -332,7 +332,7 @@ void BinaryFunction::parseLSDA(ArrayRef<uint8_t> LSDASectionData,
|
||||
if (Label != Labels.end()) {
|
||||
LPSymbol = Label->second;
|
||||
} else {
|
||||
LPSymbol = BC.Ctx->createTempSymbol("LP");
|
||||
LPSymbol = BC.Ctx->createTempSymbol("LP", true);
|
||||
Labels[LandingPad] = LPSymbol;
|
||||
}
|
||||
LandingPads.insert(LPSymbol);
|
||||
@@ -429,6 +429,108 @@ void BinaryFunction::parseLSDA(ArrayRef<uint8_t> LSDASectionData,
|
||||
errs() << '\n';
|
||||
}
|
||||
|
||||
void BinaryFunction::updateEHRanges() {
|
||||
assert(CurrentState == State::CFG && "unexpected state");
|
||||
|
||||
// Build call sites table.
|
||||
struct EHInfo {
|
||||
const MCSymbol *LP; // landing pad
|
||||
uint64_t Action;
|
||||
};
|
||||
|
||||
// Markers for begining and the end of exceptions range.
|
||||
const MCSymbol *StartRange{nullptr};
|
||||
const MCSymbol *EndRange{nullptr};
|
||||
|
||||
// If previous call can throw, this is its exception handler.
|
||||
EHInfo PreviousEH = {nullptr, 0};
|
||||
|
||||
for(auto &BB : BasicBlocksLayout) {
|
||||
for (auto II = BB->begin(); II != BB->end(); ++II) {
|
||||
auto Instr = *II;
|
||||
|
||||
if (!BC.MIA->isCall(Instr))
|
||||
continue;
|
||||
|
||||
// Instruction can throw an exception that should be handled.
|
||||
bool Throws = Instr.getNumOperands() > 1;
|
||||
|
||||
// Ignore the call if it's a continuation of a no-throw gap.
|
||||
if (!Throws && !StartRange)
|
||||
continue;
|
||||
|
||||
// Extract exception handling information from the instruction.
|
||||
const MCSymbol *LP =
|
||||
Throws ? (Instr.getOperand(1).isExpr()
|
||||
? &(cast<MCSymbolRefExpr>(
|
||||
Instr.getOperand(1).getExpr())->getSymbol())
|
||||
: nullptr)
|
||||
: nullptr;
|
||||
uint64_t Action = Throws ? Instr.getOperand(2).getImm() : 0;
|
||||
|
||||
// No action if the exception handler has not changed.
|
||||
if (Throws &&
|
||||
StartRange &&
|
||||
PreviousEH.LP == LP &&
|
||||
PreviousEH.Action == Action)
|
||||
continue;
|
||||
|
||||
// Same symbol is used for the beginning and the end of the range.
|
||||
const MCSymbol *EHSymbol = BC.Ctx->createTempSymbol("EH", true);
|
||||
MCInst EHLabel;
|
||||
BC.MIA->createEHLabel(EHLabel, EHSymbol, BC.Ctx.get());
|
||||
II = BB->Instructions.insert(II, EHLabel);
|
||||
++II;
|
||||
|
||||
// At this point we could be in the one of the following states:
|
||||
//
|
||||
// I. Exception handler has changed and we need to close the prev range
|
||||
// and start the new one.
|
||||
//
|
||||
// II. Start the new exception range after the gap.
|
||||
//
|
||||
// III. Close exception range and start the new gap.
|
||||
|
||||
if (StartRange) {
|
||||
// I, III:
|
||||
EndRange = EHSymbol;
|
||||
} else {
|
||||
// II:
|
||||
StartRange = EHSymbol;
|
||||
EndRange = nullptr;
|
||||
}
|
||||
|
||||
// Close the previous range.
|
||||
if (EndRange) {
|
||||
assert(StartRange && "beginning of the range expected");
|
||||
CallSites.emplace_back(CallSite{StartRange, EndRange,
|
||||
PreviousEH.LP, PreviousEH.Action});
|
||||
EndRange = nullptr;
|
||||
}
|
||||
|
||||
if (Throws) {
|
||||
// I, II:
|
||||
StartRange = EHSymbol;
|
||||
PreviousEH = EHInfo{LP, Action};
|
||||
} else {
|
||||
StartRange = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we need to close the range.
|
||||
if (StartRange) {
|
||||
assert(!EndRange && "unexpected end of range");
|
||||
EndRange = BC.Ctx->createTempSymbol("EH", true);
|
||||
MCInst EHLabel;
|
||||
BC.MIA->createEHLabel(EHLabel, EndRange, BC.Ctx.get());
|
||||
BasicBlocksLayout.back()->Instructions.emplace_back(EHLabel);
|
||||
|
||||
CallSites.emplace_back(CallSite{StartRange, EndRange,
|
||||
PreviousEH.LP, PreviousEH.Action});
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
|
||||
const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f;
|
||||
|
||||
|
||||
@@ -127,6 +127,11 @@ static cl::opt<bool>
|
||||
PrintDisasm("print-disasm", cl::desc("print function after disassembly"),
|
||||
cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
PrintEHRanges("print-eh-ranges",
|
||||
cl::desc("print function with updated exception ranges"),
|
||||
cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
PrintReordered("print-reordered",
|
||||
cl::desc("print functions after layout optimization"),
|
||||
@@ -544,7 +549,13 @@ static void OptimizeFile(ELFObjectFileBase *File, const DataReader &DR) {
|
||||
(SectionContents.data()) + FunctionOffset,
|
||||
Function.getSize());
|
||||
|
||||
if (!Function.disassemble(FunctionData) || !Function.isSimple())
|
||||
if (!Function.disassemble(FunctionData))
|
||||
continue;
|
||||
|
||||
if (opts::PrintAll || opts::PrintDisasm)
|
||||
Function.print(errs(), "after disassembly");
|
||||
|
||||
if (!Function.isSimple())
|
||||
continue;
|
||||
|
||||
// Fill in CFI information for this function
|
||||
@@ -552,12 +563,8 @@ static void OptimizeFile(ELFObjectFileBase *File, const DataReader &DR) {
|
||||
DwCFIReader.fillCFIInfoFor(Function);
|
||||
|
||||
// Parse LSDA.
|
||||
if (Function.getLSDAAddress() != 0) {
|
||||
if (Function.getLSDAAddress() != 0)
|
||||
Function.parseLSDA(LSDAData, LSDAAddress);
|
||||
}
|
||||
|
||||
if (opts::PrintAll || opts::PrintDisasm)
|
||||
Function.print(errs(), "after disassembly");
|
||||
|
||||
if (!Function.buildCFG())
|
||||
continue;
|
||||
@@ -586,6 +593,9 @@ static void OptimizeFile(ELFObjectFileBase *File, const DataReader &DR) {
|
||||
if (!opts::shouldProcess(Function.getName()))
|
||||
continue;
|
||||
|
||||
if (!Function.isSimple())
|
||||
continue;
|
||||
|
||||
// Detect and eliminate unreachable basic blocks. We could have those
|
||||
// filled with nops and they are used for alignment.
|
||||
//
|
||||
@@ -639,6 +649,12 @@ static void OptimizeFile(ELFObjectFileBase *File, const DataReader &DR) {
|
||||
if (opts::PrintAll || opts::PrintReordered)
|
||||
Function.print(errs(), "after reordering blocks");
|
||||
}
|
||||
|
||||
// Post-processing passes.
|
||||
Function.updateEHRanges();
|
||||
if (opts::PrintAll || opts::PrintEHRanges) {
|
||||
Function.print(errs(), "after updating EH ranges");
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code EC;
|
||||
@@ -719,6 +735,15 @@ static void OptimizeFile(ELFObjectFileBase *File, const DataReader &DR) {
|
||||
Streamer->EmitCodeAlignment(BB->getAlignment());
|
||||
Streamer->EmitLabel(BB->getLabel());
|
||||
for (const auto &Instr : *BB) {
|
||||
// Handle pseudo instructions.
|
||||
if (BC->MIA->isEHLabel(Instr)) {
|
||||
assert(Instr.getNumOperands() == 1 && Instr.getOperand(0).isExpr() &&
|
||||
"bad EH_LABEL instruction");
|
||||
auto Label = &(cast<MCSymbolRefExpr>(
|
||||
Instr.getOperand(0).getExpr())->getSymbol());
|
||||
Streamer->EmitLabel(const_cast<MCSymbol *>(Label));
|
||||
continue;
|
||||
}
|
||||
Streamer->EmitInstruction(Instr, *BC->STI);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user