diff options
Diffstat (limited to 'llvm/lib/Target')
| -rw-r--r-- | llvm/lib/Target/ARM/ARMAsmPrinter.cpp | 55 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/ARMAsmPrinter.h | 6 |
2 files changed, 50 insertions, 11 deletions
diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp index 49a33774467..99e65037260 100644 --- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp @@ -120,6 +120,23 @@ bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) { // Emit the rest of the function body. EmitFunctionBody(); + // If we need V4T thumb mode Register Indirect Jump pads, emit them. + // These are created per function, rather than per TU, since it's + // relatively easy to exceed the thumb branch range within a TU. + if (! ThumbIndirectPads.empty()) { + OutStreamer.EmitAssemblerFlag(MCAF_Code16); + EmitAlignment(1); + for (unsigned i = 0, e = ThumbIndirectPads.size(); i < e; i++) { + OutStreamer.EmitLabel(ThumbIndirectPads[i].second); + EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tBX) + .addReg(ThumbIndirectPads[i].first) + // Add predicate operands. + .addImm(ARMCC::AL) + .addReg(0)); + } + ThumbIndirectPads.clear(); + } + // We didn't modify anything. return false; } @@ -1282,18 +1299,34 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) { return; } case ARM::tBX_CALL: { - EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tMOVr) - .addReg(ARM::LR) - .addReg(ARM::PC) - // Add predicate operands. - .addImm(ARMCC::AL) - .addReg(0)); + if (Subtarget->hasV5TOps()) + llvm_unreachable("Expected BLX to be selected for v5t+"); + + // On ARM v4t, when doing a call from thumb mode, we need to ensure + // that the saved lr has its LSB set correctly (the arch doesn't + // have blx). + // So here we generate a bl to a small jump pad that does bx rN. + // The jump pads are emitted after the function body. + + unsigned TReg = MI->getOperand(0).getReg(); + MCSymbol *TRegSym = nullptr; + for (unsigned i = 0, e = ThumbIndirectPads.size(); i < e; i++) { + if (ThumbIndirectPads[i].first == TReg) { + TRegSym = ThumbIndirectPads[i].second; + break; + } + } - EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tBX) - .addReg(MI->getOperand(0).getReg()) - // Add predicate operands. - .addImm(ARMCC::AL) - .addReg(0)); + if (!TRegSym) { + TRegSym = OutContext.CreateTempSymbol(); + ThumbIndirectPads.push_back(std::make_pair(TReg, TRegSym)); + } + + // Create a link-saving branch to the Reg Indirect Jump Pad. + EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tBL) + // Predicate comes first here. + .addImm(ARMCC::AL).addReg(0) + .addExpr(MCSymbolRefExpr::Create(TRegSym, OutContext))); return; } case ARM::BMOVPCRX_CALL: { diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.h b/llvm/lib/Target/ARM/ARMAsmPrinter.h index 5ff20ce777c..a6214911a78 100644 --- a/llvm/lib/Target/ARM/ARMAsmPrinter.h +++ b/llvm/lib/Target/ARM/ARMAsmPrinter.h @@ -20,6 +20,7 @@ class ARMFunctionInfo; class MCOperand; class MachineConstantPool; class MachineOperand; +class MCSymbol; namespace ARM { enum DW_ISA { @@ -45,6 +46,11 @@ class LLVM_LIBRARY_VISIBILITY ARMAsmPrinter : public AsmPrinter { /// InConstantPool - Maintain state when emitting a sequence of constant /// pool entries so we can properly mark them as data regions. bool InConstantPool; + + /// ThumbIndirectPads - These maintain a per-function list of jump pad + /// labels used for ARMv4t thumb code to make register indirect calls. + SmallVector<std::pair<unsigned, MCSymbol*>, 4> ThumbIndirectPads; + public: explicit ARMAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) : AsmPrinter(TM, Streamer), AFI(nullptr), MCP(nullptr), |

