diff options
77 files changed, 5029 insertions, 0 deletions
diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h index b6c8193f89e..5d584f4fe6c 100644 --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -38,6 +38,7 @@ public:      alpha,   // alpha      arm,     // arm, armv.* +    bfin,    // blackfin      cellspu, // spu, cellspu      mips,    // mips, mipsallegrex      mipsel,  // mipsel, mipsallegrexel, psp diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp index af372e2da6e..391c98656df 100644 --- a/llvm/lib/Support/Triple.cpp +++ b/llvm/lib/Support/Triple.cpp @@ -23,6 +23,7 @@ const char *Triple::getArchTypeName(ArchType Kind) {    case alpha:   return "alpha";    case arm:     return "arm"; +  case bfin:    return "bfin";    case cellspu: return "cellspu";    case mips:    return "mips";    case mipsel:  return "mipsel"; @@ -107,6 +108,8 @@ void Triple::Parse() const {      Arch = sparc;    else if (ArchName == "s390x")      Arch = systemz; +  else if (ArchName == "bfin") +    Arch = bfin;    else      Arch = UnknownArch; diff --git a/llvm/lib/Target/Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp b/llvm/lib/Target/Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp new file mode 100644 index 00000000000..60744ddfff2 --- /dev/null +++ b/llvm/lib/Target/Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp @@ -0,0 +1,237 @@ +//===-- BlackfinAsmPrinter.cpp - Blackfin LLVM assembly writer ------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to GAS-format BLACKFIN assembly language. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "Blackfin.h" +#include "BlackfinInstrInfo.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DwarfWriter.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Support/Mangler.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/FormattedStream.h" + +using namespace llvm; + +STATISTIC(EmittedInsts, "Number of machine instrs printed"); + +namespace { +  class VISIBILITY_HIDDEN BlackfinAsmPrinter : public AsmPrinter { +  public: +    BlackfinAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, +                       const TargetAsmInfo *TAI, bool V) +      : AsmPrinter(O, TM, TAI, V) {} + +    virtual const char *getPassName() const { +      return "Blackfin Assembly Printer"; +    } + +    void printOperand(const MachineInstr *MI, int opNum); +    void printMemoryOperand(const MachineInstr *MI, int opNum); +    bool printInstruction(const MachineInstr *MI);  // autogenerated. +    void emitLinkage(const std::string &n, GlobalValue::LinkageTypes l); +    bool runOnMachineFunction(MachineFunction &F); +    bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, +                         unsigned AsmVariant, const char *ExtraCode); +    bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, +                               unsigned AsmVariant, const char *ExtraCode); +    void PrintGlobalVariable(const GlobalVariable* GVar); +  }; +} // end of anonymous namespace + +#include "BlackfinGenAsmWriter.inc" + +extern "C" void LLVMInitializeBlackfinAsmPrinter() { +  RegisterAsmPrinter<BlackfinAsmPrinter> X(TheBlackfinTarget); +} + +void BlackfinAsmPrinter::emitLinkage(const std::string &name, +                                     GlobalValue::LinkageTypes l) { +  switch (l) { +  default: llvm_unreachable("Unknown linkage type!"); +  case GlobalValue::InternalLinkage:  // Symbols default to internal. +  case GlobalValue::PrivateLinkage: +  case GlobalValue::LinkerPrivateLinkage: +    break; +  case GlobalValue::ExternalLinkage: +    O << TAI->getGlobalDirective() << name << "\n"; +    break; +  case GlobalValue::LinkOnceAnyLinkage: +  case GlobalValue::LinkOnceODRLinkage: +  case GlobalValue::WeakAnyLinkage: +  case GlobalValue::WeakODRLinkage: +    O << TAI->getGlobalDirective() << name << "\n"; +    O << TAI->getWeakDefDirective() << name << "\n"; +    break; +  } +} + +void BlackfinAsmPrinter::PrintGlobalVariable(const GlobalVariable* GV) { +  const TargetData *TD = TM.getTargetData(); + +  if (!GV->hasInitializer() || EmitSpecialLLVMGlobal(GV)) +    return; + +  std::string name = Mang->getMangledName(GV); +  Constant *C = GV->getInitializer(); + +  SwitchToSection(getObjFileLowering().SectionForGlobal(GV, Mang, TM)); +  emitLinkage(name, GV->getLinkage()); +  EmitAlignment(TD->getPreferredAlignmentLog(GV), GV); +  printVisibility(name, GV->getVisibility()); + +  O << "\t.type " << name << ", STT_OBJECT\n"; +  O << "\t.size " << name << ',' << TD->getTypeAllocSize(C->getType()) << '\n'; +  O << name << ":\n"; +  EmitGlobalConstant(C); +} + +/// runOnMachineFunction - This uses the printInstruction() +/// method to print assembly for each instruction. +/// +bool BlackfinAsmPrinter::runOnMachineFunction(MachineFunction &MF) { +  SetupMachineFunction(MF); +  EmitConstantPool(MF.getConstantPool()); +  EmitJumpTableInfo(MF.getJumpTableInfo(), MF); + +  const Function *F = MF.getFunction(); +  SwitchToSection(getObjFileLowering().SectionForGlobal(F, Mang, TM)); +  EmitAlignment(2, F); +  emitLinkage(CurrentFnName, F->getLinkage()); +  printVisibility(CurrentFnName, F->getVisibility()); + +  O << "\t.type\t" << CurrentFnName << ", STT_FUNC\n" +    << CurrentFnName << ":\n"; + +  if (DW) +    DW->BeginFunction(&MF); + +  // Print out code for the function. +  for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); +       I != E; ++I) { +    // Print a label for the basic block. +    if (!VerboseAsm && (I->pred_empty() || I->isOnlyReachableByFallthrough())) { +      // This is an entry block or a block that's only reachable via a +      // fallthrough edge. In non-VerboseAsm mode, don't print the label. +    } else { +      printBasicBlockLabel(I, true, true, VerboseAsm); +      O << '\n'; +    } + +    for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); +         II != E; ++II) { +      // Print the assembly for the instruction. +      printInstruction(II); +      ++EmittedInsts; +    } +  } + +  O << "\t.size " << CurrentFnName << ", .-" << CurrentFnName << "\n"; + +  if (DW) +    DW->EndFunction(&MF); + +  return false; +} + +void BlackfinAsmPrinter::printOperand(const MachineInstr *MI, int opNum) { +  const MachineOperand &MO = MI->getOperand (opNum); +  const TargetRegisterInfo &RI = *TM.getRegisterInfo(); +  switch (MO.getType()) { +  case MachineOperand::MO_Register: +    assert (TargetRegisterInfo::isPhysicalRegister(MO.getReg()) && +            "Virtual registers should be already mapped!"); +    O << RI.get(MO.getReg()).AsmName; +    break; + +  case MachineOperand::MO_Immediate: +    O << MO.getImm(); +    break; +  case MachineOperand::MO_MachineBasicBlock: +    printBasicBlockLabel(MO.getMBB(), false, false, false); +    return; +  case MachineOperand::MO_GlobalAddress: +    O << Mang->getMangledName(MO.getGlobal()); +    printOffset(MO.getOffset()); +    break; +  case MachineOperand::MO_ExternalSymbol: +    O << Mang->makeNameProper(MO.getSymbolName()); +    break; +  case MachineOperand::MO_ConstantPoolIndex: +    O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" +      << MO.getIndex(); +    break; +  case MachineOperand::MO_JumpTableIndex: +    O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() +      << '_' << MO.getIndex(); +    break; +  default: +    llvm_unreachable("<unknown operand type>"); +    break; +  } +} + +void BlackfinAsmPrinter::printMemoryOperand(const MachineInstr *MI, int opNum) { +  printOperand(MI, opNum); + +  if (MI->getOperand(opNum+1).isImm() && MI->getOperand(opNum+1).getImm() == 0) +    return; + +  O << " + "; +  printOperand(MI, opNum+1); +} + +/// PrintAsmOperand - Print out an operand for an inline asm expression. +/// +bool BlackfinAsmPrinter::PrintAsmOperand(const MachineInstr *MI, +                                         unsigned OpNo, +                                         unsigned AsmVariant, +                                         const char *ExtraCode) { +  if (ExtraCode && ExtraCode[0]) { +    if (ExtraCode[1] != 0) return true; // Unknown modifier. + +    switch (ExtraCode[0]) { +    default: return true;  // Unknown modifier. +    case 'r': +      break; +    } +  } + +  printOperand(MI, OpNo); + +  return false; +} + +bool BlackfinAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, +                                               unsigned OpNo, +                                               unsigned AsmVariant, +                                               const char *ExtraCode) { +  if (ExtraCode && ExtraCode[0]) +    return true;  // Unknown modifier + +  O << '['; +  printOperand(MI, OpNo); +  O << ']'; + +  return false; +} diff --git a/llvm/lib/Target/Blackfin/AsmPrinter/CMakeLists.txt b/llvm/lib/Target/Blackfin/AsmPrinter/CMakeLists.txt new file mode 100644 index 00000000000..cd20f0754ba --- /dev/null +++ b/llvm/lib/Target/Blackfin/AsmPrinter/CMakeLists.txt @@ -0,0 +1,3 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) +add_llvm_library(LLVMBlackfinAsmPrinter BlackfinAsmPrinter.cpp) +add_dependencies(LLVMBlackfinAsmPrinter BlackfinCodeGenTable_gen) diff --git a/llvm/lib/Target/Blackfin/AsmPrinter/Makefile b/llvm/lib/Target/Blackfin/AsmPrinter/Makefile new file mode 100644 index 00000000000..a2b0d1d1a1c --- /dev/null +++ b/llvm/lib/Target/Blackfin/AsmPrinter/Makefile @@ -0,0 +1,16 @@ +##===- lib/Target/Blackfin/Makefile ------------------------*- Makefile -*-===## +# +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +LIBRARYNAME = LLVMBlackfinAsmPrinter + +# Hack: we need to include 'main' Blackfin target directory to grab private +# headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/llvm/lib/Target/Blackfin/Blackfin.h b/llvm/lib/Target/Blackfin/Blackfin.h new file mode 100644 index 00000000000..ec1fa8689de --- /dev/null +++ b/llvm/lib/Target/Blackfin/Blackfin.h @@ -0,0 +1,38 @@ +//=== Blackfin.h - Top-level interface for Blackfin backend -----*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the entry points for global functions defined in the LLVM +// Blackfin back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef TARGET_BLACKFIN_H +#define TARGET_BLACKFIN_H + +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +  class FunctionPass; +  class BlackfinTargetMachine; + +  FunctionPass *createBlackfinISelDag(BlackfinTargetMachine &TM, +                                      CodeGenOpt::Level OptLevel); +  extern Target TheBlackfinTarget; + +} // end namespace llvm + +// Defines symbolic names for Blackfin registers.  This defines a mapping from +// register name to register number. +#include "BlackfinGenRegisterNames.inc" + +// Defines symbolic names for the Blackfin instructions. +#include "BlackfinGenInstrNames.inc" + +#endif diff --git a/llvm/lib/Target/Blackfin/Blackfin.td b/llvm/lib/Target/Blackfin/Blackfin.td new file mode 100644 index 00000000000..0b73d1f4db9 --- /dev/null +++ b/llvm/lib/Target/Blackfin/Blackfin.td @@ -0,0 +1,52 @@ +//===- Blackfin.td - Describe the Blackfin Target Machine --*- tablegen -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces which we are implementing +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// Blackfin Subtarget features. +//===----------------------------------------------------------------------===// + +def FeatureSSYNC : SubtargetFeature<"ssync","ssyncWorkaround", "true", +                                    "Work around SSYNC bugs">; + +//===----------------------------------------------------------------------===// +// Register File, Calling Conv, Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "BlackfinRegisterInfo.td" +include "BlackfinCallingConv.td" +include "BlackfinInstrInfo.td" + +def BlackfinInstrInfo : InstrInfo {} + +//===----------------------------------------------------------------------===// +// Blackfin processors supported. +//===----------------------------------------------------------------------===// + +class Proc<string Name, list<SubtargetFeature> Features> + : Processor<Name, NoItineraries, Features>; + +def : Proc<"generic", [FeatureSSYNC]>; + +//===----------------------------------------------------------------------===// +// Declare the target which we are implementing +//===----------------------------------------------------------------------===// + +def Blackfin : Target { +  // Pull in Instruction Info: +  let InstructionSet = BlackfinInstrInfo; +} diff --git a/llvm/lib/Target/Blackfin/BlackfinCallingConv.td b/llvm/lib/Target/Blackfin/BlackfinCallingConv.td new file mode 100644 index 00000000000..0abc84c3c40 --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinCallingConv.td @@ -0,0 +1,30 @@ +//===--- BlackfinCallingConv.td - Calling Conventions ------*- tablegen -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This describes the calling conventions for the Blackfin architectures. +// +//===----------------------------------------------------------------------===// + +// Blackfin C Calling convention. +def CC_Blackfin : CallingConv<[ +  CCIfType<[i16], CCPromoteToType<i32>>, +  CCIfSRet<CCAssignToReg<[P0]>>, +  CCAssignToReg<[R0, R1, R2]>, +  CCAssignToStack<4, 4> +]>; + +//===----------------------------------------------------------------------===// +// Return Value Calling Conventions +//===----------------------------------------------------------------------===// + +// Blackfin C return-value convention. +def RetCC_Blackfin : CallingConv<[ +  CCIfType<[i16], CCPromoteToType<i32>>, +  CCAssignToReg<[R0, R1]> +]>; diff --git a/llvm/lib/Target/Blackfin/BlackfinISelDAGToDAG.cpp b/llvm/lib/Target/Blackfin/BlackfinISelDAGToDAG.cpp new file mode 100644 index 00000000000..062b22abe6e --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinISelDAGToDAG.cpp @@ -0,0 +1,191 @@ +//===- BlackfinISelDAGToDAG.cpp - A dag to dag inst selector for Blackfin -===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the Blackfin target. +// +//===----------------------------------------------------------------------===// + +#include "Blackfin.h" +#include "BlackfinISelLowering.h" +#include "BlackfinTargetMachine.h" +#include "BlackfinRegisterInfo.h" +#include "llvm/Intrinsics.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Instruction Selector Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +/// BlackfinDAGToDAGISel - Blackfin specific code to select blackfin machine +/// instructions for SelectionDAG operations. +namespace { +  class BlackfinDAGToDAGISel : public SelectionDAGISel { +    /// Subtarget - Keep a pointer to the Blackfin Subtarget around so that we +    /// can make the right decision when generating code for different targets. +    //const BlackfinSubtarget &Subtarget; +  public: +    BlackfinDAGToDAGISel(BlackfinTargetMachine &TM, CodeGenOpt::Level OptLevel) +      : SelectionDAGISel(TM, OptLevel) {} + +    virtual void InstructionSelect(); + +    virtual const char *getPassName() const { +      return "Blackfin DAG->DAG Pattern Instruction Selection"; +    } + +    // Include the pieces autogenerated from the target description. +#include "BlackfinGenDAGISel.inc" + +  private: +    SDNode *Select(SDValue Op); +    bool SelectADDRspii(SDValue Op, SDValue Addr, +                        SDValue &Base, SDValue &Offset); + +    // Walk the DAG after instruction selection, fixing register class issues. +    void FixRegisterClasses(SelectionDAG &DAG); + +    const BlackfinInstrInfo &getInstrInfo() { +      return *static_cast<const BlackfinTargetMachine&>(TM).getInstrInfo(); +    } +    const BlackfinRegisterInfo *getRegisterInfo() { +      return static_cast<const BlackfinTargetMachine&>(TM).getRegisterInfo(); +    } +  }; +}  // end anonymous namespace + +FunctionPass *llvm::createBlackfinISelDag(BlackfinTargetMachine &TM, +                                          CodeGenOpt::Level OptLevel) { +  return new BlackfinDAGToDAGISel(TM, OptLevel); +} + +/// InstructionSelect - This callback is invoked by +/// SelectionDAGISel when it has created a SelectionDAG for us to codegen. +void BlackfinDAGToDAGISel::InstructionSelect() { +  // Select target instructions for the DAG. +  SelectRoot(*CurDAG); +  DOUT << "Selected selection DAG before regclass fixup:\n"; +  DEBUG(CurDAG->dump()); +  FixRegisterClasses(*CurDAG); +} + +SDNode *BlackfinDAGToDAGISel::Select(SDValue Op) { +  SDNode *N = Op.getNode(); +  DebugLoc dl = N->getDebugLoc(); +  if (N->isMachineOpcode()) +    return NULL;   // Already selected. + +  switch (N->getOpcode()) { +  default: break; +  case ISD::FrameIndex: { +    // Selects to ADDpp FI, 0 which in turn will become ADDimm7 SP, imm or ADDpp +    // SP, Px +    int FI = cast<FrameIndexSDNode>(N)->getIndex(); +    SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32); +    return CurDAG->SelectNodeTo(N, BF::ADDpp, MVT::i32, TFI, +                                CurDAG->getTargetConstant(0, MVT::i32)); +  } +  } + +  return SelectCode(Op); +} + +bool BlackfinDAGToDAGISel::SelectADDRspii(SDValue Op, +                                          SDValue Addr, +                                          SDValue &Base, +                                          SDValue &Offset) { +  FrameIndexSDNode *FIN = 0; +  if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) { +    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); +    Offset = CurDAG->getTargetConstant(0, MVT::i32); +    return true; +  } +  if (Addr.getOpcode() == ISD::ADD) { +    ConstantSDNode *CN = 0; +    if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) && +        (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) && +        (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) { +      // Constant positive word offset from frame index +      Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); +      Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32); +      return true; +    } +  } +  return false; +} + +static inline bool isCC(const TargetRegisterClass *RC) { +  return RC == &BF::AnyCCRegClass || BF::AnyCCRegClass.hasSubClass(RC); +} + +static inline bool isDCC(const TargetRegisterClass *RC) { +  return RC == &BF::DRegClass || BF::DRegClass.hasSubClass(RC) || isCC(RC); +} + +static void UpdateNodeOperand(SelectionDAG &DAG, +                              SDNode *N, +                              unsigned Num, +                              SDValue Val) { +  SmallVector<SDValue, 8> ops(N->op_begin(), N->op_end()); +  ops[Num] = Val; +  SDValue New = DAG.UpdateNodeOperands(SDValue(N, 0), ops.data(), ops.size()); +  DAG.ReplaceAllUsesWith(N, New.getNode()); +} + +// After instruction selection, insert COPY_TO_REGCLASS nodes to help in +// choosing the proper register classes. +void BlackfinDAGToDAGISel::FixRegisterClasses(SelectionDAG &DAG) { +  const BlackfinInstrInfo &TII = getInstrInfo(); +  const BlackfinRegisterInfo *TRI = getRegisterInfo(); +  DAG.AssignTopologicalOrder(); +  HandleSDNode Dummy(DAG.getRoot()); + +  for (SelectionDAG::allnodes_iterator NI = DAG.allnodes_begin(); +       NI != DAG.allnodes_end(); ++NI) { +    if (NI->use_empty() || !NI->isMachineOpcode()) +      continue; +    const TargetInstrDesc &DefTID = TII.get(NI->getMachineOpcode()); +    for (SDNode::use_iterator UI = NI->use_begin(); !UI.atEnd(); ++UI) { +      if (!UI->isMachineOpcode()) +        continue; + +      if (UI.getUse().getResNo() >= DefTID.getNumDefs()) +        continue; +      const TargetRegisterClass *DefRC = +        DefTID.OpInfo[UI.getUse().getResNo()].getRegClass(TRI); + +      const TargetInstrDesc &UseTID = TII.get(UI->getMachineOpcode()); +      if (UseTID.getNumDefs()+UI.getOperandNo() >= UseTID.getNumOperands()) +        continue; +      const TargetRegisterClass *UseRC = +        UseTID.OpInfo[UseTID.getNumDefs()+UI.getOperandNo()].getRegClass(TRI); +      if (!DefRC || !UseRC) +        continue; +      // We cannot copy CC <-> !(CC/D) +      if ((isCC(DefRC) && !isDCC(UseRC)) || (isCC(UseRC) && !isDCC(DefRC))) { +        SDNode *Copy = +          DAG.getTargetNode(TargetInstrInfo::COPY_TO_REGCLASS, +                            NI->getDebugLoc(), +                            MVT::i32, +                            UI.getUse().get(), +                            DAG.getTargetConstant(BF::DRegClassID, MVT::i32)); +        UpdateNodeOperand(DAG, *UI, UI.getOperandNo(), SDValue(Copy, 0)); +      } +    } +  } +  DAG.setRoot(Dummy.getValue()); +} + diff --git a/llvm/lib/Target/Blackfin/BlackfinISelLowering.cpp b/llvm/lib/Target/Blackfin/BlackfinISelLowering.cpp new file mode 100644 index 00000000000..a4af0ad9e79 --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinISelLowering.cpp @@ -0,0 +1,536 @@ +//===- BlackfinISelLowering.cpp - Blackfin DAG Lowering Implementation ----===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the interfaces that Blackfin uses to lower LLVM code +// into a selection DAG. +// +//===----------------------------------------------------------------------===// + +#include "BlackfinISelLowering.h" +#include "BlackfinTargetMachine.h" +#include "llvm/Function.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/ADT/VectorExtras.h" +#include "llvm/Support/Debug.h" + +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// + +#include "BlackfinGenCallingConv.inc" + +//===----------------------------------------------------------------------===// +// TargetLowering Implementation +//===----------------------------------------------------------------------===// + +BlackfinTargetLowering::BlackfinTargetLowering(TargetMachine &TM) +  : TargetLowering(TM, new TargetLoweringObjectFileELF()) { +  setShiftAmountType(MVT::i16); +  setBooleanContents(ZeroOrOneBooleanContent); +  setStackPointerRegisterToSaveRestore(BF::SP); +  setIntDivIsCheap(false); + +  // Set up the legal register classes. +  addRegisterClass(MVT::i32, BF::DRegisterClass); +  addRegisterClass(MVT::i16, BF::D16RegisterClass); + +  computeRegisterProperties(); + +  // Blackfin doesn't have i1 loads or stores +  setLoadExtAction(ISD::EXTLOAD,  MVT::i1, Promote); +  setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote); +  setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); + +  setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); +  setOperationAction(ISD::JumpTable,     MVT::i32, Custom); + +  setOperationAction(ISD::SELECT_CC, MVT::Other, Expand); +  setOperationAction(ISD::BR_JT,     MVT::Other, Expand); +  setOperationAction(ISD::BR_CC,     MVT::Other, Expand); + +  // i16 registers don't do much +  setOperationAction(ISD::AND,   MVT::i16, Promote); +  setOperationAction(ISD::OR,    MVT::i16, Promote); +  setOperationAction(ISD::XOR,   MVT::i16, Promote); +  setOperationAction(ISD::CTPOP, MVT::i16, Promote); +  // The expansion of CTLZ/CTTZ uses AND/OR, so we might as well promote +  // immediately. +  setOperationAction(ISD::CTLZ,  MVT::i16, Promote); +  setOperationAction(ISD::CTTZ,  MVT::i16, Promote); +  setOperationAction(ISD::SETCC, MVT::i16, Promote); + +  // Blackfin has no division +  setOperationAction(ISD::SDIV,    MVT::i16, Expand); +  setOperationAction(ISD::SDIV,    MVT::i32, Expand); +  setOperationAction(ISD::SDIVREM, MVT::i16, Expand); +  setOperationAction(ISD::SDIVREM, MVT::i32, Expand); +  setOperationAction(ISD::SREM,    MVT::i16, Expand); +  setOperationAction(ISD::SREM,    MVT::i32, Expand); +  setOperationAction(ISD::UDIV,    MVT::i16, Expand); +  setOperationAction(ISD::UDIV,    MVT::i32, Expand); +  setOperationAction(ISD::UDIVREM, MVT::i16, Expand); +  setOperationAction(ISD::UDIVREM, MVT::i32, Expand); +  setOperationAction(ISD::UREM,    MVT::i16, Expand); +  setOperationAction(ISD::UREM,    MVT::i32, Expand); + +  setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); +  setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); +  setOperationAction(ISD::MULHU,     MVT::i32, Expand); +  setOperationAction(ISD::MULHS,     MVT::i32, Expand); + +  // No carry-in operations. +  setOperationAction(ISD::ADDE, MVT::i32, Custom); +  setOperationAction(ISD::SUBE, MVT::i32, Custom); + +  // Blackfin has no intrinsics for these particular operations. +  setOperationAction(ISD::MEMBARRIER, MVT::Other, Expand); +  setOperationAction(ISD::BSWAP, MVT::i32, Expand); + +  setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); +  setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); +  setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand); + +  setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + +  // i32 has native CTPOP, but not CTLZ/CTTZ +  setOperationAction(ISD::CTLZ, MVT::i32, Expand); +  setOperationAction(ISD::CTTZ, MVT::i32, Expand); + +  // We don't have line number support yet. +  setOperationAction(ISD::DBG_STOPPOINT, MVT::Other, Expand); +  setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand); +  setOperationAction(ISD::DBG_LABEL, MVT::Other, Expand); +  setOperationAction(ISD::EH_LABEL, MVT::Other, Expand); +  setOperationAction(ISD::DECLARE, MVT::Other, Expand); + +  // Use the default implementation. +  setOperationAction(ISD::VACOPY, MVT::Other, Expand); +  setOperationAction(ISD::VAEND, MVT::Other, Expand); +  setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); +  setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + +  // RET must be custom lowered, to meet ABI requirements +  setOperationAction(ISD::RET, MVT::Other, Custom); +} + +const char *BlackfinTargetLowering::getTargetNodeName(unsigned Opcode) const { +  switch (Opcode) { +  default: return 0; +  case BFISD::CALL:     return "BFISD::CALL"; +  case BFISD::RET_FLAG: return "BFISD::RET_FLAG"; +  case BFISD::Wrapper:  return "BFISD::Wrapper"; +  } +} + +MVT BlackfinTargetLowering::getSetCCResultType(MVT VT) const { +  // SETCC always sets the CC register. Technically that is an i1 register, but +  // that type is not legal, so we treat it as an i32 register. +  return MVT::i32; +} + +SDValue BlackfinTargetLowering::LowerGlobalAddress(SDValue Op, +                                                   SelectionDAG &DAG) { +  DebugLoc DL = Op.getDebugLoc(); +  GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); + +  Op = DAG.getTargetGlobalAddress(GV, MVT::i32); +  return DAG.getNode(BFISD::Wrapper, DL, MVT::i32, Op); +} + +SDValue BlackfinTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) { +  DebugLoc DL = Op.getDebugLoc(); +  int JTI = cast<JumpTableSDNode>(Op)->getIndex(); + +  Op = DAG.getTargetJumpTable(JTI, MVT::i32); +  return DAG.getNode(BFISD::Wrapper, DL, MVT::i32, Op); +} + +// FORMAL_ARGUMENTS(CHAIN, CC#, ISVARARG, FLAG0, ..., FLAGn) - This node +// represents the formal arguments for a function.  CC# is a Constant value +// indicating the calling convention of the function, and ISVARARG is a +// flag that indicates whether the function is varargs or not. This node +// has one result value for each incoming argument, plus one for the output +// chain. +SDValue BlackfinTargetLowering::LowerFORMAL_ARGUMENTS(SDValue Op, +                                                      SelectionDAG &DAG) { +  DebugLoc dl = Op.getDebugLoc(); +  SDValue Root = Op.getOperand(0); +  unsigned CC = Op.getConstantOperandVal(1); +  bool isVarArg = Op.getConstantOperandVal(2); +  MachineFunction &MF = DAG.getMachineFunction(); +  MachineFrameInfo *MFI = MF.getFrameInfo(); + +  SmallVector<CCValAssign, 16> ArgLocs; +  CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs, *DAG.getContext()); +  CCInfo.AllocateStack(12, 4);	// ABI requires 12 bytes stack space +  CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_Blackfin); + +  SmallVector<SDValue, 8> ArgValues; +  for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { +    CCValAssign &VA = ArgLocs[i]; + +    if (VA.isRegLoc()) { +      MVT RegVT = VA.getLocVT(); +      TargetRegisterClass *RC = VA.getLocReg() == BF::P0 ? +        BF::PRegisterClass : BF::DRegisterClass; +      assert(RC->contains(VA.getLocReg())); +      assert(RC->hasType(RegVT)); + +      unsigned Reg = MF.getRegInfo().createVirtualRegister(RC); +      MF.getRegInfo().addLiveIn(VA.getLocReg(), Reg); +      SDValue ArgValue = DAG.getCopyFromReg(Root, dl, Reg, RegVT); + +      // If this is an 8 or 16-bit value, it is really passed promoted to 32 +      // bits.  Insert an assert[sz]ext to capture this, then truncate to the +      // right size. +      if (VA.getLocInfo() == CCValAssign::SExt) +        ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue, +                               DAG.getValueType(VA.getValVT())); +      else if (VA.getLocInfo() == CCValAssign::ZExt) +        ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue, +                               DAG.getValueType(VA.getValVT())); + +      if (VA.getLocInfo() != CCValAssign::Full) +        ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); + +      ArgValues.push_back(ArgValue); +    } else { +      assert(VA.isMemLoc()); +      unsigned ObjSize = VA.getLocVT().getStoreSizeInBits()/8; +      int FI = MFI->CreateFixedObject(ObjSize, VA.getLocMemOffset()); +      SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); +      ArgValues.push_back(DAG.getLoad(VA.getValVT(), dl, Root, FIN, NULL, 0)); +    } +  } + +  ArgValues.push_back(Root); + +  // Return the new list of results. +  return DAG.getNode(ISD::MERGE_VALUES, dl, Op.getNode()->getVTList(), +                     &ArgValues[0], ArgValues.size()).getValue(Op.getResNo()); +} + +SDValue BlackfinTargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) { +  // CCValAssign - represent the assignment of the return value to locations. +  SmallVector<CCValAssign, 16> RVLocs; +  unsigned CC = DAG.getMachineFunction().getFunction()->getCallingConv(); +  bool isVarArg = DAG.getMachineFunction().getFunction()->isVarArg(); +  DebugLoc dl = Op.getDebugLoc(); + +  // CCState - Info about the registers and stack slot. +  CCState CCInfo(CC, isVarArg, DAG.getTarget(), RVLocs, *DAG.getContext()); + +  // Analize return values of ISD::RET +  CCInfo.AnalyzeReturn(Op.getNode(), RetCC_Blackfin); + +  // If this is the first return lowered for this function, add the regs to the +  // liveout set for the function. +  if (DAG.getMachineFunction().getRegInfo().liveout_empty()) { +    for (unsigned i = 0; i != RVLocs.size(); ++i) +      DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg()); +  } + +  SDValue Chain = Op.getOperand(0); +  SDValue Flag; + +  // Copy the result values into the output registers. +  for (unsigned i = 0; i != RVLocs.size(); ++i) { +    CCValAssign &VA = RVLocs[i]; +    assert(VA.isRegLoc() && "Can only return in registers!"); +    SDValue Opi = Op.getOperand(i*2+1); + +    // Expand to i32 if necessary +    switch (VA.getLocInfo()) { +    default: llvm_unreachable("Unknown loc info!"); +    case CCValAssign::Full: break; +    case CCValAssign::SExt: +      Opi = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Opi); +      break; +    case CCValAssign::ZExt: +      Opi = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Opi); +      break; +    case CCValAssign::AExt: +      Opi = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Opi); +      break; +    } +    // ISD::RET => ret chain, (regnum1,val1), ... +    // So i*2+1 index only the regnums. +    Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), Opi, SDValue()); +    // Guarantee that all emitted copies are stuck together with flags. +    Flag = Chain.getValue(1); +  } + +  if (Flag.getNode()) { +    return DAG.getNode(BFISD::RET_FLAG, dl, MVT::Other, Chain, Flag); +  } else { +    return DAG.getNode(BFISD::RET_FLAG, dl, MVT::Other, Chain); +  } +} + +SDValue BlackfinTargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) { +  CallSDNode *TheCall = cast<CallSDNode>(Op.getNode()); +  unsigned CallingConv = TheCall->getCallingConv(); +  SDValue Chain = TheCall->getChain(); +  SDValue Callee = TheCall->getCallee(); +  bool isVarArg = TheCall->isVarArg(); +  DebugLoc dl = TheCall->getDebugLoc(); + +  // Analyze operands of the call, assigning locations to each operand. +  SmallVector<CCValAssign, 16> ArgLocs; +  CCState CCInfo(CallingConv, isVarArg, DAG.getTarget(), ArgLocs, +                 *DAG.getContext()); +  CCInfo.AllocateStack(12, 4);	// ABI requires 12 bytes stack space +  CCInfo.AnalyzeCallOperands(TheCall, CC_Blackfin); + +  // Get the size of the outgoing arguments stack space requirement. +  unsigned ArgsSize = CCInfo.getNextStackOffset(); + +  Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, true)); +  SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass; +  SmallVector<SDValue, 8> MemOpChains; + +  // Walk the register/memloc assignments, inserting copies/loads. +  for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { +    CCValAssign &VA = ArgLocs[i]; + +    // Arguments start after the 5 first operands of ISD::CALL +    SDValue Arg = TheCall->getArg(i); + +    // Promote the value if needed. +    switch (VA.getLocInfo()) { +    default: llvm_unreachable("Unknown loc info!"); +    case CCValAssign::Full: break; +    case CCValAssign::SExt: +      Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); +      break; +    case CCValAssign::ZExt: +      Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg); +      break; +    case CCValAssign::AExt: +      Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg); +      break; +    } + +    // Arguments that can be passed on register must be kept at +    // RegsToPass vector +    if (VA.isRegLoc()) { +      RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); +    } else { +      assert(VA.isMemLoc()); +      int Offset = VA.getLocMemOffset(); +      assert(Offset%4 == 0); +      assert(VA.getLocVT()==MVT::i32); +      SDValue SPN = DAG.getCopyFromReg(Chain, dl, BF::SP, MVT::i32); +      SDValue OffsetN = DAG.getIntPtrConstant(Offset); +      OffsetN = DAG.getNode(ISD::ADD, dl, MVT::i32, SPN, OffsetN); +      MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, OffsetN, +                                         PseudoSourceValue::getStack(), +                                         Offset)); +    } +  } + +  // Transform all store nodes into one single node because +  // all store nodes are independent of each other. +  if (!MemOpChains.empty()) +    Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, +                        &MemOpChains[0], MemOpChains.size()); + +  // Build a sequence of copy-to-reg nodes chained together with token +  // chain and flag operands which copy the outgoing args into registers. +  // The InFlag in necessary since all emited instructions must be +  // stuck together. +  SDValue InFlag; +  for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { +    Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, +                             RegsToPass[i].second, InFlag); +    InFlag = Chain.getValue(1); +  } + +  // If the callee is a GlobalAddress node (quite common, every direct call is) +  // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. +  // Likewise ExternalSymbol -> TargetExternalSymbol. +  if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) +    Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i32); +  else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) +    Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32); + +  std::vector<MVT> NodeTys; +  NodeTys.push_back(MVT::Other);   // Returns a chain +  NodeTys.push_back(MVT::Flag);    // Returns a flag for retval copy to use. +  SDValue Ops[] = { Chain, Callee, InFlag }; +  Chain = DAG.getNode(BFISD::CALL, dl, NodeTys, Ops, +                      InFlag.getNode() ? 3 : 2); +  InFlag = Chain.getValue(1); + +  Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, true), +                             DAG.getIntPtrConstant(0, true), InFlag); +  InFlag = Chain.getValue(1); + +  // Assign locations to each value returned by this call. +  SmallVector<CCValAssign, 16> RVLocs; +  CCState RVInfo(CallingConv, isVarArg, DAG.getTarget(), RVLocs, +                 *DAG.getContext()); + +  RVInfo.AnalyzeCallResult(TheCall, RetCC_Blackfin); +  SmallVector<SDValue, 8> ResultVals; + +  // Copy all of the result registers out of their specified physreg. +  for (unsigned i = 0; i != RVLocs.size(); ++i) { +    CCValAssign &RV = RVLocs[i]; +    unsigned Reg = RV.getLocReg(); + +    Chain = DAG.getCopyFromReg(Chain, dl, Reg, +                               RVLocs[i].getLocVT(), InFlag); +    SDValue Val = Chain.getValue(0); +    InFlag = Chain.getValue(2); +    Chain = Chain.getValue(1); + +    // Callee is responsible for extending any i16 return values. +    switch (RV.getLocInfo()) { +    case CCValAssign::SExt: +      Val = DAG.getNode(ISD::AssertSext, dl, RV.getLocVT(), Val, +                        DAG.getValueType(RV.getValVT())); +      break; +    case CCValAssign::ZExt: +      Val = DAG.getNode(ISD::AssertZext, dl, RV.getLocVT(), Val, +                        DAG.getValueType(RV.getValVT())); +      break; +    default: +      break; +    } + +    // Truncate to valtype +    if (RV.getLocInfo() != CCValAssign::Full) +      Val = DAG.getNode(ISD::TRUNCATE, dl, RV.getValVT(), Val); +    ResultVals.push_back(Val); +  } + +  ResultVals.push_back(Chain); + +  // Merge everything together with a MERGE_VALUES node. +  SDValue merge = DAG.getNode(ISD::MERGE_VALUES, dl, +                              TheCall->getVTList(), &ResultVals[0], +                              ResultVals.size()); +  return merge; +} + +// Expansion of ADDE / SUBE. This is a bit involved since blackfin doesn't have +// add-with-carry instructions. +SDValue BlackfinTargetLowering::LowerADDE(SDValue Op, SelectionDAG &DAG) { +  // Operands: lhs, rhs, carry-in (AC0 flag) +  // Results: sum, carry-out (AC0 flag) +  DebugLoc dl = Op.getDebugLoc(); + +  unsigned Opcode = Op.getOpcode()==ISD::ADDE ? BF::ADD : BF::SUB; + +  // zext incoming carry flag in AC0 to 32 bits +  SDNode* CarryIn = DAG.getTargetNode(BF::MOVE_cc_ac0, dl, MVT::i32, +                                      /* flag= */ Op.getOperand(2)); +  CarryIn = DAG.getTargetNode(BF::MOVECC_zext, dl, MVT::i32, +                              SDValue(CarryIn, 0)); + +  // Add operands, produce sum and carry flag +  SDNode *Sum = DAG.getTargetNode(Opcode, dl, MVT::i32, MVT::Flag, +                                  Op.getOperand(0), Op.getOperand(1)); + +  // Store intermediate carry from Sum +  SDNode* Carry1 = DAG.getTargetNode(BF::MOVE_cc_ac0, dl, MVT::i32, +                                     /* flag= */ SDValue(Sum, 1)); + +  // Add incoming carry, again producing an output flag +  Sum = DAG.getTargetNode(Opcode, dl, MVT::i32, MVT::Flag, +                          SDValue(Sum, 0), SDValue(CarryIn, 0)); + +  // Update AC0 with the intermediate carry, producing a flag. +  SDNode *CarryOut = DAG.getTargetNode(BF::OR_ac0_cc, dl, MVT::Flag, +                                       SDValue(Carry1, 0)); + +  // Compose (i32, flag) pair +  SDValue ops[2] = { SDValue(Sum, 0), SDValue(CarryOut, 0) }; +  return DAG.getMergeValues(ops, 2, dl); +} + +SDValue BlackfinTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { +  switch (Op.getOpcode()) { +  default: +    Op.getNode()->dump(); +    llvm_unreachable("Should not custom lower this!"); +  case ISD::GlobalAddress:      return LowerGlobalAddress(Op, DAG); +  case ISD::GlobalTLSAddress: +    llvm_unreachable("TLS not implemented for Blackfin."); +  case ISD::JumpTable:          return LowerJumpTable(Op, DAG); +    // Frame & Return address.  Currently unimplemented +  case ISD::FRAMEADDR:          return SDValue(); +  case ISD::RETURNADDR:         return SDValue(); +  case ISD::FORMAL_ARGUMENTS:   return LowerFORMAL_ARGUMENTS(Op, DAG); +  case ISD::CALL:               return LowerCALL(Op, DAG); +  case ISD::RET:                return LowerRET(Op, DAG); +  case ISD::ADDE: +  case ISD::SUBE:               return LowerADDE(Op, DAG); +  } +} + +/// getFunctionAlignment - Return the Log2 alignment of this function. +unsigned BlackfinTargetLowering::getFunctionAlignment(const Function *F) const { +  return 2; +} + +//===----------------------------------------------------------------------===// +//                         Blackfin Inline Assembly Support +//===----------------------------------------------------------------------===// + +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +BlackfinTargetLowering::ConstraintType +BlackfinTargetLowering::getConstraintType(const std::string &Constraint) const { +  if (Constraint.size() == 1) { +    switch (Constraint[0]) { +    default:  break; +    case 'r': return C_RegisterClass; +    } +  } + +  return TargetLowering::getConstraintType(Constraint); +} + +std::pair<unsigned, const TargetRegisterClass*> BlackfinTargetLowering:: +getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const { +  if (Constraint.size() == 1) { +    switch (Constraint[0]) { +    case 'r': +      return std::make_pair(0U, BF::DRegisterClass); +    } +  } + +  return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); +} + +std::vector<unsigned> BlackfinTargetLowering:: +getRegClassForInlineAsmConstraint(const std::string &Constraint, +                                  MVT VT) const { +  if (Constraint.size() != 1) +    return std::vector<unsigned>(); + +  return std::vector<unsigned>(); +} + +bool BlackfinTargetLowering:: +isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { +  // The Blackfin target isn't yet aware of offsets. +  return false; +} diff --git a/llvm/lib/Target/Blackfin/BlackfinISelLowering.h b/llvm/lib/Target/Blackfin/BlackfinISelLowering.h new file mode 100644 index 00000000000..7acbd1a8e58 --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinISelLowering.h @@ -0,0 +1,61 @@ +//===- BlackfinISelLowering.h - Blackfin DAG Lowering Interface -*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that Blackfin uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef BLACKFIN_ISELLOWERING_H +#define BLACKFIN_ISELLOWERING_H + +#include "llvm/Target/TargetLowering.h" +#include "Blackfin.h" + +namespace llvm { + +  namespace BFISD { +    enum { +      FIRST_NUMBER = ISD::BUILTIN_OP_END, +      CALL,                     // A call instruction. +      RET_FLAG,                 // Return with a flag operand. +      Wrapper                   // Address wrapper +    }; +  } + +  class BlackfinTargetLowering : public TargetLowering { +    int VarArgsFrameOffset;   // Frame offset to start of varargs area. +  public: +    BlackfinTargetLowering(TargetMachine &TM); +    virtual MVT getSetCCResultType(MVT VT) const; +    virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG); + +    int getVarArgsFrameOffset() const { return VarArgsFrameOffset; } + +    ConstraintType getConstraintType(const std::string &Constraint) const; +    std::pair<unsigned, const TargetRegisterClass*> +    getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const; +    std::vector<unsigned> +    getRegClassForInlineAsmConstraint(const std::string &Constraint, +                                      MVT VT) const; +    virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; +    const char *getTargetNodeName(unsigned Opcode) const; +    unsigned getFunctionAlignment(const Function *F) const; + +  private: +    SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG); +    SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG); +    SDValue LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG); +    SDValue LowerRET(SDValue Op, SelectionDAG &DAG); +    SDValue LowerCALL(SDValue Op, SelectionDAG &DAG); +    SDValue LowerADDE(SDValue Op, SelectionDAG &DAG); +  }; +} // end namespace llvm + +#endif    // BLACKFIN_ISELLOWERING_H diff --git a/llvm/lib/Target/Blackfin/BlackfinInstrFormats.td b/llvm/lib/Target/Blackfin/BlackfinInstrFormats.td new file mode 100644 index 00000000000..d8e6e252e78 --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinInstrFormats.td @@ -0,0 +1,34 @@ +//===--- BlackfinInstrFormats.td ---------------------------*- tablegen -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Instruction format superclass +//===----------------------------------------------------------------------===// + +class InstBfin<dag outs, dag ins, string asmstr, list<dag> pattern> +  : Instruction { +  field bits<32> Inst; + +  let Namespace = "BF"; + +  dag OutOperandList = outs; +  dag InOperandList = ins; +  let AsmString   = asmstr; +  let Pattern = pattern; +} + +// Single-word (16-bit) instructions +class F1<dag outs, dag ins, string asmstr, list<dag> pattern> +    : InstBfin<outs, ins, asmstr, pattern> { +} + +// Double-word (32-bit) instructions +class F2<dag outs, dag ins, string asmstr, list<dag> pattern> +    : InstBfin<outs, ins, asmstr, pattern> { +} diff --git a/llvm/lib/Target/Blackfin/BlackfinInstrInfo.cpp b/llvm/lib/Target/Blackfin/BlackfinInstrInfo.cpp new file mode 100644 index 00000000000..3fd5d4dc0bf --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinInstrInfo.cpp @@ -0,0 +1,280 @@ +//===- BlackfinInstrInfo.cpp - Blackfin Instruction Information -*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Blackfin implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "BlackfinInstrInfo.h" +#include "BlackfinSubtarget.h" +#include "Blackfin.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Support/ErrorHandling.h" +#include "BlackfinGenInstrInfo.inc" + +using namespace llvm; + +BlackfinInstrInfo::BlackfinInstrInfo(BlackfinSubtarget &ST) +  : TargetInstrInfoImpl(BlackfinInsts, array_lengthof(BlackfinInsts)), +    RI(ST, *this), +    Subtarget(ST) {} + +/// Return true if the instruction is a register to register move and +/// leave the source and dest operands in the passed parameters. +bool BlackfinInstrInfo::isMoveInstr(const MachineInstr &MI, +                                    unsigned &SrcReg, +                                    unsigned &DstReg, +                                    unsigned &SrcSR, +                                    unsigned &DstSR) const { +  SrcSR = DstSR = 0; // No sub-registers. +  switch (MI.getOpcode()) { +  case BF::MOVE: +  case BF::MOVE_ncccc: +  case BF::MOVE_ccncc: +  case BF::MOVECC_zext: +  case BF::MOVECC_nz: +    DstReg = MI.getOperand(0).getReg(); +    SrcReg = MI.getOperand(1).getReg(); +    return true; +  case BF::SLL16i: +    if (MI.getOperand(2).getImm()!=0) +      return false; +    DstReg = MI.getOperand(0).getReg(); +    SrcReg = MI.getOperand(1).getReg(); +    return true; +  default: +    return false; +  } +} + +/// isLoadFromStackSlot - If the specified machine instruction is a direct +/// load from a stack slot, return the virtual or physical register number of +/// the destination along with the FrameIndex of the loaded stack slot.  If +/// not, return 0.  This predicate must return 0 if the instruction has +/// any side effects other than loading from the stack slot. +unsigned BlackfinInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, +                                                int &FrameIndex) const { +  switch (MI->getOpcode()) { +  default: break; +  case BF::LOAD32fi: +  case BF::LOAD16fi: +    if (MI->getOperand(1).isFI() && +        MI->getOperand(2).isImm() && +        MI->getOperand(2).getImm() == 0) { +      FrameIndex = MI->getOperand(1).getIndex(); +      return MI->getOperand(0).getReg(); +    } +    break; +  } +  return 0; +} + +/// isStoreToStackSlot - If the specified machine instruction is a direct +/// store to a stack slot, return the virtual or physical register number of +/// the source reg along with the FrameIndex of the loaded stack slot.  If +/// not, return 0.  This predicate must return 0 if the instruction has +/// any side effects other than storing to the stack slot. +unsigned BlackfinInstrInfo::isStoreToStackSlot(const MachineInstr *MI, +                                               int &FrameIndex) const { +  switch (MI->getOpcode()) { +  default: break; +  case BF::STORE32fi: +  case BF::STORE16fi: +    if (MI->getOperand(1).isFI() && +        MI->getOperand(2).isImm() && +        MI->getOperand(2).getImm() == 0) { +      FrameIndex = MI->getOperand(1).getIndex(); +      return MI->getOperand(0).getReg(); +    } +    break; +  } +  return 0; +} + +unsigned BlackfinInstrInfo:: +InsertBranch(MachineBasicBlock &MBB, +             MachineBasicBlock *TBB, +             MachineBasicBlock *FBB, +             const SmallVectorImpl<MachineOperand> &Cond) const { +  // FIXME this should probably have a DebugLoc operand +  DebugLoc dl = DebugLoc::getUnknownLoc(); + +  // Shouldn't be a fall through. +  assert(TBB && "InsertBranch must not be told to insert a fallthrough"); +  assert((Cond.size() == 1 || Cond.size() == 0) && +         "Branch conditions have one component!"); + +  if (Cond.empty()) { +    // Unconditional branch? +    assert(!FBB && "Unconditional branch with multiple successors!"); +    BuildMI(&MBB, dl, get(BF::JUMPa)).addMBB(TBB); +    return 1; +  } + +  // Conditional branch. +  llvm_unreachable("Implement conditional branches!"); +} + +static bool inClass(const TargetRegisterClass &Test, +                    unsigned Reg, +                    const TargetRegisterClass *RC) { +  if (TargetRegisterInfo::isPhysicalRegister(Reg)) +    return Test.contains(Reg); +  else +    return &Test==RC || Test.hasSubClass(RC); +} + +bool BlackfinInstrInfo::copyRegToReg(MachineBasicBlock &MBB, +                                     MachineBasicBlock::iterator I, +                                     unsigned DestReg, +                                     unsigned SrcReg, +                                     const TargetRegisterClass *DestRC, +                                     const TargetRegisterClass *SrcRC) const { +  DebugLoc dl = DebugLoc::getUnknownLoc(); + +  if (inClass(BF::ALLRegClass, DestReg, DestRC) && +      inClass(BF::ALLRegClass, SrcReg,  SrcRC)) { +    BuildMI(MBB, I, dl, get(BF::MOVE), DestReg).addReg(SrcReg); +    return true; +  } + +  if (inClass(BF::D16RegClass, DestReg, DestRC) && +      inClass(BF::D16RegClass, SrcReg,  SrcRC)) { +    BuildMI(MBB, I, dl, get(BF::SLL16i), DestReg).addReg(SrcReg).addImm(0); +    return true; +  } + +  if (inClass(BF::AnyCCRegClass, SrcReg, SrcRC) && +      inClass(BF::DRegClass, DestReg, DestRC)) { +    if (inClass(BF::NotCCRegClass, SrcReg, SrcRC)) { +      BuildMI(MBB, I, dl, get(BF::MOVENCC_z), DestReg).addReg(SrcReg); +      BuildMI(MBB, I, dl, get(BF::BITTGL), DestReg).addReg(DestReg).addImm(0); +    } else { +      BuildMI(MBB, I, dl, get(BF::MOVECC_zext), DestReg).addReg(SrcReg); +    } +    return true; +  } + +  if (inClass(BF::AnyCCRegClass, DestReg, DestRC) && +      inClass(BF::DRegClass, SrcReg,  SrcRC)) { +    if (inClass(BF::NotCCRegClass, DestReg, DestRC)) +      BuildMI(MBB, I, dl, get(BF::SETEQri_not), DestReg).addReg(SrcReg); +    else +      BuildMI(MBB, I, dl, get(BF::MOVECC_nz), DestReg).addReg(SrcReg); +    return true; +  } + +  if (inClass(BF::NotCCRegClass, DestReg, DestRC) && +      inClass(BF::JustCCRegClass, SrcReg,  SrcRC)) { +    BuildMI(MBB, I, dl, get(BF::MOVE_ncccc), DestReg).addReg(SrcReg); +    return true; +  } + +  if (inClass(BF::JustCCRegClass, DestReg, DestRC) && +      inClass(BF::NotCCRegClass, SrcReg,  SrcRC)) { +    BuildMI(MBB, I, dl, get(BF::MOVE_ccncc), DestReg).addReg(SrcReg); +    return true; +  } + +  llvm_unreachable((std::string("Bad regclasses for reg-to-reg copy: ")+ +                    SrcRC->getName() + " -> " + DestRC->getName()).c_str()); +  return false; +} + +void +BlackfinInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, +                                       MachineBasicBlock::iterator I, +                                       unsigned SrcReg, +                                       bool isKill, +                                       int FI, +                                       const TargetRegisterClass *RC) const { +  DebugLoc DL = I != MBB.end() ? +    I->getDebugLoc() : DebugLoc::getUnknownLoc(); + +  if (inClass(BF::DPRegClass, SrcReg, RC)) { +    BuildMI(MBB, I, DL, get(BF::STORE32fi)) +      .addReg(SrcReg, getKillRegState(isKill)) +      .addFrameIndex(FI) +      .addImm(0); +    return; +  } + +  if (inClass(BF::D16RegClass, SrcReg, RC)) { +    BuildMI(MBB, I, DL, get(BF::STORE16fi)) +      .addReg(SrcReg, getKillRegState(isKill)) +      .addFrameIndex(FI) +      .addImm(0); +    return; +  } + +  if (inClass(BF::AnyCCRegClass, SrcReg, RC)) { +    BuildMI(MBB, I, DL, get(BF::STORE8fi)) +      .addReg(SrcReg, getKillRegState(isKill)) +      .addFrameIndex(FI) +      .addImm(0); +    return; +  } + +  llvm_unreachable((std::string("Cannot store regclass to stack slot: ")+ +                    RC->getName()).c_str()); +} + +void BlackfinInstrInfo:: +storeRegToAddr(MachineFunction &MF, +               unsigned SrcReg, +               bool isKill, +               SmallVectorImpl<MachineOperand> &Addr, +               const TargetRegisterClass *RC, +               SmallVectorImpl<MachineInstr*> &NewMIs) const { +  llvm_unreachable("storeRegToAddr not implemented"); +} + +void +BlackfinInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, +                                        MachineBasicBlock::iterator I, +                                        unsigned DestReg, +                                        int FI, +                                        const TargetRegisterClass *RC) const { +  DebugLoc DL = I != MBB.end() ? +    I->getDebugLoc() : DebugLoc::getUnknownLoc(); +  if (inClass(BF::DPRegClass, DestReg, RC)) { +    BuildMI(MBB, I, DL, get(BF::LOAD32fi), DestReg) +      .addFrameIndex(FI) +      .addImm(0); +    return; +  } + +  if (inClass(BF::D16RegClass, DestReg, RC)) { +    BuildMI(MBB, I, DL, get(BF::LOAD16fi), DestReg) +      .addFrameIndex(FI) +      .addImm(0); +    return; +  } + +  if (inClass(BF::AnyCCRegClass, DestReg, RC)) { +    BuildMI(MBB, I, DL, get(BF::LOAD8fi), DestReg) +      .addFrameIndex(FI) +      .addImm(0); +    return; +  } + +  llvm_unreachable("Cannot load regclass from stack slot"); +} + +void BlackfinInstrInfo:: +loadRegFromAddr(MachineFunction &MF, +                unsigned DestReg, +                SmallVectorImpl<MachineOperand> &Addr, +                const TargetRegisterClass *RC, +                SmallVectorImpl<MachineInstr*> &NewMIs) const { +  llvm_unreachable("loadRegFromAddr not implemented"); +} diff --git a/llvm/lib/Target/Blackfin/BlackfinInstrInfo.h b/llvm/lib/Target/Blackfin/BlackfinInstrInfo.h new file mode 100644 index 00000000000..ea3429c1014 --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinInstrInfo.h @@ -0,0 +1,80 @@ +//===- BlackfinInstrInfo.h - Blackfin Instruction Information ---*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Blackfin implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef BLACKFININSTRUCTIONINFO_H +#define BLACKFININSTRUCTIONINFO_H + +#include "llvm/Target/TargetInstrInfo.h" +#include "BlackfinRegisterInfo.h" + +namespace llvm { + +  class BlackfinInstrInfo : public TargetInstrInfoImpl { +    const BlackfinRegisterInfo RI; +    const BlackfinSubtarget& Subtarget; +  public: +    explicit BlackfinInstrInfo(BlackfinSubtarget &ST); + +    /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info.  As +    /// such, whenever a client has an instance of instruction info, it should +    /// always be able to get register info as well (through this method). +    virtual const BlackfinRegisterInfo &getRegisterInfo() const { return RI; } + +    virtual bool isMoveInstr(const MachineInstr &MI, +                             unsigned &SrcReg, unsigned &DstReg, +                             unsigned &SrcSubIdx, unsigned &DstSubIdx) const; + +    virtual unsigned isLoadFromStackSlot(const MachineInstr *MI, +                                         int &FrameIndex) const; + +    virtual unsigned isStoreToStackSlot(const MachineInstr *MI, +                                        int &FrameIndex) const; + +    virtual unsigned +    InsertBranch(MachineBasicBlock &MBB, +                 MachineBasicBlock *TBB, +                 MachineBasicBlock *FBB, +                 const SmallVectorImpl<MachineOperand> &Cond) const; + +    virtual bool copyRegToReg(MachineBasicBlock &MBB, +                              MachineBasicBlock::iterator I, +                              unsigned DestReg, unsigned SrcReg, +                              const TargetRegisterClass *DestRC, +                              const TargetRegisterClass *SrcRC) const; + +    virtual void storeRegToStackSlot(MachineBasicBlock &MBB, +                                     MachineBasicBlock::iterator MBBI, +                                     unsigned SrcReg, bool isKill, +                                     int FrameIndex, +                                     const TargetRegisterClass *RC) const; + +    virtual void storeRegToAddr(MachineFunction &MF, +                                unsigned SrcReg, bool isKill, +                                SmallVectorImpl<MachineOperand> &Addr, +                                const TargetRegisterClass *RC, +                                SmallVectorImpl<MachineInstr*> &NewMIs) const; + +    virtual void loadRegFromStackSlot(MachineBasicBlock &MBB, +                                      MachineBasicBlock::iterator MBBI, +                                      unsigned DestReg, int FrameIndex, +                                      const TargetRegisterClass *RC) const; + +    virtual void loadRegFromAddr(MachineFunction &MF, unsigned DestReg, +                                 SmallVectorImpl<MachineOperand> &Addr, +                                 const TargetRegisterClass *RC, +                                 SmallVectorImpl<MachineInstr*> &NewMIs) const; +  }; + +} // end namespace llvm + +#endif diff --git a/llvm/lib/Target/Blackfin/BlackfinInstrInfo.td b/llvm/lib/Target/Blackfin/BlackfinInstrInfo.td new file mode 100644 index 00000000000..a6653517c9d --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinInstrInfo.td @@ -0,0 +1,838 @@ +//===- BlackfinInstrInfo.td - Target Description for Blackfin Target ------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the Blackfin instructions in TableGen format. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Instruction format superclass +//===----------------------------------------------------------------------===// + +include "BlackfinInstrFormats.td" + +// These are target-independent nodes, but have target-specific formats. +def SDT_BfinCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>; +def SDT_BfinCallSeqEnd   : SDCallSeqEnd<[ SDTCisVT<0, i32>, +                                        SDTCisVT<1, i32> ]>; + +def BfinCallseqStart : SDNode<"ISD::CALLSEQ_START", SDT_BfinCallSeqStart, +                              [SDNPHasChain, SDNPOutFlag]>; +def BfinCallseqEnd   : SDNode<"ISD::CALLSEQ_END",   SDT_BfinCallSeqEnd, +                              [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>; + +def SDT_BfinCall  : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>; +def BfinCall      : SDNode<"BFISD::CALL", SDT_BfinCall, +                           [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>; + +def BfinRet: SDNode<"BFISD::RET_FLAG", SDTNone, +                    [SDNPHasChain, SDNPOptInFlag]>; + +def BfinWrapper: SDNode<"BFISD::Wrapper", SDTIntUnaryOp>; + +//===----------------------------------------------------------------------===// +// Transformations +//===----------------------------------------------------------------------===// + +def trailingZeros_xform : SDNodeXForm<imm, [{ +  return CurDAG->getTargetConstant(N->getAPIntValue().countTrailingZeros(), +                                   MVT::i32); +}]>; + +def trailingOnes_xform : SDNodeXForm<imm, [{ +  return CurDAG->getTargetConstant(N->getAPIntValue().countTrailingOnes(), +                                   MVT::i32); +}]>; + +def LO16 : SDNodeXForm<imm, [{ +  return CurDAG->getTargetConstant((unsigned short)N->getZExtValue(), MVT::i16); +}]>; + +def HI16 : SDNodeXForm<imm, [{ +  // Transformation function: shift the immediate value down into the low bits. +  return CurDAG->getTargetConstant((unsigned)N->getZExtValue() >> 16, MVT::i16); +}]>; + +//===----------------------------------------------------------------------===// +// Immediates +//===----------------------------------------------------------------------===// + +def imm3  : PatLeaf<(imm), [{return isImm<3>(N->getSExtValue());}]>; +def uimm3 : PatLeaf<(imm), [{return isUimm<3>(N->getZExtValue());}]>; +def uimm4 : PatLeaf<(imm), [{return isUimm<4>(N->getZExtValue());}]>; +def uimm5 : PatLeaf<(imm), [{return isUimm<5>(N->getZExtValue());}]>; + +def uimm5m2 : PatLeaf<(imm), [{ +    uint64_t value = N->getZExtValue(); +    return value % 2 == 0 && isUimm<5>(value); +}]>; + +def uimm6m4 : PatLeaf<(imm), [{ +    uint64_t value = N->getZExtValue(); +    return value % 4 == 0 && isUimm<6>(value); +}]>; + +def imm7   : PatLeaf<(imm), [{return isImm<7>(N->getSExtValue());}]>; +def imm16  : PatLeaf<(imm), [{return isImm<16>(N->getSExtValue());}]>; +def uimm16 : PatLeaf<(imm), [{return isUimm<16>(N->getZExtValue());}]>; + +def ximm16 : PatLeaf<(imm), [{ +    int64_t value = N->getSExtValue(); +    return value < (1<<16) && value >= -(1<<15); +}]>; + +def imm17m2 : PatLeaf<(imm), [{ +    int64_t value = N->getSExtValue(); +    return value % 2 == 0 && isImm<17>(value); +}]>; + +def imm18m4 : PatLeaf<(imm), [{ +    int64_t value = N->getSExtValue(); +    return value % 4 == 0 && isImm<18>(value); +}]>; + +// 32-bit bitmask transformed to a bit number +def uimm5mask : Operand<i32>, PatLeaf<(imm), [{ +    return isPowerOf2_32(N->getZExtValue()); +}], trailingZeros_xform>; + +// 32-bit inverse bitmask transformed to a bit number +def uimm5imask : Operand<i32>, PatLeaf<(imm), [{ +    return isPowerOf2_32(~N->getZExtValue()); +}], trailingOnes_xform>; + +//===----------------------------------------------------------------------===// +// Operands +//===----------------------------------------------------------------------===// + +def calltarget : Operand<iPTR>; + +def brtarget : Operand<OtherVT>; + +// Addressing modes +def ADDRspii : ComplexPattern<i32, 2, "SelectADDRspii", [add, frameindex], []>; + +// Address operands +def MEMii : Operand<i32> { +  let PrintMethod = "printMemoryOperand"; +  let MIOperandInfo = (ops i32imm, i32imm); +} + +//===----------------------------------------------------------------------===// +// Instructions +//===----------------------------------------------------------------------===// + +// Pseudo instructions. +class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern> +   : InstBfin<outs, ins, asmstr, pattern>; + +let Defs = [SP], Uses = [SP] in { +def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt), +                              "${:comment}ADJCALLSTACKDOWN $amt", +                              [(BfinCallseqStart timm:$amt)]>; +def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), +                            "${:comment}ADJCALLSTACKUP $amt1 $amt2", +                            [(BfinCallseqEnd timm:$amt1, timm:$amt2)]>; +} + +//===----------------------------------------------------------------------===// +// Table C-9. Program Flow Control Instructions +//===----------------------------------------------------------------------===// + +let isBranch = 1, isTerminator = 1 in { + +let isIndirectBranch = 1 in +def JUMPp : F1<(outs), (ins P:$target), +               "JUMP ($target);", +               [(brind P:$target)]>; + +// TODO JUMP (PC-P) + +// NOTE: assembler chooses between JUMP.S and JUMP.L +def JUMPa : F1<(outs), (ins brtarget:$target), +               "jump $target;", +               [(br bb:$target)]>; + +def JUMPcc : F1<(outs), (ins AnyCC:$cc, brtarget:$target), +               "if $cc jump $target;", +               [(brcond AnyCC:$cc, bb:$target)]>; +} + +let isCall = 1, +    Defs   = [R0, R1, R2, R3, P0, P1, P2, LB0, LB1, LC0, LC1, RETS, ASTAT] in { +def CALLa: F1<(outs), (ins calltarget:$func, variable_ops), +              "call $func;", []>; +def CALLp: F1<(outs), (ins P:$func, variable_ops), +              "call ($func);", [(BfinCall P:$func)]>; +} + +let isReturn     = 1, +    isTerminator = 1, +    Uses         = [RETS] in +def RTS: F1<(outs), (ins), "rts;", [(BfinRet)]>; + +//===----------------------------------------------------------------------===// +// Table C-10. Load / Store Instructions +//===----------------------------------------------------------------------===// + +// Immediate constant loads + +// sext immediate, i32 D/P regs +def LOADimm7: F1<(outs DP:$dst), (ins i32imm:$src), +                 "$dst = $src (x);", +                 [(set DP:$dst, imm7:$src)]>; + +// zext immediate, i32 reg groups 0-3 +def LOADuimm16: F2<(outs GR:$dst), (ins i32imm:$src), +                   "$dst = $src (z);", +                   [(set GR:$dst, uimm16:$src)]>; + +// sext immediate, i32 reg groups 0-3 +def LOADimm16: F2<(outs GR:$dst), (ins i32imm:$src), +                  "$dst = $src (x);", +                  [(set GR:$dst, imm16:$src)]>; + +// Pseudo-instruction for loading a general 32-bit constant. +def LOAD32imm: Pseudo<(outs GR:$dst), (ins i32imm:$src), +                      "$dst.h = ($src >> 16); $dst.l = ($src & 0xffff);", +                      [(set GR:$dst, imm:$src)]>; + +def LOAD32sym: Pseudo<(outs GR:$dst), (ins i32imm:$src), +                      "$dst.h = $src; $dst.l = $src;", []>; + + +// 16-bit immediate, i16 reg groups 0-3 +def LOAD16i: F2<(outs GR16:$dst), (ins i16imm:$src), +                 "$dst = $src;", []>; + +def : Pat<(BfinWrapper (i32 tglobaladdr:$addr)), +          (LOAD32sym tglobaladdr:$addr)>; + +def : Pat<(BfinWrapper (i32 tjumptable:$addr)), +          (LOAD32sym tjumptable:$addr)>; + +// We cannot copy from GR16 to D16, and codegen wants to insert copies if we +// emit GR16 instructions. As a hack, we use this fake instruction instead. +def LOAD16i_d16: F2<(outs D16:$dst), (ins i16imm:$src), +                    "$dst = $src;", +                    [(set D16:$dst, ximm16:$src)]>; + +// Memory loads with patterns + +def LOAD32p: F1<(outs DP:$dst), (ins P:$ptr), +                "$dst = [$ptr];", +                [(set DP:$dst, (load P:$ptr))]>; + +// Pseudo-instruction for loading a stack slot +def LOAD32fi: Pseudo<(outs DP:$dst), (ins MEMii:$mem), +                     "${:comment}FI $dst = [$mem];", +                     [(set DP:$dst, (load ADDRspii:$mem))]>; + +// Note: Expands to multiple insns +def LOAD16fi: Pseudo<(outs D16:$dst), (ins MEMii:$mem), +                     "${:comment}FI $dst = [$mem];", +                     [(set D16:$dst, (load ADDRspii:$mem))]>; + +// Pseudo-instruction for loading a stack slot, used for AnyCC regs. +// Replaced with Load D + CC=D +def LOAD8fi: Pseudo<(outs AnyCC:$dst), (ins MEMii:$mem), +                    "${:comment}FI $dst = B[$mem];", +                    [(set AnyCC:$dst, (load ADDRspii:$mem))]>; + +def LOAD32p_uimm6m4: F1<(outs DP:$dst), (ins P:$ptr, i32imm:$off), +                        "$dst = [$ptr + $off];", +                        [(set DP:$dst, (load (add P:$ptr, uimm6m4:$off)))]>; + +def LOAD32p_imm18m4: F2<(outs DP:$dst), (ins P:$ptr, i32imm:$off), +                         "$dst = [$ptr + $off];", +                         [(set DP:$dst, (load (add P:$ptr, imm18m4:$off)))]>; + +def LOAD32p_16z: F1<(outs D:$dst), (ins P:$ptr), +                    "$dst = W[$ptr] (z);", +                    [(set D:$dst, (zextloadi16 P:$ptr))]>; + +def : Pat<(i32 (extloadi16 P:$ptr)),(LOAD32p_16z P:$ptr)>; + +def LOAD32p_uimm5m2_16z: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off), +                            "$dst = w[$ptr + $off] (z);", +                            [(set D:$dst, (zextloadi16 (add P:$ptr, +                                                        uimm5m2:$off)))]>; + +def : Pat<(i32 (extloadi16 (add P:$ptr, uimm5m2:$off))), +          (LOAD32p_uimm5m2_16z P:$ptr, imm:$off)>; + +def LOAD32p_imm17m2_16z: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off), +                            "$dst = w[$ptr + $off] (z);", +                            [(set D:$dst, +                                  (zextloadi16 (add P:$ptr, imm17m2:$off)))]>; + +def : Pat<(i32 (extloadi16 (add P:$ptr, imm17m2:$off))), +          (LOAD32p_imm17m2_16z P:$ptr, imm:$off)>; + +def LOAD32p_16s: F1<(outs D:$dst), (ins P:$ptr), +                    "$dst = w[$ptr] (x);", +                    [(set D:$dst, (sextloadi16 P:$ptr))]>; + +def LOAD32p_uimm5m2_16s: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off), +                            "$dst = w[$ptr + $off] (x);", +                            [(set D:$dst, +                                  (sextloadi16 (add P:$ptr, uimm5m2:$off)))]>; + +def LOAD32p_imm17m2_16s: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off), +                            "$dst = w[$ptr + $off] (x);", +                            [(set D:$dst, +                                  (sextloadi16 (add P:$ptr, imm17m2:$off)))]>; + +def LOAD16pi: F1<(outs D16:$dst), (ins PI:$ptr), +                "$dst = w[$ptr];", +                [(set D16:$dst, (load PI:$ptr))]>; + +def LOAD32p_8z: F1<(outs D:$dst), (ins P:$ptr), +                   "$dst = B[$ptr] (z);", +                   [(set D:$dst, (zextloadi8 P:$ptr))]>; + +def : Pat<(i32 (extloadi8 P:$ptr)), (LOAD32p_8z P:$ptr)>; +def : Pat<(i16 (extloadi8 P:$ptr)), +          (EXTRACT_SUBREG (LOAD32p_8z P:$ptr), bfin_subreg_lo16)>; +def : Pat<(i16 (zextloadi8 P:$ptr)), +          (EXTRACT_SUBREG (LOAD32p_8z P:$ptr), bfin_subreg_lo16)>; + +def LOAD32p_imm16_8z: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off), +                         "$dst = b[$ptr + $off] (z);", +                         [(set D:$dst, (zextloadi8 (add P:$ptr, imm16:$off)))]>; + +def : Pat<(i32 (extloadi8 (add P:$ptr, imm16:$off))), +          (LOAD32p_imm16_8z P:$ptr, imm:$off)>; +def : Pat<(i16 (extloadi8 (add P:$ptr, imm16:$off))), +          (EXTRACT_SUBREG (LOAD32p_imm16_8z P:$ptr, imm:$off), +                           bfin_subreg_lo16)>; +def : Pat<(i16 (zextloadi8 (add P:$ptr, imm16:$off))), +          (EXTRACT_SUBREG (LOAD32p_imm16_8z P:$ptr, imm:$off), +                           bfin_subreg_lo16)>; + +def LOAD32p_8s: F1<(outs D:$dst), (ins P:$ptr), +                   "$dst = b[$ptr] (x);", +                   [(set D:$dst, (sextloadi8 P:$ptr))]>; + +def : Pat<(i16 (sextloadi8 P:$ptr)), +          (EXTRACT_SUBREG (LOAD32p_8s P:$ptr), bfin_subreg_lo16)>; + +def LOAD32p_imm16_8s: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off), +                         "$dst = b[$ptr + $off] (x);", +                         [(set D:$dst, (sextloadi8 (add P:$ptr, imm16:$off)))]>; + +def : Pat<(i16 (sextloadi8 (add P:$ptr, imm16:$off))), +          (EXTRACT_SUBREG (LOAD32p_imm16_8s P:$ptr, imm:$off), +                           bfin_subreg_lo16)>; +// Memory loads without patterns + +let mayLoad = 1 in { + +multiclass LOAD_incdec<RegisterClass drc, RegisterClass prc, +                       string mem="", string suf=";"> { +  def _inc : F1<(outs drc:$dst, prc:$ptr_wb), (ins prc:$ptr), +                !strconcat(!subst("M", mem, "$dst = M[$ptr++]"), suf), []>; +  def _dec : F1<(outs drc:$dst, prc:$ptr_wb), (ins prc:$ptr), +                !strconcat(!subst("M", mem, "$dst = M[$ptr--]"), suf), []>; +} +multiclass LOAD_incdecpost<RegisterClass drc, RegisterClass prc, +                           string mem="", string suf=";"> +         : LOAD_incdec<drc, prc, mem, suf> { +  def _post : F1<(outs drc:$dst, prc:$ptr_wb), (ins prc:$ptr, prc:$off), +                 !strconcat(!subst("M", mem, "$dst = M[$ptr++$off]"), suf), []>; +} + +defm LOAD32p:    LOAD_incdec<DP, P>; +defm LOAD32i:    LOAD_incdec<D, I>; +defm LOAD8z32p:  LOAD_incdec<D, P, "b", " (z);">; +defm LOAD8s32p:  LOAD_incdec<D, P, "b", " (x);">; +defm LOADhi:     LOAD_incdec<D16, I, "w">; +defm LOAD16z32p: LOAD_incdecpost<D, P, "w", " (z);">; +defm LOAD16s32p: LOAD_incdecpost<D, P, "w", " (x);">; + +def LOAD32p_post: F1<(outs D:$dst, P:$ptr_wb), (ins P:$ptr, P:$off), +                     "$dst = [$ptr ++ $off];", []>; + +// Note: $fp MUST be FP +def LOAD32fp_nimm7m4: F1<(outs DP:$dst), (ins P:$fp, i32imm:$off), +                         "$dst = [$fp - $off];", []>; + +def LOAD32i:      F1<(outs D:$dst), (ins I:$ptr), +                     "$dst = [$ptr];", []>; +def LOAD32i_post: F1<(outs D:$dst, I:$ptr_wb), (ins I:$ptr, M:$off), +                     "$dst = [$ptr ++ $off];", []>; + + + +def LOADhp_post: F1<(outs D16:$dst, P:$ptr_wb), (ins P:$ptr, P:$off), +                    "$dst = w[$ptr ++ $off];", []>; + + +} + +// Memory stores with patterns +def STORE32p: F1<(outs), (ins DP:$val, P:$ptr), +                 "[$ptr] = $val;", +                 [(store DP:$val, P:$ptr)]>; + +// Pseudo-instructions for storing to a stack slot +def STORE32fi: Pseudo<(outs), (ins DP:$val, MEMii:$mem), +                      "${:comment}FI [$mem] = $val;", +                      [(store DP:$val, ADDRspii:$mem)]>; + +// Note: This stack-storing pseudo-instruction is expanded to multiple insns +def STORE16fi: Pseudo<(outs), (ins D16:$val, MEMii:$mem), +                  "${:comment}FI [$mem] = $val;", +                  [(store D16:$val, ADDRspii:$mem)]>; + +// Pseudo-instructions for storing AnyCC register to a stack slot. +// Replaced with D=CC + STORE byte +def STORE8fi: Pseudo<(outs), (ins AnyCC:$val, MEMii:$mem), +                      "${:comment}FI b[$mem] = $val;", +                      [(store AnyCC:$val, ADDRspii:$mem)]>; + +def STORE32p_uimm6m4: F1<(outs), (ins DP:$val, P:$ptr, i32imm:$off), +                 "[$ptr + $off] = $val;", +                 [(store DP:$val, (add P:$ptr, uimm6m4:$off))]>; + +def STORE32p_imm18m4: F1<(outs), (ins DP:$val, P:$ptr, i32imm:$off), +                 "[$ptr + $off] = $val;", +                 [(store DP:$val, (add P:$ptr, imm18m4:$off))]>; + +def STORE16pi: F1<(outs), (ins D16:$val, PI:$ptr), +                  "w[$ptr] = $val;", +                  [(store D16:$val, PI:$ptr)]>; + +def STORE8p: F1<(outs), (ins D:$val, P:$ptr), +                "b[$ptr] = $val;", +                [(truncstorei8 D:$val, P:$ptr)]>; + +def STORE8p_imm16: F1<(outs), (ins D:$val, P:$ptr, i32imm:$off), +                 "b[$ptr + $off] = $val;", +                 [(truncstorei8 D:$val, (add P:$ptr, imm16:$off))]>; + +let Constraints = "$ptr = $ptr_wb" in { + +multiclass STORE_incdec<RegisterClass drc, RegisterClass prc, +                        int off=4, string pre=""> { +  def _inc : F1<(outs prc:$ptr_wb), (ins drc:$val, prc:$ptr), +                !strconcat(pre, "[$ptr++] = $val;"), +                [(set prc:$ptr_wb, (post_store drc:$val, prc:$ptr, off))]>; +  def _dec : F1<(outs prc:$ptr_wb), (ins drc:$val, prc:$ptr), +                !strconcat(pre, "[$ptr--] = $val;"), +                [(set prc:$ptr_wb, (post_store drc:$val, prc:$ptr, +                                               (ineg off)))]>; +} + +defm STORE32p: STORE_incdec<DP, P>; +defm STORE16i: STORE_incdec<D16, I, 2, "w">; +defm STORE8p:  STORE_incdec<D, P, 1, "b">; + +def STORE32p_post: F1<(outs P:$ptr_wb), (ins D:$val, P:$ptr, P:$off), +                      "[$ptr ++ $off] = $val;", +                      [(set P:$ptr_wb, (post_store D:$val, P:$ptr, P:$off))]>; + +def STORE16p_post: F1<(outs P:$ptr_wb), (ins D16:$val, P:$ptr, P:$off), +                      "w[$ptr ++ $off] = $val;", +                      [(set P:$ptr_wb, (post_store D16:$val, P:$ptr, P:$off))]>; +} + +// Memory stores without patterns + +let mayStore = 1 in { + +// Note: only works for $fp == FP +def STORE32fp_nimm7m4: F1<(outs), (ins DP:$val, P:$fp, i32imm:$off), +                         "[$fp - $off] = $val;", []>; + +def STORE32i: F1<(outs), (ins D:$val, I:$ptr), +                 "[$ptr] = $val;", []>; + +def STORE32i_inc: F1<(outs I:$ptr_wb), (ins D:$val, I:$ptr), +                 "[$ptr++] = $val;", []>; + +def STORE32i_dec: F1<(outs I:$ptr_wb), (ins D:$val, I:$ptr), +                 "[$ptr--] = $val;", []>; + +def STORE32i_post: F1<(outs I:$ptr_wb), (ins D:$val, I:$ptr, M:$off), +                      "[$ptr ++ $off] = $val;", []>; +} + +def : Pat<(truncstorei16 D:$val, PI:$ptr), +          (STORE16pi (EXTRACT_SUBREG (COPY_TO_REGCLASS D:$val, D), +                                     bfin_subreg_lo16), PI:$ptr)>; + +def : Pat<(truncstorei16 (srl D:$val, (i16 16)), PI:$ptr), +          (STORE16pi (EXTRACT_SUBREG (COPY_TO_REGCLASS D:$val, D), +                                     bfin_subreg_hi16), PI:$ptr)>; + +def : Pat<(truncstorei8 D16L:$val, P:$ptr), +          (STORE8p (INSERT_SUBREG (i32 (IMPLICIT_DEF)), +                                  (COPY_TO_REGCLASS D16L:$val, D16L), +                                  bfin_subreg_lo16), +                   P:$ptr)>; + +//===----------------------------------------------------------------------===// +// Table C-11. Move Instructions. +//===----------------------------------------------------------------------===// + +def MOVE: F1<(outs ALL:$dst), (ins ALL:$src), +             "$dst = $src;", +             []>; + +let isTwoAddress = 1 in +def MOVEcc: F1<(outs DP:$dst), (ins DP:$src1, DP:$src2, AnyCC:$cc), +               "if $cc $dst = $src2;", +               [(set DP:$dst, (select AnyCC:$cc, DP:$src2, DP:$src1))]>; + +let Defs = [AZ, AN, AC0, V] in { +def MOVEzext: F1<(outs D:$dst), (ins D16L:$src), +                 "$dst = $src (z);", +                 [(set D:$dst, (zext D16L:$src))]>; + +def MOVEsext: F1<(outs D:$dst), (ins D16L:$src), +                 "$dst = $src (x);", +                 [(set D:$dst, (sext D16L:$src))]>; + +def MOVEzext8: F1<(outs D:$dst), (ins D:$src), +                  "$dst = $src.b (z);", +                  [(set D:$dst, (and D:$src, 0xff))]>; + +def MOVEsext8: F1<(outs D:$dst), (ins D:$src), +                  "$dst = $src.b (x);", +                  [(set D:$dst, (sext_inreg D:$src, i8))]>; + +} + +def : Pat<(sext_inreg D16L:$src, i8), +          (EXTRACT_SUBREG (MOVEsext8 +                           (INSERT_SUBREG (i32 (IMPLICIT_DEF)), +                                          D16L:$src, +                                          bfin_subreg_lo16)), +                          bfin_subreg_lo16)>; + +def : Pat<(sext_inreg D:$src, i16), +          (MOVEsext (EXTRACT_SUBREG D:$src, bfin_subreg_lo16))>; + +def : Pat<(and D:$src, 0xffff), +          (MOVEzext (EXTRACT_SUBREG D:$src, bfin_subreg_lo16))>; + +def : Pat<(i32 (anyext D16L:$src)), +          (INSERT_SUBREG (i32 (IMPLICIT_DEF)), +                         (COPY_TO_REGCLASS D16L:$src, D16L), +                         bfin_subreg_lo16)>; + +// TODO Dreg = Dreg_byte (X/Z) + +// TODO Accumulator moves + +//===----------------------------------------------------------------------===// +// Table C-12. Stack Control Instructions +//===----------------------------------------------------------------------===// + +let Uses = [SP], Defs = [SP] in { +def PUSH: F1<(outs), (ins ALL:$src), +             "[--sp] = $src;", []> { let mayStore = 1; } + +// NOTE: POP does not work for DP regs, use LOAD instead +def POP:  F1<(outs ALL:$dst), (ins), +             "$dst = [sp++];", []> { let mayLoad = 1; } +} + +// TODO: push/pop multiple + +def LINK: F2<(outs), (ins i32imm:$amount), +             "link $amount;", []>; + +def UNLINK: F2<(outs), (ins), +               "unlink;", []>; + +//===----------------------------------------------------------------------===// +// Table C-13. Control Code Bit Management Instructions +//===----------------------------------------------------------------------===// + +multiclass SETCC<PatFrag opnode, PatFrag invnode, string cond, string suf=";"> { +  def dd : F1<(outs JustCC:$cc), (ins D:$a, D:$b), +              !strconcat(!subst("XX", cond, "cc = $a XX $b"), suf), +              [(set JustCC:$cc, (opnode  D:$a, D:$b))]>; + +  def ri : F1<(outs JustCC:$cc), (ins DP:$a, i32imm:$b), +              !strconcat(!subst("XX", cond, "cc = $a XX $b"), suf), +              [(set JustCC:$cc, (opnode  DP:$a, imm3:$b))]>; + +  def pp : F1<(outs JustCC:$cc), (ins P:$a, P:$b), +              !strconcat(!subst("XX", cond, "cc = $a XX $b"), suf), +              []>; + +  def ri_not : F1<(outs NotCC:$cc), (ins DP:$a, i32imm:$b), +                  !strconcat(!subst("XX", cond, "cc = $a XX $b"), suf), +                  [(set NotCC:$cc, (invnode  DP:$a, imm3:$b))]>; +} + +defm SETEQ  : SETCC<seteq,  setne,  "==">; +defm SETLT  : SETCC<setlt,  setge,  "<">; +defm SETLE  : SETCC<setle,  setgt,  "<=">; +defm SETULT : SETCC<setult, setuge, "<",  " (iu);">; +defm SETULE : SETCC<setule, setugt, "<=", " (iu);">; + +def SETNEdd : F1<(outs NotCC:$cc), (ins D:$a, D:$b), +                 "cc = $a == $b;", +                 [(set NotCC:$cc, (setne  D:$a, D:$b))]>; + +def : Pat<(setgt  D:$a, D:$b), (SETLTdd  D:$b, D:$a)>; +def : Pat<(setge  D:$a, D:$b), (SETLEdd  D:$b, D:$a)>; +def : Pat<(setugt D:$a, D:$b), (SETULTdd D:$b, D:$a)>; +def : Pat<(setuge D:$a, D:$b), (SETULEdd D:$b, D:$a)>; + +// TODO: compare pointer for P-P comparisons +// TODO: compare accumulator + +let Defs = [AC0] in +def OR_ac0_cc : F1<(outs), (ins JustCC:$cc), +                   "ac0 \\|= cc;", []>; + +let Uses = [AC0] in +def MOVE_cc_ac0 : F1<(outs JustCC:$cc), (ins), +                   "cc = ac0;", []>; + +def MOVE_ccncc : F1<(outs JustCC:$cc), (ins NotCC:$sb), +                    "cc = !cc;", []>; + +def MOVE_ncccc : F1<(outs NotCC:$cc), (ins JustCC:$sb), +                    "cc = !cc;", []>; + +def MOVECC_zext : F1<(outs D:$dst), (ins JustCC:$cc), +                      "$dst = $cc;", +                      [(set D:$dst, (zext JustCC:$cc))]>; + +def MOVENCC_z : F1<(outs D:$dst), (ins NotCC:$cc), +                   "$dst = cc;", []>; + +def MOVECC_nz : F1<(outs AnyCC:$cc), (ins D:$src), +                   "cc = $src;", +                   [(set AnyCC:$cc, (setne D:$src, 0))]>; + +//===----------------------------------------------------------------------===// +// Table C-14. Logical Operations Instructions +//===----------------------------------------------------------------------===// + +def AND: F1<(outs D:$dst), (ins D:$src1, D:$src2), +            "$dst = $src1 & $src2;", +            [(set D:$dst, (and D:$src1, D:$src2))]>; + +def NOT: F1<(outs D:$dst), (ins D:$src), +            "$dst = ~$src;", +            [(set D:$dst, (not D:$src))]>; + +def OR: F1<(outs D:$dst), (ins D:$src1, D:$src2), +           "$dst = $src1 \\| $src2;", +           [(set D:$dst, (or D:$src1, D:$src2))]>; + +def XOR: F1<(outs D:$dst), (ins D:$src1, D:$src2), +            "$dst = $src1 ^ $src2;", +            [(set D:$dst, (xor D:$src1, D:$src2))]>; + +// missing: BXOR, BXORSHIFT + +//===----------------------------------------------------------------------===// +// Table C-15. Bit Operations Instructions +//===----------------------------------------------------------------------===// + +let isTwoAddress = 1 in { +def BITCLR: F1<(outs D:$dst), (ins D:$src1, uimm5imask:$src2), +              "bitclr($dst, $src2);", +              [(set D:$dst, (and D:$src1, uimm5imask:$src2))]>; + +def BITSET: F1<(outs D:$dst), (ins D:$src1, uimm5mask:$src2), +              "bitset($dst, $src2);", +              [(set D:$dst, (or D:$src1, uimm5mask:$src2))]>; + +def BITTGL: F1<(outs D:$dst), (ins D:$src1, uimm5mask:$src2), +              "bittgl($dst, $src2);", +              [(set D:$dst, (xor D:$src1, uimm5mask:$src2))]>; +} + +def BITTST: F1<(outs JustCC:$cc), (ins D:$src1, uimm5mask:$src2), +              "cc = bittst($src1, $src2);", +              [(set JustCC:$cc, (setne (and D:$src1, uimm5mask:$src2), +                                       (i32 0)))]>; + +def NBITTST: F1<(outs JustCC:$cc), (ins D:$src1, uimm5mask:$src2), +               "cc = !bittst($src1, $src2);", +               [(set JustCC:$cc, (seteq (and D:$src1, uimm5mask:$src2), +                                        (i32 0)))]>; + +// TODO: DEPOSIT, EXTRACT, BITMUX + +def ONES: F2<(outs D16L:$dst), (ins D:$src), +              "$dst = ones $src;", +              [(set D16L:$dst, (trunc (ctpop D:$src)))]>; + +def : Pat<(ctpop D:$src), (MOVEzext (ONES D:$src))>; + +//===----------------------------------------------------------------------===// +// Table C-16. Shift / Rotate Instructions +//===----------------------------------------------------------------------===// + +multiclass SHIFT32<SDNode opnode, string ops> { +  def i : F1<(outs D:$dst), (ins D:$src, i16imm:$amount), +             !subst("XX", ops, "$dst XX= $amount;"), +             [(set D:$dst, (opnode D:$src, (i16 uimm5:$amount)))]>; +  def r : F1<(outs D:$dst), (ins D:$src, D:$amount), +             !subst("XX", ops, "$dst XX= $amount;"), +             [(set D:$dst, (opnode D:$src, D:$amount))]>; +} + +let Defs = [AZ, AN, V, VS], +    isTwoAddress = 1 in { +defm SRA : SHIFT32<sra, ">>>">; +defm SRL : SHIFT32<srl, ">>">; +defm SLL : SHIFT32<shl, "<<">; +} + +// TODO: automatic switching between 2-addr and 3-addr (?) + +let Defs = [AZ, AN, V, VS] in { +def SLLr16: F2<(outs D:$dst), (ins D:$src, D16L:$amount), +             "$dst = lshift $src by $amount;", +             [(set D:$dst, (shl D:$src, D16L:$amount))]>; + +// Arithmetic left-shift = saturing overflow. +def SLAr16: F2<(outs D:$dst), (ins D:$src, D16L:$amount), +             "$dst = ashift $src by $amount;", +             [(set D:$dst, (sra D:$src, (ineg D16L:$amount)))]>; + +def SRA16i: F1<(outs D16:$dst), (ins D16:$src, i16imm:$amount), +              "$dst = $src >>> $amount;", +              [(set D16:$dst, (sra D16:$src, (i16 uimm4:$amount)))]>; + +def SRL16i: F1<(outs D16:$dst), (ins D16:$src, i16imm:$amount), +              "$dst = $src >> $amount;", +              [(set D16:$dst, (srl D16:$src, (i16 uimm4:$amount)))]>; + +// Arithmetic left-shift = saturing overflow. +def SLA16r: F1<(outs D16:$dst), (ins D16:$src, D16L:$amount), +              "$dst = ashift $src BY $amount;", +              [(set D16:$dst, (srl D16:$src, (ineg D16L:$amount)))]>; + +def SLL16i: F1<(outs D16:$dst), (ins D16:$src, i16imm:$amount), +              "$dst = $src << $amount;", +              [(set D16:$dst, (shl D16:$src, (i16 uimm4:$amount)))]>; + +def SLL16r: F1<(outs D16:$dst), (ins D16:$src, D16L:$amount), +              "$dst = lshift $src by $amount;", +              [(set D16:$dst, (shl D16:$src, D16L:$amount))]>; + +} + +//===----------------------------------------------------------------------===// +// Table C-17. Arithmetic Operations Instructions +//===----------------------------------------------------------------------===// + +// TODO: ABS + +let Defs = [AZ, AN, AC0, V, VS] in { + +def ADD: F1<(outs D:$dst), (ins D:$src1, D:$src2), +            "$dst = $src1 + $src2;", +            [(set D:$dst, (add D:$src1, D:$src2))]>; + +def ADD16: F2<(outs D16:$dst), (ins D16:$src1, D16:$src2), +              "$dst = $src1 + $src2;", +              [(set D16:$dst, (add D16:$src1, D16:$src2))]>; + +let isTwoAddress = 1 in +def ADDimm7: F1<(outs D:$dst), (ins D:$src1, i32imm:$src2), +                "$dst += $src2;", +                [(set D:$dst, (add D:$src1, imm7:$src2))]>; + +def SUB: F1<(outs D:$dst), (ins D:$src1, D:$src2), +            "$dst = $src1 - $src2;", +            [(set D:$dst, (sub D:$src1, D:$src2))]>; + +def SUB16: F2<(outs D16:$dst), (ins D16:$src1, D16:$src2), +              "$dst = $src1 - $src2;", +              [(set D16:$dst, (sub D16:$src1, D16:$src2))]>; + +} + +def : Pat<(addc D:$src1, D:$src2), (ADD D:$src1, D:$src2)>; +def : Pat<(subc D:$src1, D:$src2), (SUB D:$src1, D:$src2)>; + +let Defs = [AZ, AN, V, VS] in +def NEG: F1<(outs D:$dst), (ins D:$src), +            "$dst = -$src;", +            [(set D:$dst, (ineg D:$src))]>; + +// No pattern, it would confuse isel to have two i32 = i32+i32 patterns +def ADDpp: F1<(outs P:$dst), (ins P:$src1, P:$src2), +              "$dst = $src1 + $src2;", []>; + +let isTwoAddress = 1 in +def ADDpp_imm7: F1<(outs P:$dst), (ins P:$src1, i32imm:$src2), +                "$dst += $src2;", []>; + +let Defs = [AZ, AN, V] in +def ADD_RND20: F2<(outs D16:$dst), (ins D:$src1, D:$src2), +                  "$dst = $src1 + $src2 (rnd20);", []>; + +let Defs = [V, VS] in { +def MUL16: F2<(outs D16:$dst), (ins D16:$src1, D16:$src2), +              "$dst = $src1 * $src2 (is);", +              [(set D16:$dst, (mul D16:$src1, D16:$src2))]>; + +def MULHS16: F2<(outs D16:$dst), (ins D16:$src1, D16:$src2), +                "$dst = $src1 * $src2 (ih);", +                [(set D16:$dst, (mulhs D16:$src1, D16:$src2))]>; + +def MULhh32s: F2<(outs D:$dst), (ins D16:$src1, D16:$src2), +                "$dst = $src1 * $src2 (is);", +                [(set D:$dst, (mul (sext D16:$src1), (sext D16:$src2)))]>; + +def MULhh32u: F2<(outs D:$dst), (ins D16:$src1, D16:$src2), +                "$dst = $src1 * $src2 (is);", +                [(set D:$dst, (mul (zext D16:$src1), (zext D16:$src2)))]>; +} + + +let isTwoAddress = 1 in +def MUL32: F1<(outs D:$dst), (ins D:$src1, D:$src2), +            "$dst *= $src2;", +            [(set D:$dst, (mul D:$src1, D:$src2))]>; + +//===----------------------------------------------------------------------===// +// Table C-18. External Exent Management Instructions +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Table C-19. Cache Control Instructions +//===----------------------------------------------------------------------===// + +// Table C-20. Video Pixel Operations Instructions +// Table C-21. Vector Operations Instructions + +// Patterns +def : Pat<(BfinCall (i32 tglobaladdr:$dst)), +          (CALLa tglobaladdr:$dst)>; +def : Pat<(BfinCall (i32 texternalsym:$dst)), +          (CALLa texternalsym:$dst)>; + +def : Pat<(sext JustCC:$cc), +          (NEG (MOVECC_zext JustCC:$cc))>; +def : Pat<(anyext JustCC:$cc), +          (MOVECC_zext JustCC:$cc)>; +def : Pat<(i16 (zext JustCC:$cc)), +          (EXTRACT_SUBREG (MOVECC_zext JustCC:$cc), bfin_subreg_lo16)>; +def : Pat<(i16 (sext JustCC:$cc)), +          (EXTRACT_SUBREG (NEG (MOVECC_zext JustCC:$cc)), bfin_subreg_lo16)>; +def : Pat<(i16 (anyext JustCC:$cc)), +          (EXTRACT_SUBREG (MOVECC_zext JustCC:$cc), bfin_subreg_lo16)>; + +def : Pat<(i16 (trunc D:$src)), +          (EXTRACT_SUBREG (COPY_TO_REGCLASS D:$src, D), bfin_subreg_lo16)>; diff --git a/llvm/lib/Target/Blackfin/BlackfinRegisterInfo.cpp b/llvm/lib/Target/Blackfin/BlackfinRegisterInfo.cpp new file mode 100644 index 00000000000..619906e37e9 --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinRegisterInfo.cpp @@ -0,0 +1,462 @@ +//===- BlackfinRegisterInfo.cpp - Blackfin Register Information -*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Blackfin implementation of the TargetRegisterInfo +// class. +// +//===----------------------------------------------------------------------===// + +#include "Blackfin.h" +#include "BlackfinRegisterInfo.h" +#include "BlackfinSubtarget.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineLocation.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Type.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +using namespace llvm; + +BlackfinRegisterInfo::BlackfinRegisterInfo(BlackfinSubtarget &st, +                                           const TargetInstrInfo &tii) +  : BlackfinGenRegisterInfo(BF::ADJCALLSTACKDOWN, BF::ADJCALLSTACKUP), +    Subtarget(st), +    TII(tii) {} + +const unsigned* +BlackfinRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { +  using namespace BF; +  static const unsigned CalleeSavedRegs[] = { +    FP, +    R4, R5, R6, R7, +    P3, P4, P5, +    0 }; +  return  CalleeSavedRegs; +} + +const TargetRegisterClass* const *BlackfinRegisterInfo:: +getCalleeSavedRegClasses(const MachineFunction *MF) const { +  using namespace BF; +  static const TargetRegisterClass * const CalleeSavedRegClasses[] = { +    &PRegClass, +    &DRegClass, &DRegClass, &DRegClass, &DRegClass, +    &PRegClass, &PRegClass, &PRegClass, +    0 }; +  return CalleeSavedRegClasses; +} + +BitVector +BlackfinRegisterInfo::getReservedRegs(const MachineFunction &MF) const { +  using namespace BF; +  BitVector Reserved(getNumRegs()); +  Reserved.set(L0); +  Reserved.set(L1); +  Reserved.set(L2); +  Reserved.set(L3); +  Reserved.set(SP); +  Reserved.set(RETS); +  if (hasFP(MF)) +    Reserved.set(FP); +  return Reserved; +} + +const TargetRegisterClass* +BlackfinRegisterInfo::getPhysicalRegisterRegClass(unsigned reg, MVT VT) const { +  assert(isPhysicalRegister(reg) && "reg must be a physical register"); + +  // Pick the smallest register class of the right type that contains +  // this physreg. +  const TargetRegisterClass* BestRC = 0; +  for (regclass_iterator I = regclass_begin(), E = regclass_end(); +       I != E; ++I) { +    const TargetRegisterClass* RC = *I; +    if ((VT == MVT::Other || RC->hasType(VT)) && RC->contains(reg) && +        (!BestRC || RC->getNumRegs() < BestRC->getNumRegs())) +      BestRC = RC; +  } + +  assert(BestRC && "Couldn't find the register class"); +  return BestRC; +} + +// hasFP - Return true if the specified function should have a dedicated frame +// pointer register.  This is true if the function has variable sized allocas or +// if frame pointer elimination is disabled. +bool BlackfinRegisterInfo::hasFP(const MachineFunction &MF) const { +  const MachineFrameInfo *MFI = MF.getFrameInfo(); +  return NoFramePointerElim || MFI->hasCalls() || MFI->hasVarSizedObjects(); +} + +bool BlackfinRegisterInfo:: +requiresRegisterScavenging(const MachineFunction &MF) const { +  return true; +} + +// Emit instructions to add delta to D/P register. ScratchReg must be of the +// same class as Reg (P). +void BlackfinRegisterInfo::adjustRegister(MachineBasicBlock &MBB, +                                          MachineBasicBlock::iterator I, +                                          DebugLoc DL, +                                          unsigned Reg, +                                          unsigned ScratchReg, +                                          int delta) const { +  if (!delta) +    return; +  if (isImm<7>(delta)) { +    BuildMI(MBB, I, DL, TII.get(BF::ADDpp_imm7), Reg) +      .addReg(Reg)              // No kill on two-addr operand +      .addImm(delta); +    return; +  } + +  // We must load delta into ScratchReg and add that. +  loadConstant(MBB, I, DL, ScratchReg, delta); +  if (BF::PRegClass.contains(Reg)) { +    assert (BF::PRegClass.contains(ScratchReg)); +    BuildMI(MBB, I, DL, TII.get(BF::ADDpp), Reg) +      .addReg(Reg, RegState::Kill) +      .addReg(ScratchReg, RegState::Kill); +  } else { +    assert (BF::DRegClass.contains(Reg)); +    assert (BF::DRegClass.contains(ScratchReg)); +    BuildMI(MBB, I, DL, TII.get(BF::ADD), Reg) +      .addReg(Reg, RegState::Kill) +      .addReg(ScratchReg, RegState::Kill); +  } +} + +// Emit instructions to load a constant into D/P register +void BlackfinRegisterInfo::loadConstant(MachineBasicBlock &MBB, +                                        MachineBasicBlock::iterator I, +                                        DebugLoc DL, +                                        unsigned Reg, +                                        int value) const { +  if (isImm<7>(value)) { +    BuildMI(MBB, I, DL, TII.get(BF::LOADimm7), Reg).addImm(value); +    return; +  } + +  if (isUimm<16>(value)) { +    BuildMI(MBB, I, DL, TII.get(BF::LOADuimm16), Reg).addImm(value); +    return; +  } + +  if (isImm<16>(value)) { +    BuildMI(MBB, I, DL, TII.get(BF::LOADimm16), Reg).addImm(value); +    return; +  } + +  // We must split into halves +  BuildMI(MBB, I, DL, +          TII.get(BF::LOAD16i), getSubReg(Reg, bfin_subreg_hi16)) +    .addImm((value >> 16) & 0xffff) +    .addReg(Reg, RegState::ImplicitDefine); +  BuildMI(MBB, I, DL, +          TII.get(BF::LOAD16i), getSubReg(Reg, bfin_subreg_lo16)) +    .addImm(value & 0xffff) +    .addReg(Reg, RegState::ImplicitKill) +    .addReg(Reg, RegState::ImplicitDefine); +} + +void BlackfinRegisterInfo:: +eliminateCallFramePseudoInstr(MachineFunction &MF, +                              MachineBasicBlock &MBB, +                              MachineBasicBlock::iterator I) const { +  if (!hasReservedCallFrame(MF)) { +    int64_t Amount = I->getOperand(0).getImm(); +    if (Amount != 0) { +      assert(Amount%4 == 0); +      if (I->getOpcode() == BF::ADJCALLSTACKDOWN) { +        adjustRegister(MBB, I, I->getDebugLoc(), BF::SP, BF::P1, -Amount); +      } else { +        assert(I->getOpcode() == BF::ADJCALLSTACKUP); +        adjustRegister(MBB, I, I->getDebugLoc(), BF::SP, BF::P1, Amount); +      } +    } +  } +  MBB.erase(I); +} + +/// findScratchRegister - Find a 'free' register. Try for a call-clobbered +/// register first and then a spilled callee-saved register if that fails. +static unsigned findScratchRegister(MachineBasicBlock::iterator II, +                                    RegScavenger *RS, +                                    const TargetRegisterClass *RC, +                                    int SPAdj) { +  assert(RS && "Register scavenging must be on"); +  unsigned Reg = RS->FindUnusedReg(RC, true); +  if (Reg == 0) +    Reg = RS->scavengeRegister(RC, II, SPAdj); +  return Reg; +} + +void BlackfinRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, +                                               int SPAdj, +                                               RegScavenger *RS) const { +  unsigned i; +  MachineInstr &MI = *II; +  MachineBasicBlock &MBB = *MI.getParent(); +  MachineFunction &MF = *MBB.getParent(); +  DebugLoc DL = MI.getDebugLoc(); + +  for (i=0; !MI.getOperand(i).isFI(); i++) { +    assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); +  } +  int FrameIndex = MI.getOperand(i).getIndex(); +  assert(i+1 < MI.getNumOperands() && MI.getOperand(i+1).isImm()); +  int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +    + MI.getOperand(i+1).getImm(); +  unsigned BaseReg = BF::FP; +  if (hasFP(MF)) { +    assert(SPAdj==0); +  } else { +    BaseReg = BF::SP; +    Offset += MF.getFrameInfo()->getStackSize() + SPAdj; +  } + +  bool isStore = false; + +  switch (MI.getOpcode()) { +  case BF::STORE32fi: +    isStore = true; +  case BF::LOAD32fi: { +    assert(Offset%4 == 0 && "Badly aligned i32 stack access"); +    assert(i==1); +    MI.getOperand(i).ChangeToRegister(BaseReg, false); +    MI.getOperand(i+1).setImm(Offset); +    if (isUimm<6>(Offset)) { +      MI.setDesc(TII.get(isStore +                         ? BF::STORE32p_uimm6m4 +                         : BF::LOAD32p_uimm6m4)); +      return; +    } +    if (BaseReg == BF::FP && isUimm<7>(-Offset)) { +      MI.setDesc(TII.get(isStore +                         ? BF::STORE32fp_nimm7m4 +                         : BF::LOAD32fp_nimm7m4)); +      MI.getOperand(i+1).setImm(-Offset); +      return; +    } +    if (isImm<18>(Offset)) { +      MI.setDesc(TII.get(isStore +                         ? BF::STORE32p_imm18m4 +                         : BF::LOAD32p_imm18m4)); +      return; +    } +    // Use RegScavenger to calculate proper offset... +    MI.dump(); +    llvm_unreachable("Stack frame offset too big"); +    break; +  } +  case BF::ADDpp: { +    assert(MI.getOperand(0).isReg()); +    unsigned DestReg = MI.getOperand(0).getReg(); +    // We need to produce a stack offset in a P register. We emit: +    // P0 = offset; +    // P0 = BR + P0; +    assert(i==1); +    loadConstant(MBB, II, DL, DestReg, Offset); +    MI.getOperand(1).ChangeToRegister(DestReg, false, false, true); +    MI.getOperand(2).ChangeToRegister(BaseReg, false); +    break; +  } +  case BF::STORE16fi: +    isStore = true; +  case BF::LOAD16fi: { +    assert(Offset%2 == 0 && "Badly aligned i16 stack access"); +    assert(i==1); +    // We need a P register to use as an address +    unsigned ScratchReg = findScratchRegister(II, RS, &BF::PRegClass, SPAdj); +    assert(ScratchReg); +    loadConstant(MBB, II, DL, ScratchReg, Offset); +    BuildMI(MBB, II, DL, TII.get(BF::ADDpp), ScratchReg) +      .addReg(ScratchReg, RegState::Kill) +      .addReg(BaseReg); +    MI.setDesc(TII.get(isStore ? BF::STORE16pi : BF::LOAD16pi)); +    MI.getOperand(1).ChangeToRegister(ScratchReg, false, false, true); +    MI.RemoveOperand(2); +    break; +  } +  case BF::STORE8fi: { +    // This is an AnyCC spill, we need a scratch register. +    assert(i==1); +    MachineOperand SpillReg = MI.getOperand(0); +    unsigned ScratchReg = findScratchRegister(II, RS, &BF::DRegClass, SPAdj); +    assert(ScratchReg); +    if (SpillReg.getReg()==BF::NCC) { +      BuildMI(MBB, II, DL, TII.get(BF::MOVENCC_z), ScratchReg) +        .addOperand(SpillReg); +      BuildMI(MBB, II, DL, TII.get(BF::BITTGL), ScratchReg) +        .addReg(ScratchReg).addImm(0); +    } else { +      BuildMI(MBB, II, DL, TII.get(BF::MOVECC_zext), ScratchReg) +        .addOperand(SpillReg); +    } +    // STORE D +    MI.setDesc(TII.get(BF::STORE8p_imm16)); +    MI.getOperand(0).ChangeToRegister(ScratchReg, false, false, true); +    MI.getOperand(i).ChangeToRegister(BaseReg, false); +    MI.getOperand(i+1).setImm(Offset); +    break; +  } +  case BF::LOAD8fi: { +    // This is an restore, we need a scratch register. +    assert(i==1); +    MachineOperand SpillReg = MI.getOperand(0); +    unsigned ScratchReg = findScratchRegister(II, RS, &BF::DRegClass, SPAdj); +    assert(ScratchReg); +    MI.setDesc(TII.get(BF::LOAD32p_imm16_8z)); +    MI.getOperand(0).ChangeToRegister(ScratchReg, true); +    MI.getOperand(i).ChangeToRegister(BaseReg, false); +    MI.getOperand(i+1).setImm(Offset); +    ++II; +    if (SpillReg.getReg()==BF::CC) { +      // CC = D +      BuildMI(MBB, II, DL, TII.get(BF::MOVECC_nz), BF::CC) +        .addReg(ScratchReg, RegState::Kill); +    } else { +      // Restore NCC (CC = D==0) +      BuildMI(MBB, II, DL, TII.get(BF::SETEQri_not), BF::NCC) +        .addReg(ScratchReg, RegState::Kill) +        .addImm(0); +    } +    break; +  } +  default: +    llvm_unreachable("Cannot eliminate frame index"); +    break; +  } +} + +void BlackfinRegisterInfo:: +processFunctionBeforeCalleeSavedScan(MachineFunction &MF, +                                     RegScavenger *RS) const { +  MachineFrameInfo *MFI = MF.getFrameInfo(); +  const TargetRegisterClass *RC = BF::DPRegisterClass; +  if (requiresRegisterScavenging(MF)) { +    // Reserve a slot close to SP or frame pointer. +    RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(), +                                                       RC->getAlignment())); +  } +} + +void BlackfinRegisterInfo:: +processFunctionBeforeFrameFinalized(MachineFunction &MF) const { +} + +// Emit a prologue that sets up a stack frame. +// On function entry, R0-R2 and P0 may hold arguments. +// R3, P1, and P2 may be used as scratch registers +void BlackfinRegisterInfo::emitPrologue(MachineFunction &MF) const { +  MachineBasicBlock &MBB = MF.front();   // Prolog goes in entry BB +  MachineBasicBlock::iterator MBBI = MBB.begin(); +  MachineFrameInfo *MFI = MF.getFrameInfo(); +  DebugLoc dl = (MBBI != MBB.end() +                 ? MBBI->getDebugLoc() +                 : DebugLoc::getUnknownLoc()); + +  int FrameSize = MFI->getStackSize(); +  if (FrameSize%4) { +    FrameSize = (FrameSize+3) & ~3; +    MFI->setStackSize(FrameSize); +  } + +  if (!hasFP(MF)) { +    // So far we only support FP elimination on leaf functions +    assert(!MFI->hasCalls()); +    adjustRegister(MBB, MBBI, dl, BF::SP, BF::P1, -FrameSize); +    return; +  } + +  // emit a LINK instruction +  if (FrameSize <= 0x3ffff) { +    BuildMI(MBB, MBBI, dl, TII.get(BF::LINK)).addImm(FrameSize); +    return; +  } + +  // Frame is too big, do a manual LINK: +  // [--SP] = RETS; +  // [--SP] = FP; +  // FP = SP; +  // P1 = -FrameSize; +  // SP = SP + P1; +  BuildMI(MBB, MBBI, dl, TII.get(BF::PUSH)) +    .addReg(BF::RETS, RegState::Kill); +  BuildMI(MBB, MBBI, dl, TII.get(BF::PUSH)) +    .addReg(BF::FP, RegState::Kill); +  BuildMI(MBB, MBBI, dl, TII.get(BF::MOVE), BF::FP) +    .addReg(BF::SP); +  loadConstant(MBB, MBBI, dl, BF::P1, -FrameSize); +  BuildMI(MBB, MBBI, dl, TII.get(BF::ADDpp), BF::SP) +    .addReg(BF::SP, RegState::Kill) +    .addReg(BF::P1, RegState::Kill); + +} + +void BlackfinRegisterInfo::emitEpilogue(MachineFunction &MF, +                                        MachineBasicBlock &MBB) const { +  MachineFrameInfo *MFI = MF.getFrameInfo(); +  MachineBasicBlock::iterator MBBI = prior(MBB.end()); +  DebugLoc dl = MBBI->getDebugLoc(); + +  int FrameSize = MFI->getStackSize(); +  assert(FrameSize%4 == 0 && "Misaligned frame size"); + +  if (!hasFP(MF)) { +    // So far we only support FP elimination on leaf functions +    assert(!MFI->hasCalls()); +    adjustRegister(MBB, MBBI, dl, BF::SP, BF::P1, FrameSize); +    return; +  } + +  // emit an UNLINK instruction +  BuildMI(MBB, MBBI, dl, TII.get(BF::UNLINK)); +} + +unsigned BlackfinRegisterInfo::getRARegister() const { +  return BF::RETS; +} + +unsigned BlackfinRegisterInfo::getFrameRegister(MachineFunction &MF) const { +  return hasFP(MF) ? BF::FP : BF::SP; +} + +int +BlackfinRegisterInfo::getFrameIndexOffset(MachineFunction &MF, int FI) const { +  const TargetFrameInfo &TFI = *MF.getTarget().getFrameInfo(); +  MachineFrameInfo *MFI = MF.getFrameInfo(); +  return MFI->getObjectOffset(FI) + MFI->getStackSize() - +    TFI.getOffsetOfLocalArea() + MFI->getOffsetAdjustment(); +} + +unsigned BlackfinRegisterInfo::getEHExceptionRegister() const { +  llvm_unreachable("What is the exception register"); +  return 0; +} + +unsigned BlackfinRegisterInfo::getEHHandlerRegister() const { +  llvm_unreachable("What is the exception handler register"); +  return 0; +} + +int BlackfinRegisterInfo::getDwarfRegNum(unsigned RegNum, bool isEH) const { +  llvm_unreachable("What is the dwarf register number"); +  return -1; +} + +#include "BlackfinGenRegisterInfo.inc" + diff --git a/llvm/lib/Target/Blackfin/BlackfinRegisterInfo.h b/llvm/lib/Target/Blackfin/BlackfinRegisterInfo.h new file mode 100644 index 00000000000..8af65a3ef84 --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinRegisterInfo.h @@ -0,0 +1,114 @@ +//===- BlackfinRegisterInfo.h - Blackfin Register Information ..-*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Blackfin implementation of the TargetRegisterInfo +// class. +// +//===----------------------------------------------------------------------===// + +#ifndef BLACKFINREGISTERINFO_H +#define BLACKFINREGISTERINFO_H + +#include "llvm/Target/TargetRegisterInfo.h" +#include "BlackfinGenRegisterInfo.h.inc" + +namespace llvm { + +  class BlackfinSubtarget; +  class TargetInstrInfo; +  class Type; + +  template<unsigned N> +  static inline bool isImm(int x) { +    return x >= -(1<<(N-1)) && x < (1<<(N-1)); +  } + +  template<unsigned N> +  static inline bool isUimm(unsigned x) { +    return x < (1<<N); +  } + +  // Subregister indices, keep in sync with BlackfinRegisterInfo.td +  enum BfinSubregIdx { +    bfin_subreg_lo16 = 1, +    bfin_subreg_hi16 = 2, +    bfin_subreg_lo32 = 3 +  }; + +  struct BlackfinRegisterInfo : public BlackfinGenRegisterInfo { +    BlackfinSubtarget &Subtarget; +    const TargetInstrInfo &TII; + +    BlackfinRegisterInfo(BlackfinSubtarget &st, const TargetInstrInfo &tii); + +    /// Code Generation virtual methods... +    const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const; + +    const TargetRegisterClass* const* +    getCalleeSavedRegClasses(const MachineFunction *MF = 0) const; + +    BitVector getReservedRegs(const MachineFunction &MF) const; + +    // getSubReg implemented by tablegen + +    const TargetRegisterClass *getPointerRegClass(unsigned Kind = 0) const { +      return &BF::PRegClass; +    } + +    const TargetRegisterClass *getPhysicalRegisterRegClass(unsigned reg, +                                                           MVT VT) const; + +    bool hasFP(const MachineFunction &MF) const; + +    // bool hasReservedCallFrame(MachineFunction &MF) const; + +    bool requiresRegisterScavenging(const MachineFunction &MF) const; + +    void eliminateCallFramePseudoInstr(MachineFunction &MF, +                                       MachineBasicBlock &MBB, +                                       MachineBasicBlock::iterator I) const; + +    void eliminateFrameIndex(MachineBasicBlock::iterator II, +                             int SPAdj, RegScavenger *RS = NULL) const; + +    void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, +                                              RegScavenger *RS) const; + +    void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; + +    void emitPrologue(MachineFunction &MF) const; +    void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + +    unsigned getFrameRegister(MachineFunction &MF) const; +    int getFrameIndexOffset(MachineFunction &MF, int FI) const; +    unsigned getRARegister() const; + +    // Exception handling queries. +    unsigned getEHExceptionRegister() const; +    unsigned getEHHandlerRegister() const; + +    int getDwarfRegNum(unsigned RegNum, bool isEH) const; + +    // Utility functions +    void adjustRegister(MachineBasicBlock &MBB, +                        MachineBasicBlock::iterator I, +                        DebugLoc DL, +                        unsigned Reg, +                        unsigned ScratchReg, +                        int delta) const; +    void loadConstant(MachineBasicBlock &MBB, +                      MachineBasicBlock::iterator I, +                      DebugLoc DL, +                      unsigned Reg, +                      int value) const; +  }; + +} // end namespace llvm + +#endif diff --git a/llvm/lib/Target/Blackfin/BlackfinRegisterInfo.td b/llvm/lib/Target/Blackfin/BlackfinRegisterInfo.td new file mode 100644 index 00000000000..2b06fe34964 --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinRegisterInfo.td @@ -0,0 +1,380 @@ +//===- BlackfinRegisterInfo.td - Blackfin Register defs ----*- tablegen -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//  Declarations that describe the Blackfin register file +//===----------------------------------------------------------------------===// + +// Registers are identified with 3-bit group and 3-bit ID numbers. + +class BlackfinReg<string n> : Register<n> { +  field bits<3> Group; +  field bits<3> Num; +  let Namespace = "BF"; +} + +// Rc - 1-bit registers +class Rc<bits<5> bitno, string n> : BlackfinReg<n> { +  field bits<5> BitNum = bitno; +} + +// Rs - 16-bit integer registers +class Rs<bits<3> group, bits<3> num, bits<1> hi, string n> : BlackfinReg<n> { +  let Group = group; +  let Num = num; +  field bits<1> High = hi; +} + +// Ri - 32-bit integer registers with subregs +class Ri<bits<3> group, bits<3> num, string n> : BlackfinReg<n> { +  let Group = group; +  let Num = num; +} + +// Ra 40-bit accumulator registers +class Ra<bits<3> num, string n, list<Register> subs> : BlackfinReg<n> { +  let SubRegs = subs; +  let Group = 4; +  let Num = num; +} + +// Ywo halves of 32-bit register +multiclass Rss<bits<3> group, bits<3> num, string n> { +  def H : Rs<group, num, 1, !strconcat(n, ".h")>; +  def L : Rs<group, num, 0, !strconcat(n, ".l")>; +} + +// Rii - 32-bit integer registers with subregs +class Rii<bits<3> group, bits<3> num, string n, list<Register> subs> +      : BlackfinReg<n> { +  let SubRegs = subs; +  let Group = group; +  let Num = num; +} + +// Status bits are all part of ASTAT +def AZ   : Rc<0,  "az">; +def AN   : Rc<1,  "an">; +def CC   : Rc<5,  "cc">, DwarfRegNum<[34]>; +def NCC  : Rc<5,  "!cc"> { let Aliases = [CC]; } +def AQ   : Rc<6,  "aq">; +def AC0  : Rc<12, "ac0">; +def AC1  : Rc<13, "ac1">; +def AV0  : Rc<16, "av0">; +def AV0S : Rc<17, "av0s">; +def AV1  : Rc<18, "av1">; +def AV1S : Rc<19, "av1s">; +def V    : Rc<24, "v">; +def VS   : Rc<25, "vs">; +// Skipped non-status bits: AC0_COPY, V_COPY, RND_MOD + +// Group 0: Integer registers +defm R0 : Rss<0, 0, "r0">; +def  R0 : Rii<0, 0, "r0", [R0H, R0L]>, DwarfRegNum<[0]>; +defm R1 : Rss<0, 1, "r1">; +def  R1 : Rii<0, 1, "r1", [R1H, R1L]>, DwarfRegNum<[1]>; +defm R2 : Rss<0, 2, "r2">; +def  R2 : Rii<0, 2, "r2", [R2H, R2L]>, DwarfRegNum<[2]>; +defm R3 : Rss<0, 3, "r3">; +def  R3 : Rii<0, 3, "r3", [R3H, R3L]>, DwarfRegNum<[3]>; +defm R4 : Rss<0, 4, "r4">; +def  R4 : Rii<0, 4, "r4", [R4H, R4L]>, DwarfRegNum<[4]>; +defm R5 : Rss<0, 5, "r5">; +def  R5 : Rii<0, 5, "r5", [R5H, R5L]>, DwarfRegNum<[5]>; +defm R6 : Rss<0, 6, "r6">; +def  R6 : Rii<0, 6, "r6", [R6H, R6L]>, DwarfRegNum<[6]>; +defm R7 : Rss<0, 7, "r7">; +def  R7 : Rii<0, 7, "r7", [R7H, R7L]>, DwarfRegNum<[7]>; + +// Group 1: Pointer registers +defm P0 : Rss<1, 0, "p0">; +def  P0 : Rii<1, 0, "p0", [P0H, P0L]>, DwarfRegNum<[8]>; +defm P1 : Rss<1, 1, "p1">; +def  P1 : Rii<1, 1, "p1", [P1H, P1L]>, DwarfRegNum<[9]>; +defm P2 : Rss<1, 2, "p2">; +def  P2 : Rii<1, 2, "p2", [P2H, P2L]>, DwarfRegNum<[10]>; +defm P3 : Rss<1, 3, "p3">; +def  P3 : Rii<1, 3, "p3", [P3H, P3L]>, DwarfRegNum<[11]>; +defm P4 : Rss<1, 4, "p4">; +def  P4 : Rii<1, 4, "p4", [P4H, P4L]>, DwarfRegNum<[12]>; +defm P5 : Rss<1, 5, "p5">; +def  P5 : Rii<1, 5, "p5", [P5H, P5L]>, DwarfRegNum<[13]>; +defm SP : Rss<1, 6, "sp">; +def  SP : Rii<1, 6, "sp", [SPH, SPL]>, DwarfRegNum<[14]>; +defm FP : Rss<1, 7, "fp">; +def  FP : Rii<1, 7, "fp", [FPH, FPL]>, DwarfRegNum<[15]>; + +// Group 2: Index registers +defm I0 : Rss<2, 0, "i0">; +def  I0 : Rii<2, 0, "i0", [I0H, I0L]>, DwarfRegNum<[16]>; +defm I1 : Rss<2, 1, "i1">; +def  I1 : Rii<2, 1, "i1", [I1H, I1L]>, DwarfRegNum<[17]>; +defm I2 : Rss<2, 2, "i2">; +def  I2 : Rii<2, 2, "i2", [I2H, I2L]>, DwarfRegNum<[18]>; +defm I3 : Rss<2, 3, "i3">; +def  I3 : Rii<2, 3, "i3", [I3H, I3L]>, DwarfRegNum<[19]>; +defm M0 : Rss<2, 4, "m0">; +def  M0 : Rii<2, 4, "m0", [M0H, M0L]>, DwarfRegNum<[20]>; +defm M1 : Rss<2, 5, "m1">; +def  M1 : Rii<2, 5, "m1", [M1H, M1L]>, DwarfRegNum<[21]>; +defm M2 : Rss<2, 6, "m2">; +def  M2 : Rii<2, 6, "m2", [M2H, M2L]>, DwarfRegNum<[22]>; +defm M3 : Rss<2, 7, "m3">; +def  M3 : Rii<2, 7, "m3", [M3H, M3L]>, DwarfRegNum<[23]>; + +// Group 3: Cyclic indexing registers +defm B0 : Rss<3, 0, "b0">; +def  B0 : Rii<3, 0, "b0", [B0H, B0L]>, DwarfRegNum<[24]>; +defm B1 : Rss<3, 1, "b1">; +def  B1 : Rii<3, 1, "b1", [B1H, B1L]>, DwarfRegNum<[25]>; +defm B2 : Rss<3, 2, "b2">; +def  B2 : Rii<3, 2, "b2", [B2H, B2L]>, DwarfRegNum<[26]>; +defm B3 : Rss<3, 3, "b3">; +def  B3 : Rii<3, 3, "b3", [B3H, B3L]>, DwarfRegNum<[27]>; +defm L0 : Rss<3, 4, "l0">; +def  L0 : Rii<3, 4, "l0", [L0H, L0L]>, DwarfRegNum<[28]>; +defm L1 : Rss<3, 5, "l1">; +def  L1 : Rii<3, 5, "l1", [L1H, L1L]>, DwarfRegNum<[29]>; +defm L2 : Rss<3, 6, "l2">; +def  L2 : Rii<3, 6, "l2", [L2H, L2L]>, DwarfRegNum<[30]>; +defm L3 : Rss<3, 7, "l3">; +def  L3 : Rii<3, 7, "l3", [L3H, L3L]>, DwarfRegNum<[31]>; + +// Accumulators +def  A0X : Ri <4, 0, "a0.x">; +defm A0  : Rss<4, 1, "a0">; +def  A0W : Rii<4, 1, "a0.w", [A0H, A0L]>, DwarfRegNum<[32]>; +def  A0  : Ra <0, "a0", [A0X, A0W]>; + +def  A1X : Ri <4, 2, "a1.x">; +defm A1  : Rss<4, 3, "a1">; +def  A1W : Rii<4, 3, "a1.w", [A1H, A1L]>, DwarfRegNum<[33]>; +def  A1  : Ra <2, "a1", [A1X, A1W]>; + +def RETS : Ri<4, 7, "rets">,  DwarfRegNum<[35]>; +def RETI : Ri<7, 3, "reti">,  DwarfRegNum<[36]>; +def RETX : Ri<7, 4, "retx">,  DwarfRegNum<[37]>; +def RETN : Ri<7, 5, "retn">,  DwarfRegNum<[38]>; +def RETE : Ri<7, 6, "rete">,  DwarfRegNum<[39]>; + +def ASTAT   : Ri<4, 6, "astat">,   DwarfRegNum<[40]> { +  let SubRegs = [AZ, AN, CC, NCC, AQ, AC0, AC1, AV0, AV0S, AV1, AV1S, V, VS]; +} + +def SEQSTAT : Ri<7, 1, "seqstat">, DwarfRegNum<[41]>; +def USP     : Ri<7, 0, "usp">,     DwarfRegNum<[42]>; +def EMUDAT  : Ri<7, 7, "emudat">,  DwarfRegNum<[43]>; +def SYSCFG  : Ri<7, 2, "syscfg">; +def CYCLES  : Ri<6, 6, "cycles">; +def CYCLES2 : Ri<6, 7, "cycles2">; + +// Hardware loops +def LT0 : Ri<6, 1, "lt0">, DwarfRegNum<[44]>; +def LT1 : Ri<6, 4, "lt1">, DwarfRegNum<[45]>; +def LC0 : Ri<6, 0, "lc0">, DwarfRegNum<[46]>; +def LC1 : Ri<6, 3, "lc1">, DwarfRegNum<[47]>; +def LB0 : Ri<6, 2, "lb0">, DwarfRegNum<[48]>; +def LB1 : Ri<6, 5, "lb1">, DwarfRegNum<[49]>; + +// Subregs are: +// 1: .L +// 2: .H +// 3: .W (32 low bits of 40-bit accu) +// Keep in sync with enum in BlackfinRegisterInfo.h +def bfin_subreg_lo16  : PatLeaf<(i32 1)>; +def bfin_subreg_hi16  : PatLeaf<(i32 2)>; +def bfin_subreg_32bit : PatLeaf<(i32 3)>; + +def : SubRegSet<1, +    [R0,  R1,  R2,  R3,  R4,  R5,  R6,  R7, +     P0,  P1,  P2,  P3,  P4,  P5,  SP,  FP, +     I0,  I1,  I2,  I3,  M0,  M1,  M2,  M3, +     B0,  B1,  B2,  B3,  L0,  L1,  L2,  L3], +    [R0L, R1L, R2L, R3L, R4L, R5L, R6L, R7L, +     P0L, P1L, P2L, P3L, P4L, P5L, SPL, FPL, +     I0L, I1L, I2L, I3L, M0L, M1L, M2L, M3L, +     B0L, B1L, B2L, B3L, L0L, L1L, L2L, L3L]>; + +def : SubRegSet<2, +    [R0,  R1,  R2,  R3,  R4,  R5,  R6,  R7, +     P0,  P1,  P2,  P3,  P4,  P5,  SP,  FP, +     I0,  I1,  I2,  I3,  M0,  M1,  M2,  M3, +     B0,  B1,  B2,  B3,  L0,  L1,  L2,  L3], +    [R0H, R1H, R2H, R3H, R4H, R5H, R6H, R7H, +     P0H, P1H, P2H, P3H, P4H, P5H, SPH, FPH, +     I0H, I1H, I2H, I3H, M0H, M1H, M2H, M3H, +     B0H, B1H, B2H, B3H, L0H, L1H, L2H, L3H]>; + +def : SubRegSet<1, [A0, A0W, A1, A1W], [A0L, A0L, A1L, A1L]>; +def : SubRegSet<2, [A0, A0W, A1, A1W], [A0H, A0H, A1H, A1H]>; + +// Register classes. +def D16 : RegisterClass<"BF", [i16], 16, +    [R0H, R0L, R1H, R1L, R2H, R2L, R3H, R3L, +     R4H, R4L, R5H, R5L, R6H, R6L, R7H, R7L]>; + +def D16L : RegisterClass<"BF", [i16], 16, +    [R0L, R1L, R2L, R3L, R4L, R5L, R6L, R7L]>; + +def D16H : RegisterClass<"BF", [i16], 16, +    [R0H, R1H, R2H, R3H, R4H, R5H, R6H, R7H]>; + +def P16 : RegisterClass<"BF", [i16], 16, +    [P0H, P0L, P1H, P1L, P2H, P2L, P3H, P3L, +     P4H, P4L, P5H, P5L, SPH, SPL, FPH, FPL]>; + +def P16L : RegisterClass<"BF", [i16], 16, +    [P0L, P1L, P2L, P3L, P4L, P5L, SPL, FPL]>; + +def P16H : RegisterClass<"BF", [i16], 16, +    [P0H, P1H, P2H, P3H, P4H, P5H, SPH, FPH]>; + +def DP16 : RegisterClass<"BF", [i16], 16, +    [R0H, R0L, R1H, R1L, R2H, R2L, R3H, R3L, +     R4H, R4L, R5H, R5L, R6H, R6L, R7H, R7L, +     P0H, P0L, P1H, P1L, P2H, P2L, P3H, P3L, +     P4H, P4L, P5H, P5L, SPH, SPL, FPH, FPL]>; + +def DP16L : RegisterClass<"BF", [i16], 16, +    [R0L, R1L, R2L, R3L, R4L, R5L, R6L, R7L, +     P0L, P1L, P2L, P3L, P4L, P5L, SPL, FPL]>; + +def DP16H : RegisterClass<"BF", [i16], 16, +    [R0H, R1H, R2H, R3H, R4H, R5H, R6H, R7H, +     P0H, P1H, P2H, P3H, P4H, P5H, SPH, FPH]>; + +def GR16 : RegisterClass<"BF", [i16], 16, +    [R0H, R0L, R1H, R1L, R2H, R2L, R3H, R3L, +     R4H, R4L, R5H, R5L, R6H, R6L, R7H, R7L, +     P0H, P0L, P1H, P1L, P2H, P2L, P3H, P3L, +     P4H, P4L, P5H, P5L, SPH, SPL, FPH, FPL, +     I0H, I0L, I1H, I1L, I2H, I2L, I3H, I3L, +     M0H, M0L, M1H, M1L, M2H, M2L, M3H, M3L, +     B0H, B0L, B1H, B1L, B2H, B2L, B3H, B3L, +     L0H, L0L, L1H, L1L, L2H, L2L, L3H, L3L]>; + +def D : RegisterClass<"BF", [i32], 32, [R0, R1, R2, R3, R4, R5, R6, R7]> { +  let SubRegClassList = [D16L, D16H]; +} + +def P : RegisterClass<"BF", [i32], 32, [P0, P1, P2, P3, P4, P5, FP, SP]> { +  let SubRegClassList = [P16L, P16H]; +  let MethodProtos = [{ +    iterator allocation_order_end(const MachineFunction &MF) const; +  }]; +  let MethodBodies = [{ +    PClass::iterator +    PClass::allocation_order_end(const MachineFunction &MF) const { +      const TargetMachine &TM = MF.getTarget(); +      const TargetRegisterInfo *RI = TM.getRegisterInfo(); +      return allocation_order_begin(MF) +             + (RI->hasFP(MF) ? 7 : 6); +    } +  }]; +} + +def I : RegisterClass<"BF", [i32], 32, [I0, I1, I2, I3]>; +def M : RegisterClass<"BF", [i32], 32, [M0, M1, M2, M3]>; + +def DP : RegisterClass<"BF", [i32], 32, +    [R0, R1, R2, R3, R4, R5, R6, R7, +     P0, P1, P2, P3, P4, P5, FP, SP]> { +  let SubRegClassList = [DP16L, DP16H]; +  let MethodProtos = [{ +    iterator allocation_order_end(const MachineFunction &MF) const; +  }]; +  let MethodBodies = [{ +    DPClass::iterator +    DPClass::allocation_order_end(const MachineFunction &MF) const { +      const TargetMachine &TM = MF.getTarget(); +      const TargetRegisterInfo *RI = TM.getRegisterInfo(); +      return allocation_order_begin(MF) +             + (RI->hasFP(MF) ? 15 : 14); +    } +  }]; +} + +def GR : RegisterClass<"BF", [i32], 32, +    [R0, R1, R2, R3, R4, R5, R6, R7, +     P0, P1, P2, P3, P4, P5, +     I0, I1, I2, I3, M0, M1, M2, M3, +     B0, B1, B2, B3, L0, L1, L2, L3, +     FP, SP]> { +  let MethodProtos = [{ +    iterator allocation_order_end(const MachineFunction &MF) const; +  }]; +  let MethodBodies = [{ +    GRClass::iterator +    GRClass::allocation_order_end(const MachineFunction &MF) const { +      const TargetMachine &TM = MF.getTarget(); +      const TargetRegisterInfo *RI = TM.getRegisterInfo(); +      return allocation_order_begin(MF) +             + (RI->hasFP(MF) ? 31 : 30); +    } +  }]; +} + +def ALL : RegisterClass<"BF", [i32], 32, +    [R0, R1, R2, R3, R4, R5, R6, R7, +     P0, P1, P2, P3, P4, P5, +     I0, I1, I2, I3, M0, M1, M2, M3, +     B0, B1, B2, B3, L0, L1, L2, L3, +     FP, SP, +     A0X, A0W, A1X, A1W, ASTAT, RETS, +     LC0, LT0, LB0, LC1, LT1, LB1, CYCLES, CYCLES2, +     USP, SEQSTAT, SYSCFG, RETI, RETX, RETN, RETE, EMUDAT]> { +  let MethodProtos = [{ +    iterator allocation_order_end(const MachineFunction &MF) const; +  }]; +  let MethodBodies = [{ +    ALLClass::iterator +    ALLClass::allocation_order_end(const MachineFunction &MF) const { +      const TargetMachine &TM = MF.getTarget(); +      const TargetRegisterInfo *RI = TM.getRegisterInfo(); +      return allocation_order_begin(MF) +             + (RI->hasFP(MF) ? 31 : 30); +    } +  }]; +} + +def PI : RegisterClass<"BF", [i32], 32, +    [P0, P1, P2, P3, P4, P5, I0, I1, I2, I3, FP, SP]> { +  let MethodProtos = [{ +    iterator allocation_order_end(const MachineFunction &MF) const; +  }]; +  let MethodBodies = [{ +    PIClass::iterator +    PIClass::allocation_order_end(const MachineFunction &MF) const { +      const TargetMachine &TM = MF.getTarget(); +      const TargetRegisterInfo *RI = TM.getRegisterInfo(); +      return allocation_order_begin(MF) +             + (RI->hasFP(MF) ? 11 : 10); +    } +  }]; +} + +// We are going to pretend that CC and !CC are 32-bit registers, even though +// they only can hold 1 bit. +let CopyCost = -1, Size = 8 in { +def JustCC  : RegisterClass<"BF", [i32], 8, [CC]>; +def NotCC   : RegisterClass<"BF", [i32], 8, [NCC]>; +def AnyCC   : RegisterClass<"BF", [i32], 8, [CC, NCC]> { +  let MethodProtos = [{ +    iterator allocation_order_end(const MachineFunction &MF) const; +  }]; +  let MethodBodies = [{ +    AnyCCClass::iterator +    AnyCCClass::allocation_order_end(const MachineFunction &MF) const { +      return allocation_order_begin(MF)+1; +    } +  }]; +} +def StatBit : RegisterClass<"BF", [i1], 8, +    [AZ, AN, CC, AQ, AC0, AC1, AV0, AV0S, AV1, AV1S, V, VS]>; +} diff --git a/llvm/lib/Target/Blackfin/BlackfinSubtarget.cpp b/llvm/lib/Target/Blackfin/BlackfinSubtarget.cpp new file mode 100644 index 00000000000..cf14b105aaf --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinSubtarget.cpp @@ -0,0 +1,26 @@ +//===- BlackfinSubtarget.cpp - BLACKFIN Subtarget Information -------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the blackfin specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#include "BlackfinSubtarget.h" +#include "BlackfinGenSubtarget.inc" + +using namespace llvm; + +BlackfinSubtarget::BlackfinSubtarget(const TargetMachine &TM, +                                     const Module &M, +                                     const std::string &FS) { +  std::string CPU = "generic"; + +  // Parse features string. +  ParseSubtargetFeatures(FS, CPU); +} diff --git a/llvm/lib/Target/Blackfin/BlackfinSubtarget.h b/llvm/lib/Target/Blackfin/BlackfinSubtarget.h new file mode 100644 index 00000000000..31df9c0fee9 --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinSubtarget.h @@ -0,0 +1,39 @@ +//===- BlackfinSubtarget.h - Define Subtarget for the Blackfin -*- C++ -*-====// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the BLACKFIN specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#ifndef BLACKFIN_SUBTARGET_H +#define BLACKFIN_SUBTARGET_H + +#include "llvm/Target/TargetSubtarget.h" +#include <string> + +namespace llvm { + +  class TargetMachine; +  class Module; + +  class BlackfinSubtarget : public TargetSubtarget { +    bool ssyncWorkaround; +  public: +    BlackfinSubtarget(const TargetMachine &TM, const Module &M, +                      const std::string &FS); + +    /// ParseSubtargetFeatures - Parses features string setting specified +    /// subtarget options.  Definition of function is auto generated by tblgen. +    std::string ParseSubtargetFeatures(const std::string &FS, +                                       const std::string &CPU); +  }; + +} // end namespace llvm + +#endif diff --git a/llvm/lib/Target/Blackfin/BlackfinTargetAsmInfo.cpp b/llvm/lib/Target/Blackfin/BlackfinTargetAsmInfo.cpp new file mode 100644 index 00000000000..8dcb44be501 --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinTargetAsmInfo.cpp @@ -0,0 +1,23 @@ +//===-- BlackfinTargetAsmInfo.cpp - Blackfin asm properties -----*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the BlackfinTargetAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "BlackfinTargetAsmInfo.h" + +using namespace llvm; + +BlackfinTargetAsmInfo::BlackfinTargetAsmInfo() { +  GlobalPrefix = "_"; +  CommentString = "//"; +  InlineAsmStart = "// APP"; +  InlineAsmEnd = "// NO_APP"; +} diff --git a/llvm/lib/Target/Blackfin/BlackfinTargetAsmInfo.h b/llvm/lib/Target/Blackfin/BlackfinTargetAsmInfo.h new file mode 100644 index 00000000000..fa4cd7c373a --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinTargetAsmInfo.h @@ -0,0 +1,27 @@ +//===-- BlackfinTargetAsmInfo.h - Blackfin asm properties -----*- C++ -*--====// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the BlackfinTargetAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef BLACKFINTARGETASMINFO_H +#define BLACKFINTARGETASMINFO_H + +#include "llvm/Target/TargetAsmInfo.h" + +namespace llvm { + +  struct BlackfinTargetAsmInfo : public TargetAsmInfo { +    explicit BlackfinTargetAsmInfo(); +  }; + +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/Blackfin/BlackfinTargetMachine.cpp b/llvm/lib/Target/Blackfin/BlackfinTargetMachine.cpp new file mode 100644 index 00000000000..059916b2007 --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinTargetMachine.cpp @@ -0,0 +1,54 @@ +//===-- BlackfinTargetMachine.cpp - Define TargetMachine for Blackfin -----===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#include "BlackfinTargetMachine.h" +#include "Blackfin.h" +#include "BlackfinTargetAsmInfo.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/Target/TargetRegistry.h" + +using namespace llvm; + +extern "C" void LLVMInitializeBlackfinTarget() { +  RegisterTargetMachine<BlackfinTargetMachine> X(TheBlackfinTarget); +} + +const TargetAsmInfo* BlackfinTargetMachine::createTargetAsmInfo() const { +  return new BlackfinTargetAsmInfo(); +} + +BlackfinTargetMachine::BlackfinTargetMachine(const Target &T, +                                             const Module &M, +                                             const std::string &FS) +  : LLVMTargetMachine(T), +    DataLayout("e-p:32:32-i64:32-f64:32"), +    Subtarget(*this, M, FS), +    TLInfo(*this), +    InstrInfo(Subtarget), +    FrameInfo(TargetFrameInfo::StackGrowsDown, 4, 0) { +} + +unsigned BlackfinTargetMachine::getModuleMatchQuality(const Module &M) { +  std::string TT = M.getTargetTriple(); +  if (TT.size() >= 5 && std::string(TT.begin(), TT.begin()+5) == "bfin-") +    return 20; + +  // Otherwise we don't match. +  return 0; +} + +bool BlackfinTargetMachine::addInstSelector(PassManagerBase &PM, +                                            CodeGenOpt::Level OptLevel) { +  PM.add(createBlackfinISelDag(*this, OptLevel)); +  return false; +} diff --git a/llvm/lib/Target/Blackfin/BlackfinTargetMachine.h b/llvm/lib/Target/Blackfin/BlackfinTargetMachine.h new file mode 100644 index 00000000000..0538c9a1a58 --- /dev/null +++ b/llvm/lib/Target/Blackfin/BlackfinTargetMachine.h @@ -0,0 +1,61 @@ +//===-- BlackfinTargetMachine.h - TargetMachine for Blackfin ----*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the Blackfin specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef BLACKFINTARGETMACHINE_H +#define BLACKFINTARGETMACHINE_H + +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameInfo.h" +#include "BlackfinInstrInfo.h" +#include "BlackfinSubtarget.h" +#include "BlackfinISelLowering.h" + +namespace llvm { + +  class Module; + +  class BlackfinTargetMachine : public LLVMTargetMachine { +    const TargetData DataLayout; +    BlackfinSubtarget Subtarget; +    BlackfinTargetLowering TLInfo; +    BlackfinInstrInfo InstrInfo; +    TargetFrameInfo FrameInfo; + +  protected: +    virtual const TargetAsmInfo *createTargetAsmInfo() const; + +  public: +    BlackfinTargetMachine(const Target &T, const Module &M, +                          const std::string &FS); + +    virtual const BlackfinInstrInfo *getInstrInfo() const { return &InstrInfo; } +    virtual const TargetFrameInfo *getFrameInfo() const { return &FrameInfo; } +    virtual const BlackfinSubtarget *getSubtargetImpl() const { +      return &Subtarget; +    } +    virtual const BlackfinRegisterInfo *getRegisterInfo() const { +      return &InstrInfo.getRegisterInfo(); +    } +    virtual BlackfinTargetLowering* getTargetLowering() const { +      return const_cast<BlackfinTargetLowering*>(&TLInfo); +    } +    virtual const TargetData *getTargetData() const { return &DataLayout; } +    static unsigned getModuleMatchQuality(const Module &M); +    virtual bool addInstSelector(PassManagerBase &PM, +                                 CodeGenOpt::Level OptLevel); +  }; + +} // end namespace llvm + +#endif diff --git a/llvm/lib/Target/Blackfin/CMakeLists.txt b/llvm/lib/Target/Blackfin/CMakeLists.txt new file mode 100644 index 00000000000..8163fc260c5 --- /dev/null +++ b/llvm/lib/Target/Blackfin/CMakeLists.txt @@ -0,0 +1,21 @@ +set(LLVM_TARGET_DEFINITIONS Blackfin.td) + +tablegen(BlackfinGenRegisterInfo.h.inc -gen-register-desc-header) +tablegen(BlackfinGenRegisterNames.inc -gen-register-enums) +tablegen(BlackfinGenRegisterInfo.inc -gen-register-desc) +tablegen(BlackfinGenInstrNames.inc -gen-instr-enums) +tablegen(BlackfinGenInstrInfo.inc -gen-instr-desc) +tablegen(BlackfinGenAsmWriter.inc -gen-asm-writer) +tablegen(BlackfinGenDAGISel.inc -gen-dag-isel) +tablegen(BlackfinGenSubtarget.inc -gen-subtarget) +tablegen(BlackfinGenCallingConv.inc -gen-callingconv) + +add_llvm_target(BlackfinCodeGen +  BlackfinInstrInfo.cpp +  BlackfinISelDAGToDAG.cpp +  BlackfinISelLowering.cpp +  BlackfinRegisterInfo.cpp +  BlackfinSubtarget.cpp +  BlackfinTargetAsmInfo.cpp +  BlackfinTargetMachine.cpp +  ) diff --git a/llvm/lib/Target/Blackfin/Makefile b/llvm/lib/Target/Blackfin/Makefile new file mode 100644 index 00000000000..c0c1bce793d --- /dev/null +++ b/llvm/lib/Target/Blackfin/Makefile @@ -0,0 +1,23 @@ +##===- lib/Target/Blackfin/Makefile ------------------------*- Makefile -*-===## +# +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../.. +LIBRARYNAME = LLVMBlackfinCodeGen +TARGET = Blackfin + +# Make sure that tblgen is run, first thing. +BUILT_SOURCES = BlackfinGenRegisterInfo.h.inc BlackfinGenRegisterNames.inc \ +                BlackfinGenRegisterInfo.inc BlackfinGenInstrNames.inc \ +                BlackfinGenInstrInfo.inc BlackfinGenAsmWriter.inc \ +                BlackfinGenDAGISel.inc BlackfinGenSubtarget.inc \ +		BlackfinGenCallingConv.inc + +DIRS = AsmPrinter TargetInfo + +include $(LEVEL)/Makefile.common + diff --git a/llvm/lib/Target/Blackfin/README.txt b/llvm/lib/Target/Blackfin/README.txt new file mode 100644 index 00000000000..4631c12f7e7 --- /dev/null +++ b/llvm/lib/Target/Blackfin/README.txt @@ -0,0 +1,122 @@ +//===-- README.txt - Notes for Blackfin Target ------------------*- org -*-===// + +* Condition codes +** DONE Problem with asymmetric SETCC operations +The instruction + +  CC = R0 < 2 + +is not symmetric - there is no R0 > 2 instruction. On the other hand, IF CC +JUMP can take both CC and !CC as a condition. We cannot pattern-match (brcond +(not cc), target), the DAG optimizer removes that kind of thing. + +This is handled by creating a pseudo-register NCC that aliases CC. Register +classes JustCC and NotCC are used to control the inversion of CC. + +** DONE CC as an i32 register +The AnyCC register class pretends to hold i32 values. It can only represent the +values 0 and 1, but we can copy to and from the D class. This hack makes it +possible to represent the setcc instruction without having i1 as a legal type. + +In most cases, the CC register is set by a "CC = .." or BITTST instruction, and +then used in a conditional branch or move. The code generator thinks it is +moving 32 bits, but the value stays in CC. In other cases, the result of a +comparison is actually used as am i32 number, and CC will be copied to a D +register. + +* Stack frames +** TODO Use Push/Pop instructions +We should use the push/pop instructions when saving callee-saved +registers. The are smaller, and we may even use push multiple instructions. + +** TODO requiresRegisterScavenging +We need more intelligence in determining when the scavenger is needed. We +should keep track of: +- Spilling D16 registers +- Spilling AnyCC registers + +* Assembler +** TODO Implement PrintGlobalVariable +** TODO Remove LOAD32sym +It's a hack combining two instructions by concatenation. + +* Inline Assembly +** TODO Support all register classes +* DAG combiner +** Create test case for each Illegal SETCC case +The DAG combiner may someimes produce illegal i16 SETCC instructions. + +*** TODO SETCC (ctlz x), 5) == const +*** TODO SETCC (and load, const) == const +*** DONE SETCC (zext x) == const +*** TODO SETCC (sext x) == const + +* Instruction selection +** TODO Better imediate constants +Like ARM, build constants as small imm + shift. + +** TODO Implement cycle counter +We have CYCLES and CYCLES2 registers, but the readcyclecounter intrinsic wants +to return i64, and the code generator doesn't know how to legalize that. + +** TODO Instruction alternatives +Some instructions come in different variants for example: + +  D = D + D +  P = P + P + +Cross combinations are not allowed: + +  P = D + D (bad) + +Similarly for the subreg pseudo-instructions: + + D16L = EXTRACT_SUBREG D16, bfin_subreg_lo16 + P16L = EXTRACT_SUBREG P16, bfin_subreg_lo16 + +We want to take advantage of the alternative instructions. This could be done by +changing the DAG after instruction selection. + + +** Multipatterns for load/store +We should try to identify multipatterns for load and store instructions. The +available instruction matrix is a bit irregular. + +Loads: + +| Addr       | D | P | D 16z | D 16s | D16 | D 8z | D 8s | +|------------+---+---+-------+-------+-----+------+------| +| P          | * | * | *     | *     | *   | *    | *    | +| P++        | * | * | *     | *     |     | *    | *    | +| P--        | * | * | *     | *     |     | *    | *    | +| P+uimm5m2  |   |   | *     | *     |     |      |      | +| P+uimm6m4  | * | * |       |       |     |      |      | +| P+imm16    |   |   |       |       |     | *    | *    | +| P+imm17m2  |   |   | *     | *     |     |      |      | +| P+imm18m4  | * | * |       |       |     |      |      | +| P++P       | * |   | *     | *     | *   |      |      | +| FP-uimm7m4 | * | * |       |       |     |      |      | +| I          | * |   |       |       | *   |      |      | +| I++        | * |   |       |       | *   |      |      | +| I--        | * |   |       |       | *   |      |      | +| I++M       | * |   |       |       |     |      |      | + +Stores: + +| Addr       | D | P | D16H | D16L | D 8 | +|------------+---+---+------+------+-----| +| P          | * | * | *    | *    | *   | +| P++        | * | * |      | *    | *   | +| P--        | * | * |      | *    | *   | +| P+uimm5m2  |   |   |      | *    |     | +| P+uimm6m4  | * | * |      |      |     | +| P+imm16    |   |   |      |      | *   | +| P+imm17m2  |   |   |      | *    |     | +| P+imm18m4  | * | * |      |      |     | +| P++P       | * |   | *    | *    |     | +| FP-uimm7m4 | * | * |      |      |     | +| I          | * |   | *    | *    |     | +| I++        | * |   | *    | *    |     | +| I--        | * |   | *    | *    |     | +| I++M       | * |   |      |      |     | + diff --git a/llvm/lib/Target/Blackfin/TargetInfo/BlackfinTargetInfo.cpp b/llvm/lib/Target/Blackfin/TargetInfo/BlackfinTargetInfo.cpp new file mode 100644 index 00000000000..402e0afde81 --- /dev/null +++ b/llvm/lib/Target/Blackfin/TargetInfo/BlackfinTargetInfo.cpp @@ -0,0 +1,21 @@ +//===-- BlackfinTargetInfo.cpp - Blackfin Target Implementation -----------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Blackfin.h" +#include "llvm/Module.h" +#include "llvm/Target/TargetRegistry.h" + +using namespace llvm; + +Target llvm::TheBlackfinTarget; + +extern "C" void LLVMInitializeBlackfinTargetInfo() { +  RegisterTarget<Triple::bfin> X(TheBlackfinTarget, "bfin", +                                 "Analog Devices Blackfin [experimental]"); +} diff --git a/llvm/lib/Target/Blackfin/TargetInfo/CMakeLists.txt b/llvm/lib/Target/Blackfin/TargetInfo/CMakeLists.txt new file mode 100644 index 00000000000..4584eeba55f --- /dev/null +++ b/llvm/lib/Target/Blackfin/TargetInfo/CMakeLists.txt @@ -0,0 +1,3 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) +add_llvm_library(LLVMBlackfinInfo BlackfinTargetInfo.cpp) +add_dependencies(LLVMBlackfinInfo BlackfinCodeGenTable_gen) diff --git a/llvm/lib/Target/Blackfin/TargetInfo/Makefile b/llvm/lib/Target/Blackfin/TargetInfo/Makefile new file mode 100644 index 00000000000..c49cfbe6907 --- /dev/null +++ b/llvm/lib/Target/Blackfin/TargetInfo/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/Blackfin/TargetInfo/Makefile -------------*- Makefile -*-===## +# +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../../.. +LIBRARYNAME = LLVMBlackfinInfo + +# Hack: we need to include 'main' target directory to grab private headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/llvm/test/CodeGen/Blackfin/add-overflow.ll b/llvm/test/CodeGen/Blackfin/add-overflow.ll new file mode 100644 index 00000000000..de80783ac6d --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/add-overflow.ll @@ -0,0 +1,18 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t + +	type { i24, i1 }		; type %0 + +define i1 @func2(i24 zeroext %v1, i24 zeroext %v2) nounwind { +entry: +	%t = call %0 @llvm.uadd.with.overflow.i24(i24 %v1, i24 %v2)		; <%0> [#uses=1] +	%obit = extractvalue %0 %t, 1		; <i1> [#uses=1] +	br i1 %obit, label %carry, label %normal + +normal:		; preds = %entry +	ret i1 true + +carry:		; preds = %entry +	ret i1 false +} + +declare %0 @llvm.uadd.with.overflow.i24(i24, i24) nounwind diff --git a/llvm/test/CodeGen/Blackfin/add.ll b/llvm/test/CodeGen/Blackfin/add.ll new file mode 100644 index 00000000000..267f3092572 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/add.ll @@ -0,0 +1,5 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs +define i32 @add(i32 %A, i32 %B) { +	%R = add i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R +} diff --git a/llvm/test/CodeGen/Blackfin/addsub-i128.ll b/llvm/test/CodeGen/Blackfin/addsub-i128.ll new file mode 100644 index 00000000000..8dd04d808a4 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/addsub-i128.ll @@ -0,0 +1,42 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs +; XFAIL: * +; Assertion failed: (isUsed(Reg) && "Using an undefined register!"), +; function forward, file RegisterScavenging.cpp, line 182. + +define void @test_add(i64 %AL, i64 %AH, i64 %BL, i64 %BH, i64* %RL, i64* %RH) { +entry: +	%tmp1 = zext i64 %AL to i128		; <i128> [#uses=1] +	%tmp23 = zext i64 %AH to i128		; <i128> [#uses=1] +	%tmp4 = shl i128 %tmp23, 64		; <i128> [#uses=1] +	%tmp5 = or i128 %tmp4, %tmp1		; <i128> [#uses=1] +	%tmp67 = zext i64 %BL to i128		; <i128> [#uses=1] +	%tmp89 = zext i64 %BH to i128		; <i128> [#uses=1] +	%tmp11 = shl i128 %tmp89, 64		; <i128> [#uses=1] +	%tmp12 = or i128 %tmp11, %tmp67		; <i128> [#uses=1] +	%tmp15 = add i128 %tmp12, %tmp5		; <i128> [#uses=2] +	%tmp1617 = trunc i128 %tmp15 to i64		; <i64> [#uses=1] +	store i64 %tmp1617, i64* %RL +	%tmp21 = lshr i128 %tmp15, 64		; <i128> [#uses=1] +	%tmp2122 = trunc i128 %tmp21 to i64		; <i64> [#uses=1] +	store i64 %tmp2122, i64* %RH +	ret void +} + +define void @test_sub(i64 %AL, i64 %AH, i64 %BL, i64 %BH, i64* %RL, i64* %RH) { +entry: +	%tmp1 = zext i64 %AL to i128		; <i128> [#uses=1] +	%tmp23 = zext i64 %AH to i128		; <i128> [#uses=1] +	%tmp4 = shl i128 %tmp23, 64		; <i128> [#uses=1] +	%tmp5 = or i128 %tmp4, %tmp1		; <i128> [#uses=1] +	%tmp67 = zext i64 %BL to i128		; <i128> [#uses=1] +	%tmp89 = zext i64 %BH to i128		; <i128> [#uses=1] +	%tmp11 = shl i128 %tmp89, 64		; <i128> [#uses=1] +	%tmp12 = or i128 %tmp11, %tmp67		; <i128> [#uses=1] +	%tmp15 = sub i128 %tmp5, %tmp12		; <i128> [#uses=2] +	%tmp1617 = trunc i128 %tmp15 to i64		; <i64> [#uses=1] +	store i64 %tmp1617, i64* %RL +	%tmp21 = lshr i128 %tmp15, 64		; <i128> [#uses=1] +	%tmp2122 = trunc i128 %tmp21 to i64		; <i64> [#uses=1] +	store i64 %tmp2122, i64* %RH +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/basic-i1.ll b/llvm/test/CodeGen/Blackfin/basic-i1.ll new file mode 100644 index 00000000000..1c0c72aaeae --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/basic-i1.ll @@ -0,0 +1,51 @@ +; RUN: llvm-as < %s | llc -march=bfin > %t + +define i1 @add(i1 %A, i1 %B) { +	%R = add i1 %A, %B		; <i1> [#uses=1] +	ret i1 %R +} + +define i1 @sub(i1 %A, i1 %B) { +	%R = sub i1 %A, %B		; <i1> [#uses=1] +	ret i1 %R +} + +define i1 @mul(i1 %A, i1 %B) { +	%R = mul i1 %A, %B		; <i1> [#uses=1] +	ret i1 %R +} + +define i1 @sdiv(i1 %A, i1 %B) { +	%R = sdiv i1 %A, %B		; <i1> [#uses=1] +	ret i1 %R +} + +define i1 @udiv(i1 %A, i1 %B) { +	%R = udiv i1 %A, %B		; <i1> [#uses=1] +	ret i1 %R +} + +define i1 @srem(i1 %A, i1 %B) { +	%R = srem i1 %A, %B		; <i1> [#uses=1] +	ret i1 %R +} + +define i1 @urem(i1 %A, i1 %B) { +	%R = urem i1 %A, %B		; <i1> [#uses=1] +	ret i1 %R +} + +define i1 @and(i1 %A, i1 %B) { +	%R = and i1 %A, %B		; <i1> [#uses=1] +	ret i1 %R +} + +define i1 @or(i1 %A, i1 %B) { +	%R = or i1 %A, %B		; <i1> [#uses=1] +	ret i1 %R +} + +define i1 @xor(i1 %A, i1 %B) { +	%R = xor i1 %A, %B		; <i1> [#uses=1] +	ret i1 %R +} diff --git a/llvm/test/CodeGen/Blackfin/basic-i16.ll b/llvm/test/CodeGen/Blackfin/basic-i16.ll new file mode 100644 index 00000000000..d8506319ef7 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/basic-i16.ll @@ -0,0 +1,36 @@ +; RUN: llvm-as < %s | llc -march=bfin + +define i16 @add(i16 %A, i16 %B) { +	%R = add i16 %A, %B		; <i16> [#uses=1] +	ret i16 %R +} + +define i16 @sub(i16 %A, i16 %B) { +	%R = sub i16 %A, %B		; <i16> [#uses=1] +	ret i16 %R +} + +define i16 @mul(i16 %A, i16 %B) { +	%R = mul i16 %A, %B		; <i16> [#uses=1] +	ret i16 %R +} + +define i16 @sdiv(i16 %A, i16 %B) { +	%R = sdiv i16 %A, %B		; <i16> [#uses=1] +	ret i16 %R +} + +define i16 @udiv(i16 %A, i16 %B) { +	%R = udiv i16 %A, %B		; <i16> [#uses=1] +	ret i16 %R +} + +define i16 @srem(i16 %A, i16 %B) { +	%R = srem i16 %A, %B		; <i16> [#uses=1] +	ret i16 %R +} + +define i16 @urem(i16 %A, i16 %B) { +	%R = urem i16 %A, %B		; <i16> [#uses=1] +	ret i16 %R +} diff --git a/llvm/test/CodeGen/Blackfin/basic-i32.ll b/llvm/test/CodeGen/Blackfin/basic-i32.ll new file mode 100644 index 00000000000..3a9377c5046 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/basic-i32.ll @@ -0,0 +1,51 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs + +define i32 @add(i32 %A, i32 %B) { +	%R = add i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R +} + +define i32 @sub(i32 %A, i32 %B) { +	%R = sub i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R +} + +define i32 @mul(i32 %A, i32 %B) { +	%R = mul i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R +} + +define i32 @sdiv(i32 %A, i32 %B) { +	%R = sdiv i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R +} + +define i32 @udiv(i32 %A, i32 %B) { +	%R = udiv i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R +} + +define i32 @srem(i32 %A, i32 %B) { +	%R = srem i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R +} + +define i32 @urem(i32 %A, i32 %B) { +	%R = urem i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R +} + +define i32 @and(i32 %A, i32 %B) { +	%R = and i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R +} + +define i32 @or(i32 %A, i32 %B) { +	%R = or i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R +} + +define i32 @xor(i32 %A, i32 %B) { +	%R = xor i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R +} diff --git a/llvm/test/CodeGen/Blackfin/basic-i64.ll b/llvm/test/CodeGen/Blackfin/basic-i64.ll new file mode 100644 index 00000000000..32dfc1ca65b --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/basic-i64.ll @@ -0,0 +1,51 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs + +define i64 @add(i64 %A, i64 %B) { +	%R = add i64 %A, %B		; <i64> [#uses=1] +	ret i64 %R +} + +define i64 @sub(i64 %A, i64 %B) { +	%R = sub i64 %A, %B		; <i64> [#uses=1] +	ret i64 %R +} + +define i64 @mul(i64 %A, i64 %B) { +	%R = mul i64 %A, %B		; <i64> [#uses=1] +	ret i64 %R +} + +define i64 @sdiv(i64 %A, i64 %B) { +	%R = sdiv i64 %A, %B		; <i64> [#uses=1] +	ret i64 %R +} + +define i64 @udiv(i64 %A, i64 %B) { +	%R = udiv i64 %A, %B		; <i64> [#uses=1] +	ret i64 %R +} + +define i64 @srem(i64 %A, i64 %B) { +	%R = srem i64 %A, %B		; <i64> [#uses=1] +	ret i64 %R +} + +define i64 @urem(i64 %A, i64 %B) { +	%R = urem i64 %A, %B		; <i64> [#uses=1] +	ret i64 %R +} + +define i64 @and(i64 %A, i64 %B) { +	%R = and i64 %A, %B		; <i64> [#uses=1] +	ret i64 %R +} + +define i64 @or(i64 %A, i64 %B) { +	%R = or i64 %A, %B		; <i64> [#uses=1] +	ret i64 %R +} + +define i64 @xor(i64 %A, i64 %B) { +	%R = xor i64 %A, %B		; <i64> [#uses=1] +	ret i64 %R +} diff --git a/llvm/test/CodeGen/Blackfin/basic-i8.ll b/llvm/test/CodeGen/Blackfin/basic-i8.ll new file mode 100644 index 00000000000..7338d461245 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/basic-i8.ll @@ -0,0 +1,51 @@ +; RUN: llvm-as < %s | llc -march=bfin + +define i8 @add(i8 %A, i8 %B) { +	%R = add i8 %A, %B		; <i8> [#uses=1] +	ret i8 %R +} + +define i8 @sub(i8 %A, i8 %B) { +	%R = sub i8 %A, %B		; <i8> [#uses=1] +	ret i8 %R +} + +define i8 @mul(i8 %A, i8 %B) { +	%R = mul i8 %A, %B		; <i8> [#uses=1] +	ret i8 %R +} + +define i8 @sdiv(i8 %A, i8 %B) { +	%R = sdiv i8 %A, %B		; <i8> [#uses=1] +	ret i8 %R +} + +define i8 @udiv(i8 %A, i8 %B) { +	%R = udiv i8 %A, %B		; <i8> [#uses=1] +	ret i8 %R +} + +define i8 @srem(i8 %A, i8 %B) { +	%R = srem i8 %A, %B		; <i8> [#uses=1] +	ret i8 %R +} + +define i8 @urem(i8 %A, i8 %B) { +	%R = urem i8 %A, %B		; <i8> [#uses=1] +	ret i8 %R +} + +define i8 @and(i8 %A, i8 %B) { +	%R = and i8 %A, %B		; <i8> [#uses=1] +	ret i8 %R +} + +define i8 @or(i8 %A, i8 %B) { +	%R = or i8 %A, %B		; <i8> [#uses=1] +	ret i8 %R +} + +define i8 @xor(i8 %A, i8 %B) { +	%R = xor i8 %A, %B		; <i8> [#uses=1] +	ret i8 %R +} diff --git a/llvm/test/CodeGen/Blackfin/basictest.ll b/llvm/test/CodeGen/Blackfin/basictest.ll new file mode 100644 index 00000000000..09a389da4c1 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/basictest.ll @@ -0,0 +1,19 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs + +define void @void(i32, i32) { +        add i32 0, 0            ; <i32>:3 [#uses=2] +        sub i32 0, 4            ; <i32>:4 [#uses=2] +        br label %5 + +; <label>:5             ; preds = %5, %2 +        add i32 %0, %1          ; <i32>:6 [#uses=2] +        sub i32 %6, %4          ; <i32>:7 [#uses=1] +        icmp sle i32 %7, %3             ; <i1>:8 [#uses=1] +        br i1 %8, label %9, label %5 + +; <label>:9             ; preds = %5 +        add i32 %0, %1          ; <i32>:10 [#uses=0] +        sub i32 %6, %4          ; <i32>:11 [#uses=1] +        icmp sle i32 %11, %3            ; <i1>:12 [#uses=0] +        ret void +} diff --git a/llvm/test/CodeGen/Blackfin/burg.ll b/llvm/test/CodeGen/Blackfin/burg.ll new file mode 100644 index 00000000000..fb5f74bddb0 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/burg.ll @@ -0,0 +1,19 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t + +	%IntList = type %struct.intlist* +	%ReadFn = type i32 ()* +	%YYSTYPE = type { %IntList } +	%struct.intlist = type { i32, %IntList } +@yyval = external global %YYSTYPE		; <%YYSTYPE*> [#uses=1] + +define i32 @yyparse() { +bb0: +	%reg254 = load i16* null		; <i16> [#uses=1] +	%reg254-idxcast = sext i16 %reg254 to i64		; <i64> [#uses=1] +	%reg254-idxcast-scale = mul i64 %reg254-idxcast, -1		; <i64> [#uses=1] +	%reg254-idxcast-scale-offset = add i64 %reg254-idxcast-scale, 1		; <i64> [#uses=1] +	%reg261.idx1 = getelementptr %YYSTYPE* null, i64 %reg254-idxcast-scale-offset, i32 0		; <%IntList*> [#uses=1] +	%reg261 = load %IntList* %reg261.idx1		; <%IntList> [#uses=1] +	store %IntList %reg261, %IntList* getelementptr (%YYSTYPE* @yyval, i64 0, i32 0) +	unreachable +} diff --git a/llvm/test/CodeGen/Blackfin/cmp-small-imm.ll b/llvm/test/CodeGen/Blackfin/cmp-small-imm.ll new file mode 100644 index 00000000000..7d87cb07f3b --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/cmp-small-imm.ll @@ -0,0 +1,9 @@ +; RUN: llvm-as < %s | llc -march=bfin > %t +; XFAIL: * +; Assertion failed: (isUsed(Reg) && "Using an undefined register!") +; function forward, file RegisterScavenging.cpp, line 259. + +define i1 @cmp3(i32 %A) { +	%R = icmp uge i32 %A, 2 +	ret i1 %R +} diff --git a/llvm/test/CodeGen/Blackfin/cmp64.ll b/llvm/test/CodeGen/Blackfin/cmp64.ll new file mode 100644 index 00000000000..c5c5f7e8ac1 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/cmp64.ll @@ -0,0 +1,17 @@ +; RUN: llvm-as < %s | llc -march=bfin + +; This test tries to use a JustCC register as a data operand for MOVEcc.  It +; calls copyRegToReg(JustCC -> DP), failing because JustCC can only be copied to +; D.  The proper solution would be to restrict the virtual register to D only. + +define i32 @main() { +entry: +	br label %loopentry + +loopentry: +	%done = icmp sle i64 undef, 5 +	br i1 %done, label %loopentry, label %exit.1 + +exit.1: +	ret i32 0 +} diff --git a/llvm/test/CodeGen/Blackfin/ct32.ll b/llvm/test/CodeGen/Blackfin/ct32.ll new file mode 100644 index 00000000000..ab5b12fbd46 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/ct32.ll @@ -0,0 +1,20 @@ +; RUN: llvm-as < %s | llc -march=bfin + +declare i32 @llvm.ctlz.i32(i32) +declare i32 @llvm.cttz.i32(i32) +declare i32 @llvm.ctpop.i32(i32) + +define i32 @ctlztest(i32 %B) { +	%b = call i32 @llvm.ctlz.i32( i32 %B ) +	ret i32 %b; +} + +define i32 @cttztest(i32 %B) { +	%b = call i32 @llvm.cttz.i32( i32 %B ) +	ret i32 %b; +} + +define i32 @ctpoptest(i32 %B) { +	%b = call i32 @llvm.ctpop.i32( i32 %B ) +	ret i32 %b; +} diff --git a/llvm/test/CodeGen/Blackfin/ct64.ll b/llvm/test/CodeGen/Blackfin/ct64.ll new file mode 100644 index 00000000000..43cde5e3231 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/ct64.ll @@ -0,0 +1,20 @@ +; RUN: llvm-as < %s | llc -march=bfin + +declare i64 @llvm.ctlz.i64(i64) +declare i64 @llvm.cttz.i64(i64) +declare i64 @llvm.ctpop.i64(i64) + +define i64 @ctlztest(i64 %B) { +	%b = call i64 @llvm.ctlz.i64( i64 %B ) +	ret i64 %b; +} + +define i64 @cttztest(i64 %B) { +	%b = call i64 @llvm.cttz.i64( i64 %B ) +	ret i64 %b; +} + +define i64 @ctpoptest(i64 %B) { +	%b = call i64 @llvm.ctpop.i64( i64 %B ) +	ret i64 %b; +} diff --git a/llvm/test/CodeGen/Blackfin/ctlz16.ll b/llvm/test/CodeGen/Blackfin/ctlz16.ll new file mode 100644 index 00000000000..039ffbd57cb --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/ctlz16.ll @@ -0,0 +1,18 @@ +; RUN: llvm-as < %s | llc -march=bfin + +declare i16 @llvm.ctlz.i16(i16) + +define i16 @ctlztest(i16 %B) { +	%b = call i16 @llvm.ctlz.i16( i16 %B )		; <i16> [#uses=1] +	ret i16 %b; +} +define i16 @ctlztest_z(i16 zeroext %B) { +	%b = call i16 @llvm.ctlz.i16( i16 %B )		; <i16> [#uses=1] +	ret i16 %b; +} + +define i16 @ctlztest_s(i16 signext %B) { +	%b = call i16 @llvm.ctlz.i16( i16 %B )		; <i16> [#uses=1] +	ret i16 %b; +} + diff --git a/llvm/test/CodeGen/Blackfin/ctlz64.ll b/llvm/test/CodeGen/Blackfin/ctlz64.ll new file mode 100644 index 00000000000..276b1d59272 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/ctlz64.ll @@ -0,0 +1,15 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t + +@.str = external constant [14 x i8]		; <[14 x i8]*> [#uses=1] + +define i32 @main(i64 %arg) nounwind { +entry: +	%tmp47 = tail call i64 @llvm.cttz.i64(i64 %arg)		; <i64> [#uses=1] +	%tmp48 = trunc i64 %tmp47 to i32		; <i32> [#uses=1] +	%tmp40 = tail call i32 (i8*, ...)* @printf(i8* noalias getelementptr ([14 x i8]* @.str, i32 0, i32 0), i64 %arg, i32 0, i32 %tmp48, i32 0) nounwind		; <i32> [#uses=0] +	ret i32 0 +} + +declare i32 @printf(i8* noalias, ...) nounwind + +declare i64 @llvm.cttz.i64(i64) nounwind readnone diff --git a/llvm/test/CodeGen/Blackfin/ctpop16.ll b/llvm/test/CodeGen/Blackfin/ctpop16.ll new file mode 100644 index 00000000000..cb06aa24fd0 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/ctpop16.ll @@ -0,0 +1,18 @@ +; RUN: llvm-as < %s | llc -march=bfin + +declare i16 @llvm.ctpop.i16(i16) + +define i16 @ctpoptest(i16 %B) { +	%b = call i16 @llvm.ctpop.i16( i16 %B )		; <i16> [#uses=1] +	ret i16 %b; +} +define i16 @ctpoptest_z(i16 zeroext %B) { +	%b = call i16 @llvm.ctpop.i16( i16 %B )		; <i16> [#uses=1] +	ret i16 %b; +} + +define i16 @ctpoptest_s(i16 signext %B) { +	%b = call i16 @llvm.ctpop.i16( i16 %B )		; <i16> [#uses=1] +	ret i16 %b; +} + diff --git a/llvm/test/CodeGen/Blackfin/cttz16.ll b/llvm/test/CodeGen/Blackfin/cttz16.ll new file mode 100644 index 00000000000..a76cd36b75b --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/cttz16.ll @@ -0,0 +1,18 @@ +; RUN: llvm-as < %s | llc -march=bfin + +declare i16 @llvm.cttz.i16(i16) + +define i16 @cttztest(i16 %B) { +	%b = call i16 @llvm.cttz.i16( i16 %B )		; <i16> [#uses=1] +	ret i16 %b; +} +define i16 @cttztest_z(i16 zeroext %B) { +	%b = call i16 @llvm.cttz.i16( i16 %B )		; <i16> [#uses=1] +	ret i16 %b; +} + +define i16 @cttztest_s(i16 signext %B) { +	%b = call i16 @llvm.cttz.i16( i16 %B )		; <i16> [#uses=1] +	ret i16 %b; +} + diff --git a/llvm/test/CodeGen/Blackfin/cycles.ll b/llvm/test/CodeGen/Blackfin/cycles.ll new file mode 100644 index 00000000000..042cb57ffc9 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/cycles.ll @@ -0,0 +1,11 @@ +; RUN: llvm-as < %s | llc -march=bfin | grep cycles +; XFAIL: * +; ExpandIntegerResult #0: 0x181a60c: i64,ch = ReadCycleCounter 0x1104b08 +; Do not know how to expand the result of this operator! + +declare i64 @llvm.readcyclecounter() + +define i64 @foo() { +	%tmp.1 = call i64 @llvm.readcyclecounter() +	ret i64 %tmp.1 +} diff --git a/llvm/test/CodeGen/Blackfin/dg.exp b/llvm/test/CodeGen/Blackfin/dg.exp new file mode 100644 index 00000000000..5fdbe5feb08 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/dg.exp @@ -0,0 +1,5 @@ +load_lib llvm.exp + +if { [llvm_supports_target Blackfin] } { +  RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,c,cpp}]] +} diff --git a/llvm/test/CodeGen/Blackfin/double-cast.ll b/llvm/test/CodeGen/Blackfin/double-cast.ll new file mode 100644 index 00000000000..774615fea9d --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/double-cast.ll @@ -0,0 +1,8 @@ +; RUN: llvm-as < %s | llc -march=bfin + +declare i32 @printf(i8*, ...) + +define i32 @main() { +	%1 = call i32 (i8*, ...)* @printf(i8* undef, double undef) +	ret i32 0 +} diff --git a/llvm/test/CodeGen/Blackfin/frameindex.ll b/llvm/test/CodeGen/Blackfin/frameindex.ll new file mode 100644 index 00000000000..34ca3eb328e --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/frameindex.ll @@ -0,0 +1,10 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs + +declare i32 @SIM(i8*, i8*, i32, i32, i32, [256 x i32]*, i32, i32, i32) + +define void @foo() { +bb0: +	%V = alloca [256 x i32], i32 256		; <[256 x i32]*> [#uses=1] +	%0 = call i32 @SIM(i8* null, i8* null, i32 0, i32 0, i32 0, [256 x i32]* %V, i32 0, i32 0, i32 2)		; <i32> [#uses=0] +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/i17mem.ll b/llvm/test/CodeGen/Blackfin/i17mem.ll new file mode 100644 index 00000000000..6a3b394a34f --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/i17mem.ll @@ -0,0 +1,9 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs +@i17_l = external global i17		; <i17*> [#uses=1] +@i17_s = external global i17		; <i17*> [#uses=1] + +define void @i17_ls() nounwind  { +	%tmp = load i17* @i17_l		; <i17> [#uses=1] +	store i17 %tmp, i17* @i17_s +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/i1mem.ll b/llvm/test/CodeGen/Blackfin/i1mem.ll new file mode 100644 index 00000000000..97bc0358850 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/i1mem.ll @@ -0,0 +1,9 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs +@i1_l = external global i1		; <i1*> [#uses=1] +@i1_s = external global i1		; <i1*> [#uses=1] + +define void @i1_ls() nounwind  { +	%tmp = load i1* @i1_l		; <i1> [#uses=1] +	store i1 %tmp, i1* @i1_s +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/i1ops.ll b/llvm/test/CodeGen/Blackfin/i1ops.ll new file mode 100644 index 00000000000..0bbd198e780 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/i1ops.ll @@ -0,0 +1,10 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs + +define i32 @adj(i32 %d.1, i32 %ct.1) { +entry: +	%tmp.22.not = trunc i32 %ct.1 to i1		; <i1> [#uses=1] +	%tmp.221 = xor i1 %tmp.22.not, true		; <i1> [#uses=1] +	%tmp.26 = or i1 false, %tmp.221		; <i1> [#uses=1] +	%tmp.27 = zext i1 %tmp.26 to i32		; <i32> [#uses=1] +	ret i32 %tmp.27 +} diff --git a/llvm/test/CodeGen/Blackfin/i216mem.ll b/llvm/test/CodeGen/Blackfin/i216mem.ll new file mode 100644 index 00000000000..085dc154a87 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/i216mem.ll @@ -0,0 +1,9 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs +@i216_l = external global i216		; <i216*> [#uses=1] +@i216_s = external global i216		; <i216*> [#uses=1] + +define void @i216_ls() nounwind  { +	%tmp = load i216* @i216_l		; <i216> [#uses=1] +	store i216 %tmp, i216* @i216_s +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/i248mem.ll b/llvm/test/CodeGen/Blackfin/i248mem.ll new file mode 100644 index 00000000000..7dde2a111cf --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/i248mem.ll @@ -0,0 +1,9 @@ +; RUN: llvm-as < %s | llc -march=bfin +@i248_l = external global i248		; <i248*> [#uses=1] +@i248_s = external global i248		; <i248*> [#uses=1] + +define void @i248_ls() nounwind  { +	%tmp = load i248* @i248_l		; <i248> [#uses=1] +	store i248 %tmp, i248* @i248_s +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/i256mem.ll b/llvm/test/CodeGen/Blackfin/i256mem.ll new file mode 100644 index 00000000000..6a3b394a34f --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/i256mem.ll @@ -0,0 +1,9 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs +@i17_l = external global i17		; <i17*> [#uses=1] +@i17_s = external global i17		; <i17*> [#uses=1] + +define void @i17_ls() nounwind  { +	%tmp = load i17* @i17_l		; <i17> [#uses=1] +	store i17 %tmp, i17* @i17_s +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/i256param.ll b/llvm/test/CodeGen/Blackfin/i256param.ll new file mode 100644 index 00000000000..85a74fa5eed --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/i256param.ll @@ -0,0 +1,7 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs +@i256_s = external global i256		; <i256*> [#uses=1] + +define void @i256_ls(i256 %x) nounwind  { +	store i256 %x, i256* @i256_s +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/i56param.ll b/llvm/test/CodeGen/Blackfin/i56param.ll new file mode 100644 index 00000000000..a03c182e321 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/i56param.ll @@ -0,0 +1,8 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs +@i56_l = external global i56		; <i56*> [#uses=1] +@i56_s = external global i56		; <i56*> [#uses=1] + +define void @i56_ls(i56 %x) nounwind  { +	store i56 %x, i56* @i56_s +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/i8mem.ll b/llvm/test/CodeGen/Blackfin/i8mem.ll new file mode 100644 index 00000000000..967a86f36e5 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/i8mem.ll @@ -0,0 +1,10 @@ +; RUN: llvm-as < %s | llc -march=bfin + +@i8_l = external global i8		; <i8*> [#uses=1] +@i8_s = external global i8		; <i8*> [#uses=1] + +define void @i8_ls() nounwind  { +	%tmp = load i8* @i8_l		; <i8> [#uses=1] +	store i8 %tmp, i8* @i8_s +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/int-setcc.ll b/llvm/test/CodeGen/Blackfin/int-setcc.ll new file mode 100644 index 00000000000..e1f822b0a30 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/int-setcc.ll @@ -0,0 +1,80 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t + +define fastcc void @Evaluate() { +entry: +	br i1 false, label %cond_false186, label %cond_true + +cond_true:		; preds = %entry +	ret void + +cond_false186:		; preds = %entry +	br i1 false, label %cond_true293, label %bb203 + +bb203:		; preds = %cond_false186 +	ret void + +cond_true293:		; preds = %cond_false186 +	br i1 false, label %cond_true298, label %cond_next317 + +cond_true298:		; preds = %cond_true293 +	br i1 false, label %cond_next518, label %cond_true397.preheader + +cond_next317:		; preds = %cond_true293 +	ret void + +cond_true397.preheader:		; preds = %cond_true298 +	ret void + +cond_next518:		; preds = %cond_true298 +	br i1 false, label %bb1069, label %cond_true522 + +cond_true522:		; preds = %cond_next518 +	ret void + +bb1069:		; preds = %cond_next518 +	br i1 false, label %cond_next1131, label %bb1096 + +bb1096:		; preds = %bb1069 +	ret void + +cond_next1131:		; preds = %bb1069 +	br i1 false, label %cond_next1207, label %cond_true1150 + +cond_true1150:		; preds = %cond_next1131 +	ret void + +cond_next1207:		; preds = %cond_next1131 +	br i1 false, label %cond_next1219, label %cond_true1211 + +cond_true1211:		; preds = %cond_next1207 +	ret void + +cond_next1219:		; preds = %cond_next1207 +	br i1 false, label %cond_true1223, label %cond_next1283 + +cond_true1223:		; preds = %cond_next1219 +	br i1 false, label %cond_true1254, label %cond_true1264 + +cond_true1254:		; preds = %cond_true1223 +	br i1 false, label %bb1567, label %cond_true1369.preheader + +cond_true1264:		; preds = %cond_true1223 +	ret void + +cond_next1283:		; preds = %cond_next1219 +	ret void + +cond_true1369.preheader:		; preds = %cond_true1254 +	ret void + +bb1567:		; preds = %cond_true1254 +	%tmp1605 = load i8* null		; <i8> [#uses=1] +	%tmp1606 = icmp eq i8 %tmp1605, 0		; <i1> [#uses=1] +	br i1 %tmp1606, label %cond_next1637, label %cond_true1607 + +cond_true1607:		; preds = %bb1567 +	ret void + +cond_next1637:		; preds = %bb1567 +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/invalid-apint.ll b/llvm/test/CodeGen/Blackfin/invalid-apint.ll new file mode 100644 index 00000000000..bc3bbb38c6a --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/invalid-apint.ll @@ -0,0 +1,15 @@ +; RUN: llvm-as < %s | llc -march=bfin + +; Assertion failed: (width < BitWidth && "Invalid APInt Truncate request"), +; function trunc, file APInt.cpp, line 956. + +@str2 = external global [29 x i8] + +define void @printArgsNoRet(i32 %a1, float %a2, i8 %a3, double %a4, i8* %a5, i32 %a6, float %a7, i8 %a8, double %a9, i8* %a10, i32 %a11, float %a12, i8 %a13, double %a14, i8* %a15) { +entry: +	%tmp17 = sext i8 %a13 to i32 +	%tmp23 = call i32 (i8*, ...)* @printf(i8* getelementptr ([29 x i8]* @str2, i32 0, i64 0), i32 %a11, double 0.000000e+00, i32 %tmp17, double %a14, i32 0) +	ret void +} + +declare i32 @printf(i8*, ...) diff --git a/llvm/test/CodeGen/Blackfin/jumptable.ll b/llvm/test/CodeGen/Blackfin/jumptable.ll new file mode 100644 index 00000000000..62b58314052 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/jumptable.ll @@ -0,0 +1,53 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs | FileCheck %s + +; CHECK: .section .rodata +; CHECK: JTI1_0: +; CHECK: .long .BB1_1 + +define i32 @oper(i32 %op, i32 %A, i32 %B) { +entry: +        switch i32 %op, label %bbx [ +               i32 1 , label %bb1 +               i32 2 , label %bb2 +               i32 3 , label %bb3 +               i32 4 , label %bb4 +               i32 5 , label %bb5 +               i32 6 , label %bb6 +               i32 7 , label %bb7 +               i32 8 , label %bb8 +               i32 9 , label %bb9 +               i32 10, label %bb10 +        ] +bb1: +	%R1 = add i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R1 +bb2: +	%R2 = sub i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R2 +bb3: +	%R3 = mul i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R3 +bb4: +	%R4 = sdiv i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R4 +bb5: +	%R5 = udiv i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R5 +bb6: +	%R6 = srem i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R6 +bb7: +	%R7 = urem i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R7 +bb8: +	%R8 = and i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R8 +bb9: +	%R9 = or i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R9 +bb10: +	%R10 = xor i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R10 +bbx: +        ret i32 0 +} diff --git a/llvm/test/CodeGen/Blackfin/large-switch.ll b/llvm/test/CodeGen/Blackfin/large-switch.ll new file mode 100644 index 00000000000..42aa4cd9faf --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/large-switch.ll @@ -0,0 +1,187 @@ +; RUN: llvm-as < %s | llc -march=bfin + +; The switch expansion uses a dynamic shl, and it produces a jumptable + +define void @athlon_fp_unit_ready_cost() { +entry: +	switch i32 0, label %UnifiedReturnBlock [ +		i32 -1, label %bb2063 +		i32 19, label %bb2035 +		i32 20, label %bb2035 +		i32 21, label %bb2035 +		i32 23, label %bb2035 +		i32 24, label %bb2035 +		i32 27, label %bb2035 +		i32 32, label %bb2035 +		i32 33, label %bb1994 +		i32 35, label %bb2035 +		i32 36, label %bb1994 +		i32 90, label %bb1948 +		i32 94, label %bb1948 +		i32 95, label %bb1948 +		i32 133, label %bb1419 +		i32 135, label %bb1238 +		i32 136, label %bb1238 +		i32 137, label %bb1238 +		i32 138, label %bb1238 +		i32 139, label %bb1201 +		i32 140, label %bb1201 +		i32 141, label %bb1154 +		i32 142, label %bb1126 +		i32 144, label %bb1201 +		i32 145, label %bb1126 +		i32 146, label %bb1201 +		i32 147, label %bb1126 +		i32 148, label %bb1201 +		i32 149, label %bb1126 +		i32 150, label %bb1201 +		i32 151, label %bb1126 +		i32 152, label %bb1096 +		i32 153, label %bb1096 +		i32 154, label %bb1096 +		i32 157, label %bb1096 +		i32 158, label %bb1096 +		i32 159, label %bb1096 +		i32 162, label %bb1096 +		i32 163, label %bb1096 +		i32 164, label %bb1096 +		i32 167, label %bb1201 +		i32 168, label %bb1201 +		i32 170, label %bb1201 +		i32 171, label %bb1201 +		i32 173, label %bb1201 +		i32 174, label %bb1201 +		i32 176, label %bb1201 +		i32 177, label %bb1201 +		i32 179, label %bb993 +		i32 180, label %bb993 +		i32 181, label %bb993 +		i32 182, label %bb993 +		i32 183, label %bb993 +		i32 184, label %bb993 +		i32 365, label %bb1126 +		i32 366, label %bb1126 +		i32 367, label %bb1126 +		i32 368, label %bb1126 +		i32 369, label %bb1126 +		i32 370, label %bb1126 +		i32 371, label %bb1126 +		i32 372, label %bb1126 +		i32 373, label %bb1126 +		i32 384, label %bb1126 +		i32 385, label %bb1126 +		i32 386, label %bb1126 +		i32 387, label %bb1126 +		i32 388, label %bb1126 +		i32 389, label %bb1126 +		i32 390, label %bb1126 +		i32 391, label %bb1126 +		i32 392, label %bb1126 +		i32 525, label %bb919 +		i32 526, label %bb839 +		i32 528, label %bb919 +		i32 529, label %bb839 +		i32 532, label %cond_next6.i97 +		i32 533, label %cond_next6.i81 +		i32 534, label %bb495 +		i32 536, label %cond_next6.i81 +		i32 537, label %cond_next6.i81 +		i32 538, label %bb396 +		i32 539, label %bb288 +		i32 541, label %bb396 +		i32 542, label %bb396 +		i32 543, label %bb396 +		i32 544, label %bb396 +		i32 545, label %bb189 +		i32 546, label %cond_next6.i +		i32 547, label %bb189 +		i32 548, label %cond_next6.i +		i32 549, label %bb189 +		i32 550, label %cond_next6.i +		i32 551, label %bb189 +		i32 552, label %cond_next6.i +		i32 553, label %bb189 +		i32 554, label %cond_next6.i +		i32 555, label %bb189 +		i32 556, label %cond_next6.i +		i32 557, label %bb189 +		i32 558, label %cond_next6.i +		i32 618, label %bb40 +		i32 619, label %bb18 +		i32 620, label %bb40 +		i32 621, label %bb10 +		i32 622, label %bb10 +	] + +bb10: +	ret void + +bb18: +	ret void + +bb40: +	ret void + +cond_next6.i: +	ret void + +bb189: +	ret void + +bb288: +	ret void + +bb396: +	ret void + +bb495: +	ret void + +cond_next6.i81: +	ret void + +cond_next6.i97: +	ret void + +bb839: +	ret void + +bb919: +	ret void + +bb993: +	ret void + +bb1096: +	ret void + +bb1126: +	ret void + +bb1154: +	ret void + +bb1201: +	ret void + +bb1238: +	ret void + +bb1419: +	ret void + +bb1948: +	ret void + +bb1994: +	ret void + +bb2035: +	ret void + +bb2063: +	ret void + +UnifiedReturnBlock: +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/load-i16.ll b/llvm/test/CodeGen/Blackfin/load-i16.ll new file mode 100644 index 00000000000..853b6621793 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/load-i16.ll @@ -0,0 +1,13 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs + +; This somewhat contrived function heavily exercises register classes +; It can trick -join-cross-class-copies into making illegal joins + +define void @f(i16** nocapture %p) nounwind readonly { +entry: +	%tmp1 = load i16** %p		; <i16*> [#uses=1] +	%tmp2 = load i16* %tmp1		; <i16> [#uses=1] +	%ptr = getelementptr i16* %tmp1, i16 %tmp2 +    store i16 %tmp2, i16* %ptr +    ret void +} diff --git a/llvm/test/CodeGen/Blackfin/logic-i16.ll b/llvm/test/CodeGen/Blackfin/logic-i16.ll new file mode 100644 index 00000000000..fba0afbfa4c --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/logic-i16.ll @@ -0,0 +1,16 @@ +; RUN: llvm-as < %s | llc -march=bfin + +define i16 @and(i16 %A, i16 %B) { +	%R = and i16 %A, %B		; <i16> [#uses=1] +	ret i16 %R +} + +define i16 @or(i16 %A, i16 %B) { +	%R = or i16 %A, %B		; <i16> [#uses=1] +	ret i16 %R +} + +define i16 @xor(i16 %A, i16 %B) { +	%R = xor i16 %A, %B		; <i16> [#uses=1] +	ret i16 %R +} diff --git a/llvm/test/CodeGen/Blackfin/many-args.ll b/llvm/test/CodeGen/Blackfin/many-args.ll new file mode 100644 index 00000000000..3160d6c5449 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/many-args.ll @@ -0,0 +1,23 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs + +	type { i32, float, float, float, float, float, float, float, float, float, float }		; type %0 +	%struct..s_segment_inf = type { float, i32, i16, i16, float, float, i32, float, float } + +define i32 @main(i32 %argc.1, i8** %argv.1) { +entry: +	%tmp.218 = load float* null		; <float> [#uses=1] +	%tmp.219 = getelementptr %0* null, i64 0, i32 6		; <float*> [#uses=1] +	%tmp.220 = load float* %tmp.219		; <float> [#uses=1] +	%tmp.221 = getelementptr %0* null, i64 0, i32 7		; <float*> [#uses=1] +	%tmp.222 = load float* %tmp.221		; <float> [#uses=1] +	%tmp.223 = getelementptr %0* null, i64 0, i32 8		; <float*> [#uses=1] +	%tmp.224 = load float* %tmp.223		; <float> [#uses=1] +	%tmp.225 = getelementptr %0* null, i64 0, i32 9		; <float*> [#uses=1] +	%tmp.226 = load float* %tmp.225		; <float> [#uses=1] +	%tmp.227 = getelementptr %0* null, i64 0, i32 10		; <float*> [#uses=1] +	%tmp.228 = load float* %tmp.227		; <float> [#uses=1] +	call void @place_and_route(i32 0, i32 0, float 0.000000e+00, i32 0, i32 0, i8* null, i32 0, i32 0, i8* null, i8* null, i8* null, i8* null, i32 0, i32 0, i32 0, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, i32 0, i32 0, i32 0, i32 0, i32 0, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, i32 0, i32 0, i16 0, i16 0, i16 0, float 0.000000e+00, float 0.000000e+00, %struct..s_segment_inf* null, i32 0, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float %tmp.218, float %tmp.220, float %tmp.222, float %tmp.224, float %tmp.226, float %tmp.228) +	ret i32 0 +} + +declare void @place_and_route(i32, i32, float, i32, i32, i8*, i32, i32, i8*, i8*, i8*, i8*, i32, i32, i32, float, float, float, float, float, float, float, float, float, i32, i32, i32, i32, i32, float, float, float, i32, i32, i16, i16, i16, float, float, %struct..s_segment_inf*, i32, float, float, float, float, float, float, float, float, float, float) diff --git a/llvm/test/CodeGen/Blackfin/mulhu.ll b/llvm/test/CodeGen/Blackfin/mulhu.ll new file mode 100644 index 00000000000..91be4502d72 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/mulhu.ll @@ -0,0 +1,106 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t + +	%struct.CUMULATIVE_ARGS = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } +	%struct.VEC_edge = type { i32, i32, [1 x %struct.edge_def*] } +	%struct._obstack_chunk = type { i8*, %struct._obstack_chunk*, [4 x i8] } +	%struct.basic_block_def = type { %struct.rtx_def*, %struct.rtx_def*, %struct.tree_node*, %struct.VEC_edge*, %struct.VEC_edge*, %struct.bitmap_head_def*, %struct.bitmap_head_def*, i8*, %struct.loop*, [2 x %struct.et_node*], %struct.basic_block_def*, %struct.basic_block_def*, %struct.reorder_block_def*, %struct.bb_ann_d*, i64, i32, i32, i32, i32 } +	%struct.bb_ann_d = type { %struct.tree_node*, i8, %struct.edge_prediction* } +	%struct.bitmap_element_def = type { %struct.bitmap_element_def*, %struct.bitmap_element_def*, i32, [4 x i32] } +	%struct.bitmap_head_def = type { %struct.bitmap_element_def*, %struct.bitmap_element_def*, i32, %struct.bitmap_obstack* } +	%struct.bitmap_obstack = type { %struct.bitmap_element_def*, %struct.bitmap_head_def*, %struct.obstack } +	%struct.cost_pair = type { %struct.iv_cand*, i32, %struct.bitmap_head_def* } +	%struct.dataflow_d = type { %struct.varray_head_tag*, [2 x %struct.tree_node*] } +	%struct.def_operand_ptr = type { %struct.tree_node** } +	%struct.def_optype_d = type { i32, [1 x %struct.def_operand_ptr] } +	%struct.edge_def = type { %struct.basic_block_def*, %struct.basic_block_def*, %struct.edge_def_insns, i8*, %struct.location_t*, i32, i32, i64, i32 } +	%struct.edge_def_insns = type { %struct.rtx_def* } +	%struct.edge_prediction = type { %struct.edge_prediction*, %struct.edge_def*, i32, i32 } +	%struct.eh_status = type opaque +	%struct.emit_status = type { i32, i32, %struct.rtx_def*, %struct.rtx_def*, %struct.sequence_stack*, i32, %struct.location_t, i32, i8*, %struct.rtx_def** } +	%struct.et_node = type opaque +	%struct.expr_status = type { i32, i32, i32, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def* } +	%struct.function = type { %struct.eh_status*, %struct.expr_status*, %struct.emit_status*, %struct.varasm_status*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.function*, i32, i32, i32, i32, %struct.rtx_def*, %struct.CUMULATIVE_ARGS, %struct.rtx_def*, %struct.rtx_def*, %struct.initial_value_struct*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, i8, i32, i64, %struct.tree_node*, %struct.tree_node*, %struct.rtx_def*, %struct.varray_head_tag*, %struct.temp_slot*, i32, %struct.var_refs_queue*, i32, i32, %struct.rtvec_def*, %struct.tree_node*, i32, i32, i32, %struct.machine_function*, i32, i32, i1, i1, %struct.language_function*, %struct.rtx_def*, i32, i32, i32, i32, %struct.location_t, %struct.varray_head_tag*, %struct.tree_node*, i8, i8, i8 } +	%struct.htab = type { i32 (i8*)*, i32 (i8*, i8*)*, void (i8*)*, i8**, i32, i32, i32, i32, i32, i8* (i32, i32)*, void (i8*)*, i8*, i8* (i8*, i32, i32)*, void (i8*, i8*)*, i32 } +	%struct.initial_value_struct = type opaque +	%struct.iv = type { %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, i1, i1, i32 } +	%struct.iv_cand = type { i32, i1, i32, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.iv*, i32 } +	%struct.iv_use = type { i32, i32, %struct.iv*, %struct.tree_node*, %struct.tree_node**, %struct.bitmap_head_def*, i32, %struct.cost_pair*, %struct.iv_cand* } +	%struct.ivopts_data = type { %struct.loop*, %struct.htab*, i32, %struct.version_info*, %struct.bitmap_head_def*, i32, %struct.varray_head_tag*, %struct.varray_head_tag*, %struct.bitmap_head_def*, i1 } +	%struct.lang_decl = type opaque +	%struct.language_function = type opaque +	%struct.location_t = type { i8*, i32 } +	%struct.loop = type { i32, %struct.basic_block_def*, %struct.basic_block_def*, %struct.basic_block_def*, %struct.lpt_decision, i32, i32, %struct.edge_def**, i32, %struct.basic_block_def*, %struct.basic_block_def*, i32, %struct.edge_def**, i32, %struct.edge_def**, i32, %struct.simple_bitmap_def*, i32, %struct.loop**, i32, %struct.loop*, %struct.loop*, %struct.loop*, %struct.loop*, i32, i8*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, i32, %struct.tree_node*, %struct.tree_node*, %struct.nb_iter_bound*, %struct.edge_def*, i1 } +	%struct.lpt_decision = type { i32, i32 } +	%struct.machine_function = type { %struct.stack_local_entry*, i8*, %struct.rtx_def*, i32, i32, i32, i32, i32 } +	%struct.nb_iter_bound = type { %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.nb_iter_bound* } +	%struct.obstack = type { i32, %struct._obstack_chunk*, i8*, i8*, i8*, i32, i32, %struct._obstack_chunk* (i8*, i32)*, void (i8*, %struct._obstack_chunk*)*, i8*, i8 } +	%struct.reorder_block_def = type { %struct.rtx_def*, %struct.rtx_def*, %struct.basic_block_def*, %struct.basic_block_def*, %struct.basic_block_def*, i32, i32, i32 } +	%struct.rtvec_def = type { i32, [1 x %struct.rtx_def*] } +	%struct.rtx_def = type { i16, i8, i8, %struct.u } +	%struct.sequence_stack = type { %struct.rtx_def*, %struct.rtx_def*, %struct.sequence_stack* } +	%struct.simple_bitmap_def = type { i32, i32, i32, [1 x i64] } +	%struct.stack_local_entry = type opaque +	%struct.stmt_ann_d = type { %struct.tree_ann_common_d, i8, %struct.basic_block_def*, %struct.stmt_operands_d, %struct.dataflow_d*, %struct.bitmap_head_def*, i32 } +	%struct.stmt_operands_d = type { %struct.def_optype_d*, %struct.def_optype_d*, %struct.v_may_def_optype_d*, %struct.vuse_optype_d*, %struct.v_may_def_optype_d* } +	%struct.temp_slot = type opaque +	%struct.tree_ann_common_d = type { i32, i8*, %struct.tree_node* } +	%struct.tree_ann_d = type { %struct.stmt_ann_d } +	%struct.tree_common = type { %struct.tree_node*, %struct.tree_node*, %struct.tree_ann_d*, i8, i8, i8, i8, i8 } +	%struct.tree_decl = type { %struct.tree_common, %struct.location_t, i32, %struct.tree_node*, i8, i8, i8, i8, i8, i8, i8, i32, %struct.tree_decl_u1, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.rtx_def*, i32, %struct.tree_decl_u2, %struct.tree_node*, %struct.tree_node*, i64, %struct.lang_decl* } +	%struct.tree_decl_u1 = type { i64 } +	%struct.tree_decl_u2 = type { %struct.function* } +	%struct.tree_node = type { %struct.tree_decl } +	%struct.u = type { [1 x i64] } +	%struct.v_def_use_operand_type_t = type { %struct.tree_node*, %struct.tree_node* } +	%struct.v_may_def_optype_d = type { i32, [1 x %struct.v_def_use_operand_type_t] } +	%struct.var_refs_queue = type { %struct.rtx_def*, i32, i32, %struct.var_refs_queue* } +	%struct.varasm_status = type opaque +	%struct.varray_head_tag = type { i32, i32, i32, i8*, %struct.u } +	%struct.version_info = type { %struct.tree_node*, %struct.iv*, i1, i32, i1 } +	%struct.vuse_optype_d = type { i32, [1 x %struct.tree_node*] } + +define i1 @determine_use_iv_cost(%struct.ivopts_data* %data, %struct.iv_use* %use, %struct.iv_cand* %cand) { +entry: +	switch i32 0, label %bb91 [ +		i32 0, label %bb +		i32 1, label %bb6 +		i32 3, label %cond_next135 +	] + +bb:		; preds = %entry +	ret i1 false + +bb6:		; preds = %entry +	br i1 false, label %bb87, label %cond_next27 + +cond_next27:		; preds = %bb6 +	br i1 false, label %cond_true30, label %cond_next55 + +cond_true30:		; preds = %cond_next27 +	br i1 false, label %cond_next41, label %cond_true35 + +cond_true35:		; preds = %cond_true30 +	ret i1 false + +cond_next41:		; preds = %cond_true30 +	%tmp44 = call i32 @force_var_cost(%struct.ivopts_data* %data, %struct.tree_node* null, %struct.bitmap_head_def** null)		; <i32> [#uses=1] +	%tmp46 = udiv i32 %tmp44, 5		; <i32> [#uses=1] +	call void @set_use_iv_cost(%struct.ivopts_data* %data, %struct.iv_use* %use, %struct.iv_cand* %cand, i32 %tmp46, %struct.bitmap_head_def* null) +	br label %bb87 + +cond_next55:		; preds = %cond_next27 +	ret i1 false + +bb87:		; preds = %cond_next41, %bb6 +	ret i1 false + +bb91:		; preds = %entry +	ret i1 false + +cond_next135:		; preds = %entry +	ret i1 false +} + +declare void @set_use_iv_cost(%struct.ivopts_data*, %struct.iv_use*, %struct.iv_cand*, i32, %struct.bitmap_head_def*) + +declare i32 @force_var_cost(%struct.ivopts_data*, %struct.tree_node*, %struct.bitmap_head_def**) diff --git a/llvm/test/CodeGen/Blackfin/printf.ll b/llvm/test/CodeGen/Blackfin/printf.ll new file mode 100644 index 00000000000..d66d1efe24e --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/printf.ll @@ -0,0 +1,10 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs +@.str_1 = external constant [42 x i8]		; <[42 x i8]*> [#uses=1] + +declare i32 @printf(i8*, ...) + +define i32 @main(i32 %argc.1, i8** %argv.1) { +entry: +	%tmp.16 = call i32 (i8*, ...)* @printf(i8* getelementptr ([42 x i8]* @.str_1, i64 0, i64 0), i32 0, i32 0, i64 0, i64 0) +	ret i32 0 +} diff --git a/llvm/test/CodeGen/Blackfin/printf2.ll b/llvm/test/CodeGen/Blackfin/printf2.ll new file mode 100644 index 00000000000..6f402d547e3 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/printf2.ll @@ -0,0 +1,11 @@ +; RUN: llvm-as < %s | llc -march=bfin +; XFAIL: * +; Assertion failed: (isUsed(Reg) && "Using an undefined register!"), +; function forward, file RegisterScavenging.cpp, line 182. + +declare i32 @printf(i8*, ...) + +define i32 @main() { +	%1 = call i32 (i8*, ...)* @printf(i8* undef, i1 undef) +	ret i32 0 +} diff --git a/llvm/test/CodeGen/Blackfin/promote-logic.ll b/llvm/test/CodeGen/Blackfin/promote-logic.ll new file mode 100644 index 00000000000..ba2caefe66d --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/promote-logic.ll @@ -0,0 +1,42 @@ +; RUN: llvm-as < %s | llc -march=bfin > %t +; XFAIL: * + +; DAG combiner can produce an illegal i16 OR operation after LegalizeOps. + +define void @mng_display_bgr565() { +entry: +	br i1 false, label %bb.preheader, label %return + +bb.preheader: +	br i1 false, label %cond_true48, label %cond_next80 + +cond_true48: +	%tmp = load i8* null +	%tmp51 = zext i8 %tmp to i16 +	%tmp99 = load i8* null +	%tmp54 = bitcast i8 %tmp99 to i8 +	%tmp54.upgrd.1 = zext i8 %tmp54 to i32 +	%tmp55 = lshr i32 %tmp54.upgrd.1, 3 +	%tmp55.upgrd.2 = trunc i32 %tmp55 to i16 +	%tmp52 = shl i16 %tmp51, 5 +	%tmp56 = and i16 %tmp55.upgrd.2, 28 +	%tmp57 = or i16 %tmp56, %tmp52 +	%tmp60 = zext i16 %tmp57 to i32 +	%tmp62 = xor i32 0, 65535 +	%tmp63 = mul i32 %tmp60, %tmp62 +	%tmp65 = add i32 0, %tmp63 +	%tmp69 = add i32 0, %tmp65 +	%tmp70 = lshr i32 %tmp69, 16 +	%tmp70.upgrd.3 = trunc i32 %tmp70 to i16 +	%tmp75 = lshr i16 %tmp70.upgrd.3, 8 +	%tmp75.upgrd.4 = trunc i16 %tmp75 to i8 +	%tmp76 = lshr i8 %tmp75.upgrd.4, 5 +	store i8 %tmp76, i8* null +	ret void + +cond_next80: +	ret void + +return: +	ret void +} diff --git a/llvm/test/CodeGen/Blackfin/promote-setcc.ll b/llvm/test/CodeGen/Blackfin/promote-setcc.ll new file mode 100644 index 00000000000..b686c542717 --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/promote-setcc.ll @@ -0,0 +1,40 @@ +; RUN: llvm-as < %s | llc -march=bfin > %t +; XFAIL: * +; Assertion failed: (isUsed(Reg) && "Using an undefined register!"), +; function forward, file RegisterScavenging.cpp, line 259. + +; The DAG combiner may sometimes create illegal i16 SETCC operations when run +; after LegalizeOps. Try to tease out all the optimizations in +; TargetLowering::SimplifySetCC. + +@x = external global i16 +@y = external global i16 + +declare i16 @llvm.ctlz.i16(i16) + +; Case (srl (ctlz x), 5) == const +; Note: ctlz is promoted, so this test does not catch the DAG combiner +define i1 @srl_ctlz_const() { +  %x = load i16* @x +  %c = call i16 @llvm.ctlz.i16(i16 %x) +  %s = lshr i16 %c, 4 +  %r = icmp eq i16 %s, 1 +  ret i1 %r +} + +; Case (zext x) == const +define i1 @zext_const() { +  %x = load i16* @x +  %r = icmp ugt i16 %x, 1 +  ret i1 %r +} + +; Case (sext x) == const +define i1 @sext_const() { +  %x = load i16* @x +  %y = add i16 %x, 1 +  %x2 = sext i16 %y to i32 +  %r = icmp ne i32 %x2, -1 +  ret i1 %r +} + diff --git a/llvm/test/CodeGen/Blackfin/sdiv.ll b/llvm/test/CodeGen/Blackfin/sdiv.ll new file mode 100644 index 00000000000..e03f4ff512c --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/sdiv.ll @@ -0,0 +1,5 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs +define i32 @sdiv(i32 %A, i32 %B) { +	%R = sdiv i32 %A, %B		; <i32> [#uses=1] +	ret i32 %R +} diff --git a/llvm/test/CodeGen/Blackfin/simple-select.ll b/llvm/test/CodeGen/Blackfin/simple-select.ll new file mode 100644 index 00000000000..286db7c2e3f --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/simple-select.ll @@ -0,0 +1,11 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t + +declare i1 @foo() + +define i32 @test(i32* %A, i32* %B) { +	%a = load i32* %A +	%b = load i32* %B +	%cond = call i1 @foo() +	%c = select i1 %cond, i32 %a, i32 %b +	ret i32 %c +} diff --git a/llvm/test/CodeGen/Blackfin/switch.ll b/llvm/test/CodeGen/Blackfin/switch.ll new file mode 100644 index 00000000000..738fff7c7ac --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/switch.ll @@ -0,0 +1,18 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t + +define i32 @foo(i32 %A, i32 %B, i32 %C) { +entry: +	switch i32 %A, label %out [ +		i32 1, label %bb +		i32 0, label %bb13 +	] + +bb:		; preds = %entry +	ret i32 1 + +bb13:		; preds = %entry +	ret i32 1 + +out:		; preds = %entry +	ret i32 0 +} diff --git a/llvm/test/CodeGen/Blackfin/switch2.ll b/llvm/test/CodeGen/Blackfin/switch2.ll new file mode 100644 index 00000000000..f0fe1a7c90c --- /dev/null +++ b/llvm/test/CodeGen/Blackfin/switch2.ll @@ -0,0 +1,16 @@ +; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t + +define i8* @FindChar(i8* %CurPtr) { +entry: +	br label %bb + +bb:		; preds = %bb, %entry +	%tmp = load i8* null		; <i8> [#uses=1] +	switch i8 %tmp, label %bb [ +		i8 0, label %bb7 +		i8 120, label %bb7 +	] + +bb7:		; preds = %bb, %bb +	ret i8* null +}  | 

