diff options
-rw-r--r-- | lib/Target/ARM/MCTargetDesc/ARMMCNaCl.cpp | 147 |
1 files changed, 73 insertions, 74 deletions
diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCNaCl.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCNaCl.cpp index 98ee80c358..af2b04086a 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMMCNaCl.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMMCNaCl.cpp @@ -66,9 +66,9 @@ static void EmitTST(MCStreamer &Out, unsigned Reg) { // it must ensure that the two instructions are in the same bundle. // It just so happens that the SFI_NOP_IF_AT_BUNDLE_END is always // emitted in conjunction with a SFI_DATA_MASK -// +// static void EmitDataMask(int I, MCInst Saved[], MCStreamer &Out) { - assert(I == 3 && + assert(I == 3 && (ARM::SFI_NOP_IF_AT_BUNDLE_END == Saved[0].getOpcode()) && (ARM::SFI_DATA_MASK == Saved[2].getOpcode()) && "Unexpected SFI Pseudo while lowering"); @@ -190,6 +190,7 @@ static void EmitGuardSpLoad(int I, MCInst Saved[], MCStreamer &Out) { } namespace llvm { + // CustomExpandInstNaClARM - // If Inst is a NaCl pseudo instruction, emits the substitute // expansion to the MCStreamer and returns true. @@ -200,101 +201,99 @@ namespace llvm { // Care must be taken to ensure that this does not result in an infinite // loop. Also, global state must be managed carefully so that it is // consistent during recursive calls. -// -// We need global state to keep track of the explicit prefix (PREFIX_*) -// instructions. Unfortunately, the assembly parser prefers to generate -// these instead of combined instructions. At this time, having only -// one explicit prefix is supported. - - bool CustomExpandInstNaClARM(const MCInst &Inst, MCStreamer &Out) { + // Logic: + // This is somewhat convoluted, but in the current model, the SFI + // guard pseudo instructions occur PRIOR to the actual instruction. + // So, the bundling/alignment operation has to refer to the FOLLOWING + // instructions. + // + // When a SFI pseudo is detected, it is saved. Then, the saved SFI + // pseudo and the very next instructions (their amount depending on the kind + // of the SFI pseudo) are used as arguments to the Emit*() functions in + // this file. + // + // Some static data is used to preserve state accross calls (TODO: can this + // be lifted into a proper state object?) + // + // Saved: the saved instructions (starting with the SFI_ pseudo). + // SavedCount: the amount of saved instructions required for the SFI pseudo + // that's being expanded. + // I: the index of the currently saved instruction - used to track + // where in Saved to insert the instruction and how many more + // remain. + // const int MaxSaved = 4; static MCInst Saved[MaxSaved]; static int SaveCount = 0; static int I = 0; - // This routine only executes if RecurseGuard == 0 - static bool RecurseGuard = false; // If we are emitting to .s, just emit all pseudo-instructions directly. if (Out.hasRawTextSupport()) { return false; } - //No recursive calls allowed; - if (RecurseGuard) return false; - - unsigned Opc = Inst.getOpcode(); + // Protect against recursive execution. If RecurseGuard == true, it means + // we're already in the process of expanding a custom instruction, and we + // don't need to run recursively on anything generated by such an expansion. + static bool RecurseGuard = false; + if (RecurseGuard) + return false; DEBUG(dbgs() << "CustomExpandInstNaClARM("; Inst.dump(); dbgs() << ")\n"); - // Note: SFI_NOP_IF_AT_BUNDLE_END is only emitted directly as part of - // a stack guard in conjunction with a SFI_DATA_MASK - - // Logic: - // This is somewhat convoluted, but in the current model, the SFI - // guard pseudo instructions occur PRIOR to the actual instruction. - // So, the bundling/alignment operation has to refer to the FOLLOWING - // one or two instructions. - // - // When a SFI_* pseudo is detected, it is saved. Then, the saved SFI_* - // pseudo and the very next one or two instructions are used as arguments to - // the Emit*() functions in this file. This is the reason why we have a - // doublely nested switch here. First, to save the SFI_* pseudo, then to - // emit it and the next instruction - - // By default, we only need to save two or three instructions - if ((I == 0) && (SaveCount == 0)) { - // Base State, no saved instructions. - // If the current instruction is a SFI instruction, set the SaveCount - // and fall through. - switch (Opc) { - default: - SaveCount = 0; // Nothing to do. - return false; // Handle this Inst elsewhere. - case ARM::SFI_NOP_IF_AT_BUNDLE_END: - SaveCount = 3; - break; - case ARM::SFI_DATA_MASK: - SaveCount = 0; // Do nothing. - break; - case ARM::SFI_GUARD_CALL: - case ARM::SFI_GUARD_INDIRECT_CALL: - case ARM::SFI_GUARD_INDIRECT_JMP: - case ARM::SFI_GUARD_RETURN: - case ARM::SFI_GUARD_LOADSTORE: - case ARM::SFI_GUARD_LOADSTORE_TST: - SaveCount = 2; - break; - case ARM::SFI_GUARD_SP_LOAD: - SaveCount = 4; - break; + // Base state: no SFI guard identified yet and no saving started. + switch (Inst.getOpcode()) { + default: + // We don't handle non-SFI guards here + return false; + case ARM::SFI_NOP_IF_AT_BUNDLE_END: + // Note: SFI_NOP_IF_AT_BUNDLE_END is only emitted directly as part of + // a stack guard in conjunction with a SFI_DATA_MASK. + SaveCount = 3; + break; + case ARM::SFI_DATA_MASK: + assert(0 && + "SFI_DATA_MASK found without preceding SFI_NOP_IF_AT_BUNDLE_END"); + return false; + case ARM::SFI_GUARD_CALL: + case ARM::SFI_GUARD_INDIRECT_CALL: + case ARM::SFI_GUARD_INDIRECT_JMP: + case ARM::SFI_GUARD_RETURN: + case ARM::SFI_GUARD_LOADSTORE: + case ARM::SFI_GUARD_LOADSTORE_TST: + SaveCount = 2; + break; + case ARM::SFI_GUARD_SP_LOAD: + SaveCount = 4; + break; } } + // We're in "saving instructions" state if (I < SaveCount) { - // Othewise, save the current Inst and return + // This instruction has to be saved + assert(I < MaxSaved && "Trying to save too many instructions"); Saved[I++] = Inst; if (I < SaveCount) return true; - // Else fall through to next stat } - if (SaveCount > 0) { - assert(I == SaveCount && "Bookeeping Error"); - SaveCount = 0; // Reset for next iteration - // The following calls may call Out.EmitInstruction() - // which must not again call CustomExpandInst ... - // So set RecurseGuard = 1; - RecurseGuard = true; + // We're in "saved enough instructions, time to emit" state + assert(I == SaveCount && SaveCount > 0 && "Bookeeping Error"); - switch (Saved[0].getOpcode()) { - default: /* No action required */ break; + // When calling Emit* functions, do that with RecurseGuard set (the comment + // at the beginning of this function explains why) + RecurseGuard = true; + switch (Saved[0].getOpcode()) { + default: + break; case ARM::SFI_NOP_IF_AT_BUNDLE_END: EmitDataMask(I, Saved, Out); break; case ARM::SFI_DATA_MASK: - assert(0 && "Unexpected NOP_IF_AT_BUNDLE_END as a Saved Inst"); + assert(0 && "SFI_DATA_MASK can't start a SFI sequence"); break; case ARM::SFI_GUARD_CALL: EmitDirectGuardCall(I, Saved, Out); @@ -317,14 +316,14 @@ bool CustomExpandInstNaClARM(const MCInst &Inst, MCStreamer &Out) { case ARM::SFI_GUARD_SP_LOAD: EmitGuardSpLoad(I, Saved, Out); break; - } - I = 0; // Reset I for next. - assert(RecurseGuard && "Illegal Depth"); - RecurseGuard = false; - return true; } + assert(RecurseGuard && "Illegal Depth"); + RecurseGuard = false; - return false; + // We're done expanding a SFI guard. Reset state vars. + SaveCount = 0; + I = 0; + return true; } } // namespace llvm |