diff options
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/include/llvm/CodeGen/StackMaps.h | 50 | ||||
| -rw-r--r-- | llvm/include/llvm/Target/Target.td | 9 | ||||
| -rw-r--r-- | llvm/include/llvm/Target/TargetFrameLowering.h | 10 | ||||
| -rw-r--r-- | llvm/include/llvm/Target/TargetOpcodes.h | 8 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/InlineSpiller.cpp | 3 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/LocalStackSlotAllocation.cpp | 1 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/PrologEpilogInserter.cpp | 20 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/StackMaps.cpp | 12 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/TargetLoweringBase.cpp | 8 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/X86FrameLowering.cpp | 73 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/X86FrameLowering.h | 4 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/X86ISelLowering.cpp | 5 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/X86MCInstLower.cpp | 64 | ||||
| -rw-r--r-- | llvm/utils/TableGen/CodeGenTarget.cpp | 1 | 
14 files changed, 263 insertions, 5 deletions
diff --git a/llvm/include/llvm/CodeGen/StackMaps.h b/llvm/include/llvm/CodeGen/StackMaps.h index e343980d2ab..4e48afe1400 100644 --- a/llvm/include/llvm/CodeGen/StackMaps.h +++ b/llvm/include/llvm/CodeGen/StackMaps.h @@ -81,6 +81,52 @@ public:    unsigned getNextScratchIdx(unsigned StartIdx = 0) const;  }; +/// MI-level Statepoint operands +/// +/// Statepoint operands take the form: +///   <num call arguments>, <call target>, [call arguments], +///   <StackMaps::ConstantOp>, <flags>, +///   <StackMaps::ConstantOp>, <num other args>, [other args], +///   [gc values] +class StatepointOpers { +private: +  enum { +    NCallArgsPos = 0, +    CallTargetPos = 1 +  }; + +public: +  explicit StatepointOpers(const MachineInstr *MI): +    MI(MI) { } + +  /// Get starting index of non call related arguments +  /// (statepoint flags, vm state and gc state). +  unsigned getVarIdx() const { +    return MI->getOperand(NCallArgsPos).getImm() + 2; +  } + +  /// Returns the index of the operand containing the number of non-gc non-call +  /// arguments.  +  unsigned getNumVMSArgsIdx() const { +    return getVarIdx() + 3; +  } + +  /// Returns the number of non-gc non-call arguments attached to the +  /// statepoint.  Note that this is the number of arguments, not the number of +  /// operands required to represent those arguments. +  unsigned getNumVMSArgs() const { +    return MI->getOperand(getNumVMSArgsIdx()).getImm(); +  } + +  /// Returns the target of the underlying call. +  const MachineOperand &getCallTarget() const { +    return MI->getOperand(CallTargetPos); +  } + +private: +  const MachineInstr *MI; +}; +  class StackMaps {  public:    struct Location { @@ -132,6 +178,9 @@ public:    /// \brief Generate a stackmap record for a patchpoint instruction.    void recordPatchPoint(const MachineInstr &MI); +  /// \brief Generate a stackmap record for a statepoint instruction. +  void recordStatepoint(const MachineInstr &MI); +    /// If there is any stack map data, create a stack map section and serialize    /// the map info into it. This clears the stack map data structures    /// afterwards. @@ -139,7 +188,6 @@ public:  private:    static const char *WSMP; -    typedef SmallVector<Location, 8> LocationVec;    typedef SmallVector<LiveOutReg, 8> LiveOutVec;    typedef MapVector<uint64_t, uint64_t> ConstantPool; diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td index d28ce692a3a..688c03fd7e2 100644 --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -845,6 +845,15 @@ def PATCHPOINT : Instruction {    let mayLoad = 1;    let usesCustomInserter = 1;  } +def STATEPOINT : Instruction { +  let OutOperandList = (outs); +  let InOperandList = (ins variable_ops); +  let usesCustomInserter = 1; +  let mayLoad = 1; +  let mayStore = 1; +  let hasSideEffects = 1; +  let isCall = 1; +}  def LOAD_STACK_GUARD : Instruction {    let OutOperandList = (outs ptr_rc:$dst);    let InOperandList = (ins); diff --git a/llvm/include/llvm/Target/TargetFrameLowering.h b/llvm/include/llvm/Target/TargetFrameLowering.h index bfddd060179..82c6093d8fb 100644 --- a/llvm/include/llvm/Target/TargetFrameLowering.h +++ b/llvm/include/llvm/Target/TargetFrameLowering.h @@ -199,6 +199,16 @@ public:    virtual int getFrameIndexReference(const MachineFunction &MF, int FI,                                       unsigned &FrameReg) const; +  /// Same as above, except that the 'base register' will always be RSP, not +  /// RBP on x86.  This is used exclusively for lowering STATEPOINT nodes. +  /// TODO: This should really be a parameterizable choice. +  virtual int getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, +                                          unsigned &FrameReg) const { +    // default to calling normal version, we override this on x86 only +    llvm_unreachable("unimplemented for non-x86"); +    return 0; +  } +    /// processFunctionBeforeCalleeSavedScan - This method is called immediately    /// before PrologEpilogInserter scans the physical registers used to determine    /// what callee saved registers should be spilled. This method is optional. diff --git a/llvm/include/llvm/Target/TargetOpcodes.h b/llvm/include/llvm/Target/TargetOpcodes.h index 1fbd2ae09b1..7ab1bc3837f 100644 --- a/llvm/include/llvm/Target/TargetOpcodes.h +++ b/llvm/include/llvm/Target/TargetOpcodes.h @@ -110,7 +110,13 @@ enum {    /// to prevent the stack guard value or address from being spilled to the    /// stack should override TargetLowering::emitLoadStackGuardNode and    /// additionally expand this pseudo after register allocation. -  LOAD_STACK_GUARD = 19 +  LOAD_STACK_GUARD = 19, + +  /// Call instruction with associated vm state for deoptimization and list +  /// of live pointers for relocation by the garbage collector.  It is +  /// intended to support garbage collection with fully precise relocating +  /// collectors and deoptimizations in either the callee or caller. +  STATEPOINT = 20  };  } // end namespace TargetOpcode  } // end namespace llvm diff --git a/llvm/lib/CodeGen/InlineSpiller.cpp b/llvm/lib/CodeGen/InlineSpiller.cpp index 6a6e15dabff..121a89e0da2 100644 --- a/llvm/lib/CodeGen/InlineSpiller.cpp +++ b/llvm/lib/CodeGen/InlineSpiller.cpp @@ -1088,7 +1088,8 @@ foldMemoryOperand(ArrayRef<std::pair<MachineInstr*, unsigned> > Ops,    bool WasCopy = MI->isCopy();    unsigned ImpReg = 0; -  bool SpillSubRegs = (MI->getOpcode() == TargetOpcode::PATCHPOINT || +  bool SpillSubRegs = (MI->getOpcode() == TargetOpcode::STATEPOINT || +                       MI->getOpcode() == TargetOpcode::PATCHPOINT ||                         MI->getOpcode() == TargetOpcode::STACKMAP);    // TargetInstrInfo::foldMemoryOperand only expects explicit, non-tied diff --git a/llvm/lib/CodeGen/LocalStackSlotAllocation.cpp b/llvm/lib/CodeGen/LocalStackSlotAllocation.cpp index 5c5712f37e1..e8bf687a626 100644 --- a/llvm/lib/CodeGen/LocalStackSlotAllocation.cpp +++ b/llvm/lib/CodeGen/LocalStackSlotAllocation.cpp @@ -291,6 +291,7 @@ bool LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) {        // Debug value, stackmap and patchpoint instructions can't be out of        // range, so they don't need any updates.        if (MI->isDebugValue() || +          MI->getOpcode() == TargetOpcode::STATEPOINT ||            MI->getOpcode() == TargetOpcode::STACKMAP ||            MI->getOpcode() == TargetOpcode::PATCHPOINT)          continue; diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp index 06530b91d67..a19bd96b3f5 100644 --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -797,6 +797,26 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &Fn,          continue;        } +      // TODO: This code should be commoned with the code for +      // PATCHPOINT. There's no good reason for the difference in +      // implementation other than historical accident.  The only +      // remaining difference is the unconditional use of the stack +      // pointer as the base register. +      if (MI->getOpcode() == TargetOpcode::STATEPOINT) { +        assert((!MI->isDebugValue() || i == 0) && +               "Frame indicies can only appear as the first operand of a " +               "DBG_VALUE machine instruction"); +        unsigned Reg; +        MachineOperand &Offset = MI->getOperand(i + 1); +        const unsigned refOffset = +          TFI->getFrameIndexReferenceFromSP(Fn, MI->getOperand(i).getIndex(), +                                            Reg); + +        Offset.setImm(Offset.getImm() + refOffset); +        MI->getOperand(i).ChangeToRegister(Reg, false /*isDef*/); +        continue; +      } +        // Some instructions (e.g. inline asm instructions) can have        // multiple frame indices and/or cause eliminateFrameIndex        // to insert more than one instruction. We need the register diff --git a/llvm/lib/CodeGen/StackMaps.cpp b/llvm/lib/CodeGen/StackMaps.cpp index d3791c3feb5..aab8d522144 100644 --- a/llvm/lib/CodeGen/StackMaps.cpp +++ b/llvm/lib/CodeGen/StackMaps.cpp @@ -286,6 +286,18 @@ void StackMaps::recordPatchPoint(const MachineInstr &MI) {    }  #endif  } +void StackMaps::recordStatepoint(const MachineInstr &MI) { +  assert(MI.getOpcode() == TargetOpcode::STATEPOINT && +         "expected statepoint"); + +  StatepointOpers opers(&MI); +  // Record all the deopt and gc operands (they're contiguous and run from the +  // initial index to the end of the operand list) +  const unsigned StartIdx = opers.getVarIdx(); +  recordStackMapOpers(MI, 0xABCDEF00, +                      MI.operands_begin() + StartIdx, MI.operands_end(), +                      false); +}  /// Emit the stackmap header.  /// diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp index bd5cd4c8cc2..8805104689e 100644 --- a/llvm/lib/CodeGen/TargetLoweringBase.cpp +++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp @@ -992,8 +992,14 @@ TargetLoweringBase::emitPatchPoint(MachineInstr *MI,      // Add a new memory operand for this FI.      const MachineFrameInfo &MFI = *MF.getFrameInfo();      assert(MFI.getObjectOffset(FI) != -1); + +    unsigned Flags = MachineMemOperand::MOLoad; +    if (MI->getOpcode() == TargetOpcode::STATEPOINT) { +      Flags |= MachineMemOperand::MOStore; +      Flags |= MachineMemOperand::MOVolatile; +    }      MachineMemOperand *MMO = MF.getMachineMemOperand( -        MachinePointerInfo::getFixedStack(FI), MachineMemOperand::MOLoad, +        MachinePointerInfo::getFixedStack(FI), Flags,          TM.getSubtargetImpl()->getDataLayout()->getPointerSize(),          MFI.getObjectAlignment(FI));      MIB->addMemOperand(MF, MMO); diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp index b9920b1b84c..278e4f910d4 100644 --- a/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -1135,6 +1135,79 @@ int X86FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,    return getFrameIndexOffset(MF, FI);  } +// Simplified from getFrameIndexOffset keeping only StackPointer cases +int X86FrameLowering::getFrameIndexOffsetFromSP(const MachineFunction &MF, int FI) const { +  const X86RegisterInfo *RegInfo = +    static_cast<const X86RegisterInfo*>(MF.getSubtarget().getRegisterInfo()); +  const MachineFrameInfo *MFI = MF.getFrameInfo(); +  const uint64_t StackSize = MFI->getStackSize(); //not including dynamic realign + +  { +#ifndef NDEBUG +    // Note: LLVM arranges the stack as: +    // Args > Saved RetPC (<--FP) > CSRs > dynamic alignment (<--BP) +    //      > "Stack Slots" (<--SP) +    // We can always address StackSlots from RSP.  We can usually (unless +    // needsStackRealignment) address CSRs from RSP, but sometimes need to +    // address them from RBP.  FixedObjects can be placed anywhere in the stack +    // frame depending on their specific requirements (i.e. we can actually +    // refer to arguments to the function which are stored in the *callers* +    // frame).  As a result, THE RESULT OF THIS CALL IS MEANINGLESS FOR CSRs +    // AND FixedObjects IFF needsStackRealignment or hasVarSizedObject. +         +    assert(!RegInfo->hasBasePointer(MF) && "we don't handle this case"); + +    // We don't handle tail calls, and shouldn't be seeing them +    // either. +    int TailCallReturnAddrDelta = +        MF.getInfo<X86MachineFunctionInfo>()->getTCReturnAddrDelta(); +    assert(!(TailCallReturnAddrDelta < 0) && "we don't handle this case!"); +#endif +  } + +  // This is how the math works out: +  // +  //  %rsp grows (i.e. gets lower) left to right. Each box below is +  //  one word (eight bytes).  Obj0 is the stack slot we're trying to +  //  get to. +  // +  //    ---------------------------------- +  //    | BP | Obj0 | Obj1 | ... | ObjN | +  //    ---------------------------------- +  //    ^    ^      ^                   ^ +  //    A    B      C                   E +  // +  // A is the incoming stack pointer. +  // (B - A) is the local area offset (-8 for x86-64) [1] +  // (C - A) is the Offset returned by MFI->getObjectOffset for Obj0 [2] +  // +  // |(E - B)| is the StackSize (absolute value, positive).  For a +  // stack that grown down, this works out to be (B - E). [3] +  // +  // E is also the value of %rsp after stack has been set up, and we +  // want (C - E) -- the value we can add to %rsp to get to Obj0.  Now +  // (C - E) == (C - A) - (B - A) + (B - E) +  //            { Using [1], [2] and [3] above } +  //         == getObjectOffset - LocalAreaOffset + StackSize +  // + +  // Get the Offset from the StackPointer +  int Offset = MFI->getObjectOffset(FI) - getOffsetOfLocalArea(); + +  return Offset + StackSize; +} +// Simplified from getFrameIndexReference keeping only StackPointer cases +int X86FrameLowering::getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, +                                                  unsigned &FrameReg) const { +  const X86RegisterInfo *RegInfo = +    static_cast<const X86RegisterInfo*>(MF.getSubtarget().getRegisterInfo()); + +  assert(!RegInfo->hasBasePointer(MF) && "we don't handle this case"); + +  FrameReg = RegInfo->getStackRegister(); +  return getFrameIndexOffsetFromSP(MF, FI); +} +  bool X86FrameLowering::assignCalleeSavedSpillSlots(      MachineFunction &MF, const TargetRegisterInfo *TRI,      std::vector<CalleeSavedInfo> &CSI) const { diff --git a/llvm/lib/Target/X86/X86FrameLowering.h b/llvm/lib/Target/X86/X86FrameLowering.h index 7740c3ad6f3..2ee71159c19 100644 --- a/llvm/lib/Target/X86/X86FrameLowering.h +++ b/llvm/lib/Target/X86/X86FrameLowering.h @@ -69,6 +69,10 @@ public:    int getFrameIndexReference(const MachineFunction &MF, int FI,                               unsigned &FrameReg) const override; +  int getFrameIndexOffsetFromSP(const MachineFunction &MF, int FI) const; +  int getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, +                                   unsigned &FrameReg) const override; +    void eliminateCallFramePseudoInstr(MachineFunction &MF,                                   MachineBasicBlock &MBB,                                   MachineBasicBlock::iterator MI) const override; diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index b67bbcb39c3..7faa58cf377 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -21346,6 +21346,11 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,    case X86::EH_SjLj_LongJmp64:      return emitEHSjLjLongJmp(MI, BB); +  case TargetOpcode::STATEPOINT: +    // As an implementation detail, STATEPOINT shares the STACKMAP format at +    // this point in the process.  We diverge later. +    return emitPatchPoint(MI, BB); +    case TargetOpcode::STACKMAP:    case TargetOpcode::PATCHPOINT:      return emitPatchPoint(MI, BB); diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp index 4e0d594238c..6a10916aa60 100644 --- a/llvm/lib/Target/X86/X86MCInstLower.cpp +++ b/llvm/lib/Target/X86/X86MCInstLower.cpp @@ -808,6 +808,66 @@ static void EmitNops(MCStreamer &OS, unsigned NumBytes, bool Is64Bit, const MCSu    } // while (NumBytes)  } +static void LowerSTATEPOINT(MCStreamer &OS, StackMaps &SM, +                            const MachineInstr &MI, bool Is64Bit, +                            const TargetMachine& TM, +                            const MCSubtargetInfo& STI, +                            X86MCInstLower &MCInstLowering) { +  assert(Is64Bit && "Statepoint currently only supports X86-64"); + +  // We need to record the frame size for stack walking +  const MachineFunction* MF = MI.getParent()->getParent(); +  assert(MF && "can't find machine function?"); + +  // +  // Emit call instruction +  // + +  // Lower call target and choose correct opcode +  const MachineOperand &call_target = StatepointOpers(&MI).getCallTarget(); +  MCOperand call_target_mcop; +  unsigned call_opcode; +  switch (call_target.getType()) { +  case MachineOperand::MO_GlobalAddress: +  case MachineOperand::MO_ExternalSymbol: +    call_target_mcop = MCInstLowering.LowerSymbolOperand( +      call_target, +      MCInstLowering.GetSymbolFromOperand(call_target)); +    call_opcode = X86::CALL64pcrel32; +    // Currently, we only support relative addressing with statepoints. +    // Otherwise, we'll need a scratch register to hold the target +    // address.  You'll fail asserts during load & relocation if this +    // symbol is to far away. (TODO: support non-relative addressing) +    break; +  case MachineOperand::MO_Immediate: +    call_target_mcop = MCOperand::CreateImm(call_target.getImm()); +    call_opcode = X86::CALL64pcrel32; +    // Currently, we only support relative addressing with statepoints. +    // Otherwise, we'll need a scratch register to hold the target +    // immediate.  You'll fail asserts during load & relocation if this +    // address is to far away. (TODO: support non-relative addressing) +    break; +  case MachineOperand::MO_Register: +    call_target_mcop = MCOperand::CreateReg(call_target.getReg()); +    call_opcode = X86::CALL64r; +    break; +  default: +    llvm_unreachable("Unsupported operand type in statepoint call target"); +    break; +  } + +  // Emit call +  MCInst call_inst; +  call_inst.setOpcode(call_opcode); +  call_inst.addOperand(call_target_mcop); +  OS.EmitInstruction(call_inst, STI); + +  // Record our statepoint node in the same section used by STACKMAP +  // and PATCHPOINT +  SM.recordStatepoint(MI);   +} + +  // Lower a stackmap of the form:  // <id>, <shadowBytes>, ...  void X86AsmPrinter::LowerSTACKMAP(const MachineInstr &MI) { @@ -1030,7 +1090,9 @@ void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) {        .addExpr(DotExpr));      return;    } - +  case TargetOpcode::STATEPOINT: +    return LowerSTATEPOINT(OutStreamer, SM, *MI, Subtarget->is64Bit(), TM, +      getSubtargetInfo(), MCInstLowering);    case TargetOpcode::STACKMAP:      return LowerSTACKMAP(*MI); diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp index 87777d46018..5b301d70edb 100644 --- a/llvm/utils/TableGen/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/CodeGenTarget.cpp @@ -300,6 +300,7 @@ void CodeGenTarget::ComputeInstrsByEnum() const {        "IMPLICIT_DEF", "SUBREG_TO_REG", "COPY_TO_REGCLASS", "DBG_VALUE",        "REG_SEQUENCE", "COPY",          "BUNDLE",           "LIFETIME_START",        "LIFETIME_END", "STACKMAP",      "PATCHPOINT",       "LOAD_STACK_GUARD", +      "STATEPOINT",        nullptr};    const DenseMap<const Record*, CodeGenInstruction*> &Insts = getInstructions();    for (const char *const *p = FixedInstrs; *p; ++p) {  | 

