<commit_before>//===-- PrologEpilogInserter.cpp - Insert Prolog/Epilog code in function --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass is responsible for finalizing the functions frame layout, saving
// callee saved registers, and for emitting prolog & epilog code for the
// function.
//
// This pass must be run after register allocation.  After this pass is
// executed, it is illegal to construct MO_FrameIndex operands.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
using namespace llvm;

namespace {
  struct PEI : public MachineFunctionPass {
    const char *getPassName() const {
      return "Prolog/Epilog Insertion & Frame Finalization";
    }

    /// runOnMachineFunction - Insert prolog/epilog code and replace abstract
    /// frame indexes with appropriate references.
    ///
    bool runOnMachineFunction(MachineFunction &Fn) {
      // Scan the function for modified caller saved registers and insert spill
      // code for any caller saved registers that are modified.  Also calculate
      // the MaxCallFrameSize and HasCalls variables for the function's frame
      // information and eliminates call frame pseudo instructions.
      calculateCallerSavedRegisters(Fn);

      // Add the code to save and restore the caller saved registers
      saveCallerSavedRegisters(Fn);

      // Allow the target machine to make final modifications to the function
      // before the frame layout is finalized.
      Fn.getTarget().getRegisterInfo()->processFunctionBeforeFrameFinalized(Fn);

      // Calculate actual frame offsets for all of the abstract stack objects...
      calculateFrameObjectOffsets(Fn);

      // Add prolog and epilog code to the function.  This function is required
      // to align the stack frame as necessary for any stack variables or
      // called functions.  Because of this, calculateCallerSavedRegisters
      // must be called before this function in order to set the HasCalls
      // and MaxCallFrameSize variables.
      insertPrologEpilogCode(Fn);

      // Replace all MO_FrameIndex operands with physical register references
      // and actual offsets.
      //
      replaceFrameIndices(Fn);

      RegsToSave.clear();
      StackSlots.clear();
      return true;
    }

  private:
    std::vector<std::pair<unsigned, const TargetRegisterClass*> > RegsToSave;
    std::vector<int> StackSlots;

    void calculateCallerSavedRegisters(MachineFunction &Fn);
    void saveCallerSavedRegisters(MachineFunction &Fn);
    void calculateFrameObjectOffsets(MachineFunction &Fn);
    void replaceFrameIndices(MachineFunction &Fn);
    void insertPrologEpilogCode(MachineFunction &Fn);
  };
}

/// createPrologEpilogCodeInserter - This function returns a pass that inserts
/// prolog and epilog code, and eliminates abstract frame references.
///
FunctionPass *llvm::createPrologEpilogCodeInserter() { return new PEI(); }

/// calculateCallerSavedRegisters - Scan the function for modified caller saved
/// registers.  Also calculate the MaxCallFrameSize and HasCalls variables for
/// the function's frame information and eliminates call frame pseudo
/// instructions.
///
void PEI::calculateCallerSavedRegisters(MachineFunction &Fn) {
  const MRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo();
  const TargetFrameInfo *TFI = Fn.getTarget().getFrameInfo();
  const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo();

  // Get the callee saved register list...
  const unsigned *CSRegs = RegInfo->getCalleeSaveRegs();

  // Get the function call frame set-up and tear-down instruction opcode
  int FrameSetupOpcode   = RegInfo->getCallFrameSetupOpcode();
  int FrameDestroyOpcode = RegInfo->getCallFrameDestroyOpcode();

  // Early exit for targets which have no callee saved registers and no call
  // frame setup/destroy pseudo instructions.
  if ((CSRegs == 0 || CSRegs[0] == 0) &&
      FrameSetupOpcode == -1 && FrameDestroyOpcode == -1)
    return;

  unsigned MaxCallFrameSize = 0;
  bool HasCalls = false;

  for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB)
    for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); )
      if (I->getOpcode() == FrameSetupOpcode ||
          I->getOpcode() == FrameDestroyOpcode) {
        assert(I->getNumOperands() >= 1 && "Call Frame Setup/Destroy Pseudo"
               " instructions should have a single immediate argument!");
        unsigned Size = I->getOperand(0).getImmedValue();
        if (Size > MaxCallFrameSize) MaxCallFrameSize = Size;
        HasCalls = true;
        RegInfo->eliminateCallFramePseudoInstr(Fn, *BB, I++);
      } else {
        ++I;
      }

  MachineFrameInfo *FFI = Fn.getFrameInfo();
  FFI->setHasCalls(HasCalls);
  FFI->setMaxCallFrameSize(MaxCallFrameSize);

  // Now figure out which *callee saved* registers are modified by the current
  // function, thus needing to be saved and restored in the prolog/epilog.
  //
  const bool *PhysRegsUsed = Fn.getUsedPhysregs();
  const TargetRegisterClass* const *CSRegClasses =
    RegInfo->getCalleeSaveRegClasses();
  for (unsigned i = 0; CSRegs[i]; ++i) {
    unsigned Reg = CSRegs[i];
    if (PhysRegsUsed[Reg]) {
        // If the reg is modified, save it!
      RegsToSave.push_back(std::make_pair(Reg, CSRegClasses[i]));
    } else {
      for (const unsigned *AliasSet = RegInfo->getAliasSet(Reg);
           *AliasSet; ++AliasSet) {  // Check alias registers too.
        if (PhysRegsUsed[*AliasSet]) {
          RegsToSave.push_back(std::make_pair(Reg, CSRegClasses[i]));
          break;
        }
      }
    }
  }

  if (RegsToSave.empty())
    return;   // Early exit if no caller saved registers are modified!

  unsigned NumFixedSpillSlots;
  const std::pair<unsigned,int> *FixedSpillSlots =
    TFI->getCalleeSaveSpillSlots(NumFixedSpillSlots);

  // Now that we know which registers need to be saved and restored, allocate
  // stack slots for them.
  for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
    unsigned Reg = RegsToSave[i].first;
    const TargetRegisterClass *RC = RegsToSave[i].second;

    // Check to see if this physreg must be spilled to a particular stack slot
    // on this target.
    const std::pair<unsigned,int> *FixedSlot = FixedSpillSlots;
    while (FixedSlot != FixedSpillSlots+NumFixedSpillSlots &&
           FixedSlot->first != Reg)
      ++FixedSlot;

    int FrameIdx;
    if (FixedSlot == FixedSpillSlots+NumFixedSpillSlots) {
      // Nope, just spill it anywhere convenient.
      FrameIdx = FFI->CreateStackObject(RC->getSize(), RC->getAlignment());
    } else {
      // Spill it to the stack where we must.
      FrameIdx = FFI->CreateFixedObject(RC->getSize(), FixedSlot->second);
    }
    StackSlots.push_back(FrameIdx);
  }
}

/// saveCallerSavedRegisters -  Insert spill code for any caller saved registers
/// that are modified in the function.
///
void PEI::saveCallerSavedRegisters(MachineFunction &Fn) {
  // Early exit if no caller saved registers are modified!
  if (RegsToSave.empty())
    return;

  const MRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo();

  // Now that we have a stack slot for each register to be saved, insert spill
  // code into the entry block.
  MachineBasicBlock *MBB = Fn.begin();
  MachineBasicBlock::iterator I = MBB->begin();
  for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
    // Insert the spill to the stack frame.
    RegInfo->storeRegToStackSlot(*MBB, I, RegsToSave[i].first, StackSlots[i],
                                 RegsToSave[i].second);
  }

  // Add code to restore the callee-save registers in each exiting block.
  const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo();
  for (MachineFunction::iterator FI = Fn.begin(), E = Fn.end(); FI != E; ++FI)
    // If last instruction is a return instruction, add an epilogue.
    if (!FI->empty() && TII.isReturn(FI->back().getOpcode())) {
      MBB = FI;
      I = MBB->end(); --I;

      // Skip over all terminator instructions, which are part of the return
      // sequence.
      MachineBasicBlock::iterator I2 = I;
      while (I2 != MBB->begin() && TII.isTerminatorInstr((--I2)->getOpcode()))
        I = I2;

      bool AtStart = I == MBB->begin();
      MachineBasicBlock::iterator BeforeI = I;
      if (!AtStart)
        --BeforeI;

      // Restore all registers immediately before the return and any terminators
      // that preceed it.
      for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
        RegInfo->loadRegFromStackSlot(*MBB, I, RegsToSave[i].first,
                                      StackSlots[i], RegsToSave[i].second);
        assert(I != MBB->begin() &&
               "loadRegFromStackSlot didn't insert any code!");
        // Insert in reverse order.  loadRegFromStackSlot can insert multiple
        // instructions.
        if (AtStart)
          I = MBB->begin();
        else {
          I = BeforeI;
          ++I;
        }
      }
    }
}

/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the
/// abstract stack objects.
///
void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
  const TargetFrameInfo &TFI = *Fn.getTarget().getFrameInfo();

  bool StackGrowsDown =
    TFI.getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown;

  // Loop over all of the stack objects, assigning sequential addresses...
  MachineFrameInfo *FFI = Fn.getFrameInfo();

  unsigned StackAlignment = TFI.getStackAlignment();
  unsigned MaxAlign = 0;

  // Start at the beginning of the local area.
  // The Offset is the distance from the stack top in the direction
  // of stack growth -- so it's always positive.
  int Offset = TFI.getOffsetOfLocalArea();
  if (StackGrowsDown)
    Offset = -Offset;
  assert(Offset >= 0
         && "Local area offset should be in direction of stack growth");

  // If there are fixed sized objects that are preallocated in the local area,
  // non-fixed objects can't be allocated right at the start of local area.
  // We currently don't support filling in holes in between fixed sized objects,
  // so we adjust 'Offset' to point to the end of last fixed sized
  // preallocated object.
  for (int i = FFI->getObjectIndexBegin(); i != 0; ++i) {
    int FixedOff;
    if (StackGrowsDown) {
      // The maximum distance from the stack pointer is at lower address of
      // the object -- which is given by offset. For down growing stack
      // the offset is negative, so we negate the offset to get the distance.
      FixedOff = -FFI->getObjectOffset(i);
    } else {
      // The maximum distance from the start pointer is at the upper
      // address of the object.
      FixedOff = FFI->getObjectOffset(i) + FFI->getObjectSize(i);
    }
    if (FixedOff > Offset) Offset = FixedOff;
  }

  for (unsigned i = 0, e = FFI->getObjectIndexEnd(); i != e; ++i) {
    // If stack grows down, we need to add size of find the lowest
    // address of the object.
    if (StackGrowsDown)
      Offset += FFI->getObjectSize(i);

    unsigned Align = FFI->getObjectAlignment(i);
    // If the alignment of this object is greater than that of the stack, then
    // increase the stack alignment to match.
    MaxAlign = std::max(MaxAlign, Align);
    // Adjust to alignment boundary
    Offset = (Offset+Align-1)/Align*Align;

    if (StackGrowsDown) {
      FFI->setObjectOffset(i, -Offset);        // Set the computed offset
    } else {
      FFI->setObjectOffset(i, Offset);
      Offset += FFI->getObjectSize(i);
    }
  }

  // Align the final stack pointer offset, but only if there are calls in the
  // function.  This ensures that any calls to subroutines have their stack
  // frames suitable aligned.
  if (FFI->hasCalls())
    Offset = (Offset+StackAlignment-1)/StackAlignment*StackAlignment;

  // Set the final value of the stack pointer...
  FFI->setStackSize(Offset+TFI.getOffsetOfLocalArea());

  // Remember the required stack alignment in case targets need it to perform
  // dynamic stack alignment.
  FFI->setMaxAlignment(MaxAlign);
}

/// insertPrologEpilogCode - Scan the function for modified caller saved
/// registers, insert spill code for these caller saved registers, then add
/// prolog and epilog code to the function.
///
void PEI::insertPrologEpilogCode(MachineFunction &Fn) {
  // Add prologue to the function...
  Fn.getTarget().getRegisterInfo()->emitPrologue(Fn);

  // Add epilogue to restore the callee-save registers in each exiting block
  const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo();
  for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) {
    // If last instruction is a return instruction, add an epilogue
    if (!I->empty() && TII.isReturn(I->back().getOpcode()))
      Fn.getTarget().getRegisterInfo()->emitEpilogue(Fn, *I);
  }
}

/// replaceFrameIndices - Replace all MO_FrameIndex operands with physical
/// register references and actual offsets.
///
void PEI::replaceFrameIndices(MachineFunction &Fn) {
  if (!Fn.getFrameInfo()->hasStackObjects()) return; // Nothing to do?

  const TargetMachine &TM = Fn.getTarget();
  assert(TM.getRegisterInfo() && "TM::getRegisterInfo() must be implemented!");
  const MRegisterInfo &MRI = *TM.getRegisterInfo();

  for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB)
    for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I)
      for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i)
        if (I->getOperand(i).isFrameIndex()) {
          // If this instruction has a FrameIndex operand, we need to use that
          // target machine register info object to eliminate it.
          MRI.eliminateFrameIndex(I);
          break;
        }
}
<commit_msg>The stack alignment is now computed dynamically, just verify it is correct.<commit_after>//===-- PrologEpilogInserter.cpp - Insert Prolog/Epilog code in function --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass is responsible for finalizing the functions frame layout, saving
// callee saved registers, and for emitting prolog & epilog code for the
// function.
//
// This pass must be run after register allocation.  After this pass is
// executed, it is illegal to construct MO_FrameIndex operands.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
using namespace llvm;

namespace {
  struct PEI : public MachineFunctionPass {
    const char *getPassName() const {
      return "Prolog/Epilog Insertion & Frame Finalization";
    }

    /// runOnMachineFunction - Insert prolog/epilog code and replace abstract
    /// frame indexes with appropriate references.
    ///
    bool runOnMachineFunction(MachineFunction &Fn) {
      // Scan the function for modified caller saved registers and insert spill
      // code for any caller saved registers that are modified.  Also calculate
      // the MaxCallFrameSize and HasCalls variables for the function's frame
      // information and eliminates call frame pseudo instructions.
      calculateCallerSavedRegisters(Fn);

      // Add the code to save and restore the caller saved registers
      saveCallerSavedRegisters(Fn);

      // Allow the target machine to make final modifications to the function
      // before the frame layout is finalized.
      Fn.getTarget().getRegisterInfo()->processFunctionBeforeFrameFinalized(Fn);

      // Calculate actual frame offsets for all of the abstract stack objects...
      calculateFrameObjectOffsets(Fn);

      // Add prolog and epilog code to the function.  This function is required
      // to align the stack frame as necessary for any stack variables or
      // called functions.  Because of this, calculateCallerSavedRegisters
      // must be called before this function in order to set the HasCalls
      // and MaxCallFrameSize variables.
      insertPrologEpilogCode(Fn);

      // Replace all MO_FrameIndex operands with physical register references
      // and actual offsets.
      //
      replaceFrameIndices(Fn);

      RegsToSave.clear();
      StackSlots.clear();
      return true;
    }

  private:
    std::vector<std::pair<unsigned, const TargetRegisterClass*> > RegsToSave;
    std::vector<int> StackSlots;

    void calculateCallerSavedRegisters(MachineFunction &Fn);
    void saveCallerSavedRegisters(MachineFunction &Fn);
    void calculateFrameObjectOffsets(MachineFunction &Fn);
    void replaceFrameIndices(MachineFunction &Fn);
    void insertPrologEpilogCode(MachineFunction &Fn);
  };
}

/// createPrologEpilogCodeInserter - This function returns a pass that inserts
/// prolog and epilog code, and eliminates abstract frame references.
///
FunctionPass *llvm::createPrologEpilogCodeInserter() { return new PEI(); }

/// calculateCallerSavedRegisters - Scan the function for modified caller saved
/// registers.  Also calculate the MaxCallFrameSize and HasCalls variables for
/// the function's frame information and eliminates call frame pseudo
/// instructions.
///
void PEI::calculateCallerSavedRegisters(MachineFunction &Fn) {
  const MRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo();
  const TargetFrameInfo *TFI = Fn.getTarget().getFrameInfo();
  const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo();

  // Get the callee saved register list...
  const unsigned *CSRegs = RegInfo->getCalleeSaveRegs();

  // Get the function call frame set-up and tear-down instruction opcode
  int FrameSetupOpcode   = RegInfo->getCallFrameSetupOpcode();
  int FrameDestroyOpcode = RegInfo->getCallFrameDestroyOpcode();

  // Early exit for targets which have no callee saved registers and no call
  // frame setup/destroy pseudo instructions.
  if ((CSRegs == 0 || CSRegs[0] == 0) &&
      FrameSetupOpcode == -1 && FrameDestroyOpcode == -1)
    return;

  unsigned MaxCallFrameSize = 0;
  bool HasCalls = false;

  for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB)
    for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); )
      if (I->getOpcode() == FrameSetupOpcode ||
          I->getOpcode() == FrameDestroyOpcode) {
        assert(I->getNumOperands() >= 1 && "Call Frame Setup/Destroy Pseudo"
               " instructions should have a single immediate argument!");
        unsigned Size = I->getOperand(0).getImmedValue();
        if (Size > MaxCallFrameSize) MaxCallFrameSize = Size;
        HasCalls = true;
        RegInfo->eliminateCallFramePseudoInstr(Fn, *BB, I++);
      } else {
        ++I;
      }

  MachineFrameInfo *FFI = Fn.getFrameInfo();
  FFI->setHasCalls(HasCalls);
  FFI->setMaxCallFrameSize(MaxCallFrameSize);

  // Now figure out which *callee saved* registers are modified by the current
  // function, thus needing to be saved and restored in the prolog/epilog.
  //
  const bool *PhysRegsUsed = Fn.getUsedPhysregs();
  const TargetRegisterClass* const *CSRegClasses =
    RegInfo->getCalleeSaveRegClasses();
  for (unsigned i = 0; CSRegs[i]; ++i) {
    unsigned Reg = CSRegs[i];
    if (PhysRegsUsed[Reg]) {
        // If the reg is modified, save it!
      RegsToSave.push_back(std::make_pair(Reg, CSRegClasses[i]));
    } else {
      for (const unsigned *AliasSet = RegInfo->getAliasSet(Reg);
           *AliasSet; ++AliasSet) {  // Check alias registers too.
        if (PhysRegsUsed[*AliasSet]) {
          RegsToSave.push_back(std::make_pair(Reg, CSRegClasses[i]));
          break;
        }
      }
    }
  }

  if (RegsToSave.empty())
    return;   // Early exit if no caller saved registers are modified!

  unsigned NumFixedSpillSlots;
  const std::pair<unsigned,int> *FixedSpillSlots =
    TFI->getCalleeSaveSpillSlots(NumFixedSpillSlots);

  // Now that we know which registers need to be saved and restored, allocate
  // stack slots for them.
  for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
    unsigned Reg = RegsToSave[i].first;
    const TargetRegisterClass *RC = RegsToSave[i].second;

    // Check to see if this physreg must be spilled to a particular stack slot
    // on this target.
    const std::pair<unsigned,int> *FixedSlot = FixedSpillSlots;
    while (FixedSlot != FixedSpillSlots+NumFixedSpillSlots &&
           FixedSlot->first != Reg)
      ++FixedSlot;

    int FrameIdx;
    if (FixedSlot == FixedSpillSlots+NumFixedSpillSlots) {
      // Nope, just spill it anywhere convenient.
      FrameIdx = FFI->CreateStackObject(RC->getSize(), RC->getAlignment());
    } else {
      // Spill it to the stack where we must.
      FrameIdx = FFI->CreateFixedObject(RC->getSize(), FixedSlot->second);
    }
    StackSlots.push_back(FrameIdx);
  }
}

/// saveCallerSavedRegisters -  Insert spill code for any caller saved registers
/// that are modified in the function.
///
void PEI::saveCallerSavedRegisters(MachineFunction &Fn) {
  // Early exit if no caller saved registers are modified!
  if (RegsToSave.empty())
    return;

  const MRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo();

  // Now that we have a stack slot for each register to be saved, insert spill
  // code into the entry block.
  MachineBasicBlock *MBB = Fn.begin();
  MachineBasicBlock::iterator I = MBB->begin();
  for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
    // Insert the spill to the stack frame.
    RegInfo->storeRegToStackSlot(*MBB, I, RegsToSave[i].first, StackSlots[i],
                                 RegsToSave[i].second);
  }

  // Add code to restore the callee-save registers in each exiting block.
  const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo();
  for (MachineFunction::iterator FI = Fn.begin(), E = Fn.end(); FI != E; ++FI)
    // If last instruction is a return instruction, add an epilogue.
    if (!FI->empty() && TII.isReturn(FI->back().getOpcode())) {
      MBB = FI;
      I = MBB->end(); --I;

      // Skip over all terminator instructions, which are part of the return
      // sequence.
      MachineBasicBlock::iterator I2 = I;
      while (I2 != MBB->begin() && TII.isTerminatorInstr((--I2)->getOpcode()))
        I = I2;

      bool AtStart = I == MBB->begin();
      MachineBasicBlock::iterator BeforeI = I;
      if (!AtStart)
        --BeforeI;

      // Restore all registers immediately before the return and any terminators
      // that preceed it.
      for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
        RegInfo->loadRegFromStackSlot(*MBB, I, RegsToSave[i].first,
                                      StackSlots[i], RegsToSave[i].second);
        assert(I != MBB->begin() &&
               "loadRegFromStackSlot didn't insert any code!");
        // Insert in reverse order.  loadRegFromStackSlot can insert multiple
        // instructions.
        if (AtStart)
          I = MBB->begin();
        else {
          I = BeforeI;
          ++I;
        }
      }
    }
}

/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the
/// abstract stack objects.
///
void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
  const TargetFrameInfo &TFI = *Fn.getTarget().getFrameInfo();

  bool StackGrowsDown =
    TFI.getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown;

  // Loop over all of the stack objects, assigning sequential addresses...
  MachineFrameInfo *FFI = Fn.getFrameInfo();

  unsigned StackAlignment = TFI.getStackAlignment();
  unsigned MaxAlign = 0;

  // Start at the beginning of the local area.
  // The Offset is the distance from the stack top in the direction
  // of stack growth -- so it's always positive.
  int Offset = TFI.getOffsetOfLocalArea();
  if (StackGrowsDown)
    Offset = -Offset;
  assert(Offset >= 0
         && "Local area offset should be in direction of stack growth");

  // If there are fixed sized objects that are preallocated in the local area,
  // non-fixed objects can't be allocated right at the start of local area.
  // We currently don't support filling in holes in between fixed sized objects,
  // so we adjust 'Offset' to point to the end of last fixed sized
  // preallocated object.
  for (int i = FFI->getObjectIndexBegin(); i != 0; ++i) {
    int FixedOff;
    if (StackGrowsDown) {
      // The maximum distance from the stack pointer is at lower address of
      // the object -- which is given by offset. For down growing stack
      // the offset is negative, so we negate the offset to get the distance.
      FixedOff = -FFI->getObjectOffset(i);
    } else {
      // The maximum distance from the start pointer is at the upper
      // address of the object.
      FixedOff = FFI->getObjectOffset(i) + FFI->getObjectSize(i);
    }
    if (FixedOff > Offset) Offset = FixedOff;
  }

  for (unsigned i = 0, e = FFI->getObjectIndexEnd(); i != e; ++i) {
    // If stack grows down, we need to add size of find the lowest
    // address of the object.
    if (StackGrowsDown)
      Offset += FFI->getObjectSize(i);

    unsigned Align = FFI->getObjectAlignment(i);
    // If the alignment of this object is greater than that of the stack, then
    // increase the stack alignment to match.
    MaxAlign = std::max(MaxAlign, Align);
    // Adjust to alignment boundary
    Offset = (Offset+Align-1)/Align*Align;

    if (StackGrowsDown) {
      FFI->setObjectOffset(i, -Offset);        // Set the computed offset
    } else {
      FFI->setObjectOffset(i, Offset);
      Offset += FFI->getObjectSize(i);
    }
  }

  // Align the final stack pointer offset, but only if there are calls in the
  // function.  This ensures that any calls to subroutines have their stack
  // frames suitable aligned.
  if (FFI->hasCalls())
    Offset = (Offset+StackAlignment-1)/StackAlignment*StackAlignment;

  // Set the final value of the stack pointer...
  FFI->setStackSize(Offset+TFI.getOffsetOfLocalArea());

  // Remember the required stack alignment in case targets need it to perform
  // dynamic stack alignment.
  assert(FFI->getMaxAlignment() == MaxAlign &&
         "Stack alignment calculation broken!");
}

/// insertPrologEpilogCode - Scan the function for modified caller saved
/// registers, insert spill code for these caller saved registers, then add
/// prolog and epilog code to the function.
///
void PEI::insertPrologEpilogCode(MachineFunction &Fn) {
  // Add prologue to the function...
  Fn.getTarget().getRegisterInfo()->emitPrologue(Fn);

  // Add epilogue to restore the callee-save registers in each exiting block
  const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo();
  for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) {
    // If last instruction is a return instruction, add an epilogue
    if (!I->empty() && TII.isReturn(I->back().getOpcode()))
      Fn.getTarget().getRegisterInfo()->emitEpilogue(Fn, *I);
  }
}

/// replaceFrameIndices - Replace all MO_FrameIndex operands with physical
/// register references and actual offsets.
///
void PEI::replaceFrameIndices(MachineFunction &Fn) {
  if (!Fn.getFrameInfo()->hasStackObjects()) return; // Nothing to do?

  const TargetMachine &TM = Fn.getTarget();
  assert(TM.getRegisterInfo() && "TM::getRegisterInfo() must be implemented!");
  const MRegisterInfo &MRI = *TM.getRegisterInfo();

  for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB)
    for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I)
      for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i)
        if (I->getOperand(i).isFrameIndex()) {
          // If this instruction has a FrameIndex operand, we need to use that
          // target machine register info object to eliminate it.
          MRI.eliminateFrameIndex(I);
          break;
        }
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "probe.h"

#include "msvcprobe.h"
#include "xcodeprobe.h"

#include <logging/translator.h>
#include <tools/error.h>
#include <tools/hostosinfo.h>
#include <tools/profile.h>
#include <tools/settings.h>

#include <QDir>
#include <QFileInfo>
#include <QProcess>
#include <QStringList>
#include <QTextStream>

#include <cstdio>

using namespace qbs;
using Internal::HostOsInfo;
using Internal::Tr;

static QTextStream qStdout(stdout);
static QTextStream qStderr(stderr);

static QString findExecutable(const QString &fileName)
{
    const QString path = QString::fromLocal8Bit(qgetenv("PATH"));
    foreach (const QString &ppath, path.split(HostOsInfo::pathListSeparator())) {
        const QString fullPath = ppath + QLatin1Char('/') + fileName;
        if (QFileInfo(fullPath).exists())
            return QDir::cleanPath(fullPath);
    }
    return QString();
}

static QString qsystem(const QString &exe, const QStringList &args = QStringList())
{
    QProcess p;
    p.setProcessChannelMode(QProcess::MergedChannels);
    p.start(exe, args);
    if (!p.waitForStarted()) {
        throw qbs::ErrorInfo(Tr::tr("Failed to start compiler '%1': %2")
                             .arg(exe, p.errorString()));
    }
    if (!p.waitForFinished() || p.exitCode() != 0)
        throw qbs::ErrorInfo(Tr::tr("Failed to run compiler '%1': %2").arg(exe, p.errorString()));
    return QString::fromLocal8Bit(p.readAll());
}

static QStringList validMinGWMachines()
{
    // List of MinGW machine names (gcc -dumpmachine) recognized by Qbs
    return QStringList()
            << QLatin1String("mingw32") << QLatin1String("mingw64")
            << QLatin1String("i686-w64-mingw32") << QLatin1String("x86_64-w64-mingw32")
            << QLatin1String("i586-mingw32msvc") << QLatin1String("amd64-mingw32msvc");
}

static QStringList completeToolchainList(const QString &toolchainName)
{
    QStringList toolchains(toolchainName);
    if (toolchainName == QLatin1String("clang"))
        toolchains << completeToolchainList(QLatin1String("llvm"));
    else if (toolchainName == QLatin1String("llvm") ||
             toolchainName == QLatin1String("mingw")) {
        toolchains << completeToolchainList(QLatin1String("gcc"));
    }
    return toolchains;
}

static QStringList toolchainTypeFromCompilerName(const QString &compilerName)
{
    if (compilerName == QLatin1String("cl.exe"))
        return completeToolchainList(QLatin1String("msvc"));
    foreach (const QString &type, (QStringList() << QLatin1String("clang") << QLatin1String("llvm")
                                                 << QLatin1String("mingw") << QLatin1String("gcc")))
        if (compilerName.contains(type))
            return completeToolchainList(type);
    return QStringList();
}

static QString actualCompilerFilePath(const QString &compilerFilePath)
{
    const QFileInfo cfi(compilerFilePath);
    QString compilerFileName = cfi.fileName();

    // People usually want to compile C++. Since we currently link via
    // the compiler executable, using the plain C compiler will likely lead to linking problems.
    compilerFileName.replace(QLatin1String("gcc"), QLatin1String("g++"));
    compilerFileName.replace(QLatin1String("clang"), QLatin1String("clang++"));
    return cfi.absolutePath() + QLatin1Char('/') + compilerFileName;
}

static QString gccMachineName(const QString &compilerFilePath)
{
    return qsystem(compilerFilePath, QStringList() << QLatin1String("-dumpmachine")).trimmed();
}

static void setCommonProperties(Profile &profile, const QString &compilerFilePath,
                                const QStringList &toolchainTypes, const QString &architecture)
{
    QFileInfo cfi(compilerFilePath);
    profile.setValue(QLatin1String("cpp.toolchainInstallPath"), cfi.absolutePath());
    profile.setValue(QLatin1String("cpp.compilerName"), cfi.fileName());
    profile.setValue(QLatin1String("qbs.toolchain"), toolchainTypes);
    profile.setValue(QLatin1String("qbs.architecture"),
                     HostOsInfo::canonicalArchitecture(architecture));
    profile.setValue(QLatin1String("qbs.endianness"),
                     HostOsInfo::defaultEndianness(architecture));
}

static Profile createGccProfile(const QString &_compilerFilePath, Settings *settings,
                                const QStringList &toolchainTypes,
                                const QString &profileName = QString())
{
    const QString compilerFilePath = actualCompilerFilePath(_compilerFilePath);
    const QString machineName = gccMachineName(compilerFilePath);
    const QStringList compilerTriplet = machineName.split(QLatin1Char('-'));
    const bool isMingw = toolchainTypes.contains(QLatin1String("mingw"));

    if (isMingw && !validMinGWMachines().contains(machineName)) {
        throw qbs::ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.")
                .arg(machineName));
    } else if (compilerTriplet.count() < 2) {
        throw qbs::ErrorInfo(Tr::tr("Architecture of compiler for platform '%1' at '%2' not understood.")
                             .arg(machineName, compilerFilePath));
    }

    Profile profile(!profileName.isEmpty() ? profileName : machineName, settings);
    profile.removeProfile();
    if (isMingw) {
        profile.setValue(QLatin1String("qbs.targetOS"), QStringList(QLatin1String("windows")));
    }

    setCommonProperties(profile, compilerFilePath, toolchainTypes, compilerTriplet.first());
    const QString compilerName = QFileInfo(compilerFilePath).fileName();
    if (compilerName.contains(QLatin1Char('-'))) {
        QStringList nameParts = compilerName.split(QLatin1Char('-'));
        profile.setValue(QLatin1String("cpp.compilerName"), nameParts.takeLast());
        profile.setValue(QLatin1String("cpp.toolchainPrefix"),
                         nameParts.join(QLatin1String("-")) + QLatin1Char('-'));
    }
    qStdout << Tr::tr("Profile '%1' created for '%2'.").arg(profile.name(), compilerFilePath)
            << endl;
    return profile;
}

static void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compilerName)
{
    qStdout << Tr::tr("Trying to detect %1...").arg(compilerName) << endl;

    const QString crossCompilePrefix = QString::fromLocal8Bit(qgetenv("CROSS_COMPILE"));
    const QString compilerFilePath = findExecutable(crossCompilePrefix + compilerName);
    if (!QFileInfo(compilerFilePath).exists()) {
        qStderr << Tr::tr("%1 not found.").arg(compilerName) << endl;
        return;
    }
    const QString profileName = QFileInfo(compilerFilePath).completeBaseName();
    const QStringList toolchainTypes = toolchainTypeFromCompilerName(compilerName);
    profiles << createGccProfile(compilerFilePath, settings, toolchainTypes, profileName);
}

static void mingwProbe(Settings *settings, QList<Profile> &profiles)
{
    // List of possible compiler binary names for this platform
    QStringList compilerNames;
    if (HostOsInfo::isWindowsHost()) {
        compilerNames << QLatin1String("gcc");
    } else {
        foreach (const QString &machineName, validMinGWMachines()) {
            compilerNames << machineName + QLatin1String("-gcc");
        }
    }

    foreach (const QString &compilerName, compilerNames) {
        const QString gccPath
                = findExecutable(HostOsInfo::appendExecutableSuffix(compilerName));
        if (!gccPath.isEmpty())
            profiles << createGccProfile(gccPath, settings,
                                         completeToolchainList(QLatin1String("mingw")));
    }
}

void probe(Settings *settings)
{
    QList<Profile> profiles;
    if (HostOsInfo::isWindowsHost()) {
        msvcProbe(settings, profiles);
    } else {
        gccProbe(settings, profiles, QLatin1String("gcc"));
        gccProbe(settings, profiles, QLatin1String("clang"));

        if (HostOsInfo::isOsxHost()) {
            xcodeProbe(settings, profiles);
        }
    }

    mingwProbe(settings, profiles);

    if (profiles.isEmpty()) {
        qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << endl;
    } else if (profiles.count() == 1 && settings->defaultProfile().isEmpty()) {
        const QString profileName = profiles.first().name();
        qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << endl;
        settings->setValue(QLatin1String("defaultProfile"), profileName);
    }
}

void createProfile(const QString &profileName, const QString &toolchainType,
                   const QString &compilerFilePath, Settings *settings)
{
    QFileInfo compiler(compilerFilePath);
    if (compilerFilePath == compiler.fileName() && !compiler.exists())
        compiler = QFileInfo(findExecutable(compilerFilePath));

    if (!compiler.exists()) {
        throw qbs::ErrorInfo(Tr::tr("Compiler '%1' not found")
                             .arg(compilerFilePath));
    }

    QStringList toolchainTypes;
    if (toolchainType.isEmpty())
        toolchainTypes = toolchainTypeFromCompilerName(compiler.fileName());
    else
        toolchainTypes = completeToolchainList(toolchainType);

    if (toolchainTypes.contains(QLatin1String("msvc"))) {
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: MSVC toolchains can only be created "
                                    "via the auto-detection mechanism."));
    }

    if (toolchainTypes.contains(QLatin1String("gcc")))
        createGccProfile(compiler.absoluteFilePath(), settings, toolchainTypes, profileName);
    else
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type."));
}
<commit_msg>setup-toolchains: detect location of ar and nm<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "probe.h"

#include "msvcprobe.h"
#include "xcodeprobe.h"

#include <logging/translator.h>
#include <tools/error.h>
#include <tools/hostosinfo.h>
#include <tools/profile.h>
#include <tools/settings.h>

#include <QDir>
#include <QFileInfo>
#include <QProcess>
#include <QStringList>
#include <QTextStream>

#include <cstdio>

using namespace qbs;
using Internal::HostOsInfo;
using Internal::Tr;

static QTextStream qStdout(stdout);
static QTextStream qStderr(stderr);

static QString findExecutable(const QString &fileName)
{
    const QString path = QString::fromLocal8Bit(qgetenv("PATH"));
    foreach (const QString &ppath, path.split(HostOsInfo::pathListSeparator())) {
        const QString fullPath = ppath + QLatin1Char('/') + fileName;
        if (QFileInfo(fullPath).exists())
            return QDir::cleanPath(fullPath);
    }
    return QString();
}

static QString qsystem(const QString &exe, const QStringList &args = QStringList())
{
    QProcess p;
    p.setProcessChannelMode(QProcess::MergedChannels);
    p.start(exe, args);
    if (!p.waitForStarted()) {
        throw qbs::ErrorInfo(Tr::tr("Failed to start compiler '%1': %2")
                             .arg(exe, p.errorString()));
    }
    if (!p.waitForFinished() || p.exitCode() != 0)
        throw qbs::ErrorInfo(Tr::tr("Failed to run compiler '%1': %2").arg(exe, p.errorString()));
    return QString::fromLocal8Bit(p.readAll());
}

static QStringList validMinGWMachines()
{
    // List of MinGW machine names (gcc -dumpmachine) recognized by Qbs
    return QStringList()
            << QLatin1String("mingw32") << QLatin1String("mingw64")
            << QLatin1String("i686-w64-mingw32") << QLatin1String("x86_64-w64-mingw32")
            << QLatin1String("i586-mingw32msvc") << QLatin1String("amd64-mingw32msvc");
}

static QStringList completeToolchainList(const QString &toolchainName)
{
    QStringList toolchains(toolchainName);
    if (toolchainName == QLatin1String("clang"))
        toolchains << completeToolchainList(QLatin1String("llvm"));
    else if (toolchainName == QLatin1String("llvm") ||
             toolchainName == QLatin1String("mingw")) {
        toolchains << completeToolchainList(QLatin1String("gcc"));
    }
    return toolchains;
}

static QStringList toolchainTypeFromCompilerName(const QString &compilerName)
{
    if (compilerName == QLatin1String("cl.exe"))
        return completeToolchainList(QLatin1String("msvc"));
    foreach (const QString &type, (QStringList() << QLatin1String("clang") << QLatin1String("llvm")
                                                 << QLatin1String("mingw") << QLatin1String("gcc")))
        if (compilerName.contains(type))
            return completeToolchainList(type);
    return QStringList();
}

static QString actualCompilerFilePath(const QString &compilerFilePath)
{
    const QFileInfo cfi(compilerFilePath);
    QString compilerFileName = cfi.fileName();

    // People usually want to compile C++. Since we currently link via
    // the compiler executable, using the plain C compiler will likely lead to linking problems.
    compilerFileName.replace(QLatin1String("gcc"), QLatin1String("g++"));
    compilerFileName.replace(QLatin1String("clang"), QLatin1String("clang++"));
    return cfi.absolutePath() + QLatin1Char('/') + compilerFileName;
}

static QString gccMachineName(const QString &compilerFilePath)
{
    return qsystem(compilerFilePath, QStringList() << QLatin1String("-dumpmachine")).trimmed();
}

static void setCommonProperties(Profile &profile, const QString &compilerFilePath,
                                const QStringList &toolchainTypes, const QString &architecture)
{
    QFileInfo cfi(compilerFilePath);
    profile.setValue(QLatin1String("cpp.toolchainInstallPath"), cfi.absolutePath());
    profile.setValue(QLatin1String("cpp.compilerName"), cfi.fileName());
    profile.setValue(QLatin1String("qbs.toolchain"), toolchainTypes);
    profile.setValue(QLatin1String("qbs.architecture"),
                     HostOsInfo::canonicalArchitecture(architecture));
    profile.setValue(QLatin1String("qbs.endianness"),
                     HostOsInfo::defaultEndianness(architecture));
}

class ToolPathSetup
{
public:
    ToolPathSetup(Profile *profile, const QString &path, const QString &toolchainPrefix)
        : m_profile(profile), m_compilerDirPath(path), m_toolchainPrefix(toolchainPrefix)
    {
    }

    void apply(const QString &toolName, const QString &propertyName) const
    {
        QString toolFileName = m_toolchainPrefix + HostOsInfo::appendExecutableSuffix(toolName);
        if (QFile::exists(m_compilerDirPath + QLatin1Char('/') + toolFileName))
            return;
        const QString toolFilePath = findExecutable(toolFileName);
        if (toolFilePath.isEmpty()) {
            qWarning("%s", qPrintable(
                         QString(QLatin1String("'%1' exists neither in '%2' nor in PATH."))
                            .arg(toolFileName, m_compilerDirPath)));
        }
        m_profile->setValue(propertyName, toolFilePath);
    }

private:
    Profile * const m_profile;
    const QString &m_compilerDirPath;
    const QString &m_toolchainPrefix;
};

static Profile createGccProfile(const QString &_compilerFilePath, Settings *settings,
                                const QStringList &toolchainTypes,
                                const QString &profileName = QString())
{
    const QString compilerFilePath = actualCompilerFilePath(_compilerFilePath);
    const QString machineName = gccMachineName(compilerFilePath);
    const QStringList compilerTriplet = machineName.split(QLatin1Char('-'));
    const bool isMingw = toolchainTypes.contains(QLatin1String("mingw"));

    if (isMingw && !validMinGWMachines().contains(machineName)) {
        throw qbs::ErrorInfo(Tr::tr("Detected gcc platform '%1' is not supported.")
                .arg(machineName));
    } else if (compilerTriplet.count() < 2) {
        throw qbs::ErrorInfo(Tr::tr("Architecture of compiler for platform '%1' at '%2' not understood.")
                             .arg(machineName, compilerFilePath));
    }

    Profile profile(!profileName.isEmpty() ? profileName : machineName, settings);
    profile.removeProfile();
    if (isMingw) {
        profile.setValue(QLatin1String("qbs.targetOS"), QStringList(QLatin1String("windows")));
    }

    setCommonProperties(profile, compilerFilePath, toolchainTypes, compilerTriplet.first());
    const QString compilerName = QFileInfo(compilerFilePath).fileName();
    QString toolchainPrefix;
    if (compilerName.contains(QLatin1Char('-'))) {
        QStringList nameParts = compilerName.split(QLatin1Char('-'));
        profile.setValue(QLatin1String("cpp.compilerName"), nameParts.takeLast());
        toolchainPrefix = nameParts.join(QLatin1String("-")) + QLatin1Char('-');
        profile.setValue(QLatin1String("cpp.toolchainPrefix"), toolchainPrefix);
    }

    // Check whether auxiliary tools reside within the toolchain's install path.
    // This might not be the case when using icecc or another compiler wrapper.
    const QString compilerDirPath = QFileInfo(compilerFilePath).absolutePath();
    const ToolPathSetup toolPathSetup(&profile, compilerDirPath, toolchainPrefix);
    toolPathSetup.apply(QLatin1String("ar"), QLatin1String("cpp.archiverPath"));
    toolPathSetup.apply(QLatin1String("nm"), QLatin1String("cpp.nmPath"));

    qStdout << Tr::tr("Profile '%1' created for '%2'.").arg(profile.name(), compilerFilePath)
            << endl;
    return profile;
}

static void gccProbe(Settings *settings, QList<Profile> &profiles, const QString &compilerName)
{
    qStdout << Tr::tr("Trying to detect %1...").arg(compilerName) << endl;

    const QString crossCompilePrefix = QString::fromLocal8Bit(qgetenv("CROSS_COMPILE"));
    const QString compilerFilePath = findExecutable(crossCompilePrefix + compilerName);
    if (!QFileInfo(compilerFilePath).exists()) {
        qStderr << Tr::tr("%1 not found.").arg(compilerName) << endl;
        return;
    }
    const QString profileName = QFileInfo(compilerFilePath).completeBaseName();
    const QStringList toolchainTypes = toolchainTypeFromCompilerName(compilerName);
    profiles << createGccProfile(compilerFilePath, settings, toolchainTypes, profileName);
}

static void mingwProbe(Settings *settings, QList<Profile> &profiles)
{
    // List of possible compiler binary names for this platform
    QStringList compilerNames;
    if (HostOsInfo::isWindowsHost()) {
        compilerNames << QLatin1String("gcc");
    } else {
        foreach (const QString &machineName, validMinGWMachines()) {
            compilerNames << machineName + QLatin1String("-gcc");
        }
    }

    foreach (const QString &compilerName, compilerNames) {
        const QString gccPath
                = findExecutable(HostOsInfo::appendExecutableSuffix(compilerName));
        if (!gccPath.isEmpty())
            profiles << createGccProfile(gccPath, settings,
                                         completeToolchainList(QLatin1String("mingw")));
    }
}

void probe(Settings *settings)
{
    QList<Profile> profiles;
    if (HostOsInfo::isWindowsHost()) {
        msvcProbe(settings, profiles);
    } else {
        gccProbe(settings, profiles, QLatin1String("gcc"));
        gccProbe(settings, profiles, QLatin1String("clang"));

        if (HostOsInfo::isOsxHost()) {
            xcodeProbe(settings, profiles);
        }
    }

    mingwProbe(settings, profiles);

    if (profiles.isEmpty()) {
        qStderr << Tr::tr("Could not detect any toolchains. No profile created.") << endl;
    } else if (profiles.count() == 1 && settings->defaultProfile().isEmpty()) {
        const QString profileName = profiles.first().name();
        qStdout << Tr::tr("Making profile '%1' the default.").arg(profileName) << endl;
        settings->setValue(QLatin1String("defaultProfile"), profileName);
    }
}

void createProfile(const QString &profileName, const QString &toolchainType,
                   const QString &compilerFilePath, Settings *settings)
{
    QFileInfo compiler(compilerFilePath);
    if (compilerFilePath == compiler.fileName() && !compiler.exists())
        compiler = QFileInfo(findExecutable(compilerFilePath));

    if (!compiler.exists()) {
        throw qbs::ErrorInfo(Tr::tr("Compiler '%1' not found")
                             .arg(compilerFilePath));
    }

    QStringList toolchainTypes;
    if (toolchainType.isEmpty())
        toolchainTypes = toolchainTypeFromCompilerName(compiler.fileName());
    else
        toolchainTypes = completeToolchainList(toolchainType);

    if (toolchainTypes.contains(QLatin1String("msvc"))) {
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: MSVC toolchains can only be created "
                                    "via the auto-detection mechanism."));
    }

    if (toolchainTypes.contains(QLatin1String("gcc")))
        createGccProfile(compiler.absoluteFilePath(), settings, toolchainTypes, profileName);
    else
        throw qbs::ErrorInfo(Tr::tr("Cannot create profile: Unknown toolchain type."));
}
<|endoftext|>


<commit_before>//===- StrongPhiElimination.cpp - Eliminate PHI nodes by inserting copies -===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "strongphielim"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;

namespace {
class StrongPHIElimination : public MachineFunctionPass {
public:
  static char ID; // Pass identification, replacement for typeid
  StrongPHIElimination() : MachineFunctionPass(ID) {
    initializeStrongPHIEliminationPass(*PassRegistry::getPassRegistry());
  }

private:
  bool runOnMachineFunction(MachineFunction &Fn) {
    llvm_unreachable("Strong phi elimination is not implemented");
  }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.setPreservesCFG();
    AU.addRequired<MachineDominatorTree>();
    AU.addRequired<SlotIndexes>();
    AU.addPreserved<SlotIndexes>();
    AU.addRequired<LiveIntervals>();
    AU.addPreserved<LiveIntervals>();
    MachineFunctionPass::getAnalysisUsage(AU);
  }
};
} // namespace

char StrongPHIElimination::ID = 0;
INITIALIZE_PASS_BEGIN(StrongPHIElimination, "strong-phi-node-elimination",
  "Eliminate PHI nodes for register allocation, intelligently", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_DEPENDENCY(SlotIndexes)
INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
INITIALIZE_PASS_END(StrongPHIElimination, "strong-phi-node-elimination",
  "Eliminate PHI nodes for register allocation, intelligently", false, false)

char &llvm::StrongPHIEliminationID = StrongPHIElimination::ID;

<commit_msg>Some cleanup before I start committing some incremental progress on StrongPHIElimination.<commit_after>//===- StrongPhiElimination.cpp - Eliminate PHI nodes by inserting copies -===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "strongphielim"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;

namespace {
  class StrongPHIElimination : public MachineFunctionPass {
  public:
    static char ID; // Pass identification, replacement for typeid
    StrongPHIElimination() : MachineFunctionPass(ID) {
      initializeStrongPHIEliminationPass(*PassRegistry::getPassRegistry());
    }

    virtual void getAnalysisUsage(AnalysisUsage&) const;
    bool runOnMachineFunction(MachineFunction&);
  };
} // namespace

char StrongPHIElimination::ID = 0;
INITIALIZE_PASS_BEGIN(StrongPHIElimination, "strong-phi-node-elimination",
  "Eliminate PHI nodes for register allocation, intelligently", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_DEPENDENCY(SlotIndexes)
INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
INITIALIZE_PASS_END(StrongPHIElimination, "strong-phi-node-elimination",
  "Eliminate PHI nodes for register allocation, intelligently", false, false)

char &llvm::StrongPHIEliminationID = StrongPHIElimination::ID;

void StrongPHIElimination::getAnalysisUsage(AnalysisUsage& AU) const {
  AU.setPreservesCFG();
  AU.addRequired<MachineDominatorTree>();
  AU.addRequired<SlotIndexes>();
  AU.addPreserved<SlotIndexes>();
  AU.addRequired<LiveIntervals>();
  AU.addPreserved<LiveIntervals>();
  MachineFunctionPass::getAnalysisUsage(AU);
}

bool StrongPHIElimination::runOnMachineFunction(MachineFunction& Fn) {
  llvm_unreachable("Strong phi elimination is not implemented");
}
<|endoftext|>


<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <gtest/gtest.h>

#include <memory>

#include "SurgSim/DataStructures/PlyReader.h"
#include "SurgSim/Framework/Assert.h"
#include "SurgSim/Framework/Runtime.h"
#include "SurgSim/Framework/Timer.h"
#include "SurgSim/Math/Vector.h"
#include "SurgSim/Physics/Fem3DRepresentation.h"
#include "SurgSim/Physics/Fem3DRepresentationPlyReaderDelegate.h"
#include "SurgSim/Physics/FemElement3DCube.h"
#include "SurgSim/Testing/MockPhysicsManager.h"

using SurgSim::Math::Vector3d;

namespace
{
static const double dt = 0.001;
static const int frameCount = 100;
}

namespace SurgSim
{
namespace Physics
{

class DivisbleCubeRepresentation : public Fem3DRepresentation
{
public:
	/// Constructor
	/// \param name	The name of the truth cube representation.
	/// \param corners The 8 corners of the truth cube
	DivisbleCubeRepresentation(const std::string& name, unsigned int nodesPerAxis)
		: Fem3DRepresentation(name), m_numNodesPerAxis(nodesPerAxis)
	{
		// Compute the center point of the cube
		SurgSim::Math::Vector3d center = SurgSim::Math::Vector3d::Zero();

		// Compute the cube's corners for the Fem3d simulation
		double halfLength = static_cast<double>(nodesPerAxis);
		Vector3d X = Vector3d::UnitX();
		Vector3d Y = Vector3d::UnitY();
		Vector3d Z = Vector3d::UnitZ();
		m_cubeNodes[0] = center - halfLength * X - halfLength * Y - halfLength * Z;
		m_cubeNodes[1] = center + halfLength * X - halfLength * Y - halfLength * Z;
		m_cubeNodes[2] = center - halfLength * X + halfLength * Y - halfLength * Z;
		m_cubeNodes[3] = center + halfLength * X + halfLength * Y - halfLength * Z;
		m_cubeNodes[4] = center - halfLength * X - halfLength * Y + halfLength * Z;
		m_cubeNodes[5] = center + halfLength * X - halfLength * Y + halfLength * Z;
		m_cubeNodes[6] = center - halfLength * X + halfLength * Y + halfLength * Z;
		m_cubeNodes[7] = center + halfLength * X + halfLength * Y + halfLength * Z;

		auto initialState = std::make_shared<DeformableRepresentationState>();
		fillUpDeformableState(initialState);
		setInitialState(initialState);
		addFemCubes(initialState);
	}

protected:
	/// Convert an node index from a 3d indexing to a 1d indexing
	/// \param i, j, k Indices along the X, Y and Z axis
	/// \return Unique index of the corresponding point (to access a linear array for example)
	unsigned int get1DIndexFrom3D(unsigned int i, unsigned int j, unsigned int k)
	{
		return m_numNodesPerAxis * m_numNodesPerAxis * i + m_numNodesPerAxis * j + k;
	}

	/// Fills up a given deformable state with the truth cube nodes
	/// border nodes and internal nodes (i.e. the beads)
	/// \param[in,out] state	The deformable state to be filled up
	void fillUpDeformableState(std::shared_ptr<DeformableRepresentationState> state)
	{
		state->setNumDof(getNumDofPerNode(), m_numNodesPerAxis * m_numNodesPerAxis * m_numNodesPerAxis);
		SurgSim::Math::Vector& nodePositions = state->getPositions();

		for (unsigned int i = 0; i < m_numNodesPerAxis; i++)
		{
			// For a given index i, we intersect the cube with a (Y Z) plane, which defines a square on a (Y Z) plane
			Vector3d extremitiesX0[4] = {m_cubeNodes[0], m_cubeNodes[2], m_cubeNodes[4], m_cubeNodes[6]};
			Vector3d extremitiesX1[4] = {m_cubeNodes[1], m_cubeNodes[3], m_cubeNodes[5], m_cubeNodes[7]};
			Vector3d extremitiesXi[4];
			double coefI = static_cast<double>(i) / (static_cast<double>(m_numNodesPerAxis) - 1.0);

			for (int index = 0; index < 4; index++)
			{
				extremitiesXi[index] =
					extremitiesX0[index] * (1.0 - coefI) +
					extremitiesX1[index] *        coefI;
			}

			for (unsigned int j = 0; j < m_numNodesPerAxis; j++)
			{
				// For a given index j, we intersect the square with a (X Z) plane, which defines a line along (Z)
				Vector3d extremitiesY0[2] = {extremitiesXi[0], extremitiesXi[2]};
				Vector3d extremitiesY1[2] = {extremitiesXi[1], extremitiesXi[3]};
				Vector3d extremitiesYi[2];
				double coefJ = static_cast<double>(j) / (static_cast<double>(m_numNodesPerAxis) - 1.0);

				for (int index = 0; index < 2; index++)
				{
					extremitiesYi[index] =
						extremitiesY0[index] * (1.0 - coefJ) +
						extremitiesY1[index] *        coefJ;
				}

				for (unsigned int k = 0; k < m_numNodesPerAxis; k++)
				{
					// For a given index k, we intersect the line with a (X Y) plane, which defines a 3d point
					double coefK = static_cast<double>(k) / (static_cast<double>(m_numNodesPerAxis) - 1.0);
					Vector3d position3d = extremitiesYi[0] * (1.0 - coefK) + extremitiesYi[1] * coefK;
					SurgSim::Math::setSubVector(position3d, get1DIndexFrom3D(i, j, k), 3, &nodePositions);
				}
			}
		}
	}

	/// Adds the Fem3D elements of small cubes
	/// \param state	The deformable state for initialization.
	void addFemCubes(std::shared_ptr<DeformableRepresentationState> state)
	{
		for (unsigned int i = 0; i < m_numNodesPerAxis - 1; i++)
		{
			for (unsigned int j = 0; j < m_numNodesPerAxis - 1; j++)
			{
				for (unsigned int k = 0; k < m_numNodesPerAxis - 1; k++)
				{
					std::array<unsigned int, 8> cubeNodeIds;
					cubeNodeIds[0] = get1DIndexFrom3D(i  , j  , k  );
					cubeNodeIds[1] = get1DIndexFrom3D(i+1, j  , k  );
					cubeNodeIds[2] = get1DIndexFrom3D(i  , j+1, k  );
					cubeNodeIds[3] = get1DIndexFrom3D(i+1, j+1, k  );
					cubeNodeIds[4] = get1DIndexFrom3D(i  , j  , k+1);
					cubeNodeIds[5] = get1DIndexFrom3D(i+1, j  , k+1);
					cubeNodeIds[6] = get1DIndexFrom3D(i  , j+1, k+1);
					cubeNodeIds[7] = get1DIndexFrom3D(i+1, j+1, k+1);

					std::array<unsigned int, 8> cube = {
						cubeNodeIds[0], cubeNodeIds[1], cubeNodeIds[3], cubeNodeIds[2],
						cubeNodeIds[4], cubeNodeIds[5], cubeNodeIds[7], cubeNodeIds[6]};

					// Add FemElement3DCube for each cube
					std::shared_ptr<FemElement3DCube> femElement = std::make_shared<FemElement3DCube>(cube, *state);
					femElement->setMassDensity(980.0);   // 0.98 g/cm^-3 (2-part silicone rubber a.k.a. RTV6166)
					femElement->setPoissonRatio(0.499);  // From the paper (near 0.5)
					femElement->setYoungModulus(15.3e3); // 15.3 kPa (From the paper)
					femElement->initialize(*state);
					addFemElement(femElement);
				}
			}
		}
	}

private:
	// Number of point per dimensions
	unsigned int m_numNodesPerAxis;

	// Nodes of the original truth cube
	std::array<SurgSim::Math::Vector3d, 8> m_cubeNodes;
};

class Fem3DPerformanceTest : public ::testing::Test
{
public:
	virtual void SetUp()
	{
		m_physicsManager = std::make_shared<SurgSim::Testing::MockPhysicsManager>();

		m_physicsManager->doInitialize();
		m_physicsManager->doStartUp();
	}

	void initializeRepresentation(std::shared_ptr<Fem3DRepresentation> fem)
	{
		fem->initialize(std::make_shared<SurgSim::Framework::Runtime>());
		m_physicsManager->executeAdditions(fem);
	}

	void performTimingTest()
	{
		SurgSim::Framework::Timer totalTime;
		totalTime.beginFrame();

		SurgSim::Framework::Timer timer;
		timer.setMaxNumberOfFrames(frameCount);
		for (int i = 0; i < frameCount; i++)
		{
			timer.beginFrame();
			m_physicsManager->doUpdate(dt);
			timer.endFrame();
		}

		totalTime.endFrame();
		RecordProperty("Duration", boost::to_string(totalTime.getCumulativeTime()));
		RecordProperty("FrameRate", boost::to_string(timer.getAverageFrameRate()));
	}

protected:
	std::shared_ptr<SurgSim::Testing::MockPhysicsManager> m_physicsManager;
};

TEST_F(Fem3DPerformanceTest, WoundTest)
{
	auto fem = std::make_shared<SurgSim::Physics::Fem3DRepresentation>("wound");
	fem->setFilename("Data/Fem3DPerformanceTest/wound_deformable.ply");
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube2Test)
{
	static const int numCubes = 2;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube3Test)
{
	static const int numCubes = 3;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube4Test)
{
	static const int numCubes = 4;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube5Test)
{
	static const int numCubes = 5;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube6Test)
{
	static const int numCubes = 6;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube7Test)
{
	static const int numCubes = 7;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube8Test)
{
	static const int numCubes = 8;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube9Test)
{
	static const int numCubes = 9;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube10Test)
{
	static const int numCubes = 10;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube11Test)
{
	static const int numCubes = 11;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube12Test)
{
	static const int numCubes = 12;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

} // namespace Physics
} // namespace SurgSim
<commit_msg>Fem3DPerformanceTest, remove mention of truth cube<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <gtest/gtest.h>

#include <memory>

#include "SurgSim/DataStructures/PlyReader.h"
#include "SurgSim/Framework/Assert.h"
#include "SurgSim/Framework/Runtime.h"
#include "SurgSim/Framework/Timer.h"
#include "SurgSim/Math/Vector.h"
#include "SurgSim/Physics/Fem3DRepresentation.h"
#include "SurgSim/Physics/Fem3DRepresentationPlyReaderDelegate.h"
#include "SurgSim/Physics/FemElement3DCube.h"
#include "SurgSim/Testing/MockPhysicsManager.h"

using SurgSim::Math::Vector3d;

namespace
{
static const double dt = 0.001;
static const int frameCount = 100;
}

namespace SurgSim
{
namespace Physics
{

class DivisbleCubeRepresentation : public Fem3DRepresentation
{
public:
	/// Constructor
	/// \param name	The name of the divisible cube representation.
	/// \param corners The 8 corners of the divisible cube
	DivisbleCubeRepresentation(const std::string& name, unsigned int nodesPerAxis)
		: Fem3DRepresentation(name), m_numNodesPerAxis(nodesPerAxis)
	{
		// Compute the center point of the cube
		SurgSim::Math::Vector3d center = SurgSim::Math::Vector3d::Zero();

		// Compute the cube's corners for the Fem3d simulation
		double halfLength = static_cast<double>(nodesPerAxis);
		Vector3d X = Vector3d::UnitX();
		Vector3d Y = Vector3d::UnitY();
		Vector3d Z = Vector3d::UnitZ();
		m_cubeNodes[0] = center - halfLength * X - halfLength * Y - halfLength * Z;
		m_cubeNodes[1] = center + halfLength * X - halfLength * Y - halfLength * Z;
		m_cubeNodes[2] = center - halfLength * X + halfLength * Y - halfLength * Z;
		m_cubeNodes[3] = center + halfLength * X + halfLength * Y - halfLength * Z;
		m_cubeNodes[4] = center - halfLength * X - halfLength * Y + halfLength * Z;
		m_cubeNodes[5] = center + halfLength * X - halfLength * Y + halfLength * Z;
		m_cubeNodes[6] = center - halfLength * X + halfLength * Y + halfLength * Z;
		m_cubeNodes[7] = center + halfLength * X + halfLength * Y + halfLength * Z;

		auto initialState = std::make_shared<DeformableRepresentationState>();
		fillUpDeformableState(initialState);
		setInitialState(initialState);
		addFemCubes(initialState);
	}

protected:
	/// Convert an node index from a 3d indexing to a 1d indexing
	/// \param i, j, k Indices along the X, Y and Z axis
	/// \return Unique index of the corresponding point (to access a linear array for example)
	unsigned int get1DIndexFrom3D(unsigned int i, unsigned int j, unsigned int k)
	{
		return m_numNodesPerAxis * m_numNodesPerAxis * i + m_numNodesPerAxis * j + k;
	}

	/// Fills up a given deformable state with the cube's nodes
	/// border nodes and internal nodes (i.e. the beads)
	/// \param[in,out] state	The deformable state to be filled up
	void fillUpDeformableState(std::shared_ptr<DeformableRepresentationState> state)
	{
		state->setNumDof(getNumDofPerNode(), m_numNodesPerAxis * m_numNodesPerAxis * m_numNodesPerAxis);
		SurgSim::Math::Vector& nodePositions = state->getPositions();

		for (unsigned int i = 0; i < m_numNodesPerAxis; i++)
		{
			// For a given index i, we intersect the cube with a (Y Z) plane, which defines a square on a (Y Z) plane
			Vector3d extremitiesX0[4] = {m_cubeNodes[0], m_cubeNodes[2], m_cubeNodes[4], m_cubeNodes[6]};
			Vector3d extremitiesX1[4] = {m_cubeNodes[1], m_cubeNodes[3], m_cubeNodes[5], m_cubeNodes[7]};
			Vector3d extremitiesXi[4];
			double coefI = static_cast<double>(i) / (static_cast<double>(m_numNodesPerAxis) - 1.0);

			for (int index = 0; index < 4; index++)
			{
				extremitiesXi[index] =
					extremitiesX0[index] * (1.0 - coefI) +
					extremitiesX1[index] *        coefI;
			}

			for (unsigned int j = 0; j < m_numNodesPerAxis; j++)
			{
				// For a given index j, we intersect the square with a (X Z) plane, which defines a line along (Z)
				Vector3d extremitiesY0[2] = {extremitiesXi[0], extremitiesXi[2]};
				Vector3d extremitiesY1[2] = {extremitiesXi[1], extremitiesXi[3]};
				Vector3d extremitiesYi[2];
				double coefJ = static_cast<double>(j) / (static_cast<double>(m_numNodesPerAxis) - 1.0);

				for (int index = 0; index < 2; index++)
				{
					extremitiesYi[index] =
						extremitiesY0[index] * (1.0 - coefJ) +
						extremitiesY1[index] *        coefJ;
				}

				for (unsigned int k = 0; k < m_numNodesPerAxis; k++)
				{
					// For a given index k, we intersect the line with a (X Y) plane, which defines a 3d point
					double coefK = static_cast<double>(k) / (static_cast<double>(m_numNodesPerAxis) - 1.0);
					Vector3d position3d = extremitiesYi[0] * (1.0 - coefK) + extremitiesYi[1] * coefK;
					SurgSim::Math::setSubVector(position3d, get1DIndexFrom3D(i, j, k), 3, &nodePositions);
				}
			}
		}
	}

	/// Adds the Fem3D elements of small cubes
	/// \param state	The deformable state for initialization.
	void addFemCubes(std::shared_ptr<DeformableRepresentationState> state)
	{
		for (unsigned int i = 0; i < m_numNodesPerAxis - 1; i++)
		{
			for (unsigned int j = 0; j < m_numNodesPerAxis - 1; j++)
			{
				for (unsigned int k = 0; k < m_numNodesPerAxis - 1; k++)
				{
					std::array<unsigned int, 8> cubeNodeIds;
					cubeNodeIds[0] = get1DIndexFrom3D(i  , j  , k  );
					cubeNodeIds[1] = get1DIndexFrom3D(i+1, j  , k  );
					cubeNodeIds[2] = get1DIndexFrom3D(i  , j+1, k  );
					cubeNodeIds[3] = get1DIndexFrom3D(i+1, j+1, k  );
					cubeNodeIds[4] = get1DIndexFrom3D(i  , j  , k+1);
					cubeNodeIds[5] = get1DIndexFrom3D(i+1, j  , k+1);
					cubeNodeIds[6] = get1DIndexFrom3D(i  , j+1, k+1);
					cubeNodeIds[7] = get1DIndexFrom3D(i+1, j+1, k+1);

					std::array<unsigned int, 8> cube = {
						cubeNodeIds[0], cubeNodeIds[1], cubeNodeIds[3], cubeNodeIds[2],
						cubeNodeIds[4], cubeNodeIds[5], cubeNodeIds[7], cubeNodeIds[6]};

					// Add FemElement3DCube for each cube
					std::shared_ptr<FemElement3DCube> femElement = std::make_shared<FemElement3DCube>(cube, *state);
					femElement->setMassDensity(980.0);   // 0.98 g/cm^-3 (2-part silicone rubber a.k.a. RTV6166)
					femElement->setPoissonRatio(0.499);  // From the paper (near 0.5)
					femElement->setYoungModulus(15.3e3); // 15.3 kPa (From the paper)
					femElement->initialize(*state);
					addFemElement(femElement);
				}
			}
		}
	}

private:
	// Number of point per dimensions
	unsigned int m_numNodesPerAxis;

	// Corner nodes of the original cube
	std::array<SurgSim::Math::Vector3d, 8> m_cubeNodes;
};

class Fem3DPerformanceTest : public ::testing::Test
{
public:
	virtual void SetUp()
	{
		m_physicsManager = std::make_shared<SurgSim::Testing::MockPhysicsManager>();

		m_physicsManager->doInitialize();
		m_physicsManager->doStartUp();
	}

	void initializeRepresentation(std::shared_ptr<Fem3DRepresentation> fem)
	{
		fem->initialize(std::make_shared<SurgSim::Framework::Runtime>());
		m_physicsManager->executeAdditions(fem);
	}

	void performTimingTest()
	{
		SurgSim::Framework::Timer totalTime;
		totalTime.beginFrame();

		SurgSim::Framework::Timer timer;
		timer.setMaxNumberOfFrames(frameCount);
		for (int i = 0; i < frameCount; i++)
		{
			timer.beginFrame();
			m_physicsManager->doUpdate(dt);
			timer.endFrame();
		}

		totalTime.endFrame();
		RecordProperty("Duration", boost::to_string(totalTime.getCumulativeTime()));
		RecordProperty("FrameRate", boost::to_string(timer.getAverageFrameRate()));
	}

protected:
	std::shared_ptr<SurgSim::Testing::MockPhysicsManager> m_physicsManager;
};

TEST_F(Fem3DPerformanceTest, WoundTest)
{
	auto fem = std::make_shared<SurgSim::Physics::Fem3DRepresentation>("wound");
	fem->setFilename("Data/Fem3DPerformanceTest/wound_deformable.ply");
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube2Test)
{
	static const int numCubes = 2;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube3Test)
{
	static const int numCubes = 3;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube4Test)
{
	static const int numCubes = 4;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube5Test)
{
	static const int numCubes = 5;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube6Test)
{
	static const int numCubes = 6;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube7Test)
{
	static const int numCubes = 7;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube8Test)
{
	static const int numCubes = 8;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube9Test)
{
	static const int numCubes = 9;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube10Test)
{
	static const int numCubes = 10;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube11Test)
{
	static const int numCubes = 11;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

TEST_F(Fem3DPerformanceTest, Cube12Test)
{
	static const int numCubes = 12;
	auto fem = std::make_shared<DivisbleCubeRepresentation>("cube", numCubes);
	fem->setIntegrationScheme(SurgSim::Math::INTEGRATIONSCHEME_IMPLICIT_EULER);

	initializeRepresentation(fem);
	performTimingTest();
}

} // namespace Physics
} // namespace SurgSim
<|endoftext|>


<commit_before>//===- AsmMatcherEmitter.cpp - Generate an assembly matcher ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend emits a target specifier matcher for converting parsed
// assembly operands in the MCInst structures.
//
//===----------------------------------------------------------------------===//

#include "AsmMatcherEmitter.h"
#include "CodeGenTarget.h"
#include "Record.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Debug.h"
#include <set>
#include <list>
using namespace llvm;

/// FlattenVariants - Flatten an .td file assembly string by selecting the
/// variant at index \arg N.
static std::string FlattenVariants(const std::string &AsmString,
                                   unsigned N) {
  StringRef Cur = AsmString;
  std::string Res = "";

  for (;;) {
    // Add the prefix until the next '{', and split out the contents in the
    // braces.
    std::pair<StringRef, StringRef> Inner, Split = Cur.split('{');

    Res += Split.first;
    if (Split.second.empty())
      break;

    Inner = Split.second.split('}');

    // Select the Nth variant (or empty).
    StringRef Selection = Inner.first;
    for (unsigned i = 0; i != N; ++i)
      Selection = Selection.split('|').second;
    Res += Selection.split('|').first;

    Cur = Inner.second;
  }

  return Res;
}

/// TokenizeAsmString - Tokenize a simplified assembly string.
static void TokenizeAsmString(const std::string &AsmString,
                              SmallVectorImpl<StringRef> &Tokens) {
  unsigned Prev = 0;
  bool InTok = true;
  for (unsigned i = 0, e = AsmString.size(); i != e; ++i) {
    switch (AsmString[i]) {
    case '*':
    case '!':
    case ' ':
    case '\t':
    case ',':
      if (InTok) {
        Tokens.push_back(StringRef(&AsmString[Prev], i - Prev));
        InTok = false;
      }
      if (AsmString[i] == '*' || AsmString[i] == '!')
        Tokens.push_back(StringRef(&AsmString[i], 1));
      Prev = i + 1;
      break;

    default:
      InTok = true;
    }
  }
  if (InTok && Prev != AsmString.size())
    Tokens.push_back(StringRef(&AsmString[Prev], AsmString.size() - Prev));
}

void AsmMatcherEmitter::run(raw_ostream &OS) {
  CodeGenTarget Target;
  const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
  Record *AsmParser = Target.getAsmParser();
  std::string ClassName = AsmParser->getValueAsString("AsmParserClassName");

  std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace");

  EmitSourceFileHeader("Assembly Matcher Source Fragment", OS);

  // Emit the function to match a register name to number.

  OS << "bool " << Target.getName() << ClassName
     << "::MatchRegisterName(const StringRef &Name, unsigned &RegNo) {\n";

  // FIXME: TableGen should have a fast string matcher generator.
  for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
    const CodeGenRegister &Reg = Registers[i];
    if (Reg.TheDef->getValueAsString("AsmName").empty())
      continue;

    OS << "  if (Name == \""
       << Reg.TheDef->getValueAsString("AsmName") << "\")\n"
       << "    return RegNo=" << i + 1 << ", false;\n";
  }
  OS << "  return true;\n";
  OS << "}\n";

  // Emit the function to match instructions.
  std::vector<const CodeGenInstruction*> NumberedInstructions;
  Target.getInstructionsByEnumValue(NumberedInstructions);

  std::list<std::string> MatchFns;

  OS << "\n";
  const std::map<std::string, CodeGenInstruction> &Instructions =
    Target.getInstructions();
  for (std::map<std::string, CodeGenInstruction>::const_iterator
         it = Instructions.begin(), ie = Instructions.end(); it != ie; ++it) {
    const CodeGenInstruction &CGI = it->second;

    // Ignore psuedo ops.
    //
    // FIXME: This is a hack.
    if (const RecordVal *Form = CGI.TheDef->getValue("Form"))
      if (Form->getValue()->getAsString() == "Pseudo")
        continue;

    // Ignore instructions with no .s string.
    //
    // FIXME: What are these?
    if (CGI.AsmString.empty())
      continue;

    // FIXME: Hack; ignore "lock".
    if (StringRef(CGI.AsmString).startswith("lock"))
      continue;

    // FIXME: Hack.
#if 0
    if (1 && it->first != "SUB8mr")
      continue;
#endif

    std::string Flattened = FlattenVariants(CGI.AsmString, 0);
    SmallVector<StringRef, 8> Tokens;

    TokenizeAsmString(Flattened, Tokens);

    DEBUG({
        outs() << it->first << " -- flattened:\""
               << Flattened << "\", tokens:[";
        for (unsigned i = 0, e = Tokens.size(); i != e; ++i) {
          outs() << Tokens[i];
          if (i + 1 != e)
            outs() << ", ";
        }
        outs() << "]\n";

        for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
          const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i];
          outs() << "  op[" << i << "] = " << OI.Name
                 << " " << OI.Rec->getName()
                 << " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n";
        }
      });

    // FIXME: Ignore non-literal tokens.
    if (std::find(Tokens[0].begin(), Tokens[0].end(), '$') != Tokens[0].end())
      continue;

    std::string FnName = "Match_" + Target.getName() + "_Inst_" + it->first;
    MatchFns.push_back(FnName);

    OS << "static bool " << FnName
       << "(const StringRef &Name,"
       << " SmallVectorImpl<X86Operand> &Operands,"
       << " MCInst &Inst) {\n\n";

    OS << "  // Match name.\n";
    OS << "  if (Name != \"" << Tokens[0] << "\")\n";
    OS << "    return true;\n\n";

    OS << "  // Match number of operands.\n";
    OS << "  if (Operands.size() != " << Tokens.size() - 1 << ")\n";
    OS << "    return true;\n\n";

    // Compute the total number of MCOperands.
    //
    // FIXME: Isn't this somewhere else?
    unsigned NumMIOperands = 0;
    for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
      const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i];
      NumMIOperands = std::max(NumMIOperands,
                               OI.MIOperandNo + OI.MINumOperands);
    }

    std::set<unsigned> MatchedOperands;
    // This the list of operands we need to fill in.
    if (NumMIOperands)
      OS << "  MCOperand Ops[" << NumMIOperands << "];\n\n";

    unsigned ParsedOpIdx = 0;
    for (unsigned i = 1, e = Tokens.size(); i < e; ++i) {
      // FIXME: Can only match simple operands.
      if (Tokens[i][0] != '$') {
        OS << "  // FIXME: unable to match token: '" << Tokens[i] << "'!\n";
        OS << "  return true;\n\n";
        continue;
      }

      // Map this token to an operand. FIXME: Move elsewhere.

      unsigned Idx;
      try {
        Idx = CGI.getOperandNamed(Tokens[i].substr(1));
      } catch(...) {
        OS << "  // FIXME: unable to find operand: '" << Tokens[i] << "'!\n";
        OS << "  return true;\n\n";
        continue;
      }

      // FIXME: Each match routine should always end up filling the same number
      // of operands, we should just check that the number matches what the
      // match routine expects here instead of passing it. We can do this once
      // we start generating the class match functions.
      const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[Idx];

      // Track that we have matched these operands.
      //
      // FIXME: Verify that we don't parse something to the same operand twice.
      for (unsigned j = 0; j != OI.MINumOperands; ++j)
        MatchedOperands.insert(OI.MIOperandNo + j);

      OS << "  // Match '" << Tokens[i] << "' (parsed operand " << ParsedOpIdx
         << ") to machine operands [" << OI.MIOperandNo << ", "
         << OI.MIOperandNo + OI.MINumOperands << ").\n";
      OS << "  if (Match_" << Target.getName()
         << "_Op_" << OI.Rec->getName()  << "("
         << "Operands[" << ParsedOpIdx << "], "
         << "&Ops[" << OI.MIOperandNo << "], "
         << OI.MINumOperands << "))\n";
      OS << "    return true;\n\n";

      ++ParsedOpIdx;
    }

    // Generate code to construct the MCInst.

    OS << "  // Construct MCInst.\n";
    OS << "  Inst.setOpcode(" << Target.getName() << "::"
       << it->first << ");\n";
    for (unsigned i = 0, e = NumMIOperands; i != e; ++i) {
      // FIXME: Oops! Ignore this for now, the instruction should print ok. If
      // we need to evaluate the constraints.
      if (!MatchedOperands.count(i)) {
        OS << "\n";
        OS << "  // FIXME: Nothing matched Ops[" << i << "]!\n";
        OS << "  Ops[" << i << "].MakeReg(0);\n";
        OS << "\n";
      }

      OS << "  Inst.addOperand(Ops[" << i << "]);\n";
    }
    OS << "\n";
    OS << "  return false;\n";
    OS << "}\n\n";
  }

  // Generate the top level match function.

  OS << "bool " << Target.getName() << ClassName
     << "::MatchInstruction(const StringRef &Name, "
     << "SmallVectorImpl<" << Target.getName() << "Operand> &Operands, "
     << "MCInst &Inst) {\n";
  for (std::list<std::string>::iterator it = MatchFns.begin(),
         ie = MatchFns.end(); it != ie; ++it) {
    OS << "  if (!" << *it << "(Name, Operands, Inst))\n";
    OS << "    return false;\n\n";
  }

  OS << "  return true;\n";
  OS << "}\n\n";
}
<commit_msg>Change MCOperand to use Create style instead of Make style for constructing operands.<commit_after>//===- AsmMatcherEmitter.cpp - Generate an assembly matcher ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend emits a target specifier matcher for converting parsed
// assembly operands in the MCInst structures.
//
//===----------------------------------------------------------------------===//

#include "AsmMatcherEmitter.h"
#include "CodeGenTarget.h"
#include "Record.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Debug.h"
#include <set>
#include <list>
using namespace llvm;

/// FlattenVariants - Flatten an .td file assembly string by selecting the
/// variant at index \arg N.
static std::string FlattenVariants(const std::string &AsmString,
                                   unsigned N) {
  StringRef Cur = AsmString;
  std::string Res = "";

  for (;;) {
    // Add the prefix until the next '{', and split out the contents in the
    // braces.
    std::pair<StringRef, StringRef> Inner, Split = Cur.split('{');

    Res += Split.first;
    if (Split.second.empty())
      break;

    Inner = Split.second.split('}');

    // Select the Nth variant (or empty).
    StringRef Selection = Inner.first;
    for (unsigned i = 0; i != N; ++i)
      Selection = Selection.split('|').second;
    Res += Selection.split('|').first;

    Cur = Inner.second;
  }

  return Res;
}

/// TokenizeAsmString - Tokenize a simplified assembly string.
static void TokenizeAsmString(const std::string &AsmString,
                              SmallVectorImpl<StringRef> &Tokens) {
  unsigned Prev = 0;
  bool InTok = true;
  for (unsigned i = 0, e = AsmString.size(); i != e; ++i) {
    switch (AsmString[i]) {
    case '*':
    case '!':
    case ' ':
    case '\t':
    case ',':
      if (InTok) {
        Tokens.push_back(StringRef(&AsmString[Prev], i - Prev));
        InTok = false;
      }
      if (AsmString[i] == '*' || AsmString[i] == '!')
        Tokens.push_back(StringRef(&AsmString[i], 1));
      Prev = i + 1;
      break;

    default:
      InTok = true;
    }
  }
  if (InTok && Prev != AsmString.size())
    Tokens.push_back(StringRef(&AsmString[Prev], AsmString.size() - Prev));
}

void AsmMatcherEmitter::run(raw_ostream &OS) {
  CodeGenTarget Target;
  const std::vector<CodeGenRegister> &Registers = Target.getRegisters();
  Record *AsmParser = Target.getAsmParser();
  std::string ClassName = AsmParser->getValueAsString("AsmParserClassName");

  std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace");

  EmitSourceFileHeader("Assembly Matcher Source Fragment", OS);

  // Emit the function to match a register name to number.

  OS << "bool " << Target.getName() << ClassName
     << "::MatchRegisterName(const StringRef &Name, unsigned &RegNo) {\n";

  // FIXME: TableGen should have a fast string matcher generator.
  for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
    const CodeGenRegister &Reg = Registers[i];
    if (Reg.TheDef->getValueAsString("AsmName").empty())
      continue;

    OS << "  if (Name == \""
       << Reg.TheDef->getValueAsString("AsmName") << "\")\n"
       << "    return RegNo=" << i + 1 << ", false;\n";
  }
  OS << "  return true;\n";
  OS << "}\n";

  // Emit the function to match instructions.
  std::vector<const CodeGenInstruction*> NumberedInstructions;
  Target.getInstructionsByEnumValue(NumberedInstructions);

  std::list<std::string> MatchFns;

  OS << "\n";
  const std::map<std::string, CodeGenInstruction> &Instructions =
    Target.getInstructions();
  for (std::map<std::string, CodeGenInstruction>::const_iterator
         it = Instructions.begin(), ie = Instructions.end(); it != ie; ++it) {
    const CodeGenInstruction &CGI = it->second;

    // Ignore psuedo ops.
    //
    // FIXME: This is a hack.
    if (const RecordVal *Form = CGI.TheDef->getValue("Form"))
      if (Form->getValue()->getAsString() == "Pseudo")
        continue;

    // Ignore instructions with no .s string.
    //
    // FIXME: What are these?
    if (CGI.AsmString.empty())
      continue;

    // FIXME: Hack; ignore "lock".
    if (StringRef(CGI.AsmString).startswith("lock"))
      continue;

    // FIXME: Hack.
#if 0
    if (1 && it->first != "SUB8mr")
      continue;
#endif

    std::string Flattened = FlattenVariants(CGI.AsmString, 0);
    SmallVector<StringRef, 8> Tokens;

    TokenizeAsmString(Flattened, Tokens);

    DEBUG({
        outs() << it->first << " -- flattened:\""
               << Flattened << "\", tokens:[";
        for (unsigned i = 0, e = Tokens.size(); i != e; ++i) {
          outs() << Tokens[i];
          if (i + 1 != e)
            outs() << ", ";
        }
        outs() << "]\n";

        for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
          const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i];
          outs() << "  op[" << i << "] = " << OI.Name
                 << " " << OI.Rec->getName()
                 << " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n";
        }
      });

    // FIXME: Ignore non-literal tokens.
    if (std::find(Tokens[0].begin(), Tokens[0].end(), '$') != Tokens[0].end())
      continue;

    std::string FnName = "Match_" + Target.getName() + "_Inst_" + it->first;
    MatchFns.push_back(FnName);

    OS << "static bool " << FnName
       << "(const StringRef &Name,"
       << " SmallVectorImpl<X86Operand> &Operands,"
       << " MCInst &Inst) {\n\n";

    OS << "  // Match name.\n";
    OS << "  if (Name != \"" << Tokens[0] << "\")\n";
    OS << "    return true;\n\n";

    OS << "  // Match number of operands.\n";
    OS << "  if (Operands.size() != " << Tokens.size() - 1 << ")\n";
    OS << "    return true;\n\n";

    // Compute the total number of MCOperands.
    //
    // FIXME: Isn't this somewhere else?
    unsigned NumMIOperands = 0;
    for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) {
      const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[i];
      NumMIOperands = std::max(NumMIOperands,
                               OI.MIOperandNo + OI.MINumOperands);
    }

    std::set<unsigned> MatchedOperands;
    // This the list of operands we need to fill in.
    if (NumMIOperands)
      OS << "  MCOperand Ops[" << NumMIOperands << "];\n\n";

    unsigned ParsedOpIdx = 0;
    for (unsigned i = 1, e = Tokens.size(); i < e; ++i) {
      // FIXME: Can only match simple operands.
      if (Tokens[i][0] != '$') {
        OS << "  // FIXME: unable to match token: '" << Tokens[i] << "'!\n";
        OS << "  return true;\n\n";
        continue;
      }

      // Map this token to an operand. FIXME: Move elsewhere.

      unsigned Idx;
      try {
        Idx = CGI.getOperandNamed(Tokens[i].substr(1));
      } catch(...) {
        OS << "  // FIXME: unable to find operand: '" << Tokens[i] << "'!\n";
        OS << "  return true;\n\n";
        continue;
      }

      // FIXME: Each match routine should always end up filling the same number
      // of operands, we should just check that the number matches what the
      // match routine expects here instead of passing it. We can do this once
      // we start generating the class match functions.
      const CodeGenInstruction::OperandInfo &OI = CGI.OperandList[Idx];

      // Track that we have matched these operands.
      //
      // FIXME: Verify that we don't parse something to the same operand twice.
      for (unsigned j = 0; j != OI.MINumOperands; ++j)
        MatchedOperands.insert(OI.MIOperandNo + j);

      OS << "  // Match '" << Tokens[i] << "' (parsed operand " << ParsedOpIdx
         << ") to machine operands [" << OI.MIOperandNo << ", "
         << OI.MIOperandNo + OI.MINumOperands << ").\n";
      OS << "  if (Match_" << Target.getName()
         << "_Op_" << OI.Rec->getName()  << "("
         << "Operands[" << ParsedOpIdx << "], "
         << "&Ops[" << OI.MIOperandNo << "], "
         << OI.MINumOperands << "))\n";
      OS << "    return true;\n\n";

      ++ParsedOpIdx;
    }

    // Generate code to construct the MCInst.

    OS << "  // Construct MCInst.\n";
    OS << "  Inst.setOpcode(" << Target.getName() << "::"
       << it->first << ");\n";
    for (unsigned i = 0, e = NumMIOperands; i != e; ++i) {
      // FIXME: Oops! Ignore this for now, the instruction should print ok. If
      // we need to evaluate the constraints.
      if (!MatchedOperands.count(i)) {
        OS << "\n";
        OS << "  // FIXME: Nothing matched Ops[" << i << "]!\n";
        OS << "  Ops[" << i << "] = MCOperand::CreateReg(0);\n";
        OS << "\n";
      }

      OS << "  Inst.addOperand(Ops[" << i << "]);\n";
    }
    OS << "\n";
    OS << "  return false;\n";
    OS << "}\n\n";
  }

  // Generate the top level match function.

  OS << "bool " << Target.getName() << ClassName
     << "::MatchInstruction(const StringRef &Name, "
     << "SmallVectorImpl<" << Target.getName() << "Operand> &Operands, "
     << "MCInst &Inst) {\n";
  for (std::list<std::string>::iterator it = MatchFns.begin(),
         ie = MatchFns.end(); it != ie; ++it) {
    OS << "  if (!" << *it << "(Name, Operands, Inst))\n";
    OS << "    return false;\n\n";
  }

  OS << "  return true;\n";
  OS << "}\n\n";
}
<|endoftext|>