170 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			170 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- CodeGenCommonISel.cpp ---------------------------------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// This file defines common utilies that are shared between SelectionDAG and
 | 
						|
// GlobalISel frameworks.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "llvm/CodeGen/CodeGenCommonISel.h"
 | 
						|
#include "llvm/Analysis/BranchProbabilityInfo.h"
 | 
						|
#include "llvm/CodeGen/MachineBasicBlock.h"
 | 
						|
#include "llvm/CodeGen/MachineFunction.h"
 | 
						|
#include "llvm/CodeGen/TargetInstrInfo.h"
 | 
						|
#include "llvm/CodeGen/TargetOpcodes.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
/// Add a successor MBB to ParentMBB< creating a new MachineBB for BB if SuccMBB
 | 
						|
/// is 0.
 | 
						|
MachineBasicBlock *
 | 
						|
StackProtectorDescriptor::addSuccessorMBB(
 | 
						|
    const BasicBlock *BB, MachineBasicBlock *ParentMBB, bool IsLikely,
 | 
						|
    MachineBasicBlock *SuccMBB) {
 | 
						|
  // If SuccBB has not been created yet, create it.
 | 
						|
  if (!SuccMBB) {
 | 
						|
    MachineFunction *MF = ParentMBB->getParent();
 | 
						|
    MachineFunction::iterator BBI(ParentMBB);
 | 
						|
    SuccMBB = MF->CreateMachineBasicBlock(BB);
 | 
						|
    MF->insert(++BBI, SuccMBB);
 | 
						|
  }
 | 
						|
  // Add it as a successor of ParentMBB.
 | 
						|
  ParentMBB->addSuccessor(
 | 
						|
      SuccMBB, BranchProbabilityInfo::getBranchProbStackProtector(IsLikely));
 | 
						|
  return SuccMBB;
 | 
						|
}
 | 
						|
 | 
						|
/// Given that the input MI is before a partial terminator sequence TSeq, return
 | 
						|
/// true if M + TSeq also a partial terminator sequence.
 | 
						|
///
 | 
						|
/// A Terminator sequence is a sequence of MachineInstrs which at this point in
 | 
						|
/// lowering copy vregs into physical registers, which are then passed into
 | 
						|
/// terminator instructors so we can satisfy ABI constraints. A partial
 | 
						|
/// terminator sequence is an improper subset of a terminator sequence (i.e. it
 | 
						|
/// may be the whole terminator sequence).
 | 
						|
static bool MIIsInTerminatorSequence(const MachineInstr &MI) {
 | 
						|
  // If we do not have a copy or an implicit def, we return true if and only if
 | 
						|
  // MI is a debug value.
 | 
						|
  if (!MI.isCopy() && !MI.isImplicitDef()) {
 | 
						|
    // Sometimes DBG_VALUE MI sneak in between the copies from the vregs to the
 | 
						|
    // physical registers if there is debug info associated with the terminator
 | 
						|
    // of our mbb. We want to include said debug info in our terminator
 | 
						|
    // sequence, so we return true in that case.
 | 
						|
    if (MI.isDebugInstr())
 | 
						|
      return true;
 | 
						|
 | 
						|
    // For GlobalISel, we may have extension instructions for arguments within
 | 
						|
    // copy sequences. Allow these.
 | 
						|
    switch (MI.getOpcode()) {
 | 
						|
    case TargetOpcode::G_TRUNC:
 | 
						|
    case TargetOpcode::G_ZEXT:
 | 
						|
    case TargetOpcode::G_ANYEXT:
 | 
						|
    case TargetOpcode::G_SEXT:
 | 
						|
    case TargetOpcode::G_MERGE_VALUES:
 | 
						|
    case TargetOpcode::G_UNMERGE_VALUES:
 | 
						|
    case TargetOpcode::G_CONCAT_VECTORS:
 | 
						|
    case TargetOpcode::G_BUILD_VECTOR:
 | 
						|
    case TargetOpcode::G_EXTRACT:
 | 
						|
      return true;
 | 
						|
    default:
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // We have left the terminator sequence if we are not doing one of the
 | 
						|
  // following:
 | 
						|
  //
 | 
						|
  // 1. Copying a vreg into a physical register.
 | 
						|
  // 2. Copying a vreg into a vreg.
 | 
						|
  // 3. Defining a register via an implicit def.
 | 
						|
 | 
						|
  // OPI should always be a register definition...
 | 
						|
  MachineInstr::const_mop_iterator OPI = MI.operands_begin();
 | 
						|
  if (!OPI->isReg() || !OPI->isDef())
 | 
						|
    return false;
 | 
						|
 | 
						|
  // Defining any register via an implicit def is always ok.
 | 
						|
  if (MI.isImplicitDef())
 | 
						|
    return true;
 | 
						|
 | 
						|
  // Grab the copy source...
 | 
						|
  MachineInstr::const_mop_iterator OPI2 = OPI;
 | 
						|
  ++OPI2;
 | 
						|
  assert(OPI2 != MI.operands_end()
 | 
						|
         && "Should have a copy implying we should have 2 arguments.");
 | 
						|
 | 
						|
  // Make sure that the copy dest is not a vreg when the copy source is a
 | 
						|
  // physical register.
 | 
						|
  if (!OPI2->isReg() || (!Register::isPhysicalRegister(OPI->getReg()) &&
 | 
						|
                         Register::isPhysicalRegister(OPI2->getReg())))
 | 
						|
    return false;
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
/// Find the split point at which to splice the end of BB into its success stack
 | 
						|
/// protector check machine basic block.
 | 
						|
///
 | 
						|
/// On many platforms, due to ABI constraints, terminators, even before register
 | 
						|
/// allocation, use physical registers. This creates an issue for us since
 | 
						|
/// physical registers at this point can not travel across basic
 | 
						|
/// blocks. Luckily, selectiondag always moves physical registers into vregs
 | 
						|
/// when they enter functions and moves them through a sequence of copies back
 | 
						|
/// into the physical registers right before the terminator creating a
 | 
						|
/// ``Terminator Sequence''. This function is searching for the beginning of the
 | 
						|
/// terminator sequence so that we can ensure that we splice off not just the
 | 
						|
/// terminator, but additionally the copies that move the vregs into the
 | 
						|
/// physical registers.
 | 
						|
MachineBasicBlock::iterator
 | 
						|
llvm::findSplitPointForStackProtector(MachineBasicBlock *BB,
 | 
						|
                                      const TargetInstrInfo &TII) {
 | 
						|
  MachineBasicBlock::iterator SplitPoint = BB->getFirstTerminator();
 | 
						|
  if (SplitPoint == BB->begin())
 | 
						|
    return SplitPoint;
 | 
						|
 | 
						|
  MachineBasicBlock::iterator Start = BB->begin();
 | 
						|
  MachineBasicBlock::iterator Previous = SplitPoint;
 | 
						|
  --Previous;
 | 
						|
 | 
						|
  if (TII.isTailCall(*SplitPoint) &&
 | 
						|
      Previous->getOpcode() == TII.getCallFrameDestroyOpcode()) {
 | 
						|
    // Call frames cannot be nested, so if this frame is describing the tail
 | 
						|
    // call itself, then we must insert before the sequence even starts. For
 | 
						|
    // example:
 | 
						|
    //     <split point>
 | 
						|
    //     ADJCALLSTACKDOWN ...
 | 
						|
    //     <Moves>
 | 
						|
    //     ADJCALLSTACKUP ...
 | 
						|
    //     TAILJMP somewhere
 | 
						|
    // On the other hand, it could be an unrelated call in which case this tail
 | 
						|
    // call has to register moves of its own and should be the split point. For
 | 
						|
    // example:
 | 
						|
    //     ADJCALLSTACKDOWN
 | 
						|
    //     CALL something_else
 | 
						|
    //     ADJCALLSTACKUP
 | 
						|
    //     <split point>
 | 
						|
    //     TAILJMP somewhere
 | 
						|
    do {
 | 
						|
      --Previous;
 | 
						|
      if (Previous->isCall())
 | 
						|
        return SplitPoint;
 | 
						|
    } while(Previous->getOpcode() != TII.getCallFrameSetupOpcode());
 | 
						|
 | 
						|
    return Previous;
 | 
						|
  }
 | 
						|
 | 
						|
  while (MIIsInTerminatorSequence(*Previous)) {
 | 
						|
    SplitPoint = Previous;
 | 
						|
    if (Previous == Start)
 | 
						|
      break;
 | 
						|
    --Previous;
 | 
						|
  }
 | 
						|
 | 
						|
  return SplitPoint;
 | 
						|
}
 |