Commit f3b5cd16 authored by Hans Wennborg's avatar Hans Wennborg
Browse files

Merging r294348:

------------------------------------------------------------------------
r294348 | hans | 2017-02-07 12:37:45 -0800 (Tue, 07 Feb 2017) | 6 lines

[X86] Disable conditional tail calls (PR31257)

They are currently modelled incorrectly (as calls, which clobber
registers, confusing e.g. Machine Copy Propagation).

Reverting until we figure out the proper solution.
------------------------------------------------------------------------

llvm-svn: 294476
parent fc2173cc
Loading
Loading
Loading
Loading
+0 −19
Original line number Diff line number Diff line
@@ -1108,25 +1108,6 @@ public:
  /// terminator instruction that has not been predicated.
  virtual bool isUnpredicatedTerminator(const MachineInstr &MI) const;

  /// Returns true if MI is an unconditional tail call.
  virtual bool isUnconditionalTailCall(const MachineInstr &MI) const {
    return false;
  }

  /// Returns true if the tail call can be made conditional on BranchCond.
  virtual bool
  canMakeTailCallConditional(SmallVectorImpl<MachineOperand> &Cond,
                             const MachineInstr &TailCall) const {
    return false;
  }

  /// Replace the conditional branch in MBB with a conditional tail call.
  virtual void replaceBranchWithTailCall(MachineBasicBlock &MBB,
                                         SmallVectorImpl<MachineOperand> &Cond,
                                         const MachineInstr &TailCall) const {
    llvm_unreachable("Target didn't implement replaceBranchWithTailCall!");
  }

  /// Convert the instruction into a predicated instruction.
  /// It returns true if the operation was successful.
  virtual bool PredicateInstruction(MachineInstr &MI,
+0 −37
Original line number Diff line number Diff line
@@ -49,7 +49,6 @@ STATISTIC(NumDeadBlocks, "Number of dead blocks removed");
STATISTIC(NumBranchOpts, "Number of branches optimized");
STATISTIC(NumTailMerge , "Number of block tails merged");
STATISTIC(NumHoist     , "Number of times common instructions are hoisted");
STATISTIC(NumTailCalls,  "Number of tail calls optimized");

static cl::opt<cl::boolOrDefault> FlagEnableTailMerge("enable-tail-merge",
                              cl::init(cl::BOU_UNSET), cl::Hidden);
@@ -1387,42 +1386,6 @@ ReoptimizeBlock:
    }
  }

  if (!IsEmptyBlock(MBB) && MBB->pred_size() == 1 &&
      MF.getFunction()->optForSize()) {
    // Changing "Jcc foo; foo: jmp bar;" into "Jcc bar;" might change the branch
    // direction, thereby defeating careful block placement and regressing
    // performance. Therefore, only consider this for optsize functions.
    MachineInstr &TailCall = *MBB->getFirstNonDebugInstr();
    if (TII->isUnconditionalTailCall(TailCall)) {
      MachineBasicBlock *Pred = *MBB->pred_begin();
      MachineBasicBlock *PredTBB = nullptr, *PredFBB = nullptr;
      SmallVector<MachineOperand, 4> PredCond;
      bool PredAnalyzable =
          !TII->analyzeBranch(*Pred, PredTBB, PredFBB, PredCond, true);

      if (PredAnalyzable && !PredCond.empty() && PredTBB == MBB) {
        // The predecessor has a conditional branch to this block which consists
        // of only a tail call. Try to fold the tail call into the conditional
        // branch.
        if (TII->canMakeTailCallConditional(PredCond, TailCall)) {
          // TODO: It would be nice if analyzeBranch() could provide a pointer
          // to the branch insturction so replaceBranchWithTailCall() doesn't
          // have to search for it.
          TII->replaceBranchWithTailCall(*Pred, PredCond, TailCall);
          ++NumTailCalls;
          Pred->removeSuccessor(MBB);
          MadeChange = true;
          return MadeChange;
        }
      }
      // If the predecessor is falling through to this block, we could reverse
      // the branch condition and fold the tail call into that. However, after
      // that we might have to re-arrange the CFG to fall through to the other
      // block and there is a high risk of regressing code size rather than
      // improving it.
    }
  }

  // Analyze the branch in the current block.
  MachineBasicBlock *CurTBB = nullptr, *CurFBB = nullptr;
  SmallVector<MachineOperand, 4> CurCond;
+1 −20
Original line number Diff line number Diff line
@@ -77,11 +77,9 @@ bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
  default:
    return false;
  case X86::TCRETURNdi:
  case X86::TCRETURNdicc:
  case X86::TCRETURNri:
  case X86::TCRETURNmi:
  case X86::TCRETURNdi64:
  case X86::TCRETURNdi64cc:
  case X86::TCRETURNri64:
  case X86::TCRETURNmi64: {
    bool isMem = Opcode == X86::TCRETURNmi || Opcode == X86::TCRETURNmi64;
@@ -99,10 +97,6 @@ bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
    Offset = StackAdj - MaxTCDelta;
    assert(Offset >= 0 && "Offset should never be negative");

    if (Opcode == X86::TCRETURNdicc || Opcode == X86::TCRETURNdi64cc) {
      assert(Offset == 0 && "Conditional tail call cannot adjust the stack.");
    }

    if (Offset) {
      // Check for possible merge with preceding ADD instruction.
      Offset += X86FL->mergeSPUpdates(MBB, MBBI, true);
@@ -111,21 +105,12 @@ bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB,

    // Jump to label or value in register.
    bool IsWin64 = STI->isTargetWin64();
    if (Opcode == X86::TCRETURNdi || Opcode == X86::TCRETURNdicc ||
        Opcode == X86::TCRETURNdi64 || Opcode == X86::TCRETURNdi64cc) {
    if (Opcode == X86::TCRETURNdi || Opcode == X86::TCRETURNdi64) {
      unsigned Op;
      switch (Opcode) {
      case X86::TCRETURNdi:
        Op = X86::TAILJMPd;
        break;
      case X86::TCRETURNdicc:
        Op = X86::TAILJMPd_CC;
        break;
      case X86::TCRETURNdi64cc:
        assert(!IsWin64 && "Conditional tail calls confuse the Win64 unwinder.");
        // TODO: We could do it for Win64 "leaf" functions though; PR30337.
        Op = X86::TAILJMPd64_CC;
        break;
      default:
        // Note: Win64 uses REX prefixes indirect jumps out of functions, but
        // not direct ones.
@@ -141,10 +126,6 @@ bool X86ExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
        MIB.addExternalSymbol(JumpTarget.getSymbolName(),
                              JumpTarget.getTargetFlags());
      }
      if (Op == X86::TAILJMPd_CC || Op == X86::TAILJMPd64_CC) {
        MIB.addImm(MBBI->getOperand(2).getImm());
      }

    } else if (Opcode == X86::TCRETURNmi || Opcode == X86::TCRETURNmi64) {
      unsigned Op = (Opcode == X86::TCRETURNmi)
                        ? X86::TAILJMPm
+0 −31
Original line number Diff line number Diff line
@@ -264,21 +264,6 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
                   "jmp{l}\t{*}$dst", [], IIC_JMP_MEM>;
}

// Conditional tail calls are similar to the above, but they are branches
// rather than barriers, and they use EFLAGS.
let isCall = 1, isTerminator = 1, isReturn = 1, isBranch = 1,
    isCodeGenOnly = 1, SchedRW = [WriteJumpLd] in
  let Uses = [ESP, EFLAGS] in {
  def TCRETURNdicc : PseudoI<(outs),
                     (ins i32imm_pcrel:$dst, i32imm:$offset, i32imm:$cond), []>;

  // This gets substituted to a conditional jump instruction in MC lowering.
  def TAILJMPd_CC : Ii32PCRel<0x80, RawFrm, (outs),
                           (ins i32imm_pcrel:$dst, i32imm:$cond),
                           "",
                           [], IIC_JMP_REL>;
}


//===----------------------------------------------------------------------===//
//  Call Instructions...
@@ -340,19 +325,3 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
                           "rex64 jmp{q}\t{*}$dst", [], IIC_JMP_MEM>;
  }
}

// Conditional tail calls are similar to the above, but they are branches
// rather than barriers, and they use EFLAGS.
let isCall = 1, isTerminator = 1, isReturn = 1, isBranch = 1,
    isCodeGenOnly = 1, SchedRW = [WriteJumpLd] in
  let Uses = [RSP, EFLAGS] in {
  def TCRETURNdi64cc : PseudoI<(outs),
                           (ins i64i32imm_pcrel:$dst, i32imm:$offset,
                            i32imm:$cond), []>;

  // This gets substituted to a conditional jump instruction in MC lowering.
  def TAILJMPd64_CC : Ii32PCRel<0x80, RawFrm, (outs),
                           (ins i64i32imm_pcrel:$dst, i32imm:$cond),
                           "",
                           [], IIC_JMP_REL>;
}
+0 −79
Original line number Diff line number Diff line
@@ -5108,85 +5108,6 @@ bool X86InstrInfo::isUnpredicatedTerminator(const MachineInstr &MI) const {
  return !isPredicated(MI);
}

bool X86InstrInfo::isUnconditionalTailCall(const MachineInstr &MI) const {
  switch (MI.getOpcode()) {
  case X86::TCRETURNdi:
  case X86::TCRETURNri:
  case X86::TCRETURNmi:
  case X86::TCRETURNdi64:
  case X86::TCRETURNri64:
  case X86::TCRETURNmi64:
    return true;
  default:
    return false;
  }
}

bool X86InstrInfo::canMakeTailCallConditional(
    SmallVectorImpl<MachineOperand> &BranchCond,
    const MachineInstr &TailCall) const {
  if (TailCall.getOpcode() != X86::TCRETURNdi &&
      TailCall.getOpcode() != X86::TCRETURNdi64) {
    // Only direct calls can be done with a conditional branch.
    return false;
  }

  if (Subtarget.isTargetWin64()) {
    // Conditional tail calls confuse the Win64 unwinder.
    // TODO: Allow them for "leaf" functions; PR30337.
    return false;
  }

  assert(BranchCond.size() == 1);
  if (BranchCond[0].getImm() > X86::LAST_VALID_COND) {
    // Can't make a conditional tail call with this condition.
    return false;
  }

  const X86MachineFunctionInfo *X86FI =
      TailCall.getParent()->getParent()->getInfo<X86MachineFunctionInfo>();
  if (X86FI->getTCReturnAddrDelta() != 0 ||
      TailCall.getOperand(1).getImm() != 0) {
    // A conditional tail call cannot do any stack adjustment.
    return false;
  }

  return true;
}

void X86InstrInfo::replaceBranchWithTailCall(
    MachineBasicBlock &MBB, SmallVectorImpl<MachineOperand> &BranchCond,
    const MachineInstr &TailCall) const {
  assert(canMakeTailCallConditional(BranchCond, TailCall));

  MachineBasicBlock::iterator I = MBB.end();
  while (I != MBB.begin()) {
    --I;
    if (I->isDebugValue())
      continue;
    if (!I->isBranch())
      assert(0 && "Can't find the branch to replace!");

    X86::CondCode CC = getCondFromBranchOpc(I->getOpcode());
    assert(BranchCond.size() == 1);
    if (CC != BranchCond[0].getImm())
      continue;

    break;
  }

  unsigned Opc = TailCall.getOpcode() == X86::TCRETURNdi ? X86::TCRETURNdicc
                                                         : X86::TCRETURNdi64cc;

  auto MIB = BuildMI(MBB, I, MBB.findDebugLoc(I), get(Opc));
  MIB->addOperand(TailCall.getOperand(0)); // Destination.
  MIB.addImm(0); // Stack offset (not used).
  MIB->addOperand(BranchCond[0]); // Condition.
  MIB.copyImplicitOps(TailCall); // Regmask and (imp-used) parameters.

  I->eraseFromParent();
}

// Given a MBB and its TBB, find the FBB which was a fallthrough MBB (it may
// not be a fallthrough MBB now due to layout changes). Return nullptr if the
// fallthrough MBB cannot be identified.
Loading