diff options
56 files changed, 6736 insertions, 2 deletions
diff --git a/CREDITS.TXT b/CREDITS.TXT index f6467abfc0..e58b85fdbd 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -335,3 +335,8 @@ D: Bunches of stuff N: Bob Wilson E: bob.wilson@acm.org D: Advanced SIMD (NEON) support in the ARM backend + +N: Wesley Peck +E: peckw@wesleypeck.com +W: http://wesleypeck.com/ +D: MicroBlaze backend diff --git a/autoconf/configure.ac b/autoconf/configure.ac index a4ba7a4af2..c354411a16 100644 --- a/autoconf/configure.ac +++ b/autoconf/configure.ac @@ -291,6 +291,7 @@ AC_CACHE_CHECK([target architecture],[llvm_cv_target_arch], msp430-*) llvm_cv_target_arch="MSP430" ;; s390x-*) llvm_cv_target_arch="SystemZ" ;; bfin-*) llvm_cv_target_arch="Blackfin" ;; + mblaze-*) llvm_cv_target_arch="MBlaze" ;; *) llvm_cv_target_arch="Unknown" ;; esac]) @@ -427,6 +428,7 @@ else MSP430) AC_SUBST(TARGET_HAS_JIT,0) ;; SystemZ) AC_SUBST(TARGET_HAS_JIT,0) ;; Blackfin) AC_SUBST(TARGET_HAS_JIT,0) ;; + MBlaze) AC_SUBST(TARGET_HAS_JIT,0) ;; *) AC_SUBST(TARGET_HAS_JIT,0) ;; esac fi @@ -493,7 +495,7 @@ if test "$enableval" = host-only ; then enableval=host fi case "$enableval" in - all) TARGETS_TO_BUILD="X86 Sparc PowerPC Alpha ARM Mips CellSPU PIC16 XCore MSP430 SystemZ Blackfin CBackend MSIL CppBackend" ;; + all) TARGETS_TO_BUILD="X86 Sparc PowerPC Alpha ARM Mips CellSPU PIC16 XCore MSP430 SystemZ Blackfin CBackend MSIL CppBackend MBlaze" ;; *)for a_target in `echo $enableval|sed -e 's/,/ /g' ` ; do case "$a_target" in x86) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;; @@ -512,6 +514,7 @@ case "$enableval" in cbe) TARGETS_TO_BUILD="CBackend $TARGETS_TO_BUILD" ;; msil) TARGETS_TO_BUILD="MSIL $TARGETS_TO_BUILD" ;; cpp) TARGETS_TO_BUILD="CppBackend $TARGETS_TO_BUILD" ;; + mblaze) TARGETS_TO_BUILD="MBlaze $TARGETS_TO_BUILD" ;; host) case "$llvm_cv_target_arch" in x86) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;; x86_64) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;; @@ -520,6 +523,7 @@ case "$enableval" in Alpha) TARGETS_TO_BUILD="Alpha $TARGETS_TO_BUILD" ;; ARM) TARGETS_TO_BUILD="ARM $TARGETS_TO_BUILD" ;; Mips) TARGETS_TO_BUILD="Mips $TARGETS_TO_BUILD" ;; + MBlaze) TARGETS_TO_BUILD="MBlaze $TARGETS_TO_BUILD" ;; CellSPU|SPU) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;; PIC16) TARGETS_TO_BUILD="PIC16 $TARGETS_TO_BUILD" ;; XCore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;; @@ -2330,6 +2330,7 @@ else msp430-*) llvm_cv_target_arch="MSP430" ;; s390x-*) llvm_cv_target_arch="SystemZ" ;; bfin-*) llvm_cv_target_arch="Blackfin" ;; + microblaze-*) llvm_cv_target_arch="MBlaze" ;; *) llvm_cv_target_arch="Unknown" ;; esac fi @@ -4795,6 +4796,8 @@ else ;; Blackfin) TARGET_HAS_JIT=0 ;; + MBlaze) TARGET_HAS_JIT=0 + ;; *) TARGET_HAS_JIT=0 ;; esac @@ -4898,7 +4901,7 @@ if test "$enableval" = host-only ; then enableval=host fi case "$enableval" in - all) TARGETS_TO_BUILD="X86 Sparc PowerPC Alpha ARM Mips CellSPU PIC16 XCore MSP430 SystemZ Blackfin CBackend MSIL CppBackend" ;; + all) TARGETS_TO_BUILD="X86 Sparc PowerPC Alpha ARM Mips CellSPU PIC16 XCore MSP430 SystemZ Blackfin CBackend MSIL CppBackend MBlaze" ;; *)for a_target in `echo $enableval|sed -e 's/,/ /g' ` ; do case "$a_target" in x86) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;; @@ -4917,6 +4920,7 @@ case "$enableval" in cbe) TARGETS_TO_BUILD="CBackend $TARGETS_TO_BUILD" ;; msil) TARGETS_TO_BUILD="MSIL $TARGETS_TO_BUILD" ;; cpp) TARGETS_TO_BUILD="CppBackend $TARGETS_TO_BUILD" ;; + mblaze) TARGETS_TO_BUILD="MBlaze $TARGETS_TO_BUILD" ;; host) case "$llvm_cv_target_arch" in x86) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;; x86_64) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;; @@ -4925,6 +4929,7 @@ case "$enableval" in Alpha) TARGETS_TO_BUILD="Alpha $TARGETS_TO_BUILD" ;; ARM) TARGETS_TO_BUILD="ARM $TARGETS_TO_BUILD" ;; Mips) TARGETS_TO_BUILD="Mips $TARGETS_TO_BUILD" ;; + MBlaze) TARGETS_TO_BUILD="MBlaze $TARGETS_TO_BUILD" ;; CellSPU|SPU) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;; PIC16) TARGETS_TO_BUILD="PIC16 $TARGETS_TO_BUILD" ;; XCore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;; diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h index 8798b0e394..be31ea0128 100644 --- a/include/llvm/ADT/Triple.h +++ b/include/llvm/ADT/Triple.h @@ -73,6 +73,7 @@ public: x86, // X86: i[3-9]86 x86_64, // X86-64: amd64, x86_64 xcore, // XCore: xcore + mblaze, // MBlaze: mblaze InvalidArch }; diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp index 5a76184caa..61bf0a73c9 100644 --- a/lib/Support/Triple.cpp +++ b/lib/Support/Triple.cpp @@ -40,6 +40,7 @@ const char *Triple::getArchTypeName(ArchType Kind) { case x86: return "i386"; case x86_64: return "x86_64"; case xcore: return "xcore"; + case mblaze: return "mblaze"; } return "<invalid>"; @@ -62,6 +63,8 @@ const char *Triple::getArchTypePrefix(ArchType Kind) { case ppc64: case ppc: return "ppc"; + case mblaze: return "mblaze"; + case sparcv9: case sparc: return "sparc"; @@ -127,6 +130,8 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { return ppc64; if (Name == "ppc") return ppc; + if (Name == "mblaze") + return mblaze; if (Name == "sparc") return sparc; if (Name == "sparcv9") @@ -198,6 +203,8 @@ const char *Triple::getArchNameForAssembler() { return "ppc"; if (Str == "powerpc64") return "ppc64"; + if (Str == "mblaze" || Str == "microblaze") + return "mblaze"; if (Str == "arm") return "arm"; if (Str == "armv4t" || Str == "thumbv4t") @@ -234,6 +241,8 @@ void Triple::Parse() const { Arch = ppc; else if ((ArchName == "powerpc64") || (ArchName == "ppu")) Arch = ppc64; + else if (ArchName == "mblaze") + Arch = mblaze; else if (ArchName == "arm" || ArchName.startswith("armv") || ArchName == "xscale") diff --git a/lib/Target/MBlaze/AsmPrinter/CMakeLists.txt b/lib/Target/MBlaze/AsmPrinter/CMakeLists.txt new file mode 100644 index 0000000000..cfb2fc8bf9 --- /dev/null +++ b/lib/Target/MBlaze/AsmPrinter/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ )
+
+add_llvm_library(LLVMMBlazeAsmPrinter
+ MBlazeAsmPrinter.cpp + )
+add_dependencies(LLVMMBlazeAsmPrinter MBlazeCodeGenTable_gen)
\ No newline at end of file diff --git a/lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp b/lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp new file mode 100644 index 0000000000..6fe102645a --- /dev/null +++ b/lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp @@ -0,0 +1,302 @@ +//===-- MBlazeAsmPrinter.cpp - MBlaze 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 MBlaze assembly language. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mblaze-asm-printer" + +#include "MBlaze.h" +#include "MBlazeSubtarget.h" +#include "MBlazeInstrInfo.h" +#include "MBlazeTargetMachine.h" +#include "MBlazeMachineFunction.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/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/MathExtras.h" +#include <cctype> + +using namespace llvm; + +namespace { + class MBlazeAsmPrinter : public AsmPrinter { + const MBlazeSubtarget *Subtarget; + public: + explicit MBlazeAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM, + MCContext &Ctx, MCStreamer &Streamer, + const MCAsmInfo *T ) + : AsmPrinter(O, TM, Ctx, Streamer, T) { + Subtarget = &TM.getSubtarget<MBlazeSubtarget>(); + } + + virtual const char *getPassName() const { + return "MBlaze Assembly Printer"; + } + + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode); + void printOperand(const MachineInstr *MI, int opNum); + void printUnsignedImm(const MachineInstr *MI, int opNum); + void printFSLImm(const MachineInstr *MI, int opNum); + void printMemOperand(const MachineInstr *MI, int opNum, + const char *Modifier = 0); + void printFCCOperand(const MachineInstr *MI, int opNum, + const char *Modifier = 0); + void printSavedRegsBitmask(); + void printHex32(unsigned int Value); + + const char *emitCurrentABIString(); + void emitFrameDirective(); + + void printInstruction(const MachineInstr *MI); // autogenerated. + void EmitInstruction(const MachineInstr *MI) { + printInstruction(MI); + O << '\n'; + } + virtual void EmitFunctionBodyStart(); + virtual void EmitFunctionBodyEnd(); + static const char *getRegisterName(unsigned RegNo); + + virtual void EmitFunctionEntryLabel(); + void EmitStartOfAsmFile(Module &M); + }; +} // end of anonymous namespace + +#include "MBlazeGenAsmWriter.inc" + +//===----------------------------------------------------------------------===// +// +// MBlaze Asm Directives +// +// -- Frame directive "frame Stackpointer, Stacksize, RARegister" +// Describe the stack frame. +// +// -- Mask directives "mask bitmask, offset" +// Tells the assembler which registers are saved and where. +// bitmask - contain a little endian bitset indicating which registers are +// saved on function prologue (e.g. with a 0x80000000 mask, the +// assembler knows the register 31 (RA) is saved at prologue. +// offset - the position before stack pointer subtraction indicating where +// the first saved register on prologue is located. (e.g. with a +// +// Consider the following function prologue: +// +// .frame R19,48,R15 +// .mask 0xc0000000,-8 +// addiu R1, R1, -48 +// sw R15, 40(R1) +// sw R19, 36(R1) +// +// With a 0xc0000000 mask, the assembler knows the register 15 (R15) and +// 19 (R19) are saved at prologue. As the save order on prologue is from +// left to right, R15 is saved first. A -8 offset means that after the +// stack pointer subtration, the first register in the mask (R15) will be +// saved at address 48-8=40. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Mask directives +//===----------------------------------------------------------------------===// + +// Create a bitmask with all callee saved registers for CPU or Floating Point +// registers. For CPU registers consider RA, GP and FP for saving if necessary. +void MBlazeAsmPrinter::printSavedRegsBitmask() { + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + const MBlazeFunctionInfo *MBlazeFI = MF->getInfo<MBlazeFunctionInfo>(); + + // CPU Saved Registers Bitmasks + unsigned int CPUBitmask = 0; + + // Set the CPU Bitmasks + const MachineFrameInfo *MFI = MF->getFrameInfo(); + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + unsigned RegNum = MBlazeRegisterInfo::getRegisterNumbering(CSI[i].getReg()); + if (CSI[i].getRegClass() == MBlaze::CPURegsRegisterClass) + CPUBitmask |= (1 << RegNum); + } + + // Return Address and Frame registers must also be set in CPUBitmask. + if (RI.hasFP(*MF)) + CPUBitmask |= (1 << MBlazeRegisterInfo:: + getRegisterNumbering(RI.getFrameRegister(*MF))); + + if (MFI->hasCalls()) + CPUBitmask |= (1 << MBlazeRegisterInfo:: + getRegisterNumbering(RI.getRARegister())); + + // Print CPUBitmask + O << "\t.mask \t"; printHex32(CPUBitmask); O << ',' + << MBlazeFI->getCPUTopSavedRegOff() << '\n'; +} + +// Print a 32 bit hex number with all numbers. +void MBlazeAsmPrinter::printHex32(unsigned int Value) { + O << "0x"; + for (int i = 7; i >= 0; i--) + O << utohexstr( (Value & (0xF << (i*4))) >> (i*4) ); +} + +//===----------------------------------------------------------------------===// +// Frame and Set directives +//===----------------------------------------------------------------------===// + +/// Frame Directive +void MBlazeAsmPrinter::emitFrameDirective() { + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + + unsigned stackReg = RI.getFrameRegister(*MF); + unsigned returnReg = RI.getRARegister(); + unsigned stackSize = MF->getFrameInfo()->getStackSize(); + + + O << "\t.frame\t" << getRegisterName(stackReg) + << ',' << stackSize << ',' + << getRegisterName(returnReg) + << '\n'; +} + +void MBlazeAsmPrinter::EmitFunctionEntryLabel() { + O << "\t.ent\t" << *CurrentFnSym << '\n'; + OutStreamer.EmitLabel(CurrentFnSym); +} + +/// EmitFunctionBodyStart - Targets can override this to emit stuff before +/// the first basic block in the function. +void MBlazeAsmPrinter::EmitFunctionBodyStart() { + emitFrameDirective(); + printSavedRegsBitmask(); +} + +/// EmitFunctionBodyEnd - Targets can override this to emit stuff after +/// the last basic block in the function. +void MBlazeAsmPrinter::EmitFunctionBodyEnd() { + O << "\t.end\t" << *CurrentFnSym << '\n'; +} + +// Print out an operand for an inline asm expression. +bool MBlazeAsmPrinter:: +PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant,const char *ExtraCode){ + // Does this asm operand have a single letter operand modifier? + if (ExtraCode && ExtraCode[0]) + return true; // Unknown modifier. + + printOperand(MI, OpNo); + return false; +} + +void MBlazeAsmPrinter::printOperand(const MachineInstr *MI, int opNum) { + const MachineOperand &MO = MI->getOperand(opNum); + + switch (MO.getType()) { + case MachineOperand::MO_Register: + O << getRegisterName(MO.getReg()); + break; + + case MachineOperand::MO_Immediate: + O << (int)MO.getImm(); + break; + + case MachineOperand::MO_FPImmediate: { + const ConstantFP* fp = MO.getFPImm(); + printHex32(fp->getValueAPF().bitcastToAPInt().getZExtValue()); + O << ";\t# immediate = " << *fp; + break; + } + + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(OutContext); + return; + + case MachineOperand::MO_GlobalAddress: + O << *GetGlobalValueSymbol(MO.getGlobal()); + break; + + case MachineOperand::MO_ExternalSymbol: + O << *GetExternalSymbolSymbol(MO.getSymbolName()); + break; + + case MachineOperand::MO_JumpTableIndex: + O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() + << '_' << MO.getIndex(); + break; + + case MachineOperand::MO_ConstantPoolIndex: + O << MAI->getPrivateGlobalPrefix() << "CPI" + << getFunctionNumber() << "_" << MO.getIndex(); + if (MO.getOffset()) + O << "+" << MO.getOffset(); + break; + + default: + llvm_unreachable("<unknown operand type>"); + } +} + +void MBlazeAsmPrinter::printUnsignedImm(const MachineInstr *MI, int opNum) { + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.getType() == MachineOperand::MO_Immediate) + O << (unsigned int)MO.getImm(); + else + printOperand(MI, opNum); +} + +void MBlazeAsmPrinter::printFSLImm(const MachineInstr *MI, int opNum) { + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.getType() == MachineOperand::MO_Immediate) + O << "rfsl" << (unsigned int)MO.getImm(); + else + printOperand(MI, opNum); +} + +void MBlazeAsmPrinter:: +printMemOperand(const MachineInstr *MI, int opNum, const char *Modifier) { + printOperand(MI, opNum+1); + O << ", "; + printOperand(MI, opNum); +} + +void MBlazeAsmPrinter:: +printFCCOperand(const MachineInstr *MI, int opNum, const char *Modifier) { + const MachineOperand& MO = MI->getOperand(opNum); + O << MBlaze::MBlazeFCCToString((MBlaze::CondCode)MO.getImm()); +} + +void MBlazeAsmPrinter::EmitStartOfAsmFile(Module &M) { +} + +// Force static initialization. +extern "C" void LLVMInitializeMBlazeAsmPrinter() { + RegisterAsmPrinter<MBlazeAsmPrinter> X(TheMBlazeTarget); +} diff --git a/lib/Target/MBlaze/AsmPrinter/Makefile b/lib/Target/MBlaze/AsmPrinter/Makefile new file mode 100644 index 0000000000..c8e4d8f644 --- /dev/null +++ b/lib/Target/MBlaze/AsmPrinter/Makefile @@ -0,0 +1,17 @@ +##===- lib/Target/MBlaze/AsmPrinter/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 = LLVMMBlazeAsmPrinter + +# Hack: we need to include 'main' MBlaze target directory to grab +# private headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/lib/Target/MBlaze/CMakeLists.txt b/lib/Target/MBlaze/CMakeLists.txt new file mode 100644 index 0000000000..c93e3dfc78 --- /dev/null +++ b/lib/Target/MBlaze/CMakeLists.txt @@ -0,0 +1,27 @@ +set(LLVM_TARGET_DEFINITIONS MBlaze.td) + +tablegen(MBlazeGenRegisterInfo.h.inc -gen-register-desc-header) +tablegen(MBlazeGenRegisterNames.inc -gen-register-enums) +tablegen(MBlazeGenRegisterInfo.inc -gen-register-desc) +tablegen(MBlazeGenInstrNames.inc -gen-instr-enums) +tablegen(MBlazeGenInstrInfo.inc -gen-instr-desc) +tablegen(MBlazeGenAsmWriter.inc -gen-asm-writer) +tablegen(MBlazeGenDAGISel.inc -gen-dag-isel) +tablegen(MBlazeGenCallingConv.inc -gen-callingconv) +tablegen(MBlazeGenSubtarget.inc -gen-subtarget) +tablegen(MBlazeGenIntrinsics.inc -gen-tgt-intrinsic) + +add_llvm_target(MBlazeCodeGen + MBlazeDelaySlotFiller.cpp + MBlazeInstrInfo.cpp + MBlazeISelDAGToDAG.cpp + MBlazeISelLowering.cpp + MBlazeMCAsmInfo.cpp + MBlazeRegisterInfo.cpp + MBlazeSubtarget.cpp + MBlazeTargetMachine.cpp + MBlazeTargetObjectFile.cpp + MBlazeIntrinsicInfo.cpp + ) + +target_link_libraries (LLVMMBlazeCodeGen LLVMSelectionDAG) diff --git a/lib/Target/MBlaze/MBlaze.h b/lib/Target/MBlaze/MBlaze.h new file mode 100644 index 0000000000..f9d828b266 --- /dev/null +++ b/lib/Target/MBlaze/MBlaze.h @@ -0,0 +1,39 @@ +//===-- MBlaze.h - Top-level interface for MBlaze ---------------*- 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 MBlaze back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef TARGET_MBLAZE_H +#define TARGET_MBLAZE_H + +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + class MBlazeTargetMachine; + class FunctionPass; + class MachineCodeEmitter; + class formatted_raw_ostream; + + FunctionPass *createMBlazeISelDag(MBlazeTargetMachine &TM); + FunctionPass *createMBlazeDelaySlotFillerPass(MBlazeTargetMachine &TM); + + extern Target TheMBlazeTarget; +} // end namespace llvm; + +// Defines symbolic names for MBlaze registers. This defines a mapping from +// register name to register number. +#include "MBlazeGenRegisterNames.inc" + +// Defines symbolic names for the MBlaze instructions. +#include "MBlazeGenInstrNames.inc" + +#endif diff --git a/lib/Target/MBlaze/MBlaze.td b/lib/Target/MBlaze/MBlaze.td new file mode 100644 index 0000000000..16797529cb --- /dev/null +++ b/lib/Target/MBlaze/MBlaze.td @@ -0,0 +1,85 @@ +//===- MBlaze.td - Describe the MBlaze Target Machine -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This is the top level entry point for the MBlaze target. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// Register File, Calling Conv, Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "MBlazeRegisterInfo.td" +include "MBlazeSchedule.td" +include "MBlazeIntrinsics.td" +include "MBlazeInstrInfo.td" +include "MBlazeCallingConv.td" + +def MBlazeInstrInfo : InstrInfo { + let TSFlagsFields = []; + let TSFlagsShifts = []; +} + + +//===----------------------------------------------------------------------===// +// Microblaze Subtarget features // +//===----------------------------------------------------------------------===// + +def FeaturePipe3 : SubtargetFeature<"pipe3", "HasPipe3", "true", + "Implements 3-stage pipeline.">; +def FeatureBarrel : SubtargetFeature<"barrel", "HasBarrel", "true", + "Implements barrel shifter.">; +def FeatureDiv : SubtargetFeature<"div", "HasDiv", "true", + "Implements hardware divider.">; +def FeatureMul : SubtargetFeature<"mul", "HasMul", "true", + "Implements hardware multiplier.">; +def FeatureFSL : SubtargetFeature<"fsl", "HasFSL", "true", + "Implements FSL instructions.">; +def FeatureEFSL : SubtargetFeature<"efsl", "HasEFSL", "true", + "Implements extended FSL instructions.">; +def FeatureMSRSet : SubtargetFeature<"msrset", "HasMSRSet", "true", + "Implements MSR register set and clear.">; +def FeatureException : SubtargetFeature<"exception", "HasException", "true", + "Implements hardware exception support.">; +def FeaturePatCmp : SubtargetFeature<"patcmp", "HasPatCmp", "true", + "Implements pattern compare instruction.">; +def FeatureFPU : SubtargetFeature<"fpu", "HasFPU", "true", + "Implements floating point unit.">; +def FeatureESR : SubtargetFeature<"esr", "HasESR", "true", + "Implements ESR and EAR registers">; +def FeaturePVR : SubtargetFeature<"pvr", "HasPVR", "true", + "Implements processor version register.">; +def FeatureMul64 : SubtargetFeature<"mul64", "HasMul64", "true", + "Implements multiplier with 64-bit result">; +def FeatureSqrt : SubtargetFeature<"sqrt", "HasSqrt", "true", + "Implements sqrt and floating point convert.">; +def FeatureMMU : SubtargetFeature<"mmu", "HasMMU", "true", + "Implements memory management unit.">; + +//===----------------------------------------------------------------------===// +// MBlaze processors supported. +//===----------------------------------------------------------------------===// + +class Proc<string Name, list<SubtargetFeature> Features> + : Processor<Name, MBlazeGenericItineraries, Features>; + + +def : Proc<"v400", []>; +def : Proc<"v500", []>; +def : Proc<"v600", []>; +def : Proc<"v700", []>; +def : Proc<"v710", []>; + +def MBlaze : Target { + let InstructionSet = MBlazeInstrInfo; +} diff --git a/lib/Target/MBlaze/MBlazeCallingConv.td b/lib/Target/MBlaze/MBlazeCallingConv.td new file mode 100644 index 0000000000..dfc87f5952 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeCallingConv.td @@ -0,0 +1,41 @@ +//===- MBlazeCallingConv.td - Calling Conventions for MBlaze ----*- C++ -*-===// +// +// 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 MBlaze architecture. +//===----------------------------------------------------------------------===// + +/// CCIfSubtarget - Match if the current subtarget has a feature F. +class CCIfSubtarget<string F, CCAction A>: + CCIf<!strconcat("State.getTarget().getSubtarget<MBlazeSubtarget>().", F), A>; + +//===----------------------------------------------------------------------===// +// MBlaze ABI Calling Convention +//===----------------------------------------------------------------------===// + +def CC_MBlaze : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType<i32>>, + + // Integer arguments are passed in integer registers. + CCIfType<[i32], CCAssignToReg<[R5, R6, R7, R8, R9, R10]>>, + + // Single fp arguments are passed in floating point registers + CCIfType<[f32], CCAssignToReg<[F5, F6, F7, F8, F9, F10]>>, + + // 32-bit values get stored in stack slots that are 4 bytes in + // size and 4-byte aligned. + CCIfType<[i32, f32], CCAssignToStack<4, 4>> +]>; + +def RetCC_MBlaze : CallingConv<[ + // i32 are returned in registers R3, R4 + CCIfType<[i32], CCAssignToReg<[R3, R4]>>, + + // f32 are returned in registers F3, F4 + CCIfType<[f32], CCAssignToReg<[F3, F4]>> +]>; diff --git a/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp b/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp new file mode 100644 index 0000000000..42fea25073 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp @@ -0,0 +1,75 @@ +//===-- DelaySlotFiller.cpp - MBlaze delay slot filler --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Simple pass to fills delay slots with NOPs. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "delay-slot-filler" + +#include "MBlaze.h" +#include "MBlazeTargetMachine.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/ADT/Statistic.h" + +using namespace llvm; + +STATISTIC(FilledSlots, "Number of delay slots filled"); + +namespace { + struct Filler : public MachineFunctionPass { + + TargetMachine &TM; + const TargetInstrInfo *TII; + + static char ID; + Filler(TargetMachine &tm) + : MachineFunctionPass(&ID), TM(tm), TII(tm.getInstrInfo()) { } + + virtual const char *getPassName() const { + return "MBlaze Delay Slot Filler"; + } + + bool runOnMachineBasicBlock(MachineBasicBlock &MBB); + bool runOnMachineFunction(MachineFunction &F) { + bool Changed = false; + for (MachineFunction::iterator FI = F.begin(), FE = F.end(); + FI != FE; ++FI) + Changed |= runOnMachineBasicBlock(*FI); + return Changed; + } + + }; + char Filler::ID = 0; +} // end of anonymous namespace + +/// runOnMachineBasicBlock - Fill in delay slots for the given basic block. +/// Currently, we fill delay slots with NOPs. We assume there is only one +/// delay slot per delayed instruction. +bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { + bool Changed = false; + for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) + if (I->getDesc().hasDelaySlot()) { + MachineBasicBlock::iterator J = I; + ++J; + BuildMI(MBB, J, I->getDebugLoc(), TII->get(MBlaze::NOP)); + ++FilledSlots; + Changed = true; + } + return Changed; +} + +/// createMBlazeDelaySlotFillerPass - Returns a pass that fills in delay +/// slots in MBlaze MachineFunctions +FunctionPass *llvm::createMBlazeDelaySlotFillerPass(MBlazeTargetMachine &tm) { + return new Filler(tm); +} + diff --git a/lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp b/lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp new file mode 100644 index 0000000000..f4b4c3d6ad --- /dev/null +++ b/lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp @@ -0,0 +1,368 @@ +//===-- MBlazeISelDAGToDAG.cpp - A dag to dag inst selector for MBlaze ----===// +// +// 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 MBlaze target. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mblaze-isel" +#include "MBlaze.h" +#include "MBlazeISelLowering.h" +#include "MBlazeMachineFunction.h" +#include "MBlazeRegisterInfo.h" +#include "MBlazeSubtarget.h" +#include "MBlazeTargetMachine.h" +#include "llvm/GlobalValue.h" +#include "llvm/Instructions.h" +#include "llvm/Intrinsics.h" +#include "llvm/Support/CFG.h" +#include "llvm/Type.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Instruction Selector Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MBlazeDAGToDAGISel - MBlaze specific code to select MBlaze machine +// instructions for SelectionDAG operations. +//===----------------------------------------------------------------------===// +namespace { + +class MBlazeDAGToDAGISel : public SelectionDAGISel { + + /// TM - Keep a reference to MBlazeTargetMachine. + MBlazeTargetMachine &TM; + + /// Subtarget - Keep a pointer to the MBlazeSubtarget around so that we can + /// make the right decision when generating code for different targets. + const MBlazeSubtarget &Subtarget; + +public: + explicit MBlazeDAGToDAGISel(MBlazeTargetMachine &tm) : + SelectionDAGISel(tm), + TM(tm), Subtarget(tm.getSubtarget<MBlazeSubtarget>()) {} + + virtual void InstructionSelect(); + + // Pass Name + virtual const char *getPassName() const { + return "MBlaze DAG->DAG Pattern Instruction Selection"; + } +private: + // Include the pieces autogenerated from the target description. + #include "MBlazeGenDAGISel.inc" + + /// getTargetMachine - Return a reference to the TargetMachine, casted + /// to the target-specific type. + const MBlazeTargetMachine &getTargetMachine() { + return static_cast<const MBlazeTargetMachine &>(TM); + } + + /// getInstrInfo - Return a reference to the TargetInstrInfo, casted + /// to the target-specific type. + const MBlazeInstrInfo *getInstrInfo() { + return getTargetMachine().getInstrInfo(); + } + + SDNode *getGlobalBaseReg(); + SDNode *Select(SDNode *N); + + // Complex Pattern. + bool SelectAddr(SDNode *Op, SDValue N, + SDValue &Base, SDValue &Offset); + + // Address Selection + bool SelectAddrRegReg(SDNode *Op, SDValue N, SDValue &Base, SDValue &Index); + bool SelectAddrRegImm(SDNode *Op, SDValue N, SDValue &Disp, SDValue &Base); + + // getI32Imm - Return a target constant with the specified value, of type i32. + inline SDValue getI32Imm(unsigned Imm) { + return CurDAG->getTargetConstant(Imm, MVT::i32); + } + + + #ifndef NDEBUG + unsigned Indent; + #endif +}; + +} + +/// isIntS32Immediate - This method tests to see if the node is either a 32-bit +/// or 64-bit immediate, and if the value can be accurately represented as a +/// sign extension from a 32-bit value. If so, this returns true and the +/// immediate. +static bool isIntS32Immediate(SDNode *N, int32_t &Imm) { + unsigned Opc = N->getOpcode(); + if (Opc != ISD::Constant) + return false; + + Imm = (int32_t)cast<ConstantSDNode>(N)->getZExtValue(); + if (N->getValueType(0) == MVT::i32) + return Imm == (int32_t)cast<ConstantSDNode>(N)->getZExtValue(); + else + return Imm == (int64_t)cast<ConstantSDNode>(N)->getZExtValue(); +} + +static bool isIntS32Immediate(SDValue Op, int32_t &Imm) { + return isIntS32Immediate(Op.getNode(), Imm); +} + +/// InstructionSelect - This callback is invoked by +/// SelectionDAGISel when it has created a SelectionDAG for us to codegen. +void MBlazeDAGToDAGISel::InstructionSelect() { + // Codegen the basic block. + DEBUG(errs() << "===== Instruction selection begins:\n"); + DEBUG(Indent = 0); + + // Select target instructions for the DAG. + SelectRoot(*CurDAG); + + DEBUG(errs() << "===== Instruction selection ends:\n"); + + CurDAG->RemoveDeadNodes(); +} + +/// SelectAddressRegReg - Given the specified addressed, check to see if it +/// can be represented as an indexed [r+r] operation. Returns false if it +/// can be more efficiently represented with [r+imm]. +bool MBlazeDAGToDAGISel:: +SelectAddrRegReg(SDNode *Op, SDValue N, SDValue &Base, SDValue &Index) { + if (N.getOpcode() == ISD::FrameIndex) return false; + if (N.getOpcode() == ISD::TargetExternalSymbol || + N.getOpcode() == ISD::TargetGlobalAddress) + return false; // direct calls. + + if (N.getOperand(0).getOpcode() == ISD::TargetJumpTable || + N.getOperand(1).getOpcode() == ISD::TargetJumpTable) + return false; // jump tables. + + int32_t imm = 0; + if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) { + if (isIntS32Immediate(N.getOperand(1), imm)) + return false; // r+i + + Base = N.getOperand(1); + Index = N.getOperand(0); + return true; + } + + return false; +} + +/// Returns true if the address N can be represented by a base register plus +/// a signed 32-bit displacement [r+imm], and if it is not better +/// represented as reg+reg. +bool MBlazeDAGToDAGISel:: +SelectAddrRegImm(SDNode *Op, SDValue N, SDValue &Disp, SDValue &Base) { + // If this can be more profitably realized as r+r, fail. + if (SelectAddrRegReg(Op, N, Disp, Base)) + return false; + + if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) { + int32_t imm = 0; + if (isIntS32Immediate(N.getOperand(1), imm)) { + Disp = CurDAG->getTargetConstant(imm, MVT::i32); + if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N.getOperand(0))) { + Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType()); + } else { + Base = N.getOperand(0); + } + DEBUG( errs() << "WESLEY: Using Operand Immediate\n" ); + return true; // [r+i] + } + } else if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) { + // Loading from a constant address. + uint32_t Imm = CN->getZExtValue(); + Disp = CurDAG->getTargetConstant(Imm, CN->getValueType(0)); + Base = CurDAG->getRegister(MBlaze::R0, CN->getValueType(0)); + DEBUG( errs() << "WESLEY: Using Constant Node\n" ); + return true; + } + + Disp = CurDAG->getTargetConstant(0, TM.getTargetLowering()->getPointerTy()); + if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N)) + Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType()); + else + Base = N; + return true; // [r+0] +} + +/// getGlobalBaseReg - Output the instructions required to put the +/// GOT address into a register. +SDNode *MBlazeDAGToDAGISel::getGlobalBaseReg() { + unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF); + return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode(); +} + +/// ComplexPattern used on MBlazeInstrInfo +/// Used on MBlaze Load/Store instructions +bool MBlazeDAGToDAGISel:: +SelectAddr(SDNode *Op, SDValue Addr, SDValue &Offset, SDValue &Base) { + // if Address is FI, get the TargetFrameIndex. + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); + Offset = CurDAG->getTargetConstant(0, MVT::i32); + return true; + } + + // on PIC code Load GA + if (TM.getRelocationModel() == Reloc::PIC_) { + if ((Addr.getOpcode() == ISD::TargetGlobalAddress) || + (Addr.getOpcode() == ISD::TargetConstantPool) || + (Addr.getOpcode() == ISD::TargetJumpTable)){ + Base = CurDAG->getRegister(MBlaze::R15, MVT::i32); + Offset = Addr; + return true; + } + } else { + if ((Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress)) + return false; + } + + // Operand is a result from an ADD. + if (Addr.getOpcode() == ISD::ADD) { + if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { + if (Predicate_immSExt16(CN)) { + + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode> + (Addr.getOperand(0))) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); + } else { + Base = Addr.getOperand(0); + } + + Offset = CurDAG->getTargetConstant(CN->getZExtValue(), MVT::i32); + return true; + } + } + } + + Base = Addr; + Offset = CurDAG->getTargetConstant(0, MVT::i32); + return true; +} + +/// Select instructions not customized! Used for +/// expanded, promoted and normal instructions +SDNode* MBlazeDAGToDAGISel::Select(SDNode *Node) { + unsigned Opcode = Node->getOpcode(); + DebugLoc dl = Node->getDebugLoc(); + + // Dump information about the Node being selected + DEBUG(errs().indent(Indent) << "Selecting: "; + Node->dump(CurDAG); + errs() << "\n"); + DEBUG(Indent += 2); + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) { + DEBUG(errs().indent(Indent-2) << "== "; + Node->dump(CurDAG); + errs() << "\n"); + DEBUG(Indent -= 2); + return NULL; + } + + /// + // Instruction Selection not handled by the auto-generated + // tablegen selection should be handled here. + /// + switch(Opcode) { + default: break; + + // Get target GOT address. + case ISD::GLOBAL_OFFSET_TABLE: + return getGlobalBaseReg(); + + case ISD::FrameIndex: { + SDValue imm = CurDAG->getTargetConstant(0, MVT::i32); + int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex(); + EVT VT = Node->getValueType(0); + SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); + unsigned Opc = MBlaze::ADDI; + if (Node->hasOneUse()) + return CurDAG->SelectNodeTo(Node, Opc, VT, TFI, imm); + return CurDAG->getMachineNode(Opc, dl, VT, TFI, imm); + } + + + /// Handle direct and indirect calls when using PIC. On PIC, when + /// GOT is smaller than about 64k (small code) the GA target is + /// loaded with only one instruction. Otherwise GA's target must + /// be loaded with 3 instructions. + case MBlazeISD::JmpLink: { + if (TM.getRelocationModel() == Reloc::PIC_) { + SDValue Chain = Node->getOperand(0); + SDValue Callee = Node->getOperand(1); + SDValue R20Reg = CurDAG->getRegister(MBlaze::R20, MVT::i32); + SDValue InFlag(0, 0); + + if ( (isa<GlobalAddressSDNode>(Callee)) || + (isa<ExternalSymbolSDNode>(Callee)) ) + { + /// Direct call for global addresses and external symbols + SDValue GPReg = CurDAG->getRegister(MBlaze::R15, MVT::i32); + + // Use load to get GOT target + SDValue Ops[] = { Callee, GPReg, Chain }; + SDValue Load = SDValue(CurDAG->getMachineNode(MBlaze::LW, dl, + MVT::i32, MVT::Other, Ops, 3), 0); + Chain = Load.getValue(1); + + // Call target must be on T9 + Chain = CurDAG->getCopyToReg(Chain, dl, R20Reg, Load, InFlag); + } else + /// Indirect call + Chain = CurDAG->getCopyToReg(Chain, dl, R20Reg, Callee, InFlag); + + // Emit Jump and Link Register + SDNode *ResNode = CurDAG->getMachineNode(MBlaze::BRLID, dl, MVT::Other, + MVT::Flag, R20Reg, Chain); + Chain = SDValue(ResNode, 0); + InFlag = SDValue(ResNode, 1); + ReplaceUses(SDValue(Node, 0), Chain); + ReplaceUses(SDValue(Node, 1), InFlag); + return ResNode; + } + } + } + + // Select the default instruction + SDNode *ResNode = SelectCode(Node); + + DEBUG(errs().indent(Indent-2) << "=> "); + if (ResNode == NULL || ResNode == Node) + DEBUG(Node->dump(CurDAG)); + else + DEBUG(ResNode->dump(CurDAG)); + DEBUG(errs() << "\n"); + DEBUG(Indent -= 2); + + return ResNode; +} + +/// createMBlazeISelDag - This pass converts a legalized DAG into a +/// MBlaze-specific DAG, ready for instruction scheduling. +FunctionPass *llvm::createMBlazeISelDag(MBlazeTargetMachine &TM) { + return new MBlazeDAGToDAGISel(TM); +} diff --git a/lib/Target/MBlaze/MBlazeISelLowering.cpp b/lib/Target/MBlaze/MBlazeISelLowering.cpp new file mode 100644 index 0000000000..0acbe3fec6 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeISelLowering.cpp @@ -0,0 +1,882 @@ +//===-- MBlazeISelLowering.cpp - MBlaze 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 defines the interfaces that MBlaze uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mblaze-lower" +#include "MBlazeISelLowering.h" +#include "MBlazeMachineFunction.h" +#include "MBlazeTargetMachine.h" +#include "MBlazeTargetObjectFile.h" +#include "MBlazeSubtarget.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Intrinsics.h" +#include "llvm/CallingConv.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/SelectionDAGISel.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +const char *MBlazeTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + case MBlazeISD::JmpLink : return "MBlazeISD::JmpLink"; + case MBlazeISD::GPRel : return "MBlazeISD::GPRel"; + case MBlazeISD::Wrap : return "MBlazeISD::Wrap"; + case MBlazeISD::ICmp : return "MBlazeISD::ICmp"; + case MBlazeISD::Ret : return "MBlazeISD::Ret"; + case MBlazeISD::Select_CC : return "MBlazeISD::Select_CC"; + default : return NULL; + } +} + +MBlazeTargetLowering::MBlazeTargetLowering(MBlazeTargetMachine &TM) + : TargetLowering(TM, new MBlazeTargetObjectFile()) { + Subtarget = &TM.getSubtarget<MBlazeSubtarget>(); + + // MBlaze does not have i1 type, so use i32 for + // setcc operations results (slt, sgt, ...). + setBooleanContents(ZeroOrOneBooleanContent); + + // Set up the register classes + addRegisterClass(MVT::i32, MBlaze::CPURegsRegisterClass); + if (Subtarget->hasFPU()) { + addRegisterClass(MVT::f32, MBlaze::FGR32RegisterClass); + setOperationAction(ISD::ConstantFP, MVT::f32, Legal); + } + + // Floating point operations which are not supported + setOperationAction(ISD::FREM, MVT::f32, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i8, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i16, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand); + setOperationAction(ISD::FP_ROUND, MVT::f32, Expand); + setOperationAction(ISD::FP_ROUND, MVT::f64, Expand); + setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand); + setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand); + setOperationAction(ISD::FSIN, MVT::f32, Expand); + setOperationAction(ISD::FCOS, MVT::f32, Expand); + setOperationAction(ISD::FPOWI, MVT::f32, Expand); + setOperationAction(ISD::FPOW, MVT::f32, Expand); + setOperationAction(ISD::FLOG, MVT::f32, Expand); + setOperationAction(ISD::FLOG2, MVT::f32, Expand); + setOperationAction(ISD::FLOG10, MVT::f32, Expand); + setOperationAction(ISD::FEXP, MVT::f32, Expand); + + // Load extented operations for i1 types must be promoted + setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); + + // MBlaze has no REM or DIVREM operations. + setOperationAction(ISD::UREM, MVT::i32, Expand); + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::SDIVREM, MVT::i32, Expand); + setOperationAction(ISD::UDIVREM, MVT::i32, Expand); + + // If the processor doesn't support multiply then expand it + if (!Subtarget->hasMul()) { + setOperationAction(ISD::MUL, MVT::i32, Expand); + } + + // If the processor doesn't support 64-bit multiply then expand + if (!Subtarget->hasMul() || !Subtarget->hasMul64()) { + setOperationAction(ISD::MULHS, MVT::i32, Expand); + setOperationAction(ISD::MULHS, MVT::i64, Expand); + setOperationAction(ISD::MULHU, MVT::i32, Expand); + setOperationAction(ISD::MULHU, MVT::i64, Expand); + } + + // If the processor doesn't support division then expand + if (!Subtarget->hasDiv()) { + setOperationAction(ISD::UDIV, MVT::i32, Expand); + setOperationAction(ISD::SDIV, MVT::i32, Expand); + } + + // Expand unsupported conversions + setOperationAction(ISD::BIT_CONVERT, MVT::f32, Expand); + setOperationAction(ISD::BIT_CONVERT, MVT::i32, Expand); + + // Expand SELECT_CC + setOperationAction(ISD::SELECT_CC, MVT::Other, Expand); + + // MBlaze doesn't have MUL_LOHI + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand); + + // Used by legalize types to correctly generate the setcc result. + // Without this, every float setcc comes with a AND/OR with the result, + // we don't want this, since the fpcmp result goes to a flag register, + // which is used implicitly by brcond and select operations. + AddPromotedToType(ISD::SETCC, MVT::i1, MVT::i32); + AddPromotedToType(ISD::SELECT, MVT::i1, MVT::i32); + AddPromotedToType(ISD::SELECT_CC, MVT::i1, MVT::i32); + + // MBlaze Custom Operations + setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); + setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom); + setOperationAction(ISD::JumpTable, MVT::i32, Custom); + setOperationAction(ISD::ConstantPool, MVT::i32, Custom); + + // Operations not directly supported by MBlaze. + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::BR_CC, MVT::Other, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + setOperationAction(ISD::ROTL, MVT::i32, Expand); + setOperationAction(ISD::ROTR, 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::CTLZ, MVT::i32, Expand); + setOperationAction(ISD::CTTZ, MVT::i32, Expand); + setOperationAction(ISD::CTPOP, MVT::i32, Expand); + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + + // We don't have line number support yet. + setOperationAction(ISD::EH_LABEL, MVT::Other, Expand); + + // Use the default for now + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + setOperationAction(ISD::MEMBARRIER, MVT::Other, Expand); + + // MBlaze doesn't have extending float->double load/store + setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand); + setTruncStoreAction(MVT::f64, MVT::f32, Expand); + + setStackPointerRegisterToSaveRestore(MBlaze::R1); + computeRegisterProperties(); +} + +MVT::SimpleValueType MBlazeTargetLowering::getSetCCResultType(EVT VT) const { + return MVT::i32; +} + +/// getFunctionAlignment - Return the Log2 alignment of this function. +unsigned MBlazeTargetLowering::getFunctionAlignment(const Function *) const { + return 2; +} + +SDValue MBlazeTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { + switch (Op.getOpcode()) + { + case ISD::ConstantPool: return LowerConstantPool(Op, DAG); + case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); + case ISD::JumpTable: return LowerJumpTable(Op, DAG); + case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); + } + return SDValue(); +} + +//===----------------------------------------------------------------------===// +// Lower helper functions +//===----------------------------------------------------------------------===// +MachineBasicBlock* MBlazeTargetLowering:: +EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *BB, + DenseMap<MachineBasicBlock*, + MachineBasicBlock*> *EM) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + DebugLoc dl = MI->getDebugLoc(); + + switch (MI->getOpcode()) { + default: assert(false && "Unexpected instr type to insert"); + case MBlaze::ShiftRL: + case MBlaze::ShiftRA: + case MBlaze::ShiftL: { + // To "insert" a shift left instruction, we actually have to insert a + // simple loop. The incoming instruction knows the destination vreg to + // set, the source vreg to operate over and the shift amount. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = BB; + ++It; + + // start: + // andi samt, samt, 31 + // beqid samt, finish + // add dst, src, r0 + // loop: + // addik samt, samt, -1 + // sra dst, dst + // bneid samt, loop + // nop + // finish: + MachineFunction *F = BB->getParent(); + MachineRegisterInfo &R = F->getRegInfo(); + MachineBasicBlock *loop = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *finish = F->CreateMachineBasicBlock(LLVM_BB); + + unsigned IAMT = R.createVirtualRegister(MBlaze::CPURegsRegisterClass); + BuildMI(BB, dl, TII->get(MBlaze::ANDI), IAMT) + .addReg(MI->getOperand(2).getReg()) + .addImm(31); + + unsigned IVAL = R.createVirtualRegister(MBlaze::CPURegsRegisterClass); + BuildMI(BB, dl, TII->get(MBlaze::ADDI), IVAL) + .addReg(MI->getOperand(1).getReg()) + .addImm(0); + + BuildMI(BB, dl, TII->get(MBlaze::BEQID)) + .addReg(IAMT) + .addMBB(finish); + + F->insert(It, loop); + F->insert(It, finish); + + // Update machine-CFG edges by first adding all successors of the current + // block to the new block which will contain the Phi node for the select. + // Also inform sdisel of the edge changes. + for(MachineBasicBlock::succ_iterator i = BB->succ_begin(), + e = BB->succ_end(); i != e; ++i) { + EM->insert(std::make_pair(*i, finish)); + finish->addSuccessor(*i); + } + + // Next, remove all successors of the current block, and add the true + // and fallthrough blocks as its successors. + while(!BB->succ_empty()) + BB->removeSuccessor(BB->succ_begin()); + BB->addSuccessor(loop); + BB->addSuccessor(finish); + + // Next, add the finish block as a successor of the loop block + loop->addSuccessor(finish); + loop->addSuccessor(loop); + + unsigned DST = R.createVirtualRegister(MBlaze::CPURegsRegisterClass); + unsigned NDST = R.createVirtualRegister(MBlaze::CPURegsRegisterClass); + BuildMI(loop, dl, TII->get(MBlaze::PHI), DST) + .addReg(IVAL).addMBB(BB) + .addReg(NDST).addMBB(loop); + + unsigned SAMT = R.createVirtualRegister(MBlaze::CPURegsRegisterClass); + unsigned NAMT = R.createVirtualRegister(MBlaze::CPURegsRegisterClass); + BuildMI(loop, dl, TII->get(MBlaze::PHI), SAMT) + .addReg(IAMT).addMBB(BB) + .addReg(NAMT).addMBB(loop); + + if (MI->getOpcode() == MBlaze::ShiftL) + BuildMI(loop, dl, TII->get(MBlaze::ADD), NDST).addReg(DST).addReg(DST); + else if (MI->getOpcode() == MBlaze::ShiftRA) + BuildMI(loop, dl, TII->get(MBlaze::SRA), NDST).addReg(DST); + else if (MI->getOpcode() == MBlaze::ShiftRL) + BuildMI(loop, dl, TII->get(MBlaze::SRL), NDST).addReg(DST); + else + llvm_unreachable( "Cannot lower unknown shift instruction" ); + + BuildMI(loop, dl, TII->get(MBlaze::ADDI), NAMT) + .addReg(SAMT) + .addImm(-1); + + BuildMI(loop, dl, TII->get(MBlaze::BNEID)) + .addReg(NAMT) + .addMBB(loop); + + BuildMI(finish, dl, TII->get(MBlaze::PHI), MI->getOperand(0).getReg()) + .addReg(IVAL).addMBB(BB) + .addReg(NDST).addMBB(loop); + + // The pseudo instruction is no longer needed so remove it + F->DeleteMachineInstr(MI); + return finish; + } + + case MBlaze::Select_FCC: + case MBlaze::Select_CC: { + // To "insert" a SELECT_CC instruction, we actually have to insert the + // diamond control-flow pattern. The incoming instruction knows the + // destination vreg to set, the condition code register to branch on, the + // true/false values to select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = BB; + ++It; + + // thisMBB: + // ... + // TrueVal = ... + // setcc r1, r2, r3 + // bNE r1, r0, copy1MBB + // fallthrough --> copy0MBB + MachineFunction *F = BB->getParent(); + MachineBasicBlock *flsBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *dneBB = F->CreateMachineBasicBlock(LLVM_BB); + + unsigned Opc; + switch (MI->getOperand(4).getImm()) { + default: llvm_unreachable( "Unknown branch condition" ); + case MBlazeCC::EQ: Opc = MBlaze::BNEID; break; + case MBlazeCC::NE: Opc = MBlaze::BEQID; break; + case MBlazeCC::GT: Opc = MBlaze::BLEID; break; + case MBlazeCC::LT: Opc = MBlaze::BGEID; break; + case MBlazeCC::GE: Opc = MBlaze::BLTID; break; + case MBlazeCC::LE: Opc = MBlaze::BGTID; break; + } + + BuildMI(BB, dl, TII->get(Opc)) + .addReg(MI->getOperand(3).getReg()) + .addMBB(dneBB); + + F->insert(It, flsBB); + F->insert(It, dneBB); + + // Update machine-CFG edges by first adding all successors of the current + // block to the new block which will contain the Phi node for the select. + // Also inform sdisel of the edge changes. + for(MachineBasicBlock::succ_iterator i = BB->succ_begin(), + e = BB->succ_end(); i != e; ++i) { + EM->insert(std::make_pair(*i, dneBB)); + dneBB->addSuccessor(*i); + } + + // Next, remove all successors of the current block, and add the true + // and fallthrough blocks as its successors. + while(!BB->succ_empty()) + BB->removeSuccessor(BB->succ_begin()); + BB->addSuccessor(flsBB); + BB->addSuccessor(dneBB); + flsBB->addSuccessor(dneBB); + + // sinkMBB: + // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] + // ... + //BuildMI(dneBB, dl, TII->get(MBlaze::PHI), MI->getOperand(0).getReg()) + // .addReg(MI->getOperand(1).getReg()).addMBB(flsBB) + // .addReg(MI->getOperand(2).getReg()).addMBB(BB); + + BuildMI(dneBB, dl, TII->get(MBlaze::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(flsBB) + .addReg(MI->getOperand(1).getReg()).addMBB(BB); + + F->DeleteMachineInstr(MI); // The pseudo instruction is gone now. + return dneBB; + } + } +} + +//===----------------------------------------------------------------------===// +// Misc Lower Operation implementation +//===----------------------------------------------------------------------===// +// + +SDValue MBlazeTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) { + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + SDValue TrueVal = Op.getOperand(2); + SDValue FalseVal = Op.getOperand(3); + DebugLoc dl = Op.getDebugLoc(); + unsigned Opc; + + SDValue CompareFlag; + if (LHS.getValueType() == MVT::i32) { + Opc = MBlazeISD::Select_CC; + CompareFlag = DAG.getNode(MBlazeISD::ICmp, dl, MVT::i32, LHS, RHS) + .getValue(1); + } else { + llvm_unreachable( "Cannot lower select_cc with unknown type" ); + } + + return DAG.getNode(Opc, dl, TrueVal.getValueType(), TrueVal, FalseVal, + CompareFlag); +} + +SDValue MBlazeTargetLowering:: +LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) { + // FIXME there isn't actually debug info here + DebugLoc dl = Op.getDebugLoc(); + GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); + SDValue GA = DAG.getTargetGlobalAddress(GV, MVT::i32); + + return DAG.getNode(MBlazeISD::Wrap, dl, MVT::i32, GA); +} + +SDValue MBlazeTargetLowering:: +LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) { + llvm_unreachable("TLS not implemented for MicroBlaze."); + return SDValue(); // Not reached +} + +SDValue MBlazeTargetLowering:: +LowerJumpTable(SDValue Op, SelectionDAG &DAG) { + SDValue ResNode; + SDValue HiPart; + // FIXME there isn't actually debug info here + DebugLoc dl = Op.getDebugLoc(); + bool IsPIC = getTargetMachine().getRelocationModel() == Reloc::PIC_; + unsigned char OpFlag = IsPIC ? MBlazeII::MO_GOT : MBlazeII::MO_ABS_HILO; + + EVT PtrVT = Op.getValueType(); + JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); + + SDValue JTI = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, OpFlag); + return DAG.getNode(MBlazeISD::Wrap, dl, MVT::i32, JTI); + //return JTI; +} + +SDValue MBlazeTargetLowering:: +LowerConstantPool(SDValue Op, SelectionDAG &DAG) { + SDValue ResNode; + EVT PtrVT = Op.getValueType(); + ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); + Constant *C = N->getConstVal(); + SDValue Zero = DAG.getConstant(0, PtrVT); + // FIXME there isn't actually debug info here + DebugLoc dl = Op.getDebugLoc(); + + SDValue CP = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), + N->getOffset(), MBlazeII::MO_ABS_HILO); + return DAG.getNode(MBlazeISD::Wrap, dl, MVT::i32, CP); +} + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// + +#include "MBlazeGenCallingConv.inc" + +//===----------------------------------------------------------------------===// +// Call Calling Convention Implementation +//===----------------------------------------------------------------------===// + +/// LowerCall - functions arguments are copied from virtual regs to +/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. +/// TODO: isVarArg, isTailCall. +SDValue MBlazeTargetLowering:: +LowerCall(SDValue Chain, SDValue Callee, CallingConv::ID CallConv, + bool isVarArg, bool &isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + bool IsPIC = getTargetMachine().getRelocationModel() == Reloc::PIC_; + + // Analyze operands of the call, assigning locations to each operand. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), ArgLocs, + *DAG.getContext()); + CCInfo.AnalyzeCallOperands(Outs, CC_MBlaze); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NumBytes = CCInfo.getNextStackOffset(); + Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(NumBytes, true)); + + SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass; + SmallVector<SDValue, 8> MemOpChains; + + // First/LastArgStackLoc contains the first/last + // "at stack" argument location. + int LastArgStackLoc = 0; + unsigned FirstStackArgLoc = 4; + + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + EVT RegVT = VA.getLocVT(); + SDValue Arg = Outs[i].Val; + + // 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, RegVT, Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, RegVT, Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, dl, RegVT, Arg); + break; + case CCValAssign::BCvt: + Arg = DAG.getNode(ISD::BIT_CONVERT, dl, RegVT, 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 { + // Register can't get to this point... + assert(VA.isMemLoc()); + + // Create the frame index object for this incoming parameter + LastArgStackLoc = (FirstStackArgLoc + VA.getLocMemOffset()); + int FI = MFI->CreateFixedObject(VA.getValVT().getSizeInBits()/8, + LastArgStackLoc, true, false); + + SDValue PtrOff = DAG.getFrameIndex(FI,getPointerTy()); + + // emit ISD::STORE whichs stores the + // parameter value to a stack Location + MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, NULL, 0, + false, false, 0)); + } + } + + // 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/ExternalSymbol node (quite common, every + // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol + // node so that legalize doesn't hack it. + unsigned char OpFlag = IsPIC ? MBlazeII::MO_GOT_CALL : MBlazeII::MO_NO_FLAG; + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), + getPointerTy(), 0, OpFlag); + else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) + Callee = DAG.getTargetExternalSymbol(S->getSymbol(), + getPointerTy(), OpFlag); + + // MBlazeJmpLink = #chain, #target_address, #opt_in_flags... + // = Chain, Callee, Reg#1, Reg#2, ... + // + // Returns a chain & a flag for retval copy to use. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Flag); + SmallVector<SDValue, 8> Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + // Add argument registers to the end of the list so that they are + // known live into the call. + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Ops.push_back(DAG.getRegister(RegsToPass[i].first, + RegsToPass[i].second.getValueType())); + } + + if (InFlag.getNode()) + Ops.push_back(InFlag); + + Chain = DAG.getNode(MBlazeISD::JmpLink, dl, NodeTys, &Ops[0], Ops.size()); + InFlag = Chain.getValue(1); + + // Create the CALLSEQ_END node. + Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, true), + DAG.getIntPtrConstant(0, true), InFlag); + if (!Ins.empty()) + InFlag = Chain.getValue(1); + + // Handle result values, copying them out of physregs into vregs that we + // return. + return LowerCallResult(Chain, InFlag, CallConv, isVarArg, + Ins, dl, DAG, InVals); +} + +/// LowerCallResult - Lower the result values of a call into the +/// appropriate copies out of appropriate physical registers. +SDValue MBlazeTargetLowering:: +LowerCallResult(SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, + bool isVarArg, const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) { + // Assign locations to each value returned by this call. + SmallVector<CCValAssign, 16> RVLocs; + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), + RVLocs, *DAG.getContext()); + + CCInfo.AnalyzeCallResult(Ins, RetCC_MBlaze); + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + Chain = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(), + RVLocs[i].getValVT(), InFlag).getValue(1); + InFlag = Chain.getValue(2); + InVals.push_back(Chain.getValue(0)); + } + + return Chain; +} + +//===----------------------------------------------------------------------===// +// Formal Arguments Calling Convention Implementation +//===----------------------------------------------------------------------===// + +/// LowerFormalArguments - transform physical registers into +/// virtual registers and generate load operations for +/// arguments places on the stack. +/// TODO: isVarArg +SDValue MBlazeTargetLowering:: +LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + + unsigned StackReg = MF.getTarget().getRegisterInfo()->getFrameRegister(MF); + + // Assign locations to all of the incoming arguments. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), + ArgLocs, *DAG.getContext()); + + CCInfo.AnalyzeFormalArguments(Ins, CC_MBlaze); + SDValue StackPtr; + + unsigned FirstStackArgLoc = 4; + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + + // Arguments stored on registers + if (VA.isRegLoc()) { + EVT RegVT = VA.getLocVT(); + TargetRegisterClass *RC = 0; + + if (RegVT == MVT::i32) + RC = MBlaze::CPURegsRegisterClass; + else if (RegVT == MVT::f32) + RC = MBlaze::FGR32RegisterClass; + else + llvm_unreachable("RegVT not supported by LowerFormalArguments"); + + // Transform the arguments stored on + // physical registers into virtual ones + unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC); + SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT); + + // If this is an 8 or 16-bit value, it has been passed promoted + // to 32 bits. Insert an assert[sz]ext to capture this, then + // truncate to the right size. + if (VA.getLocInfo() != CCValAssign::Full) { + unsigned Opcode = 0; + if (VA.getLocInfo() == CCValAssign::SExt) + Opcode = ISD::AssertSext; + else if (VA.getLocInfo() == CCValAssign::ZExt) + Opcode = ISD::AssertZext; + if (Opcode) + ArgValue = DAG.getNode(Opcode, dl, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); + } + + InVals.push_back(ArgValue); + + // To meet ABI, when VARARGS are passed on registers, the registers + // must have their values written to the caller stack frame. + if (isVarArg) { + if (StackPtr.getNode() == 0) + StackPtr = DAG.getRegister(StackReg, getPointerTy()); + + // The stack pointer offset is relative to the caller stack frame. + // Since the real stack size is unknown here, a negative SPOffset + // is used so there's a way to adjust these offsets when the stack + // size get known (on EliminateFrameIndex). A dummy SPOffset is + // used instead of a direct negative address (which is recorded to + // be used on emitPrologue) to avoid mis-calc of the first stack + // offset on PEI::calculateFrameObjectOffsets. + // Arguments are always 32-bit. + int FI = MFI->CreateFixedObject(4, 0, true, false); + MBlazeFI->recordStoreVarArgsFI(FI, -(FirstStackArgLoc+(i*4))); + SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy()); + + // emit ISD::STORE whichs stores the + // parameter value to a stack Location + InVals.push_back(DAG.getStore(Chain, dl, ArgValue, PtrOff, NULL, 0, + false, false, 0)); + } + + } else { // VA.isRegLoc() + + // sanity check + assert(VA.isMemLoc()); + + // The stack pointer offset is relative to the caller stack frame. + // Since the real stack size is unknown here, a negative SPOffset + // is used so there's a way to adjust these offsets when the stack + // size get known (on EliminateFrameIndex). A dummy SPOffset is + // used instead of a direct negative address (which is recorded to + // be used on emitPrologue) to avoid mis-calc of the first stack + // offset on PEI::calculateFrameObjectOffsets. + // Arguments are always 32-bit. + unsigned ArgSize = VA.getLocVT().getSizeInBits()/8; + int FI = MFI->CreateFixedObject(ArgSize, 0, true, false); + MBlazeFI->recordLoadArgsFI(FI, -(ArgSize+ + (FirstStackArgLoc + VA.getLocMemOffset()))); + + // Create load nodes to retrieve arguments from the stack + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); + InVals.push_back(DAG.getLoad(VA.getValVT(), dl, Chain, FIN, NULL, 0, + false, false, 0)); + } + } + + return Chain; +} + +//===----------------------------------------------------------------------===// +// Return Value Calling Convention Implementation +//===----------------------------------------------------------------------===// + +SDValue MBlazeTargetLowering:: +LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + DebugLoc dl, SelectionDAG &DAG) { + // CCValAssign - represent the assignment of + // the return value to a location + SmallVector<CCValAssign, 16> RVLocs; + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), + RVLocs, *DAG.getContext()); + + // Analize return values. + CCInfo.AnalyzeReturn(Outs, RetCC_MBlaze); + + // 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) + if (RVLocs[i].isRegLoc()) + DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg()); + } + + 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!"); + + Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), + Outs[i].Val, Flag); + + // guarantee that all emitted copies are + // stuck together, avoiding something bad + Flag = Chain.getValue(1); + } + + // Return on MBlaze is always a "rtsd R15, 8" + if (Flag.getNode()) + return DAG.getNode(MBlazeISD::Ret, dl, MVT::Other, + Chain, DAG.getRegister(MBlaze::R15, MVT::i32), Flag); + else // Return Void + return DAG.getNode(MBlazeISD::Ret, dl, MVT::Other, + Chain, DAG.getRegister(MBlaze::R15, MVT::i32)); +} + +//===----------------------------------------------------------------------===// +// MBlaze Inline Assembly Support +//===----------------------------------------------------------------------===// + +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +MBlazeTargetLowering::ConstraintType MBlazeTargetLowering:: +getConstraintType(const std::string &Constraint) const +{ + // MBlaze specific constrainy + // + // 'd' : An address register. Equivalent to r. + // 'y' : Equivalent to r; retained for + // backwards compatibility. + // 'f' : Floating Point registers. + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default : break; + case 'd': + case 'y': + case 'f': + return C_RegisterClass; + break; + } + } + return TargetLowering::getConstraintType(Constraint); +} + +/// getRegClassForInlineAsmConstraint - Given a constraint letter (e.g. "r"), +/// return a list of registers that can be used to satisfy the constraint. +/// This should only be used for C_RegisterClass constraints. +std::pair<unsigned, const TargetRegisterClass*> MBlazeTargetLowering:: +getRegForInlineAsmConstraint(const std::string &Constraint, EVT VT) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + case 'r': + return std::make_pair(0U, MBlaze::CPURegsRegisterClass); + case 'f': + if (VT == MVT::f32) + return std::make_pair(0U, MBlaze::FGR32RegisterClass); + } + } + return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); +} + +/// Given a register class constraint, like 'r', if this corresponds directly +/// to an LLVM register class, return a register of 0 and the register class +/// pointer. +std::vector<unsigned> MBlazeTargetLowering:: +getRegClassForInlineAsmConstraint(const std::string &Constraint, EVT VT) const { + if (Constraint.size() != 1) + return std::vector<unsigned>(); + + switch (Constraint[0]) { + default : break; + case 'r': + // GCC MBlaze Constraint Letters + case 'd': + case 'y': + return make_vector<unsigned>( + MBlaze::R3, MBlaze::R4, MBlaze::R5, MBlaze::R6, + MBlaze::R7, MBlaze::R9, MBlaze::R10, MBlaze::R11, + MBlaze::R12, MBlaze::R19, MBlaze::R20, MBlaze::R21, + MBlaze::R22, MBlaze::R23, MBlaze::R24, MBlaze::R25, + MBlaze::R26, MBlaze::R27, MBlaze::R28, MBlaze::R29, + MBlaze::R30, MBlaze::R31, 0); + + case 'f': + return make_vector<unsigned>( + MBlaze::F3, MBlaze::F4, MBlaze::F5, MBlaze::F6, + MBlaze::F7, MBlaze::F9, MBlaze::F10, MBlaze::F11, + MBlaze::F12, MBlaze::F19, MBlaze::F20, MBlaze::F21, + MBlaze::F22, MBlaze::F23, MBlaze::F24, MBlaze::F25, + MBlaze::F26, MBlaze::F27, MBlaze::F28, MBlaze::F29, + MBlaze::F30, MBlaze::F31, 0); + } + return std::vector<unsigned>(); +} + +bool MBlazeTargetLowering:: +isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + // The MBlaze target isn't yet aware of offsets. + return false; +} + +bool MBlazeTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { + return VT != MVT::f32; +} diff --git a/lib/Target/MBlaze/MBlazeISelLowering.h b/lib/Target/MBlaze/MBlazeISelLowering.h new file mode 100644 index 0000000000..75d2552e73 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeISelLowering.h @@ -0,0 +1,146 @@ +//===-- MBlazeISelLowering.h - MBlaze 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 MBlaze uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef MBlazeISELLOWERING_H +#define MBlazeISELLOWERING_H + +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetLowering.h" +#include "MBlaze.h" +#include "MBlazeSubtarget.h" + +namespace llvm { + namespace MBlazeCC { + enum CC { + FIRST = 0, + EQ, + NE, + GT, + LT, + GE, + LE + }; + } + + namespace MBlazeISD { + enum NodeType { + // Start the numbering from where ISD NodeType finishes. + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + // Jump and link (call) + JmpLink, + + // Handle gp_rel (small data/bss sections) relocation. + GPRel, + + // Select CC Pseudo Instruction + Select_CC, + + // Wrap up multiple types of instructions + Wrap, + + // Integer Compare + ICmp, + + // Return + Ret + }; + } + + //===--------------------------------------------------------------------===// + // TargetLowering Implementation + //===--------------------------------------------------------------------===// + + class MBlazeTargetLowering : public TargetLowering { + public: + + explicit MBlazeTargetLowering(MBlazeTargetMachine &TM); + + /// LowerOperation - Provide custom lowering hooks for some operations. + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG); + + /// getTargetNodeName - This method returns the name of a target specific + // DAG node. + virtual const char *getTargetNodeName(unsigned Opcode) const; + + /// getSetCCResultType - get the ISD::SETCC result ValueType + MVT::SimpleValueType getSetCCResultType(EVT VT) const; + + virtual unsigned getFunctionAlignment(const Function *F) const; + private: + // Subtarget Info + const MBlazeSubtarget *Subtarget; + + + // Lower Operand helpers + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals); + + // Lower Operand specifics + SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG); + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG); + SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG); + SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG); + SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG); + + virtual SDValue + LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals); + + virtual SDValue + LowerCall(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, + bool &isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals); + + virtual SDValue + LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + DebugLoc dl, SelectionDAG &DAG); + + virtual MachineBasicBlock *EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB, + DenseMap<MachineBasicBlock*, MachineBasicBlock*> *EM) const; + + // Inline asm support + ConstraintType getConstraintType(const std::string &Constraint) const; + + std::pair<unsigned, const TargetRegisterClass*> + getRegForInlineAsmConstraint(const std::string &Constraint, + EVT VT) const; + + std::vector<unsigned> + getRegClassForInlineAsmConstraint(const std::string &Constraint, + EVT VT) const; + + virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; + + /// isFPImmLegal - Returns true if the target can instruction select the + /// specified FP immediate natively. If false, the legalizer will + /// materialize the FP immediate as a load from a constant pool. + virtual bool isFPImmLegal(const APFloat &Imm, EVT VT) const; + }; +} + +#endif // MBlazeISELLOWERING_H diff --git a/lib/Target/MBlaze/MBlazeInstrFPU.td b/lib/Target/MBlaze/MBlazeInstrFPU.td new file mode 100644 index 0000000000..a48a8c9723 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeInstrFPU.td @@ -0,0 +1,223 @@ +//===- MBlazeInstrFPU.td - MBlaze FPU Instruction defs ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MBlaze profiles and nodes +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MBlaze Operand, Complex Patterns and Transformations Definitions. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Memory Access Instructions +//===----------------------------------------------------------------------===// +class LoadFM<bits<6> op, string instr_asm, PatFrag OpNode> : + TA<op, 0x000, (outs FGR32:$dst), (ins memrr:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(set FGR32:$dst, (OpNode xaddr:$addr))], IILoad>; + +class LoadFMI<bits<6> op, string instr_asm, PatFrag OpNode> : + TAI<op, (outs FGR32:$dst), (ins memri:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(set FGR32:$dst, (OpNode iaddr:$addr))], IILoad>; + +class StoreFM<bits<6> op, string instr_asm, PatFrag OpNode> : + TA<op, 0x000, (outs), (ins FGR32:$dst, memrr:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(OpNode FGR32:$dst, xaddr:$addr)], IIStore>; + +class StoreFMI<bits<6> op, string instr_asm, PatFrag OpNode> : + TAI<op, (outs), (ins FGR32:$dst, memrr:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(OpNode FGR32:$dst, iaddr:$addr)], IIStore>; + +class ArithF<bits<6> op, bits<11> flags, string instr_asm, SDNode OpNode, + InstrItinClass itin> : + TA<op, flags, (outs FGR32:$dst), (ins FGR32:$b, FGR32:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set FGR32:$dst, (OpNode FGR32:$b, FGR32:$c))], itin>; + +class CmpFN<bits<6> op, bits<11> flags, string instr_asm, + InstrItinClass itin> : + TA<op, flags, (outs CPURegs:$dst), (ins FGR32:$b, FGR32:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [], itin>; + +class ArithFR<bits<6> op, bits<11> flags, string instr_asm, SDNode OpNode, + InstrItinClass itin> : + TA<op, flags, (outs FGR32:$dst), (ins FGR32:$b, FGR32:$c), + !strconcat(instr_asm, " $dst, $c, $b"), + [(set FGR32:$dst, (OpNode FGR32:$b, FGR32:$c))], itin>; + +class ArithF2<bits<6> op, bits<11> flags, string instr_asm, + InstrItinClass itin> : + TF<op, flags, (outs FGR32:$dst), (ins FGR32:$b), + !strconcat(instr_asm, " $dst, $b"), + [], itin>; + +class ArithIF<bits<6> op, bits<11> flags, string instr_asm, + InstrItinClass itin> : + TF<op, flags, (outs FGR32:$dst), (ins CPURegs:$b), + !strconcat(instr_asm, " $dst, $b"), + [], itin>; + +class ArithFI<bits<6> op, bits<11> flags, string instr_asm, + InstrItinClass itin> : + TF<op, flags, (outs CPURegs:$dst), (ins FGR32:$b), + !strconcat(instr_asm, " $dst, $b"), + [], itin>; + +class LogicF<bits<6> op, string instr_asm> : + TAI<op, (outs FGR32:$dst), (ins FGR32:$b, FGR32:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [], + IIAlu>; + +class LogicFI<bits<6> op, string instr_asm> : + TAI<op, (outs FGR32:$dst), (ins FGR32:$b, fimm:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [], + IIAlu>; + +//===----------------------------------------------------------------------===// +// Pseudo instructions +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// FPU Arithmetic Instructions +//===----------------------------------------------------------------------===// +let Predicates=[HasFPU] in { + def FOR : LogicF<0x28, "or ">; + def FORI : LogicFI<0x28, "ori ">; + def FADD : ArithF<0x16, 0x000, "fadd ", fadd, IIAlu>; + def FRSUB : ArithFR<0x16, 0x080, "frsub ", fsub, IIAlu>; + def FMUL : ArithF<0x16, 0x100, "fmul ", fmul, IIAlu>; + def FDIV : ArithF<0x16, 0x180, "fdiv ", fdiv, IIAlu>; + + def LWF : LoadFM<0x32, "lw ", load>; + def LWFI : LoadFMI<0x32, "lwi ", load>; + + def SWF : StoreFM<0x32, "sw ", store>; + def SWFI : StoreFMI<0x32, "swi ", store>; +} + +let Predicates=[HasFPU,HasSqrt] in { + def FLT : ArithIF<0x16, 0x280, "flt ", IIAlu>; + def FINT : ArithFI<0x16, 0x300, "fint ", IIAlu>; + def FSQRT : ArithF2<0x16, 0x300, "fsqrt ", IIAlu>; +} + +let isAsCheapAsAMove = 1 in { + def FCMP_UN : CmpFN<0x16, 0x200, "fcmp.un", IIAlu>; + def FCMP_LT : CmpFN<0x16, 0x210, "fcmp.lt", IIAlu>; + def FCMP_EQ : CmpFN<0x16, 0x220, "fcmp.eq", IIAlu>; + def FCMP_LE : CmpFN<0x16, 0x230, "fcmp.le", IIAlu>; + def FCMP_GT : CmpFN<0x16, 0x240, "fcmp.gt", IIAlu>; + def FCMP_NE : CmpFN<0x16, 0x250, "fcmp.ne", IIAlu>; + def FCMP_GE : CmpFN<0x16, 0x260, "fcmp.ge", IIAlu>; +} + + +let usesCustomInserter = 1 in { + def Select_FCC : MBlazePseudo<(outs FGR32:$dst), + (ins FGR32:$T, FGR32:$F, CPURegs:$CMP, i32imm:$CC), + "; SELECT_FCC PSEUDO!", + []>; +} + +// Floating point conversions +let Predicates=[HasFPU] in { + def : Pat<(sint_to_fp CPURegs:$V), (FLT CPURegs:$V)>; + def : Pat<(fp_to_sint FGR32:$V), (FINT FGR32:$V)>; + def : Pat<(fsqrt FGR32:$V), (FSQRT FGR32:$V)>; +} + +// SET_CC operations +let Predicates=[HasFPU] in { + def : Pat<(setcc FGR32:$L, FGR32:$R, SETEQ), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_EQ FGR32:$L, FGR32:$R), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETNE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_EQ FGR32:$L, FGR32:$R), 1)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETOEQ), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_EQ FGR32:$L, FGR32:$R), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETONE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (XOR (FCMP_UN FGR32:$L, FGR32:$R), + (FCMP_EQ FGR32:$L, FGR32:$R)), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETONE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (OR (FCMP_UN FGR32:$L, FGR32:$R), + (FCMP_EQ FGR32:$L, FGR32:$R)), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETGT), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_GT FGR32:$L, FGR32:$R), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETLT), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_LT FGR32:$L, FGR32:$R), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETGE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_GE FGR32:$L, FGR32:$R), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETLE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_LE FGR32:$L, FGR32:$R), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETOGT), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_GT FGR32:$L, FGR32:$R), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETOLT), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_LT FGR32:$L, FGR32:$R), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETOGE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_GE FGR32:$L, FGR32:$R), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETOLE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_LE FGR32:$L, FGR32:$R), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETUEQ), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (OR (FCMP_UN FGR32:$L, FGR32:$R), + (FCMP_EQ FGR32:$L, FGR32:$R)), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETUNE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_NE FGR32:$L, FGR32:$R), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETUGT), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (OR (FCMP_UN FGR32:$L, FGR32:$R), + (FCMP_GT FGR32:$L, FGR32:$R)), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETULT), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (OR (FCMP_UN FGR32:$L, FGR32:$R), + (FCMP_LT FGR32:$L, FGR32:$R)), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETUGE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (OR (FCMP_UN FGR32:$L, FGR32:$R), + (FCMP_GE FGR32:$L, FGR32:$R)), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETULE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (OR (FCMP_UN FGR32:$L, FGR32:$R), + (FCMP_LE FGR32:$L, FGR32:$R)), 2)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETO), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_UN FGR32:$L, FGR32:$R), 1)>; + def : Pat<(setcc FGR32:$L, FGR32:$R, SETUO), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (FCMP_UN FGR32:$L, FGR32:$R), 2)>; +} + +// SELECT operations +def : Pat<(select CPURegs:$C, FGR32:$T, FGR32:$F), + (Select_FCC FGR32:$T, FGR32:$F, CPURegs:$C, 2)>; + +//===----------------------------------------------------------------------===// +// Patterns for Floating Point Instructions +//===----------------------------------------------------------------------===// +def : Pat<(f32 fpimm:$imm), (FORI F0, fpimm:$imm)>; diff --git a/lib/Target/MBlaze/MBlazeInstrFSL.td b/lib/Target/MBlaze/MBlazeInstrFSL.td new file mode 100644 index 0000000000..b59999e76a --- /dev/null +++ b/lib/Target/MBlaze/MBlazeInstrFSL.td @@ -0,0 +1,153 @@ +//===- MBlazeInstrFSL.td - MBlaze FSL Instruction defs ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// FSL Instruction Formats +//===----------------------------------------------------------------------===// +class FSLGetD<bits<6> op, bits<11> flags, string instr_asm, Intrinsic OpNode> : + TA<op, flags, (outs CPURegs:$dst), (ins CPURegs:$b), + !strconcat(instr_asm, " $dst, $b"), + [(set CPURegs:$dst, (OpNode CPURegs:$b))], IIAlu>; + +class FSLGet<bits<6> op, string instr_asm, Intrinsic OpNode> : + TAI<op, (outs CPURegs:$dst), (ins fslimm:$b), + !strconcat(instr_asm, " $dst, $b"), + [(set CPURegs:$dst, (OpNode immZExt4:$b))], IIAlu>; + +class FSLPutD<bits<6> op, bits<11> flags, string instr_asm, Intrinsic OpNode> : + TA<op, flags, (outs), (ins CPURegs:$v, CPURegs:$b), + !strconcat(instr_asm, " $v, $b"), + [(OpNode CPURegs:$v, CPURegs:$b)], IIAlu>; + +class FSLPut<bits<6> op, string instr_asm, Intrinsic OpNode> : + TAI<op, (outs), (ins CPURegs:$v, fslimm:$b), + !strconcat(instr_asm, " $v, $b"), + [(OpNode CPURegs:$v, immZExt4:$b)], IIAlu>; + +class FSLPutTD<bits<6> op, bits<11> flags, string instr_asm, Intrinsic OpNode> : + TA<op, flags, (outs), (ins CPURegs:$b), + !strconcat(instr_asm, " $b"), + [(OpNode CPURegs:$b)], IIAlu>; + +class FSLPutT<bits<6> op, string instr_asm, Intrinsic OpNode> : + TAI<op, (outs), (ins fslimm:$b), + !strconcat(instr_asm, " $b"), + [(OpNode immZExt4:$b)], IIAlu>; + +//===----------------------------------------------------------------------===// +// FSL Get Instructions +//===----------------------------------------------------------------------===// +def GET : FSLGet<0x1B, "get ", int_mblaze_fsl_get>; +def AGET : FSLGet<0x1B, "aget ", int_mblaze_fsl_aget>; +def CGET : FSLGet<0x1B, "cget ", int_mblaze_fsl_cget>; +def CAGET : FSLGet<0x1B, "caget ", int_mblaze_fsl_caget>; +def EGET : FSLGet<0x1B, "eget ", int_mblaze_fsl_eget>; +def EAGET : FSLGet<0x1B, "eaget ", int_mblaze_fsl_eaget>; +def ECGET : FSLGet<0x1B, "ecget ", int_mblaze_fsl_ecget>; +def ECAGET : FSLGet<0x1B, "ecaget ", int_mblaze_fsl_ecaget>; +def NGET : FSLGet<0x1B, "nget ", int_mblaze_fsl_nget>; +def NAGET : FSLGet<0x1B, "naget ", int_mblaze_fsl_naget>; +def NCGET : FSLGet<0x1B, "ncget ", int_mblaze_fsl_ncget>; +def NCAGET : FSLGet<0x1B, "ncaget ", int_mblaze_fsl_ncaget>; +def NEGET : FSLGet<0x1B, "neget ", int_mblaze_fsl_neget>; +def NEAGET : FSLGet<0x1B, "neaget ", int_mblaze_fsl_neaget>; +def NECGET : FSLGet<0x1B, "necget ", int_mblaze_fsl_necget>; +def NECAGET : FSLGet<0x1B, "necaget ", int_mblaze_fsl_necaget>; +def TGET : FSLGet<0x1B, "tget ", int_mblaze_fsl_tget>; +def TAGET : FSLGet<0x1B, "taget ", int_mblaze_fsl_taget>; +def TCGET : FSLGet<0x1B, "tcget ", int_mblaze_fsl_tcget>; +def TCAGET : FSLGet<0x1B, "tcaget ", int_mblaze_fsl_tcaget>; +def TEGET : FSLGet<0x1B, "teget ", int_mblaze_fsl_teget>; +def TEAGET : FSLGet<0x1B, "teaget ", int_mblaze_fsl_teaget>; +def TECGET : FSLGet<0x1B, "tecget ", int_mblaze_fsl_tecget>; +def TECAGET : FSLGet<0x1B, "tecaget ", int_mblaze_fsl_tecaget>; +def TNGET : FSLGet<0x1B, "tnget ", int_mblaze_fsl_tnget>; +def TNAGET : FSLGet<0x1B, "tnaget ", int_mblaze_fsl_tnaget>; +def TNCGET : FSLGet<0x1B, "tncget ", int_mblaze_fsl_tncget>; +def TNCAGET : FSLGet<0x1B, "tncaget ", int_mblaze_fsl_tncaget>; +def TNEGET : FSLGet<0x1B, "tneget ", int_mblaze_fsl_tneget>; +def TNEAGET : FSLGet<0x1B, "tneaget ", int_mblaze_fsl_tneaget>; +def TNECGET : FSLGet<0x1B, "tnecget ", int_mblaze_fsl_tnecget>; +def TNECAGET : FSLGet<0x1B, "tnecaget ", int_mblaze_fsl_tnecaget>; + +//===----------------------------------------------------------------------===// +// FSL Dynamic Get Instructions +//===----------------------------------------------------------------------===// +def GETD : FSLGetD<0x1B, 0x00, "getd ", int_mblaze_fsl_get>; +def AGETD : FSLGetD<0x1B, 0x00, "agetd ", int_mblaze_fsl_aget>; +def CGETD : FSLGetD<0x1B, 0x00, "cgetd ", int_mblaze_fsl_cget>; +def CAGETD : FSLGetD<0x1B, 0x00, "cagetd ", int_mblaze_fsl_caget>; +def EGETD : FSLGetD<0x1B, 0x00, "egetd ", int_mblaze_fsl_eget>; +def EAGETD : FSLGetD<0x1B, 0x00, "eagetd ", int_mblaze_fsl_eaget>; +def ECGETD : FSLGetD<0x1B, 0x00, "ecgetd ", int_mblaze_fsl_ecget>; +def ECAGETD : FSLGetD<0x1B, 0x00, "ecagetd ", int_mblaze_fsl_ecaget>; +def NGETD : FSLGetD<0x1B, 0x00, "ngetd ", int_mblaze_fsl_nget>; +def NAGETD : FSLGetD<0x1B, 0x00, "nagetd ", int_mblaze_fsl_naget>; +def NCGETD : FSLGetD<0x1B, 0x00, "ncgetd ", int_mblaze_fsl_ncget>; +def NCAGETD : FSLGetD<0x1B, 0x00, "ncagetd ", int_mblaze_fsl_ncaget>; +def NEGETD : FSLGetD<0x1B, 0x00, "negetd ", int_mblaze_fsl_neget>; +def NEAGETD : FSLGetD<0x1B, 0x00, "neagetd ", int_mblaze_fsl_neaget>; +def NECGETD : FSLGetD<0x1B, 0x00, "necgetd ", int_mblaze_fsl_necget>; +def NECAGETD : FSLGetD<0x1B, 0x00, "necagetd ", int_mblaze_fsl_necaget>; +def TGETD : FSLGetD<0x1B, 0x00, "tgetd ", int_mblaze_fsl_tget>; +def TAGETD : FSLGetD<0x1B, 0x00, "tagetd ", int_mblaze_fsl_taget>; +def TCGETD : FSLGetD<0x1B, 0x00, "tcgetd ", int_mblaze_fsl_tcget>; +def TCAGETD : FSLGetD<0x1B, 0x00, "tcagetd ", int_mblaze_fsl_tcaget>; +def TEGETD : FSLGetD<0x1B, 0x00, "tegetd ", int_mblaze_fsl_teget>; +def TEAGETD : FSLGetD<0x1B, 0x00, "teagetd ", int_mblaze_fsl_teaget>; +def TECGETD : FSLGetD<0x1B, 0x00, "tecgetd ", int_mblaze_fsl_tecget>; +def TECAGETD : FSLGetD<0x1B, 0x00, "tecagetd ", int_mblaze_fsl_tecaget>; +def TNGETD : FSLGetD<0x1B, 0x00, "tngetd ", int_mblaze_fsl_tnget>; +def TNAGETD : FSLGetD<0x1B, 0x00, "tnagetd ", int_mblaze_fsl_tnaget>; +def TNCGETD : FSLGetD<0x1B, 0x00, "tncgetd ", int_mblaze_fsl_tncget>; +def TNCAGETD : FSLGetD<0x1B, 0x00, "tncagetd ", int_mblaze_fsl_tncaget>; +def TNEGETD : FSLGetD<0x1B, 0x00, "tnegetd ", int_mblaze_fsl_tneget>; +def TNEAGETD : FSLGetD<0x1B, 0x00, "tneagetd ", int_mblaze_fsl_tneaget>; +def TNECGETD : FSLGetD<0x1B, 0x00, "tnecgetd ", int_mblaze_fsl_tnecget>; +def TNECAGETD : FSLGetD<0x1B, 0x00, "tnecagetd", int_mblaze_fsl_tnecaget>; + +//===----------------------------------------------------------------------===// +// FSL Put Instructions +//===----------------------------------------------------------------------===// +def PUT : FSLPut<0x1B, "put ", int_mblaze_fsl_put>; +def APUT : FSLPut<0x1B, "aput ", int_mblaze_fsl_aput>; +def CPUT : FSLPut<0x1B, "cput ", int_mblaze_fsl_cput>; +def CAPUT : FSLPut<0x1B, "caput ", int_mblaze_fsl_caput>; +def NPUT : FSLPut<0x1B, "nput ", int_mblaze_fsl_nput>; +def NAPUT : FSLPut<0x1B, "naput ", int_mblaze_fsl_naput>; +def NCPUT : FSLPut<0x1B, "ncput ", int_mblaze_fsl_ncput>; +def NCAPUT : FSLPut<0x1B, "ncaput ", int_mblaze_fsl_ncaput>; +def TPUT : FSLPutT<0x1B, "tput ", int_mblaze_fsl_tput>; +def TAPUT : FSLPutT<0x1B, "taput ", int_mblaze_fsl_taput>; +def TCPUT : FSLPutT<0x1B, "tcput ", int_mblaze_fsl_tcput>; +def TCAPUT : FSLPutT<0x1B, "tcaput ", int_mblaze_fsl_tcaput>; +def TNPUT : FSLPutT<0x1B, "tnput ", int_mblaze_fsl_tnput>; +def TNAPUT : FSLPutT<0x1B, "tnaput ", int_mblaze_fsl_tnaput>; +def TNCPUT : FSLPutT<0x1B, "tncput ", int_mblaze_fsl_tncput>; +def TNCAPUT : FSLPutT<0x1B, "tncaput ", int_mblaze_fsl_tncaput>; + +//===----------------------------------------------------------------------===// +// FSL Dynamic Put Instructions +//===----------------------------------------------------------------------===// +def PUTD : FSLPutD<0x1B, 0x00, "putd ", int_mblaze_fsl_put>; +def APUTD : FSLPutD<0x1B, 0x00, "aputd ", int_mblaze_fsl_aput>; +def CPUTD : FSLPutD<0x1B, 0x00, "cputd ", int_mblaze_fsl_cput>; +def CAPUTD : FSLPutD<0x1B, 0x00, "caputd ", int_mblaze_fsl_caput>; +def NPUTD : FSLPutD<0x1B, 0x00, "nputd ", int_mblaze_fsl_nput>; +def NAPUTD : FSLPutD<0x1B, 0x00, "naputd ", int_mblaze_fsl_naput>; +def NCPUTD : FSLPutD<0x1B, 0x00, "ncputd ", int_mblaze_fsl_ncput>; +def NCAPUTD : FSLPutD<0x1B, 0x00, "ncaputd ", int_mblaze_fsl_ncaput>; +def TPUTD : FSLPutTD<0x1B, 0x00, "tputd ", int_mblaze_fsl_tput>; +def TAPUTD : FSLPutTD<0x1B, 0x00, "taputd ", int_mblaze_fsl_taput>; +def TCPUTD : FSLPutTD<0x1B, 0x00, "tcputd ", int_mblaze_fsl_tcput>; +def TCAPUTD : FSLPutTD<0x1B, 0x00, "tcaputd ", int_mblaze_fsl_tcaput>; +def TNPUTD : FSLPutTD<0x1B, 0x00, "tnputd ", int_mblaze_fsl_tnput>; +def TNAPUTD : FSLPutTD<0x1B, 0x00, "tnaputd ", int_mblaze_fsl_tnaput>; +def TNCPUTD : FSLPutTD<0x1B, 0x00, "tncputd ", int_mblaze_fsl_tncput>; +def TNCAPUTD : FSLPutTD<0x1B, 0x00, "tncaputd ", int_mblaze_fsl_tncaput>; diff --git a/lib/Target/MBlaze/MBlazeInstrFormats.td b/lib/Target/MBlaze/MBlazeInstrFormats.td new file mode 100644 index 0000000000..7d655433d4 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeInstrFormats.td @@ -0,0 +1,246 @@ +//===- MBlazeInstrFormats.td - MB Instruction defs --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Describe MBlaze instructions format +// +// CPU INSTRUCTION FORMATS +// +// opcode - operation code. +// rd - dst reg. +// ra - first src. reg. +// rb - second src. reg. +// imm16 - 16-bit immediate value. +// +//===----------------------------------------------------------------------===// + +// Generic MBlaze Format +class MBlazeInst<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin> : Instruction +{ + field bits<32> Inst; + + let Namespace = "MBlaze"; + + bits<6> opcode; + + // Top 6 bits are the 'opcode' field + let Inst{0-5} = opcode; + + dag OutOperandList = outs; + dag InOperandList = ins; + + let AsmString = asmstr; + let Pattern = pattern; + let Itinerary = itin; +} + +//===----------------------------------------------------------------------===// +// Pseudo instruction class +//===----------------------------------------------------------------------===// +class MBlazePseudo<dag outs, dag ins, string asmstr, list<dag> pattern>: + MBlazeInst<outs, ins, asmstr, pattern, IIPseudo>; + +//===----------------------------------------------------------------------===// +// Type A instruction class in MBlaze : <|opcode|rd|ra|rb|flags|> +//===----------------------------------------------------------------------===// + +class TA<bits<6> op, bits<11> flags, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<5> rd; + bits<5> ra; + bits<5> rb; + + let opcode = op; + + let Inst{6-10} = rd; + let Inst{11-15} = ra; + let Inst{16-20} = rb; + let Inst{21-31} = flags; +} + +class TAI<bits<6> op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<5> rd; + bits<5> ra; + bits<16> imm16; + + let opcode = op; + + let Inst{6-10} = rd; + let Inst{11-15} = ra; + let Inst{16-31} = imm16; +} + +class TIMM<bits<6> op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<5> ra; + bits<16> imm16; + + let opcode = op; + + let Inst{6-15} = 0; + let Inst{16-31} = imm16; +} + +class TADDR<bits<6> op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<26> addr; + + let opcode = op; + + let Inst{6-31} = addr; +} + +//===----------------------------------------------------------------------===// +// Type B instruction class in MBlaze : <|opcode|rd|ra|immediate|> +//===----------------------------------------------------------------------===// + +class TB<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<5> rd; + bits<5> ra; + bits<16> imm16; + + let opcode = op; + + let Inst{6-10} = rd; + let Inst{11-15} = ra; + let Inst{16-31} = imm16; +} + +//===----------------------------------------------------------------------===// +// Float instruction class in MBlaze : <|opcode|rd|ra|flags|> +//===----------------------------------------------------------------------===// + +class TF<bits<6> op, bits<11> flags, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<5> rd; + bits<5> ra; + + let opcode = op; + + let Inst{6-10} = rd; + let Inst{11-15} = ra; + let Inst{16-20} = 0; + let Inst{21-31} = flags; +} + +//===----------------------------------------------------------------------===// +// Branch instruction class in MBlaze : <|opcode|rd|br|ra|flags|> +//===----------------------------------------------------------------------===// + +class TBR<bits<6> op, bits<5> br, bits<11> flags, dag outs, dag ins, + string asmstr, list<dag> pattern, InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<5> ra; + + let opcode = op; + + let Inst{6-10} = 0; + let Inst{11-15} = br; + let Inst{16-20} = ra; + let Inst{21-31} = flags; +} + +class TBRC<bits<6> op, bits<5> br, bits<11> flags, dag outs, dag ins, + string asmstr, list<dag> pattern, InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<5> ra; + bits<5> rb; + + let opcode = op; + + let Inst{6-10} = br; + let Inst{11-15} = ra; + let Inst{16-20} = rb; + let Inst{21-31} = flags; +} + +class TBRL<bits<6> op, bits<5> br, bits<11> flags, dag outs, dag ins, + string asmstr, list<dag> pattern, InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<5> ra; + + let opcode = op; + + let Inst{6-10} = 0xF; + let Inst{11-15} = br; + let Inst{16-20} = ra; + let Inst{21-31} = flags; +} + +class TBRI<bits<6> op, bits<5> br, dag outs, dag ins, + string asmstr, list<dag> pattern, InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<16> imm16; + + let opcode = op; + + let Inst{6-10} = 0; + let Inst{11-15} = br; + let Inst{16-31} = imm16; +} + +class TBRLI<bits<6> op, bits<5> br, dag outs, dag ins, + string asmstr, list<dag> pattern, InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<16> imm16; + + let opcode = op; + + let Inst{6-10} = 0xF; + let Inst{11-15} = br; + let Inst{16-31} = imm16; +} + +class TBRCI<bits<6> op, bits<5> br, dag outs, dag ins, + string asmstr, list<dag> pattern, InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<5> ra; + bits<16> imm16; + + let opcode = op; + + let Inst{6-10} = br; + let Inst{11-15} = ra; + let Inst{16-31} = imm16; +} + +class TRET<bits<6> op, dag outs, dag ins, + string asmstr, list<dag> pattern, InstrItinClass itin> : + MBlazeInst<outs, ins, asmstr, pattern, itin> +{ + bits<5> ra; + bits<16> imm16; + + let opcode = op; + + let Inst{6-10} = 0x10; + let Inst{11-15} = ra; + let Inst{16-31} = imm16; +} diff --git a/lib/Target/MBlaze/MBlazeInstrInfo.cpp b/lib/Target/MBlaze/MBlazeInstrInfo.cpp new file mode 100644 index 0000000000..a7e8eb7d55 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeInstrInfo.cpp @@ -0,0 +1,222 @@ +//===- MBlazeInstrInfo.cpp - MBlaze 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 MBlaze implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeInstrInfo.h" +#include "MBlazeTargetMachine.h" +#include "MBlazeMachineFunction.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "MBlazeGenInstrInfo.inc" + +using namespace llvm; + +MBlazeInstrInfo::MBlazeInstrInfo(MBlazeTargetMachine &tm) + : TargetInstrInfoImpl(MBlazeInsts, array_lengthof(MBlazeInsts)), + TM(tm), RI(*TM.getSubtargetImpl(), *this) {} + +static bool isZeroImm(const MachineOperand &op) { + return op.isImm() && op.getImm() == 0; +} + +/// Return true if the instruction is a register to register move and +/// leave the source and dest operands in the passed parameters. +bool MBlazeInstrInfo:: +isMoveInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg, + unsigned &SrcSubIdx, unsigned &DstSubIdx) const { + SrcSubIdx = DstSubIdx = 0; // No sub-registers. + + // add $dst, $src, $zero || addu $dst, $zero, $src + // or $dst, $src, $zero || or $dst, $zero, $src + if ((MI.getOpcode() == MBlaze::ADD) || (MI.getOpcode() == MBlaze::OR)) { + if (MI.getOperand(1).isReg() && MI.getOperand(1).getReg() == MBlaze::R0) { + DstReg = MI.getOperand(0).getReg(); + SrcReg = MI.getOperand(2).getReg(); + return true; + } else if (MI.getOperand(2).isReg() && + MI.getOperand(2).getReg() == MBlaze::R0) { + DstReg = MI.getOperand(0).getReg(); + SrcReg = MI.getOperand(1).getReg(); + return true; + } + } + + // addi $dst, $src, 0 + // ori $dst, $src, 0 + if ((MI.getOpcode() == MBlaze::ADDI) || (MI.getOpcode() == MBlaze::ORI)) { + if ((MI.getOperand(1).isReg()) && (isZeroImm(MI.getOperand(2)))) { + DstReg = MI.getOperand(0).getReg(); + SrcReg = MI.getOperand(1).getReg(); + return true; + } + } + + 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 MBlazeInstrInfo:: +isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const { + if (MI->getOpcode() == MBlaze::LWI) { + if ((MI->getOperand(2).isFI()) && // is a stack slot + (MI->getOperand(1).isImm()) && // the imm is zero + (isZeroImm(MI->getOperand(1)))) { + FrameIndex = MI->getOperand(2).getIndex(); + return MI->getOperand(0).getReg(); + } + } + + 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 MBlazeInstrInfo:: +isStoreToStackSlot(const MachineInstr *MI, int &FrameIndex) const { + if (MI->getOpcode() == MBlaze::SWI) { + if ((MI->getOperand(2).isFI()) && // is a stack slot + (MI->getOperand(1).isImm()) && // the imm is zero + (isZeroImm(MI->getOperand(1)))) { + FrameIndex = MI->getOperand(2).getIndex(); + return MI->getOperand(0).getReg(); + } + } + return 0; +} + +/// insertNoop - If data hazard condition is found insert the target nop +/// instruction. +void MBlazeInstrInfo:: +insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const { + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (MI != MBB.end()) DL = MI->getDebugLoc(); + BuildMI(MBB, MI, DL, get(MBlaze::NOP)); +} + +bool MBlazeInstrInfo:: +copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *DestRC, + const TargetRegisterClass *SrcRC) const { + DebugLoc dl = DebugLoc::getUnknownLoc(); + llvm::BuildMI(MBB, I, dl, get(MBlaze::ADD), DestReg) + .addReg(SrcReg).addReg(MBlaze::R0); + return true; +} + +void MBlazeInstrInfo:: +storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned SrcReg, bool isKill, int FI, + const TargetRegisterClass *RC) const { + DebugLoc dl = DebugLoc::getUnknownLoc(); + BuildMI(MBB, I, dl, get(MBlaze::SWI)).addReg(SrcReg,getKillRegState(isKill)) + .addImm(0).addFrameIndex(FI); +} + +void MBlazeInstrInfo:: +loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned DestReg, int FI, + const TargetRegisterClass *RC) const { + DebugLoc dl = DebugLoc::getUnknownLoc(); + BuildMI(MBB, I, dl, get(MBlaze::LWI), DestReg) + .addImm(0).addFrameIndex(FI); +} + +MachineInstr *MBlazeInstrInfo:: +foldMemoryOperandImpl(MachineFunction &MF, + MachineInstr* MI, + const SmallVectorImpl<unsigned> &Ops, int FI) const { + if (Ops.size() != 1) return NULL; + + MachineInstr *NewMI = NULL; + + switch (MI->getOpcode()) { + case MBlaze::OR: + case MBlaze::ADD: + if ((MI->getOperand(0).isReg()) && + (MI->getOperand(2).isReg()) && + (MI->getOperand(2).getReg() == MBlaze::R0) && + (MI->getOperand(1).isReg())) { + if (Ops[0] == 0) { // COPY -> STORE + unsigned SrcReg = MI->getOperand(1).getReg(); + bool isKill = MI->getOperand(1).isKill(); + bool isUndef = MI->getOperand(1).isUndef(); + NewMI = BuildMI(MF, MI->getDebugLoc(), get(MBlaze::SW)) + .addReg(SrcReg, getKillRegState(isKill) | getUndefRegState(isUndef)) + .addImm(0).addFrameIndex(FI); + } else { // COPY -> LOAD + unsigned DstReg = MI->getOperand(0).getReg(); + bool isDead = MI->getOperand(0).isDead(); + bool isUndef = MI->getOperand(0).isUndef(); + NewMI = BuildMI(MF, MI->getDebugLoc(), get(MBlaze::LW)) + .addReg(DstReg, RegState::Define | getDeadRegState(isDead) | + getUndefRegState(isUndef)) + .addImm(0).addFrameIndex(FI); + } + } + break; + } + + return NewMI; +} + +//===----------------------------------------------------------------------===// +// Branch Analysis +//===----------------------------------------------------------------------===// +unsigned MBlazeInstrInfo:: +InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond) const { + DebugLoc dl = DebugLoc::getUnknownLoc(); + + // Can only insert uncond branches so far. + assert(Cond.empty() && !FBB && TBB && "Can only handle uncond branches!"); + BuildMI(&MBB, dl, get(MBlaze::BRI)).addMBB(TBB); + return 1; +} + +/// getGlobalBaseReg - Return a virtual register initialized with the +/// the global base register value. Output instructions required to +/// initialize the register in the function entry block, if necessary. +/// +unsigned MBlazeInstrInfo::getGlobalBaseReg(MachineFunction *MF) const { + MBlazeFunctionInfo *MBlazeFI = MF->getInfo<MBlazeFunctionInfo>(); + unsigned GlobalBaseReg = MBlazeFI->getGlobalBaseReg(); + if (GlobalBaseReg != 0) + return GlobalBaseReg; + + // Insert the set of GlobalBaseReg into the first MBB of the function + MachineBasicBlock &FirstMBB = MF->front(); + MachineBasicBlock::iterator MBBI = FirstMBB.begin(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetInstrInfo *TII = MF->getTarget().getInstrInfo(); + + GlobalBaseReg = RegInfo.createVirtualRegister(MBlaze::CPURegsRegisterClass); + bool Ok = TII->copyRegToReg(FirstMBB, MBBI, GlobalBaseReg, MBlaze::R20, + MBlaze::CPURegsRegisterClass, + MBlaze::CPURegsRegisterClass); + assert(Ok && "Couldn't assign to global base register!"); + Ok = Ok; // Silence warning when assertions are turned off. + RegInfo.addLiveIn(MBlaze::R20); + + MBlazeFI->setGlobalBaseReg(GlobalBaseReg); + return GlobalBaseReg; +} diff --git a/lib/Target/MBlaze/MBlazeInstrInfo.h b/lib/Target/MBlaze/MBlazeInstrInfo.h new file mode 100644 index 0000000000..4f79f1caf9 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeInstrInfo.h @@ -0,0 +1,242 @@ +//===- MBlazeInstrInfo.h - MBlaze 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 MBlaze implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZEINSTRUCTIONINFO_H +#define MBLAZEINSTRUCTIONINFO_H + +#include "MBlaze.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "MBlazeRegisterInfo.h" + +namespace llvm { + +namespace MBlaze { + + // MBlaze Branch Codes + enum FPBranchCode { + BRANCH_F, + BRANCH_T, + BRANCH_FL, + BRANCH_TL, + BRANCH_INVALID + }; + + // MBlaze Condition Codes + enum CondCode { + // To be used with float branch True + FCOND_F, + FCOND_UN, + FCOND_EQ, + FCOND_UEQ, + FCOND_OLT, + FCOND_ULT, + FCOND_OLE, + FCOND_ULE, + FCOND_SF, + FCOND_NGLE, + FCOND_SEQ, + FCOND_NGL, + FCOND_LT, + FCOND_NGE, + FCOND_LE, + FCOND_NGT, + + // To be used with float branch False + // This conditions have the same mnemonic as the + // above ones, but are used with a branch False; + FCOND_T, + FCOND_OR, + FCOND_NEQ, + FCOND_OGL, + FCOND_UGE, + FCOND_OGE, + FCOND_UGT, + FCOND_OGT, + FCOND_ST, + FCOND_GLE, + FCOND_SNE, + FCOND_GL, + FCOND_NLT, + FCOND_GE, + FCOND_NLE, + FCOND_GT, + + // Only integer conditions + COND_E, + COND_GZ, + COND_GEZ, + COND_LZ, + COND_LEZ, + COND_NE, + COND_INVALID + }; + + // Turn condition code into conditional branch opcode. + unsigned GetCondBranchFromCond(CondCode CC); + + /// GetOppositeBranchCondition - Return the inverse of the specified cond, + /// e.g. turning COND_E to COND_NE. + CondCode GetOppositeBranchCondition(MBlaze::CondCode CC); + + /// MBlazeCCToString - Map each FP condition code to its string + inline static const char *MBlazeFCCToString(MBlaze::CondCode CC) + { + switch (CC) { + default: llvm_unreachable("Unknown condition code"); + case FCOND_F: + case FCOND_T: return "f"; + case FCOND_UN: + case FCOND_OR: return "un"; + case FCOND_EQ: + case FCOND_NEQ: return "eq"; + case FCOND_UEQ: + case FCOND_OGL: return "ueq"; + case FCOND_OLT: + case FCOND_UGE: return "olt"; + case FCOND_ULT: + case FCOND_OGE: return "ult"; + case FCOND_OLE: + case FCOND_UGT: return "ole"; + case FCOND_ULE: + case FCOND_OGT: return "ule"; + case FCOND_SF: + case FCOND_ST: return "sf"; + case FCOND_NGLE: + case FCOND_GLE: return "ngle"; + case FCOND_SEQ: + case FCOND_SNE: return "seq"; + case FCOND_NGL: + case FCOND_GL: return "ngl"; + case FCOND_LT: + case FCOND_NLT: return "lt"; + case FCOND_NGE: + case FCOND_GE: return "ge"; + case FCOND_LE: + case FCOND_NLE: return "nle"; + case FCOND_NGT: + case FCOND_GT: return "gt"; + } + } +} + +/// MBlazeII - This namespace holds all of the target specific flags that +/// instruction info tracks. +/// +namespace MBlazeII { + /// Target Operand Flag enum. + enum TOF { + //===------------------------------------------------------------------===// + // MBlaze Specific MachineOperand flags. + MO_NO_FLAG, + + /// MO_GOT - Represents the offset into the global offset table at which + /// the address the relocation entry symbol resides during execution. + MO_GOT, + + /// MO_GOT_CALL - Represents the offset into the global offset table at + /// which the address of a call site relocation entry symbol resides + /// during execution. This is different from the above since this flag + /// can only be present in call instructions. + MO_GOT_CALL, + + /// MO_GPREL - Represents the offset from the current gp value to be used + /// for the relocatable object file being produced. + MO_GPREL, + + /// MO_ABS_HILO - Represents the hi or low part of an absolute symbol + /// address. + MO_ABS_HILO + + }; +} + +class MBlazeInstrInfo : public TargetInstrInfoImpl { + MBlazeTargetMachine &TM; + const MBlazeRegisterInfo RI; +public: + explicit MBlazeInstrInfo(MBlazeTargetMachine &TM); + + /// 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 MBlazeRegisterInfo &getRegisterInfo() const { return RI; } + + /// Return true if the instruction is a register to register move and return + /// the source and dest operands and their sub-register indices by reference. + virtual bool isMoveInstr(const MachineInstr &MI, + unsigned &SrcReg, unsigned &DstReg, + unsigned &SrcSubIdx, unsigned &DstSubIdx) const; + + /// 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. + virtual unsigned isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const; + + /// 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. + virtual unsigned isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const; + + /// Branch Analysis + 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 loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC) const; + + virtual MachineInstr* foldMemoryOperandImpl(MachineFunction &MF, + MachineInstr* MI, + const SmallVectorImpl<unsigned> &Ops, + int FrameIndex) const; + + virtual MachineInstr* foldMemoryOperandImpl(MachineFunction &MF, + MachineInstr* MI, + const SmallVectorImpl<unsigned> &Ops, + MachineInstr* LoadMI) const { + return 0; + } + + /// Insert nop instruction when hazard condition is found + virtual void insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const; + + /// getGlobalBaseReg - Return a virtual register initialized with the + /// the global base register value. Output instructions required to + /// initialize the register in the function entry block, if necessary. + /// + unsigned getGlobalBaseReg(MachineFunction *MF) const; +}; + +} + +#endif diff --git a/lib/Target/MBlaze/MBlazeInstrInfo.td b/lib/Target/MBlaze/MBlazeInstrInfo.td new file mode 100644 index 0000000000..3c406dda05 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeInstrInfo.td @@ -0,0 +1,672 @@ +//===- MBlazeInstrInfo.td - MBlaze Instruction defs -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Instruction format superclass +//===----------------------------------------------------------------------===// +include "MBlazeInstrFormats.td" + +//===----------------------------------------------------------------------===// +// MBlaze profiles and nodes +//===----------------------------------------------------------------------===// +def SDT_MBlazeRet : SDTypeProfile<0, 1, [SDTCisInt<0>]>; +def SDT_MBlazeJmpLink : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; + +// Call +def MBlazeJmpLink : SDNode<"MBlazeISD::JmpLink",SDT_MBlazeJmpLink, + [SDNPHasChain,SDNPOptInFlag,SDNPOutFlag]>; + +// Return +def MBlazeRet : SDNode<"MBlazeISD::Ret", SDT_MBlazeRet, + [SDNPHasChain, SDNPOptInFlag]>; + +// Hi and Lo nodes are used to handle global addresses. Used on +// MBlazeISelLowering to lower stuff like GlobalAddress, ExternalSymbol +// static model. +def MBWrapper : SDNode<"MBlazeISD::Wrap", SDTIntUnaryOp>; +def MBlazeGPRel : SDNode<"MBlazeISD::GPRel", SDTIntUnaryOp>; + +def SDT_MBCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>; +def SDT_MBCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; + +// These are target-independent nodes, but have target-specific formats. +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MBCallSeqStart, + [SDNPHasChain, SDNPOutFlag]>; +def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MBCallSeqEnd, + [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>; + +def SDTMBlazeSelectCC : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>]>; + +//===----------------------------------------------------------------------===// +// MBlaze Instruction Predicate Definitions. +//===----------------------------------------------------------------------===// +def HasPipe3 : Predicate<"Subtarget.hasPipe3()">; +def HasBarrel : Predicate<"Subtarget.hasBarrel()">; +def NoBarrel : Predicate<"!Subtarget.hasBarrel()">; +def HasDiv : Predicate<"Subtarget.hasDiv()">; +def HasMul : Predicate<"Subtarget.hasMul()">; +def HasFSL : Predicate<"Subtarget.hasFSL()">; +def HasEFSL : Predicate<"Subtarget.hasEFSL()">; +def HasMSRSet : Predicate<"Subtarget.hasMSRSet()">; +def HasException : Predicate<"Subtarget.hasException()">; +def HasPatCmp : Predicate<"Subtarget.hasPatCmp()">; +def HasFPU : Predicate<"Subtarget.hasFPU()">; +def HasESR : Predicate<"Subtarget.hasESR()">; +def HasPVR : Predicate<"Subtarget.hasPVR()">; +def HasMul64 : Predicate<"Subtarget.hasMul64()">; +def HasSqrt : Predicate<"Subtarget.hasSqrt()">; +def HasMMU : Predicate<"Subtarget.hasMMU()">; + +//===----------------------------------------------------------------------===// +// MBlaze Operand, Complex Patterns and Transformations Definitions. +//===----------------------------------------------------------------------===// + +// Instruction operand types +def brtarget : Operand<OtherVT>; +def calltarget : Operand<i32>; +def simm16 : Operand<i32>; +def uimm5 : Operand<i32>; +def fimm : Operand<f32>; + +// Unsigned Operand +def uimm16 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; +} + +// FSL Operand +def fslimm : Operand<i32> { + let PrintMethod = "printFSLImm"; +} + +// Address operand +def memri : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops simm16, CPURegs); +} + +def memrr : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops CPURegs, CPURegs); +} + +// Transformation Function - get the lower 16 bits. +def LO16 : SDNodeXForm<imm, [{ + return getI32Imm((unsigned)N->getZExtValue() & 0xFFFF); +}]>; + +// Transformation Function - get the higher 16 bits. +def HI16 : SDNodeXForm<imm, [{ + return getI32Imm((unsigned)N->getZExtValue() >> 16); +}]>; + +// Node immediate fits as 16-bit sign extended on target immediate. +// e.g. addi, andi +def immSExt16 : PatLeaf<(imm), [{ + return (N->getZExtValue() >> 16) == 0; +}]>; + +// Node immediate fits as 16-bit zero extended on target immediate. +// The LO16 param means that only the lower 16 bits of the node +// immediate are caught. +// e.g. addiu, sltiu +def immZExt16 : PatLeaf<(imm), [{ + return (N->getZExtValue() >> 16) == 0; +}], LO16>; + +// FSL immediate field must fit in 4 bits. +def immZExt4 : PatLeaf<(imm), [{ + return N->getZExtValue() == ((N->getZExtValue()) & 0xf) ; +}]>; + +// shamt field must fit in 5 bits. +def immZExt5 : PatLeaf<(imm), [{ + return N->getZExtValue() == ((N->getZExtValue()) & 0x1f) ; +}]>; + +// MBlaze Address Mode! SDNode frameindex could possibily be a match +// since load and store instructions from stack used it. +def iaddr : ComplexPattern<i32, 2, "SelectAddrRegImm", [frameindex], []>; +def xaddr : ComplexPattern<i32, 2, "SelectAddrRegReg", [], []>; + +//===----------------------------------------------------------------------===// +// Pseudo instructions +//===----------------------------------------------------------------------===// + +// As stack alignment is always done with addiu, we need a 16-bit immediate +let Defs = [R1], Uses = [R1] in { +def ADJCALLSTACKDOWN : MBlazePseudo<(outs), (ins simm16:$amt), + "${:comment} ADJCALLSTACKDOWN $amt", + [(callseq_start timm:$amt)]>; +def ADJCALLSTACKUP : MBlazePseudo<(outs), + (ins uimm16:$amt1, simm16:$amt2), + "${:comment} ADJCALLSTACKUP $amt1", + [(callseq_end timm:$amt1, timm:$amt2)]>; +} + +// Some assembly macros need to avoid pseudoinstructions and assembler +// automatic reodering, we should reorder ourselves. +def MACRO : MBlazePseudo<(outs), (ins), ".set macro", []>; +def REORDER : MBlazePseudo<(outs), (ins), ".set reorder", []>; +def NOMACRO : MBlazePseudo<(outs), (ins), ".set nomacro", []>; +def NOREORDER : MBlazePseudo<(outs), (ins), ".set noreorder", []>; + +// When handling PIC code the assembler needs .cpload and .cprestore +// directives. If the real instructions corresponding these directives +// are used, we have the same behavior, but get also a bunch of warnings +// from the assembler. +def CPLOAD : MBlazePseudo<(outs), (ins CPURegs:$reg), ".cpload $reg", []>; +def CPRESTORE : MBlazePseudo<(outs), (ins uimm16:$l), ".cprestore $l\n", []>; + +//===----------------------------------------------------------------------===// +// Instructions specific format +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Arithmetic Instructions +//===----------------------------------------------------------------------===// +class Arith<bits<6> op, bits<11> flags, string instr_asm, SDNode OpNode, + InstrItinClass itin> : + TA<op, flags, (outs CPURegs:$dst), (ins CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, CPURegs:$c))], itin>; + +class ArithI<bits<6> op, string instr_asm, SDNode OpNode, + Operand Od, PatLeaf imm_type> : + TAI<op, (outs CPURegs:$dst), (ins CPURegs:$b, Od:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, imm_type:$c))], IIAlu>; + +class ArithR<bits<6> op, bits<11> flags, string instr_asm, SDNode OpNode, + InstrItinClass itin> : + TA<op, flags, (outs CPURegs:$dst), (ins CPURegs:$c, CPURegs:$b), + !strconcat(instr_asm, " $dst, $c, $b"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, CPURegs:$c))], itin>; + +class ArithRI<bits<6> op, string instr_asm, SDNode OpNode, + Operand Od, PatLeaf imm_type> : + TAI<op, (outs CPURegs:$dst), (ins Od:$b, CPURegs:$c), + !strconcat(instr_asm, " $dst, $c, $b"), + [(set CPURegs:$dst, (OpNode imm_type:$b, CPURegs:$c))], IIAlu>; + +class ArithN<bits<6> op, bits<11> flags, string instr_asm, + InstrItinClass itin> : + TA<op, flags, (outs CPURegs:$dst), (ins CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [], itin>; + +class ArithNI<bits<6> op, string instr_asm,Operand Od, PatLeaf imm_type> : + TAI<op, (outs CPURegs:$dst), (ins CPURegs:$b, Od:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [], IIAlu>; + +class ArithRN<bits<6> op, bits<11> flags, string instr_asm, + InstrItinClass itin> : + TA<op, flags, (outs CPURegs:$dst), (ins CPURegs:$c, CPURegs:$b), + !strconcat(instr_asm, " $dst, $b, $c"), + [], itin>; + +class ArithRNI<bits<6> op, string instr_asm,Operand Od, PatLeaf imm_type> : + TAI<op, (outs CPURegs:$dst), (ins Od:$c, CPURegs:$b), + !strconcat(instr_asm, " $dst, $b, $c"), + [], IIAlu>; + +//===----------------------------------------------------------------------===// +// Misc Arithmetic Instructions +//===----------------------------------------------------------------------===// + +class Logic<bits<6> op, bits<11> flags, string instr_asm, SDNode OpNode> : + TA<op, flags, (outs CPURegs:$dst), (ins CPURegs:$b, CPURegs:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, CPURegs:$c))], IIAlu>; + +class LogicI<bits<6> op, string instr_asm, SDNode OpNode> : + TAI<op, (outs CPURegs:$dst), (ins CPURegs:$b, uimm16:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set CPURegs:$dst, (OpNode CPURegs:$b, immZExt16:$c))], + IIAlu>; + +class EffectiveAddress<string instr_asm> : + TAI<0x08, (outs CPURegs:$dst), (ins memri:$addr), + instr_asm, [(set CPURegs:$dst, iaddr:$addr)], IIAlu>; + +//===----------------------------------------------------------------------===// +// Memory Access Instructions +//===----------------------------------------------------------------------===// +class LoadM<bits<6> op, string instr_asm, PatFrag OpNode> : + TA<op, 0x000, (outs CPURegs:$dst), (ins memrr:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(set CPURegs:$dst, (OpNode xaddr:$addr))], IILoad>; + +class LoadMI<bits<6> op, string instr_asm, PatFrag OpNode> : + TAI<op, (outs CPURegs:$dst), (ins memri:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(set CPURegs:$dst, (OpNode iaddr:$addr))], IILoad>; + +class StoreM<bits<6> op, string instr_asm, PatFrag OpNode> : + TA<op, 0x000, (outs), (ins CPURegs:$dst, memrr:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(OpNode CPURegs:$dst, xaddr:$addr)], IIStore>; + +class StoreMI<bits<6> op, string instr_asm, PatFrag OpNode> : + TAI<op, (outs), (ins CPURegs:$dst, memri:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(OpNode CPURegs:$dst, iaddr:$addr)], IIStore>; + +//===----------------------------------------------------------------------===// +// Branch Instructions +//===----------------------------------------------------------------------===// +class Branch<bits<6> op, bits<5> br, bits<11> flags, string instr_asm> : + TBR<op, br, flags, (outs), (ins CPURegs:$target), + !strconcat(instr_asm, " $target"), + [(brind CPURegs:$target)], IIBranch>; + +class BranchI<bits<6> op, bits<5> brf, string instr_asm> : + TBRI<op, brf, (outs), (ins brtarget:$target), + !strconcat(instr_asm, " $target"), + [(br bb:$target)], IIBranch>; + +//===----------------------------------------------------------------------===// +// Branch and Link Instructions +//===----------------------------------------------------------------------===// +class BranchL<bits<6> op, bits<5> br, bits<11> flags, string instr_asm> : + TBRL<op, br, flags, (outs), (ins CPURegs:$target), + !strconcat(instr_asm, " r15, $target"), + [], IIBranch>; + +class BranchLI<bits<6> op, bits<5> br, string instr_asm> : + TBRLI<op, br, (outs), (ins calltarget:$target), + !strconcat(instr_asm, " r15, $target"), + [], IIBranch>; + +//===----------------------------------------------------------------------===// +// Conditional Branch Instructions +//===----------------------------------------------------------------------===// +class BranchC<bits<6> op, bits<5> br, bits<11> flags, string instr_asm, + PatFrag cond_op> : + TBRC<op, br, flags, (outs), + (ins CPURegs:$a, CPURegs:$b, brtarget:$offset), + !strconcat(instr_asm, " $a, $b, $offset"), + [], IIBranch>; + //(brcond (cond_op CPURegs:$a, CPURegs:$b), bb:$offset)], + //IIBranch>; + +class BranchCI<bits<6> op, bits<5> br, string instr_asm, PatFrag cond_op> : + TBRCI<op, br, (outs), (ins CPURegs:$a, brtarget:$offset), + !strconcat(instr_asm, " $a, $offset"), + [], IIBranch>; + +//===----------------------------------------------------------------------===// +// MBlaze arithmetic instructions +//===----------------------------------------------------------------------===// + +let isCommutable = 1, isAsCheapAsAMove = 1 in { + def ADD : Arith<0x00, 0x000, "add ", add, IIAlu>; + def ADDC : Arith<0x02, 0x000, "addc ", adde, IIAlu>; + def ADDK : Arith<0x04, 0x000, "addk ", addc, IIAlu>; + def ADDKC : ArithN<0x06, 0x000, "addkc ", IIAlu>; + def AND : Logic<0x21, 0x000, "and ", and>; + def OR : Logic<0x20, 0x000, "or ", or>; + def XOR : Logic<0x22, 0x000, "xor ", xor>; +} + +let isAsCheapAsAMove = 1 in { + def ANDN : ArithN<0x23, 0x000, "andn ", IIAlu>; + def CMP : ArithN<0x05, 0x001, "cmp ", IIAlu>; + def CMPU : ArithN<0x05, 0x003, "cmpu ", IIAlu>; + def RSUB : ArithR<0x01, 0x000, "rsub ", sub, IIAlu>; + def RSUBC : ArithR<0x03, 0x000, "rsubc ", sube, IIAlu>; + def RSUBK : ArithR<0x05, 0x000, "rsubk ", subc, IIAlu>; + def RSUBKC : ArithRN<0x07, 0x000, "rsubkc ", IIAlu>; +} + +let isCommutable = 1, Predicates=[HasMul] in { + def MUL : Arith<0x10, 0x000, "mul ", mul, IIAlu>; +} + +let isCommutable = 1, Predicates=[HasMul,HasMul64] in { + def MULH : Arith<0x10, 0x001, "mulh ", mulhs, IIAlu>; + def MULHU : Arith<0x10, 0x003, "mulhu ", mulhu, IIAlu>; +} + +let Predicates=[HasMul,HasMul64] in { + def MULHSU : ArithN<0x10, 0x002, "mulhsu ", IIAlu>; +} + +let Predicates=[HasBarrel] in { + def BSRL : Arith<0x11, 0x000, "bsrl ", srl, IIAlu>; + def BSRA : Arith<0x11, 0x200, "bsra ", sra, IIAlu>; + def BSLL : Arith<0x11, 0x400, "bsll ", shl, IIAlu>; + def BSRLI : ArithI<0x11, "bsrli ", srl, uimm5, immZExt5>; + def BSRAI : ArithI<0x11, "bsrai ", sra, uimm5, immZExt5>; + def BSLLI : ArithI<0x11, "bslli ", shl, uimm5, immZExt5>; +} + +let Predicates=[HasDiv] in { + def IDIV : Arith<0x12, 0x000, "idiv ", sdiv, IIAlu>; + def IDIVU : Arith<0x12, 0x002, "idivu ", udiv, IIAlu>; +} + +//===----------------------------------------------------------------------===// +// MBlaze immediate mode arithmetic instructions +//===----------------------------------------------------------------------===// + +let isAsCheapAsAMove = 1 in { + def ADDI : ArithI<0x08, "addi ", add, simm16, immSExt16>; + def ADDIC : ArithNI<0x0A, "addic ", simm16, immSExt16>; + def ADDIK : ArithNI<0x0C, "addik ", simm16, immSExt16>; + def ADDIKC : ArithI<0x0E, "addikc ", addc, simm16, immSExt16>; + def RSUBI : ArithRI<0x09, "rsubi ", sub, simm16, immSExt16>; + def RSUBIC : ArithRNI<0x0B, "rsubi ", simm16, immSExt16>; + def RSUBIK : ArithRNI<0x0E, "rsubic ", simm16, immSExt16>; + def RSUBIKC : ArithRI<0x0F, "rsubikc", subc, simm16, immSExt16>; + def ANDNI : ArithNI<0x2B, "andni ", uimm16, immZExt16>; + def ANDI : LogicI<0x29, "andi ", and>; + def ORI : LogicI<0x28, "ori ", or>; + def XORI : LogicI<0x2A, "xori ", xor>; +} + +let Predicates=[HasMul] in { + def MULI : ArithI<0x18, "muli ", mul, simm16, immSExt16>; +} + +//===----------------------------------------------------------------------===// +// MBlaze memory access instructions +//===----------------------------------------------------------------------===// + +let canFoldAsLoad = 1, isReMaterializable = 1 in { + def LBU : LoadM<0x30, "lbu ", zextloadi8>; + def LHU : LoadM<0x31, "lhu ", zextloadi16>; + def LW : LoadM<0x32, "lw ", load>; + + def LBUI : LoadMI<0x30, "lbui ", zextloadi8>; + def LHUI : LoadMI<0x31, "lhui ", zextloadi16>; + def LWI : LoadMI<0x32, "lwi ", load>; +} + + def SB : StoreM<0x34, "sb ", truncstorei8>; + def SH : StoreM<0x35, "sh ", truncstorei16>; + def SW : StoreM<0x36, "sw ", store>; + + def SBI : StoreMI<0x34, "sbi ", truncstorei8>; + def SHI : StoreMI<0x35, "shi ", truncstorei16>; + def SWI : StoreMI<0x36, "swi ", store>; + +//===----------------------------------------------------------------------===// +// MBlaze branch instructions +//===----------------------------------------------------------------------===// + +let isBranch = 1, isTerminator = 1, hasCtrlDep = 1 in { + def BRI : BranchI<0x2E, 0x00, "bri ">; + def BRAI : BranchI<0x2E, 0x08, "brai ">; + def BEQI : BranchCI<0x2F, 0x00, "beqi ", seteq>; + def BNEI : BranchCI<0x2F, 0x01, "bnei ", setne>; + def BLTI : BranchCI<0x2F, 0x02, "blti ", setlt>; + def BLEI : BranchCI<0x2F, 0x03, "blei ", setle>; + def BGTI : BranchCI<0x2F, 0x04, "bgti ", setgt>; + def BGEI : BranchCI<0x2F, 0x05, "bgei ", setge>; +} + +let isBranch = 1, isIndirectBranch = 1, isTerminator = 1, hasCtrlDep = 1 in { + def BR : Branch<0x26, 0x00, 0x000, "br ">; + def BRA : Branch<0x26, 0x08, 0x000, "bra ">; + def BEQ : BranchC<0x27, 0x00, 0x000, "beq ", seteq>; + def BNE : BranchC<0x27, 0x01, 0x000, "bne ", setne>; + def BLT : BranchC<0x27, 0x02, 0x000, "blt ", setlt>; + def BLE : BranchC<0x27, 0x03, 0x000, "ble ", setle>; + def BGT : BranchC<0x27, 0x04, 0x000, "bgt ", setgt>; + def BGE : BranchC<0x27, 0x05, 0x000, "bge ", setge>; +} + +let isBranch = 1, isTerminator = 1, hasDelaySlot = 1, hasCtrlDep = 1 in { + def BRID : BranchI<0x2E, 0x10, "brid ">; + def BRAID : BranchI<0x2E, 0x18, "braid ">; + def BEQID : BranchCI<0x2F, 0x10, "beqid ", seteq>; + def BNEID : BranchCI<0x2F, 0x11, "bneid ", setne>; + def BLTID : BranchCI<0x2F, 0x12, "bltid ", setlt>; + def BLEID : BranchCI<0x2F, 0x13, "bleid ", setle>; + def BGTID : BranchCI<0x2F, 0x14, "bgtid ", setgt>; + def BGEID : BranchCI<0x2F, 0x15, "bgeid ", setge>; +} + +let isBranch = 1, isIndirectBranch = 1, isTerminator = 1, + hasDelaySlot = 1, hasCtrlDep = 1 in { + def BRD : Branch<0x26, 0x10, 0x000, "brd ">; + def BRAD : Branch<0x26, 0x18, 0x000, "brad ">; + def BEQD : BranchC<0x27, 0x10, 0x000, "beqd ", seteq>; + def BNED : BranchC<0x27, 0x11, 0x000, "bned ", setne>; + def BLTD : BranchC<0x27, 0x12, 0x000, "bltd ", setlt>; + def BLED : BranchC<0x27, 0x13, 0x000, "bled ", setle>; + def BGTD : BranchC<0x27, 0x14, 0x000, "bgtd ", setgt>; + def BGED : BranchC<0x27, 0x15, 0x000, "bged ", setge>; +} + +let isCall = 1, hasCtrlDep = 1, isIndirectBranch = 1, + Defs = [R3,R4,R5,R6,R7,R8,R9,R10,R11,R12], + Uses = [R1,R5,R6,R7,R8,R9,R10] in { + def BRL : BranchL<0x26, 0x04, 0x000, "brl ">; + def BRAL : BranchL<0x26, 0x0C, 0x000, "bral ">; +} + +let isCall = 1, hasDelaySlot = 1, hasCtrlDep = 1, + Defs = [R3,R4,R5,R6,R7,R8,R9,R10,R11,R12], + Uses = [R1,R5,R6,R7,R8,R9,R10] in { + def BRLID : BranchLI<0x2E, 0x14, "brlid ">; + def BRALID : BranchLI<0x2E, 0x1C, "bralid ">; +} + +let isCall = 1, hasDelaySlot = 1, hasCtrlDep = 1, isIndirectBranch = 1, + Defs = [R3,R4,R5,R6,R7,R8,R9,R10,R11,R12], + Uses = [R1,R5,R6,R7,R8,R9,R10] in { + def BRLD : BranchL<0x26, 0x14, 0x000, "brld ">; + def BRALD : BranchL<0x26, 0x1C, 0x000, "brald ">; +} + +let isReturn=1, isTerminator=1, hasDelaySlot=1, + isBarrier=1, hasCtrlDep=1, imm16=0x8 in { + def RTSD : TRET<0x2D, (outs), (ins CPURegs:$target), + "rtsd $target, 8", + [(MBlazeRet CPURegs:$target)], + IIBranch>; +} + +//===----------------------------------------------------------------------===// +// MBlaze misc instructions +//===----------------------------------------------------------------------===// + +let addr = 0 in { + def NOP : TADDR<0x00, (outs), (ins), "nop ", [], IIAlu>; +} + +let usesCustomInserter = 1 in { + //class PseudoSelCC<RegisterClass RC, string asmstr>: + // MBlazePseudo<(outs RC:$D), (ins RC:$T, RC:$F, CPURegs:$CMP), asmstr, + // [(set RC:$D, (MBlazeSelectCC RC:$T, RC:$F, CPURegs:$CMP))]>; + //def Select_CC : PseudoSelCC<CPURegs, "# MBlazeSelect_CC">; + + def Select_CC : MBlazePseudo<(outs CPURegs:$dst), + (ins CPURegs:$T, CPURegs:$F, CPURegs:$CMP, i32imm:$CC), + "; SELECT_CC PSEUDO!", + []>; + + def ShiftL : MBlazePseudo<(outs CPURegs:$dst), + (ins CPURegs:$L, CPURegs:$R), + "; ShiftL PSEUDO!", + []>; + + def ShiftRA : MBlazePseudo<(outs CPURegs:$dst), + (ins CPURegs:$L, CPURegs:$R), + "; ShiftRA PSEUDO!", + []>; + + def ShiftRL : MBlazePseudo<(outs CPURegs:$dst), + (ins CPURegs:$L, CPURegs:$R), + "; ShiftRL PSEUDO!", + []>; +} + + +let rb = 0 in { + def SEXT16 : TA<0x24, 0x061, (outs CPURegs:$dst), (ins CPURegs:$src), + "sext16 $dst, $src", [], IIAlu>; + def SEXT8 : TA<0x24, 0x060, (outs CPURegs:$dst), (ins CPURegs:$src), + "sext8 $dst, $src", [], IIAlu>; + def SRL : TA<0x24, 0x041, (outs CPURegs:$dst), (ins CPURegs:$src), + "srl $dst, $src", [], IIAlu>; + def SRA : TA<0x24, 0x001, (outs CPURegs:$dst), (ins CPURegs:$src), + "sra $dst, $src", [], IIAlu>; + def SRC : TA<0x24, 0x021, (outs CPURegs:$dst), (ins CPURegs:$src), + "src $dst, $src", [], IIAlu>; +} + +def LEA_ADDI : EffectiveAddress<"addi $dst, ${addr:stackloc}">; + +//===----------------------------------------------------------------------===// +// Arbitrary patterns that map to one or more instructions +//===----------------------------------------------------------------------===// + +// Small immediates +def : Pat<(i32 0), (ADD R0, R0)>; +def : Pat<(i32 immSExt16:$imm), (ADDI R0, imm:$imm)>; +def : Pat<(i32 immZExt16:$imm), (ORI R0, imm:$imm)>; + +// Arbitrary immediates +def : Pat<(i32 imm:$imm), (ADDI R0, imm:$imm)>; + +// In register sign extension +def : Pat<(sext_inreg CPURegs:$src, i16), (SEXT16 CPURegs:$src)>; +def : Pat<(sext_inreg CPURegs:$src, i8), (SEXT8 CPURegs:$src)>; + +// Call +def : Pat<(MBlazeJmpLink (i32 tglobaladdr:$dst)), (BRLID tglobaladdr:$dst)>; +def : Pat<(MBlazeJmpLink (i32 texternalsym:$dst)),(BRLID texternalsym:$dst)>; +def : Pat<(MBlazeJmpLink CPURegs:$dst), (BRLD CPURegs:$dst)>; + +// Shift Instructions +def : Pat<(shl CPURegs:$L, CPURegs:$R), (ShiftL CPURegs:$L, CPURegs:$R)>; +def : Pat<(sra CPURegs:$L, CPURegs:$R), (ShiftRA CPURegs:$L, CPURegs:$R)>; +def : Pat<(srl CPURegs:$L, CPURegs:$R), (ShiftRL CPURegs:$L, CPURegs:$R)>; + +// SET_CC operations +def : Pat<(setcc CPURegs:$L, CPURegs:$R, SETEQ), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (CMP CPURegs:$L, CPURegs:$R), 1)>; +def : Pat<(setcc CPURegs:$L, CPURegs:$R, SETNE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (CMP CPURegs:$L, CPURegs:$R), 2)>; +def : Pat<(setcc CPURegs:$L, CPURegs:$R, SETGT), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (CMP CPURegs:$L, CPURegs:$R), 3)>; +def : Pat<(setcc CPURegs:$L, CPURegs:$R, SETLT), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (CMP CPURegs:$L, CPURegs:$R), 4)>; +def : Pat<(setcc CPURegs:$L, CPURegs:$R, SETGE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (CMP CPURegs:$L, CPURegs:$R), 5)>; +def : Pat<(setcc CPURegs:$L, CPURegs:$R, SETLE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (CMP CPURegs:$L, CPURegs:$R), 6)>; +def : Pat<(setcc CPURegs:$L, CPURegs:$R, SETUGT), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (CMPU CPURegs:$L, CPURegs:$R), 3)>; +def : Pat<(setcc CPURegs:$L, CPURegs:$R, SETULT), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (CMPU CPURegs:$L, CPURegs:$R), 4)>; +def : Pat<(setcc CPURegs:$L, CPURegs:$R, SETUGE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (CMPU CPURegs:$L, CPURegs:$R), 5)>; +def : Pat<(setcc CPURegs:$L, CPURegs:$R, SETULE), + (Select_CC (ADDI R0, 1), (ADDI R0, 0), + (CMPU CPURegs:$L, CPURegs:$R), 6)>; + +// SELECT operations +def : Pat<(select CPURegs:$C, CPURegs:$T, CPURegs:$F), + (Select_CC CPURegs:$T, CPURegs:$F, CPURegs:$C, 2)>; + +// SELECT_CC +def : Pat<(selectcc CPURegs:$L, CPURegs:$R, CPURegs:$T, CPURegs:$F, SETEQ), + (Select_CC CPURegs:$T, CPURegs:$F, (CMP CPURegs:$L, CPURegs:$R), 1)>; +def : Pat<(selectcc CPURegs:$L, CPURegs:$R, CPURegs:$T, CPURegs:$F, SETNE), + (Select_CC CPURegs:$T, CPURegs:$F, (CMP CPURegs:$L, CPURegs:$R), 2)>; +def : Pat<(selectcc CPURegs:$L, CPURegs:$R, CPURegs:$T, CPURegs:$F, SETGT), + (Select_CC CPURegs:$T, CPURegs:$F, (CMP CPURegs:$L, CPURegs:$R), 3)>; +def : Pat<(selectcc CPURegs:$L, CPURegs:$R, CPURegs:$T, CPURegs:$F, SETLT), + (Select_CC CPURegs:$T, CPURegs:$F, (CMP CPURegs:$L, CPURegs:$R), 4)>; +def : Pat<(selectcc CPURegs:$L, CPURegs:$R, CPURegs:$T, CPURegs:$F, SETGE), + (Select_CC CPURegs:$T, CPURegs:$F, (CMP CPURegs:$L, CPURegs:$R), 5)>; +def : Pat<(selectcc CPURegs:$L, CPURegs:$R, CPURegs:$T, CPURegs:$F, SETLE), + (Select_CC CPURegs:$T, CPURegs:$F, (CMP CPURegs:$L, CPURegs:$R), 6)>; +def : Pat<(selectcc CPURegs:$L, CPURegs:$R, CPURegs:$T, CPURegs:$F, SETUGT), + (Select_CC CPURegs:$T, CPURegs:$F, (CMPU CPURegs:$L, CPURegs:$R), 3)>; +def : Pat<(selectcc CPURegs:$L, CPURegs:$R, CPURegs:$T, CPURegs:$F, SETULT), + (Select_CC CPURegs:$T, CPURegs:$F, (CMPU CPURegs:$L, CPURegs:$R), 4)>; +def : Pat<(selectcc CPURegs:$L, CPURegs:$R, CPURegs:$T, CPURegs:$F, SETUGE), + (Select_CC CPURegs:$T, CPURegs:$F, (CMPU CPURegs:$L, CPURegs:$R), 5)>; +def : Pat<(selectcc CPURegs:$L, CPURegs:$R, CPURegs:$T, CPURegs:$F, SETULE), + (Select_CC CPURegs:$T, CPURegs:$F, (CMPU CPURegs:$L, CPURegs:$R), 6)>; + +// BRCOND instructions +def : Pat<(brcond (setcc CPURegs:$L, CPURegs:$R, SETEQ), bb:$T), + (BEQID (CMP CPURegs:$R, CPURegs:$L), bb:$T)>; +def : Pat<(brcond (setcc CPURegs:$L, CPURegs:$R, SETNE), bb:$T), + (BNEID (CMP CPURegs:$R, CPURegs:$L), bb:$T)>; +def : Pat<(brcond (setcc CPURegs:$L, CPURegs:$R, SETGT), bb:$T), + (BGTID (CMP CPURegs:$R, CPURegs:$L), bb:$T)>; +def : Pat<(brcond (setcc CPURegs:$L, CPURegs:$R, SETLT), bb:$T), + (BLTID (CMP CPURegs:$R, CPURegs:$L), bb:$T)>; +def : Pat<(brcond (setcc CPURegs:$L, CPURegs:$R, SETGE), bb:$T), + (BGEID (CMP CPURegs:$R, CPURegs:$L), bb:$T)>; +def : Pat<(brcond (setcc CPURegs:$L, CPURegs:$R, SETLE), bb:$T), + (BLEID (CMP CPURegs:$R, CPURegs:$L), bb:$T)>; +def : Pat<(brcond (setcc CPURegs:$L, CPURegs:$R, SETUGT), bb:$T), + (BGTID (CMPU CPURegs:$R, CPURegs:$L), bb:$T)>; +def : Pat<(brcond (setcc CPURegs:$L, CPURegs:$R, SETULT), bb:$T), + (BLTID (CMPU CPURegs:$R, CPURegs:$L), bb:$T)>; +def : Pat<(brcond (setcc CPURegs:$L, CPURegs:$R, SETUGE), bb:$T), + (BGEID (CMPU CPURegs:$R, CPURegs:$L), bb:$T)>; +def : Pat<(brcond (setcc CPURegs:$L, CPURegs:$R, SETULE), bb:$T), + (BLEID (CMPU CPURegs:$R, CPURegs:$L), bb:$T)>; +def : Pat<(brcond CPURegs:$C, bb:$T), + (BNEID CPURegs:$C, bb:$T)>; + +// Jump tables, global addresses, and constant pools +def : Pat<(MBWrapper tglobaladdr:$in), (ORI R0, tglobaladdr:$in)>; +def : Pat<(MBWrapper tjumptable:$in), (ORI R0, tjumptable:$in)>; +def : Pat<(MBWrapper tconstpool:$in), (ORI R0, tconstpool:$in)>; + +// Misc instructions +def : Pat<(and CPURegs:$lh, (not CPURegs:$rh)),(ANDN CPURegs:$lh, CPURegs:$rh)>; + +// Arithmetic with immediates +def : Pat<(add CPURegs:$in, imm:$imm),(ADDI CPURegs:$in, imm:$imm)>; +def : Pat<(or CPURegs:$in, imm:$imm),(ORI CPURegs:$in, imm:$imm)>; +def : Pat<(xor CPURegs:$in, imm:$imm),(XORI CPURegs:$in, imm:$imm)>; + +// extended load and stores +def : Pat<(extloadi1 iaddr:$src), (LBUI iaddr:$src)>; +def : Pat<(extloadi8 iaddr:$src), (LBUI iaddr:$src)>; +def : Pat<(extloadi16 iaddr:$src), (LHUI iaddr:$src)>; +def : Pat<(extloadi1 xaddr:$src), (LBU xaddr:$src)>; +def : Pat<(extloadi8 xaddr:$src), (LBU xaddr:$src)>; +def : Pat<(extloadi16 xaddr:$src), (LHU xaddr:$src)>; + +def : Pat<(sextloadi1 iaddr:$src), (SEXT8 (LBUI iaddr:$src))>; +def : Pat<(sextloadi8 iaddr:$src), (SEXT8 (LBUI iaddr:$src))>; +def : Pat<(sextloadi16 iaddr:$src), (SEXT16 (LHUI iaddr:$src))>; +def : Pat<(sextloadi1 xaddr:$src), (SEXT8 (LBU xaddr:$src))>; +def : Pat<(sextloadi8 xaddr:$src), (SEXT8 (LBU xaddr:$src))>; +def : Pat<(sextloadi16 xaddr:$src), (SEXT16 (LHU xaddr:$src))>; + +// peepholes +def : Pat<(store (i32 0), iaddr:$dst), (SWI R0, iaddr:$dst)>; + +//===----------------------------------------------------------------------===// +// Floating Point Support +//===----------------------------------------------------------------------===// +include "MBlazeInstrFSL.td" +include "MBlazeInstrFPU.td" diff --git a/lib/Target/MBlaze/MBlazeIntrinsicInfo.cpp b/lib/Target/MBlaze/MBlazeIntrinsicInfo.cpp new file mode 100644 index 0000000000..a01c76b367 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeIntrinsicInfo.cpp @@ -0,0 +1,101 @@ +//===- MBlazeIntrinsicInfo.cpp - Intrinsic Information -00-------*- 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 MBlaze implementation of TargetIntrinsicInfo. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeIntrinsicInfo.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/Intrinsics.h" +#include "llvm/Module.h" +#include "llvm/Type.h" +#include "llvm/Support/raw_ostream.h" +#include <cstring> + +using namespace llvm; + +namespace mblazeIntrinsic { + + enum ID { + last_non_mblaze_intrinsic = Intrinsic::num_intrinsics-1, +#define GET_INTRINSIC_ENUM_VALUES +#include "MBlazeGenIntrinsics.inc" +#undef GET_INTRINSIC_ENUM_VALUES + , num_mblaze_intrinsics + }; + +} + +std::string MBlazeIntrinsicInfo::getName(unsigned IntrID, const Type **Tys, + unsigned numTys) const { + static const char *const names[] = { +#define GET_INTRINSIC_NAME_TABLE +#include "MBlazeGenIntrinsics.inc" +#undef GET_INTRINSIC_NAME_TABLE + }; + + assert(!isOverloaded(IntrID) && "MBlaze intrinsics are not overloaded"); + if (IntrID < Intrinsic::num_intrinsics) + return 0; + assert(IntrID < mblazeIntrinsic::num_mblaze_intrinsics && + "Invalid intrinsic ID"); + + std::string Result(names[IntrID - Intrinsic::num_intrinsics]); + return Result; +} + +unsigned MBlazeIntrinsicInfo:: +lookupName(const char *Name, unsigned Len) const { +#define GET_FUNCTION_RECOGNIZER +#include "MBlazeGenIntrinsics.inc" +#undef GET_FUNCTION_RECOGNIZER + return 0; +} + +bool MBlazeIntrinsicInfo::isOverloaded(unsigned IntrID) const { + // Overload Table + const bool OTable[] = { +#define GET_INTRINSIC_OVERLOAD_TABLE +#include "MBlazeGenIntrinsics.inc" +#undef GET_INTRINSIC_OVERLOAD_TABLE + }; + if (IntrID == 0) + return false; + else + return OTable[IntrID - Intrinsic::num_intrinsics]; +} + +/// This defines the "getAttributes(ID id)" method. +#define GET_INTRINSIC_ATTRIBUTES +#include "MBlazeGenIntrinsics.inc" +#undef GET_INTRINSIC_ATTRIBUTES + +static const FunctionType *getType(LLVMContext &Context, unsigned id) { + const Type *ResultTy = NULL; + std::vector<const Type*> ArgTys; + bool IsVarArg = false; + +#define GET_INTRINSIC_GENERATOR +#include "MBlazeGenIntrinsics.inc" +#undef GET_INTRINSIC_GENERATOR + + return FunctionType::get(ResultTy, ArgTys, IsVarArg); +} + +Function *MBlazeIntrinsicInfo::getDeclaration(Module *M, unsigned IntrID, + const Type **Tys, + unsigned numTy) const { + assert(!isOverloaded(IntrID) && "MBlaze intrinsics are not overloaded"); + AttrListPtr AList = getAttributes((mblazeIntrinsic::ID) IntrID); + return cast<Function>(M->getOrInsertFunction(getName(IntrID), + getType(M->getContext(), IntrID), + AList)); +} diff --git a/lib/Target/MBlaze/MBlazeIntrinsicInfo.h b/lib/Target/MBlaze/MBlazeIntrinsicInfo.h new file mode 100644 index 0000000000..f40d425827 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeIntrinsicInfo.h @@ -0,0 +1,32 @@ +//===- MBlazeIntrinsicInfo.h - MBlaze Intrinsic 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 MBlaze implementation of TargetIntrinsicInfo. +// +//===----------------------------------------------------------------------===// +#ifndef MBLAZEINTRINSICS_H +#define MBLAZEINTRINSICS_H + +#include "llvm/Target/TargetIntrinsicInfo.h" + +namespace llvm { + + class MBlazeIntrinsicInfo : public TargetIntrinsicInfo { + public: + std::string getName(unsigned IntrID, const Type **Tys = 0, + unsigned numTys = 0) const; + unsigned lookupName(const char *Name, unsigned Len) const; + bool isOverloaded(unsigned IID) const; + Function *getDeclaration(Module *M, unsigned ID, const Type **Tys = 0, + unsigned numTys = 0) const; + }; + +} + +#endif diff --git a/lib/Target/MBlaze/MBlazeIntrinsics.td b/lib/Target/MBlaze/MBlazeIntrinsics.td new file mode 100644 index 0000000000..76eb56367a --- /dev/null +++ b/lib/Target/MBlaze/MBlazeIntrinsics.td @@ -0,0 +1,137 @@ +//===- IntrinsicsMBlaze.td - Defines MBlaze intrinsics -----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines all of the MicroBlaze-specific intrinsics. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Definitions for all MBlaze intrinsics. +// + +// MBlaze intrinsic classes. +let TargetPrefix = "mblaze", isTarget = 1 in { + class MBFSL_Get_Intrinsic : Intrinsic<[llvm_i32_ty], + [llvm_i32_ty], + [IntrWriteMem]>; + + class MBFSL_Put_Intrinsic : Intrinsic<[llvm_void_ty], + [llvm_i32_ty, llvm_i32_ty], + [IntrWriteMem]>; + + class MBFSL_PutT_Intrinsic : Intrinsic<[llvm_void_ty], + [llvm_i32_ty], + [IntrWriteMem]>; +} + +//===----------------------------------------------------------------------===// +// MicroBlaze FSL Get Intrinsic Definitions. +// + +def int_mblaze_fsl_get : GCCBuiltin<"__builtin_mblaze_fsl_get">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_aget : GCCBuiltin<"__builtin_mblaze_fsl_aget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_cget : GCCBuiltin<"__builtin_mblaze_fsl_cget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_caget : GCCBuiltin<"__builtin_mblaze_fsl_caget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_eget : GCCBuiltin<"__builtin_mblaze_fsl_eget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_eaget : GCCBuiltin<"__builtin_mblaze_fsl_eaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_ecget : GCCBuiltin<"__builtin_mblaze_fsl_ecget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_ecaget : GCCBuiltin<"__builtin_mblaze_fsl_ecaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_nget : GCCBuiltin<"__builtin_mblaze_fsl_nget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_naget : GCCBuiltin<"__builtin_mblaze_fsl_naget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_ncget : GCCBuiltin<"__builtin_mblaze_fsl_ncget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_ncaget : GCCBuiltin<"__builtin_mblaze_fsl_ncaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_neget : GCCBuiltin<"__builtin_mblaze_fsl_neget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_neaget : GCCBuiltin<"__builtin_mblaze_fsl_neaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_necget : GCCBuiltin<"__builtin_mblaze_fsl_necget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_necaget : GCCBuiltin<"__builtin_mblaze_fsl_necaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tget : GCCBuiltin<"__builtin_mblaze_fsl_tget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_taget : GCCBuiltin<"__builtin_mblaze_fsl_taget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tcget : GCCBuiltin<"__builtin_mblaze_fsl_tcget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tcaget : GCCBuiltin<"__builtin_mblaze_fsl_tcaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_teget : GCCBuiltin<"__builtin_mblaze_fsl_teget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_teaget : GCCBuiltin<"__builtin_mblaze_fsl_teaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tecget : GCCBuiltin<"__builtin_mblaze_fsl_tecget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tecaget : GCCBuiltin<"__builtin_mblaze_fsl_tecaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tnget : GCCBuiltin<"__builtin_mblaze_fsl_tnget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tnaget : GCCBuiltin<"__builtin_mblaze_fsl_tnaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tncget : GCCBuiltin<"__builtin_mblaze_fsl_tncget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tncaget : GCCBuiltin<"__builtin_mblaze_fsl_tncaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tneget : GCCBuiltin<"__builtin_mblaze_fsl_tneget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tneaget : GCCBuiltin<"__builtin_mblaze_fsl_tneaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tnecget : GCCBuiltin<"__builtin_mblaze_fsl_tnecget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tnecaget : GCCBuiltin<"__builtin_mblaze_fsl_tnecaget">, + MBFSL_Get_Intrinsic; + +//===----------------------------------------------------------------------===// +// MicroBlaze FSL Put Intrinsic Definitions. +// + +def int_mblaze_fsl_put : GCCBuiltin<"__builtin_mblaze_fsl_put">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_aput : GCCBuiltin<"__builtin_mblaze_fsl_aput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_cput : GCCBuiltin<"__builtin_mblaze_fsl_cput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_caput : GCCBuiltin<"__builtin_mblaze_fsl_caput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_nput : GCCBuiltin<"__builtin_mblaze_fsl_nput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_naput : GCCBuiltin<"__builtin_mblaze_fsl_naput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_ncput : GCCBuiltin<"__builtin_mblaze_fsl_ncput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_ncaput : GCCBuiltin<"__builtin_mblaze_fsl_ncaput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_tput : GCCBuiltin<"__builtin_mblaze_fsl_tput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_taput : GCCBuiltin<"__builtin_mblaze_fsl_taput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_tcput : GCCBuiltin<"__builtin_mblaze_fsl_tcput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_tcaput : GCCBuiltin<"__builtin_mblaze_fsl_tcaput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_tnput : GCCBuiltin<"__builtin_mblaze_fsl_tnput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_tnaput : GCCBuiltin<"__builtin_mblaze_fsl_tnaput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_tncput : GCCBuiltin<"__builtin_mblaze_fsl_tncput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_tncaput : GCCBuiltin<"__builtin_mblaze_fsl_tncaput">, + MBFSL_PutT_Intrinsic; diff --git a/lib/Target/MBlaze/MBlazeMCAsmInfo.cpp b/lib/Target/MBlaze/MBlazeMCAsmInfo.cpp new file mode 100644 index 0000000000..7ae465dbc5 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeMCAsmInfo.cpp @@ -0,0 +1,27 @@ +//===-- MBlazeMCAsmInfo.cpp - MBlaze asm properties -----------------------===// +// +// 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 MBlazeMCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeMCAsmInfo.h" +using namespace llvm; + +MBlazeMCAsmInfo::MBlazeMCAsmInfo(const Target &T, const StringRef &TT) { + AlignmentIsInBytes = false; + Data16bitsDirective = "\t.half\t"; + Data32bitsDirective = "\t.word\t"; + Data64bitsDirective = 0; + PrivateGlobalPrefix = "$"; + CommentString = "#"; + ZeroDirective = "\t.space\t"; + GPRel32Directive = "\t.gpword\t"; + HasSetDirective = false; +} diff --git a/lib/Target/MBlaze/MBlazeMCAsmInfo.h b/lib/Target/MBlaze/MBlazeMCAsmInfo.h new file mode 100644 index 0000000000..bccb418673 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeMCAsmInfo.h @@ -0,0 +1,30 @@ +//=====-- MBlazeMCAsmInfo.h - MBlaze 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 MBlazeMCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZETARGETASMINFO_H +#define MBLAZETARGETASMINFO_H + +#include "llvm/MC/MCAsmInfo.h" + +namespace llvm { + class Target; + class StringRef; + + class MBlazeMCAsmInfo : public MCAsmInfo { + public: + explicit MBlazeMCAsmInfo(const Target &T, const StringRef &TT); + }; + +} // namespace llvm + +#endif diff --git a/lib/Target/MBlaze/MBlazeMachineFunction.h b/lib/Target/MBlaze/MBlazeMachineFunction.h new file mode 100644 index 0000000000..a89ba13f72 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeMachineFunction.h @@ -0,0 +1,140 @@ +//===-- MBlazeMachineFunctionInfo.h - Private data ----------------*- 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 MBlaze specific subclass of MachineFunctionInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZE_MACHINE_FUNCTION_INFO_H +#define MBLAZE_MACHINE_FUNCTION_INFO_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/VectorExtras.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" + +namespace llvm { + +/// MBlazeFunctionInfo - This class is derived from MachineFunction private +/// MBlaze target-specific information for each MachineFunction. +class MBlazeFunctionInfo : public MachineFunctionInfo { + +private: + /// Holds for each function where on the stack the Frame Pointer must be + /// saved. This is used on Prologue and Epilogue to emit FP save/restore + int FPStackOffset; + + /// Holds for each function where on the stack the Return Address must be + /// saved. This is used on Prologue and Epilogue to emit RA save/restore + int RAStackOffset; + + /// At each function entry, two special bitmask directives must be emitted + /// to help debugging, for CPU and FPU callee saved registers. Both need + /// the negative offset from the final stack size and its higher registers + /// location on the stack. + int CPUTopSavedRegOff; + int FPUTopSavedRegOff; + + /// MBlazeFIHolder - Holds a FrameIndex and it's Stack Pointer Offset + struct MBlazeFIHolder { + + int FI; + int SPOffset; + + MBlazeFIHolder(int FrameIndex, int StackPointerOffset) + : FI(FrameIndex), SPOffset(StackPointerOffset) {} + }; + + /// When PIC is used the GP must be saved on the stack on the function + /// prologue and must be reloaded from this stack location after every + /// call. A reference to its stack location and frame index must be kept + /// to be used on emitPrologue and processFunctionBeforeFrameFinalized. + MBlazeFIHolder GPHolder; + + /// On LowerFormalArguments the stack size is unknown, so the Stack + /// Pointer Offset calculation of "not in register arguments" must be + /// postponed to emitPrologue. + SmallVector<MBlazeFIHolder, 16> FnLoadArgs; + bool HasLoadArgs; + + // When VarArgs, we must write registers back to caller stack, preserving + // on register arguments. Since the stack size is unknown on + // LowerFormalArguments, the Stack Pointer Offset calculation must be + // postponed to emitPrologue. + SmallVector<MBlazeFIHolder, 4> FnStoreVarArgs; + bool HasStoreVarArgs; + + /// SRetReturnReg - Some subtargets require that sret lowering includes + /// returning the value of the returned struct in a register. This field + /// holds the virtual register into which the sret argument is passed. + unsigned SRetReturnReg; + + /// GlobalBaseReg - keeps track of the virtual register initialized for + /// use as the global base register. This is used for PIC in some PIC + /// relocation models. + unsigned GlobalBaseReg; + +public: + MBlazeFunctionInfo(MachineFunction& MF) + : FPStackOffset(0), RAStackOffset(0), CPUTopSavedRegOff(0), + FPUTopSavedRegOff(0), GPHolder(-1,-1), HasLoadArgs(false), + HasStoreVarArgs(false), SRetReturnReg(0), GlobalBaseReg(0) + {} + + int getFPStackOffset() const { return FPStackOffset; } + void setFPStackOffset(int Off) { FPStackOffset = Off; } + + int getRAStackOffset() const { return RAStackOffset; } + void setRAStackOffset(int Off) { RAStackOffset = Off; } + + int getCPUTopSavedRegOff() const { return CPUTopSavedRegOff; } + void setCPUTopSavedRegOff(int Off) { CPUTopSavedRegOff = Off; } + + int getFPUTopSavedRegOff() const { return FPUTopSavedRegOff; } + void setFPUTopSavedRegOff(int Off) { FPUTopSavedRegOff = Off; } + + int getGPStackOffset() const { return GPHolder.SPOffset; } + int getGPFI() const { return GPHolder.FI; } + void setGPStackOffset(int Off) { GPHolder.SPOffset = Off; } + void setGPFI(int FI) { GPHolder.FI = FI; } + bool needGPSaveRestore() const { return GPHolder.SPOffset != -1; } + + bool hasLoadArgs() const { return HasLoadArgs; } + bool hasStoreVarArgs() const { return HasStoreVarArgs; } + + void recordLoadArgsFI(int FI, int SPOffset) { + if (!HasLoadArgs) HasLoadArgs=true; + FnLoadArgs.push_back(MBlazeFIHolder(FI, SPOffset)); + } + void recordStoreVarArgsFI(int FI, int SPOffset) { + if (!HasStoreVarArgs) HasStoreVarArgs=true; + FnStoreVarArgs.push_back(MBlazeFIHolder(FI, SPOffset)); + } + + void adjustLoadArgsFI(MachineFrameInfo *MFI) const { + if (!hasLoadArgs()) return; + for (unsigned i = 0, e = FnLoadArgs.size(); i != e; ++i) + MFI->setObjectOffset( FnLoadArgs[i].FI, FnLoadArgs[i].SPOffset ); + } + void adjustStoreVarArgsFI(MachineFrameInfo *MFI) const { + if (!hasStoreVarArgs()) return; + for (unsigned i = 0, e = FnStoreVarArgs.size(); i != e; ++i) + MFI->setObjectOffset( FnStoreVarArgs[i].FI, FnStoreVarArgs[i].SPOffset ); + } + + unsigned getSRetReturnReg() const { return SRetReturnReg; } + void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; } + + unsigned getGlobalBaseReg() const { return GlobalBaseReg; } + void setGlobalBaseReg(unsigned Reg) { GlobalBaseReg = Reg; } +}; + +} // end of namespace llvm + +#endif // MBLAZE_MACHINE_FUNCTION_INFO_H diff --git a/lib/Target/MBlaze/MBlazeRegisterInfo.cpp b/lib/Target/MBlaze/MBlazeRegisterInfo.cpp new file mode 100644 index 0000000000..b8d2349333 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeRegisterInfo.cpp @@ -0,0 +1,378 @@ +//===- MBlazeRegisterInfo.cpp - MBlaze 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 MBlaze implementation of the TargetRegisterInfo +// class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mblaze-reg-info" + +#include "MBlaze.h" +#include "MBlazeSubtarget.h" +#include "MBlazeRegisterInfo.h" +#include "MBlazeMachineFunction.h" +#include "llvm/Constants.h" +#include "llvm/Type.h" +#include "llvm/Function.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineLocation.h" +#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" + +using namespace llvm; + +MBlazeRegisterInfo:: +MBlazeRegisterInfo(const MBlazeSubtarget &ST, const TargetInstrInfo &tii) + : MBlazeGenRegisterInfo(MBlaze::ADJCALLSTACKDOWN, MBlaze::ADJCALLSTACKUP), + Subtarget(ST), TII(tii) {} + +/// getRegisterNumbering - Given the enum value for some register, e.g. +/// MBlaze::R0, return the number that it corresponds to (e.g. 0). +unsigned MBlazeRegisterInfo::getRegisterNumbering(unsigned RegEnum) { + switch (RegEnum) { + case MBlaze::R0 : case MBlaze::F0 : return 0; + case MBlaze::R1 : case MBlaze::F1 : return 1; + case MBlaze::R2 : case MBlaze::F2 : return 2; + case MBlaze::R3 : case MBlaze::F3 : return 3; + case MBlaze::R4 : case MBlaze::F4 : return 4; + case MBlaze::R5 : case MBlaze::F5 : return 5; + case MBlaze::R6 : case MBlaze::F6 : return 6; + case MBlaze::R7 : case MBlaze::F7 : return 7; + case MBlaze::R8 : case MBlaze::F8 : return 8; + case MBlaze::R9 : case MBlaze::F9 : return 9; + case MBlaze::R10 : case MBlaze::F10 : return 10; + case MBlaze::R11 : case MBlaze::F11 : return 11; + case MBlaze::R12 : case MBlaze::F12 : return 12; + case MBlaze::R13 : case MBlaze::F13 : return 13; + case MBlaze::R14 : case MBlaze::F14 : return 14; + case MBlaze::R15 : case MBlaze::F15 : return 15; + case MBlaze::R16 : case MBlaze::F16 : return 16; + case MBlaze::R17 : case MBlaze::F17 : return 17; + case MBlaze::R18 : case MBlaze::F18 : return 18; + case MBlaze::R19 : case MBlaze::F19 : return 19; + case MBlaze::R20 : case MBlaze::F20 : return 20; + case MBlaze::R21 : case MBlaze::F21 : return 21; + case MBlaze::R22 : case MBlaze::F22 : return 22; + case MBlaze::R23 : case MBlaze::F23 : return 23; + case MBlaze::R24 : case MBlaze::F24 : return 24; + case MBlaze::R25 : case MBlaze::F25 : return 25; + case MBlaze::R26 : case MBlaze::F26 : return 26; + case MBlaze::R27 : case MBlaze::F27 : return 27; + case MBlaze::R28 : case MBlaze::F28 : return 28; + case MBlaze::R29 : case MBlaze::F29 : return 29; + case MBlaze::R30 : case MBlaze::F30 : return 30; + case MBlaze::R31 : case MBlaze::F31 : return 31; + default: llvm_unreachable("Unknown register number!"); + } + return 0; // Not reached +} + +unsigned MBlazeRegisterInfo::getPICCallReg() { + return MBlaze::R20; +} + +//===----------------------------------------------------------------------===// +// Callee Saved Registers methods +//===----------------------------------------------------------------------===// + +/// MBlaze Callee Saved Registers +const unsigned* MBlazeRegisterInfo:: +getCalleeSavedRegs(const MachineFunction *MF) const { + // MBlaze callee-save register range is R19 - R31 + static const unsigned CalleeSavedRegs[] = { + MBlaze::R20, MBlaze::R21, MBlaze::R22, MBlaze::R23, + MBlaze::R24, MBlaze::R25, MBlaze::R26, MBlaze::R27, + MBlaze::R28, MBlaze::R29, MBlaze::R30, MBlaze::R31, + 0 + }; + + return CalleeSavedRegs; +} + +/// MBlaze Callee Saved Register Classes +const TargetRegisterClass* const* MBlazeRegisterInfo:: +getCalleeSavedRegClasses(const MachineFunction *MF) const { + static const TargetRegisterClass * const CalleeSavedRC[] = { + &MBlaze::CPURegsRegClass, &MBlaze::CPURegsRegClass, + &MBlaze::CPURegsRegClass, &MBlaze::CPURegsRegClass, + &MBlaze::CPURegsRegClass, &MBlaze::CPURegsRegClass, + &MBlaze::CPURegsRegClass, &MBlaze::CPURegsRegClass, + &MBlaze::CPURegsRegClass, &MBlaze::CPURegsRegClass, + &MBlaze::CPURegsRegClass, &MBlaze::CPURegsRegClass, + 0 + }; + + return CalleeSavedRC; +} + +BitVector MBlazeRegisterInfo:: +getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + Reserved.set(MBlaze::R0); + Reserved.set(MBlaze::R1); + Reserved.set(MBlaze::R2); + Reserved.set(MBlaze::R13); + Reserved.set(MBlaze::R14); + Reserved.set(MBlaze::R15); + Reserved.set(MBlaze::R16); + Reserved.set(MBlaze::R17); + Reserved.set(MBlaze::R18); + Reserved.set(MBlaze::R19); + return Reserved; +} + +//===----------------------------------------------------------------------===// +// +// Stack Frame Processing methods +// +----------------------------+ +// +// The stack is allocated decrementing the stack pointer on +// the first instruction of a function prologue. Once decremented, +// all stack references are are done through a positive offset +// from the stack/frame pointer, so the stack is considered +// to grow up. +// +//===----------------------------------------------------------------------===// + +void MBlazeRegisterInfo::adjustMBlazeStackFrame(MachineFunction &MF) const { + MachineFrameInfo *MFI = MF.getFrameInfo(); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + + // See the description at MicroBlazeMachineFunction.h + int TopCPUSavedRegOff = -1; + + // Adjust CPU Callee Saved Registers Area. Registers RA and FP must + // be saved in this CPU Area there is the need. This whole Area must + // be aligned to the default Stack Alignment requirements. + unsigned StackOffset = MFI->getStackSize(); + unsigned RegSize = 4; + + // Replace the dummy '0' SPOffset by the negative offsets, as explained on + // LowerFORMAL_ARGUMENTS. Leaving '0' for while is necessary to avoid + // the approach done by calculateFrameObjectOffsets to the stack frame. + MBlazeFI->adjustLoadArgsFI(MFI); + MBlazeFI->adjustStoreVarArgsFI(MFI); + + if (hasFP(MF)) { + MFI->setObjectOffset(MFI->CreateStackObject(RegSize, RegSize, true), + StackOffset); + MBlazeFI->setFPStackOffset(StackOffset); + TopCPUSavedRegOff = StackOffset; + StackOffset += RegSize; + } + + if (MFI->hasCalls()) { + MFI->setObjectOffset(MFI->CreateStackObject(RegSize, RegSize, true), + StackOffset); + MBlazeFI->setRAStackOffset(StackOffset); + TopCPUSavedRegOff = StackOffset; + StackOffset += RegSize; + } + + // Update frame info + MFI->setStackSize(StackOffset); + + // Recalculate the final tops offset. The final values must be '0' + // if there isn't a callee saved register for CPU or FPU, otherwise + // a negative offset is needed. + if (TopCPUSavedRegOff >= 0) + MBlazeFI->setCPUTopSavedRegOff(TopCPUSavedRegOff-StackOffset); +} + +// 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 MBlazeRegisterInfo::hasFP(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + return NoFramePointerElim || MFI->hasVarSizedObjects(); +} + +// This function eliminate ADJCALLSTACKDOWN, +// ADJCALLSTACKUP pseudo instructions +void MBlazeRegisterInfo:: +eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + // Simply discard ADJCALLSTACKDOWN, ADJCALLSTACKUP instructions. + MBB.erase(I); +} + +// FrameIndex represent objects inside a abstract stack. +// We must replace FrameIndex with an stack/frame pointer +// direct reference. +unsigned MBlazeRegisterInfo:: +eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, + int *Value, RegScavenger *RS) const { + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + + unsigned i = 0; + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && + "Instr doesn't have FrameIndex operand!"); + } + + unsigned oi = i == 2 ? 1 : 2; + + DEBUG(errs() << "\nFunction : " << MF.getFunction()->getName() << "\n"; + errs() << "<--------->\n" << MI); + + int FrameIndex = MI.getOperand(i).getIndex(); + int stackSize = MF.getFrameInfo()->getStackSize(); + int spOffset = MF.getFrameInfo()->getObjectOffset(FrameIndex); + + DEBUG(errs() << "FrameIndex : " << FrameIndex << "\n" + << "spOffset : " << spOffset << "\n" + << "stackSize : " << stackSize << "\n"); + + // as explained on LowerFormalArguments, detect negative offsets + // and adjust SPOffsets considering the final stack size. + int Offset = ((spOffset < 0) ? (stackSize + (-(spOffset+4))) : (spOffset)); + Offset += MI.getOperand(oi).getImm(); + + DEBUG(errs() << "Offset : " << Offset << "\n" << "<--------->\n"); + + MI.getOperand(oi).ChangeToImmediate(Offset); + MI.getOperand(i).ChangeToRegister(getFrameRegister(MF), false); + return 0; +} + +void MBlazeRegisterInfo:: +emitPrologue(MachineFunction &MF) const { + MachineBasicBlock &MBB = MF.front(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + MachineBasicBlock::iterator MBBI = MBB.begin(); + DebugLoc dl = (MBBI != MBB.end() ? + MBBI->getDebugLoc() : DebugLoc::getUnknownLoc()); + + // Get the right frame order for MBlaze. + adjustMBlazeStackFrame(MF); + + // Get the number of bytes to allocate from the FrameInfo. + unsigned StackSize = MFI->getStackSize(); + + // No need to allocate space on the stack. + if (StackSize == 0 && !MFI->hasCalls()) return; + + int FPOffset = MBlazeFI->getFPStackOffset(); + int RAOffset = MBlazeFI->getRAStackOffset(); + + // Adjust stack : addi R1, R1, -imm + BuildMI(MBB, MBBI, dl, TII.get(MBlaze::ADDI), MBlaze::R1) + .addReg(MBlaze::R1).addImm(-StackSize); + + // Save the return address only if the function isnt a leaf one. + // swi R15, R1, stack_loc + if (MFI->hasCalls()) { + BuildMI(MBB, MBBI, dl, TII.get(MBlaze::SWI)) + .addReg(MBlaze::R15).addImm(RAOffset).addReg(MBlaze::R1); + } + + // if framepointer enabled, save it and set it + // to point to the stack pointer + if (hasFP(MF)) { + // swi R19, R1, stack_loc + BuildMI(MBB, MBBI, dl, TII.get(MBlaze::SWI)) + .addReg(MBlaze::R19).addImm(FPOffset).addReg(MBlaze::R1); + + // add R19, R1, R0 + BuildMI(MBB, MBBI, dl, TII.get(MBlaze::ADD), MBlaze::R19) + .addReg(MBlaze::R1).addReg(MBlaze::R0); + } +} + +void MBlazeRegisterInfo:: +emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator MBBI = prior(MBB.end()); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + DebugLoc dl = MBBI->getDebugLoc(); + + // Get the number of bytes from FrameInfo + int NumBytes = (int) MFI->getStackSize(); + + // Get the FI's where RA and FP are saved. + int FPOffset = MBlazeFI->getFPStackOffset(); + int RAOffset = MBlazeFI->getRAStackOffset(); + + // if framepointer enabled, restore it and restore the + // stack pointer + if (hasFP(MF)) { + // add R1, R19, R0 + BuildMI(MBB, MBBI, dl, TII.get(MBlaze::ADD), MBlaze::R1) + .addReg(MBlaze::R19).addReg(MBlaze::R0); + + // lwi R19, R1, stack_loc + BuildMI(MBB, MBBI, dl, TII.get(MBlaze::LWI), MBlaze::R19) + .addImm(FPOffset).addReg(MBlaze::R1); + } + + // Restore the return address only if the function isnt a leaf one. + // lwi R15, R1, stack_loc + if (MFI->hasCalls()) { + BuildMI(MBB, MBBI, dl, TII.get(MBlaze::LWI), MBlaze::R15) + .addImm(RAOffset).addReg(MBlaze::R1); + } + + // adjust stack. + // addi R1, R1, imm + if (NumBytes) { + BuildMI(MBB, MBBI, dl, TII.get(MBlaze::ADDI), MBlaze::R1) + .addReg(MBlaze::R1).addImm(NumBytes); + } +} + + +void MBlazeRegisterInfo:: +processFunctionBeforeFrameFinalized(MachineFunction &MF) const { + // Set the stack offset where GP must be saved/loaded from. + MachineFrameInfo *MFI = MF.getFrameInfo(); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + if (MBlazeFI->needGPSaveRestore()) + MFI->setObjectOffset(MBlazeFI->getGPFI(), MBlazeFI->getGPStackOffset()); +} + +unsigned MBlazeRegisterInfo::getRARegister() const { + return MBlaze::R15; +} + +unsigned MBlazeRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + return hasFP(MF) ? MBlaze::R19 : MBlaze::R1; +} + +unsigned MBlazeRegisterInfo::getEHExceptionRegister() const { + llvm_unreachable("What is the exception register"); + return 0; +} + +unsigned MBlazeRegisterInfo::getEHHandlerRegister() const { + llvm_unreachable("What is the exception handler register"); + return 0; +} + +int MBlazeRegisterInfo::getDwarfRegNum(unsigned RegNum, bool isEH) const { + llvm_unreachable("What is the dwarf register number"); + return -1; +} + +#include "MBlazeGenRegisterInfo.inc" + diff --git a/lib/Target/MBlaze/MBlazeRegisterInfo.h b/lib/Target/MBlaze/MBlazeRegisterInfo.h new file mode 100644 index 0000000000..4847f1ed52 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeRegisterInfo.h @@ -0,0 +1,90 @@ +//===- MBlazeRegisterInfo.h - MBlaze Register Information Impl --*- 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 MBlaze implementation of the TargetRegisterInfo +// class. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZEREGISTERINFO_H +#define MBLAZEREGISTERINFO_H + +#include "MBlaze.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "MBlazeGenRegisterInfo.h.inc" + +namespace llvm { +class MBlazeSubtarget; +class TargetInstrInfo; +class Type; + +namespace MBlaze { + /// SubregIndex - The index of various sized subregister classes. Note that + /// these indices must be kept in sync with the class indices in the + /// MBlazeRegisterInfo.td file. + enum SubregIndex { + SUBREG_FPEVEN = 1, SUBREG_FPODD = 2 + }; +} + +struct MBlazeRegisterInfo : public MBlazeGenRegisterInfo { + const MBlazeSubtarget &Subtarget; + const TargetInstrInfo &TII; + + MBlazeRegisterInfo(const MBlazeSubtarget &Subtarget, + const TargetInstrInfo &tii); + + /// getRegisterNumbering - Given the enum value for some register, e.g. + /// MBlaze::RA, return the number that it corresponds to (e.g. 31). + static unsigned getRegisterNumbering(unsigned RegEnum); + + /// Get PIC indirect call register + static unsigned getPICCallReg(); + + /// Adjust the MBlaze stack frame. + void adjustMBlazeStackFrame(MachineFunction &MF) const; + + /// 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; + + bool hasFP(const MachineFunction &MF) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + /// Stack Frame Processing Methods + unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, int *Value = NULL, + RegScavenger *RS = NULL) const; + + void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; + + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + + /// Debug information queries. + unsigned getRARegister() const; + unsigned getFrameRegister(const MachineFunction &MF) const; + + /// Exception handling queries. + unsigned getEHExceptionRegister() const; + unsigned getEHHandlerRegister() const; + + int getDwarfRegNum(unsigned RegNum, bool isEH) const; +}; + +} // end namespace llvm + +#endif diff --git a/lib/Target/MBlaze/MBlazeRegisterInfo.td b/lib/Target/MBlaze/MBlazeRegisterInfo.td new file mode 100644 index 0000000000..96a5c98019 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeRegisterInfo.td @@ -0,0 +1,186 @@ +//===- MBlazeRegisterInfo.td - MBlaze Register defs -------------*- C++ -*-===// +// +// 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 MicroBlaze register file +//===----------------------------------------------------------------------===// + +// We have banks of 32 registers each. +class MBlazeReg<string n> : Register<n> { + field bits<5> Num; + let Namespace = "MBlaze"; +} + +class MBlazeRegWithSubRegs<string n, list<Register> subregs> + : RegisterWithSubRegs<n, subregs> { + field bits<5> Num; + let Namespace = "MBlaze"; +} + +// MBlaze CPU Registers +class MBlazeGPRReg<bits<5> num, string n> : MBlazeReg<n> { + let Num = num; +} + +// MBlaze 32-bit (aliased) FPU Registers +class FPR<bits<5> num, string n, list<Register> subregs> + : MBlazeRegWithSubRegs<n, subregs> { + let Num = num; +} + +//===----------------------------------------------------------------------===// +// Registers +//===----------------------------------------------------------------------===// + +let Namespace = "MBlaze" in { + + // General Purpose Registers + def R0 : MBlazeGPRReg< 0, "r0">, DwarfRegNum<[0]>; + def R1 : MBlazeGPRReg< 1, "r1">, DwarfRegNum<[1]>; + def R2 : MBlazeGPRReg< 2, "r2">, DwarfRegNum<[2]>; + def R3 : MBlazeGPRReg< 3, "r3">, DwarfRegNum<[3]>; + def R4 : MBlazeGPRReg< 4, "r4">, DwarfRegNum<[5]>; + def R5 : MBlazeGPRReg< 5, "r5">, DwarfRegNum<[5]>; + def R6 : MBlazeGPRReg< 6, "r6">, DwarfRegNum<[6]>; + def R7 : MBlazeGPRReg< 7, "r7">, DwarfRegNum<[7]>; + def R8 : MBlazeGPRReg< 8, "r8">, DwarfRegNum<[8]>; + def R9 : MBlazeGPRReg< 9, "r9">, DwarfRegNum<[9]>; + def R10 : MBlazeGPRReg< 10, "r10">, DwarfRegNum<[10]>; + def R11 : MBlazeGPRReg< 11, "r11">, DwarfRegNum<[11]>; + def R12 : MBlazeGPRReg< 12, "r12">, DwarfRegNum<[12]>; + def R13 : MBlazeGPRReg< 13, "r13">, DwarfRegNum<[13]>; + def R14 : MBlazeGPRReg< 14, "r14">, DwarfRegNum<[14]>; + def R15 : MBlazeGPRReg< 15, "r15">, DwarfRegNum<[15]>; + def R16 : MBlazeGPRReg< 16, "r16">, DwarfRegNum<[16]>; + def R17 : MBlazeGPRReg< 17, "r17">, DwarfRegNum<[17]>; + def R18 : MBlazeGPRReg< 18, "r18">, DwarfRegNum<[18]>; + def R19 : MBlazeGPRReg< 19, "r19">, DwarfRegNum<[19]>; + def R20 : MBlazeGPRReg< 20, "r20">, DwarfRegNum<[20]>; + def R21 : MBlazeGPRReg< 21, "r21">, DwarfRegNum<[21]>; + def R22 : MBlazeGPRReg< 22, "r22">, DwarfRegNum<[22]>; + def R23 : MBlazeGPRReg< 23, "r23">, DwarfRegNum<[23]>; + def R24 : MBlazeGPRReg< 24, "r24">, DwarfRegNum<[24]>; + def R25 : MBlazeGPRReg< 25, "r25">, DwarfRegNum<[25]>; + def R26 : MBlazeGPRReg< 26, "r26">, DwarfRegNum<[26]>; + def R27 : MBlazeGPRReg< 27, "r27">, DwarfRegNum<[27]>; + def R28 : MBlazeGPRReg< 28, "r28">, DwarfRegNum<[28]>; + def R29 : MBlazeGPRReg< 29, "r29">, DwarfRegNum<[29]>; + def R30 : MBlazeGPRReg< 30, "r30">, DwarfRegNum<[30]>; + def R31 : MBlazeGPRReg< 31, "r31">, DwarfRegNum<[31]>; + + /// MBlaze Single point precision FPU Registers + def F0 : FPR< 0, "r0", [R0]>, DwarfRegNum<[32]>; + def F1 : FPR< 1, "r1", [R1]>, DwarfRegNum<[33]>; + def F2 : FPR< 2, "r2", [R2]>, DwarfRegNum<[34]>; + def F3 : FPR< 3, "r3", [R3]>, DwarfRegNum<[35]>; + def F4 : FPR< 4, "r4", [R4]>, DwarfRegNum<[36]>; + def F5 : FPR< 5, "r5", [R5]>, DwarfRegNum<[37]>; + def F6 : FPR< 6, "r6", [R6]>, DwarfRegNum<[38]>; + def F7 : FPR< 7, "r7", [R7]>, DwarfRegNum<[39]>; + def F8 : FPR< 8, "r8", [R8]>, DwarfRegNum<[40]>; + def F9 : FPR< 9, "r9", [R9]>, DwarfRegNum<[41]>; + def F10 : FPR<10, "r10", [R10]>, DwarfRegNum<[42]>; + def F11 : FPR<11, "r11", [R11]>, DwarfRegNum<[43]>; + def F12 : FPR<12, "r12", [R12]>, DwarfRegNum<[44]>; + def F13 : FPR<13, "r13", [R13]>, DwarfRegNum<[45]>; + def F14 : FPR<14, "r14", [R14]>, DwarfRegNum<[46]>; + def F15 : FPR<15, "r15", [R15]>, DwarfRegNum<[47]>; + def F16 : FPR<16, "r16", [R16]>, DwarfRegNum<[48]>; + def F17 : FPR<17, "r17", [R17]>, DwarfRegNum<[49]>; + def F18 : FPR<18, "r18", [R18]>, DwarfRegNum<[50]>; + def F19 : FPR<19, "r19", [R19]>, DwarfRegNum<[51]>; + def F20 : FPR<20, "r20", [R20]>, DwarfRegNum<[52]>; + def F21 : FPR<21, "r21", [R21]>, DwarfRegNum<[53]>; + def F22 : FPR<22, "r22", [R22]>, DwarfRegNum<[54]>; + def F23 : FPR<23, "r23", [R23]>, DwarfRegNum<[55]>; + def F24 : FPR<24, "r24", [R24]>, DwarfRegNum<[56]>; + def F25 : FPR<25, "r25", [R25]>, DwarfRegNum<[57]>; + def F26 : FPR<26, "r26", [R26]>, DwarfRegNum<[58]>; + def F27 : FPR<27, "r27", [R27]>, DwarfRegNum<[59]>; + def F28 : FPR<28, "r28", [R28]>, DwarfRegNum<[60]>; + def F29 : FPR<29, "r29", [R29]>, DwarfRegNum<[61]>; + def F30 : FPR<30, "r30", [R30]>, DwarfRegNum<[62]>; + def F31 : FPR<31, "r31", [R31]>, DwarfRegNum<[63]>; +} + +//===----------------------------------------------------------------------===// +// Register Classes +//===----------------------------------------------------------------------===// + +def CPURegs : RegisterClass<"MBlaze", [i32], 32, + [ + // Return Values and Arguments + R3, R4, R5, R6, R7, R8, R9, R10, + + // Not preserved across procedure calls + R11, R12, + + // Callee save + R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, R30, R31, + + // Reserved + R0, // Always zero + R1, // The stack pointer + R2, // Read-only small data area anchor + R13, // Read-write small data area anchor + R14, // Return address for interrupts + R15, // Return address for sub-routines + R16, // Return address for trap + R17, // Return address for exceptions + R18, // Reserved for assembler + R19 // The frame-pointer + ]> +{ + let MethodProtos = [{ + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + CPURegsClass::iterator + CPURegsClass::allocation_order_end(const MachineFunction &MF) const { + // The last 10 registers on the list above are reserved + return end()-10; + } + }]; +} + +def FGR32 : RegisterClass<"MBlaze", [f32], 32, + [ + // Return Values and Arguments + F3, F4, F5, F6, F7, F8, F9, F10, + + // Not preserved across procedure calls + F11, F12, + + // Callee save + F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31, + + // Reserved + F0, // Always zero + F1, // The stack pointer + F2, // Read-only small data area anchor + F13, // Read-write small data area anchor + F14, // Return address for interrupts + F15, // Return address for sub-routines + F16, // Return address for trap + F17, // Return address for exceptions + F18, // Reserved for assembler + F19 // The frame pointer + ]> +{ + let MethodProtos = [{ + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + FGR32Class::iterator + FGR32Class::allocation_order_end(const MachineFunction &MF) const { + // The last 10 registers on the list above are reserved + return end()-10; + } + }]; +} diff --git a/lib/Target/MBlaze/MBlazeSchedule.td b/lib/Target/MBlaze/MBlazeSchedule.td new file mode 100644 index 0000000000..6a94491db4 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeSchedule.td @@ -0,0 +1,63 @@ +//===- MBlazeSchedule.td - MBlaze Scheduling Definitions --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Functional units across MBlaze chips sets. Based on GCC/MBlaze backend files. +//===----------------------------------------------------------------------===// +def ALU : FuncUnit; +def IMULDIV : FuncUnit; + +//===----------------------------------------------------------------------===// +// Instruction Itinerary classes used for MBlaze +//===----------------------------------------------------------------------===// +def IIAlu : InstrItinClass; +def IILoad : InstrItinClass; +def IIStore : InstrItinClass; +def IIXfer : InstrItinClass; +def IIBranch : InstrItinClass; +def IIHiLo : InstrItinClass; +def IIImul : InstrItinClass; +def IIIdiv : InstrItinClass; +def IIFcvt : InstrItinClass; +def IIFmove : InstrItinClass; +def IIFcmp : InstrItinClass; +def IIFadd : InstrItinClass; +def IIFmulSingle : InstrItinClass; +def IIFmulDouble : InstrItinClass; +def IIFdivSingle : InstrItinClass; +def IIFdivDouble : InstrItinClass; +def IIFsqrtSingle : InstrItinClass; +def IIFsqrtDouble : InstrItinClass; +def IIFrecipFsqrtStep : InstrItinClass; +def IIPseudo : InstrItinClass; + +//===----------------------------------------------------------------------===// +// MBlaze Generic instruction itineraries. +//===----------------------------------------------------------------------===// +def MBlazeGenericItineraries : ProcessorItineraries<[ + InstrItinData<IIAlu , [InstrStage<1, [ALU]>]>, + InstrItinData<IILoad , [InstrStage<3, [ALU]>]>, + InstrItinData<IIStore , [InstrStage<1, [ALU]>]>, + InstrItinData<IIXfer , [InstrStage<2, [ALU]>]>, + InstrItinData<IIBranch , [InstrStage<1, [ALU]>]>, + InstrItinData<IIHiLo , [InstrStage<1, [IMULDIV]>]>, + InstrItinData<IIImul , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<IIIdiv , [InstrStage<38, [IMULDIV]>]>, + InstrItinData<IIFcvt , [InstrStage<1, [ALU]>]>, + InstrItinData<IIFmove , [InstrStage<2, [ALU]>]>, + InstrItinData<IIFcmp , [InstrStage<3, [ALU]>]>, + InstrItinData<IIFadd , [InstrStage<4, [ALU]>]>, + InstrItinData<IIFmulSingle , [InstrStage<7, [ALU]>]>, + InstrItinData<IIFmulDouble , [InstrStage<8, [ALU]>]>, + InstrItinData<IIFdivSingle , [InstrStage<23, [ALU]>]>, + InstrItinData<IIFdivDouble , [InstrStage<36, [ALU]>]>, + InstrItinData<IIFsqrtSingle , [InstrStage<54, [ALU]>]>, + InstrItinData<IIFsqrtDouble , [InstrStage<12, [ALU]>]>, + InstrItinData<IIFrecipFsqrtStep , [InstrStage<5, [ALU]>]> +]>; diff --git a/lib/Target/MBlaze/MBlazeSubtarget.cpp b/lib/Target/MBlaze/MBlazeSubtarget.cpp new file mode 100644 index 0000000000..3440521568 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeSubtarget.cpp @@ -0,0 +1,31 @@ +//===- MBlazeSubtarget.cpp - MBlaze Subtarget 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 implements the MBlaze specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeSubtarget.h" +#include "MBlaze.h" +#include "MBlazeGenSubtarget.inc" +#include "llvm/Support/CommandLine.h" +using namespace llvm; + +MBlazeSubtarget::MBlazeSubtarget(const std::string &TT, const std::string &FS): + HasPipe3(false), HasBarrel(false), HasDiv(false), HasMul(false), + HasFSL(false), HasEFSL(false), HasMSRSet(false), HasException(false), + HasPatCmp(false), HasFPU(false), HasESR(false), HasPVR(false), + HasMul64(false), HasSqrt(false), HasMMU(false) +{ + std::string CPU = "v400"; + MBlazeArchVersion = V400; + + // Parse features string. + ParseSubtargetFeatures(FS, CPU); +} diff --git a/lib/Target/MBlaze/MBlazeSubtarget.h b/lib/Target/MBlaze/MBlazeSubtarget.h new file mode 100644 index 0000000000..bebb3f773e --- /dev/null +++ b/lib/Target/MBlaze/MBlazeSubtarget.h @@ -0,0 +1,79 @@ +//=====-- MBlazeSubtarget.h - Define Subtarget for the MBlaze -*- 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 MBlaze specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZESUBTARGET_H +#define MBLAZESUBTARGET_H + +#include "llvm/Target/TargetSubtarget.h" +#include "llvm/Target/TargetMachine.h" + +#include <string> + +namespace llvm { + +class MBlazeSubtarget : public TargetSubtarget { + +protected: + + enum MBlazeArchEnum { + V400, V500, V600, V700, V710 + }; + + // MBlaze architecture version + MBlazeArchEnum MBlazeArchVersion; + + bool HasPipe3; + bool HasBarrel; + bool HasDiv; + bool HasMul; + bool HasFSL; + bool HasEFSL; + bool HasMSRSet; + bool HasException; + bool HasPatCmp; + bool HasFPU; + bool HasESR; + bool HasPVR; + bool HasMul64; + bool HasSqrt; + bool HasMMU; + + InstrItineraryData InstrItins; + +public: + + /// This constructor initializes the data members to match that + /// of the specified triple. + MBlazeSubtarget(const std::string &TT, 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); + + bool hasFPU() const { return HasFPU; } + bool hasSqrt() const { return HasSqrt; } + bool hasMul() const { return HasMul; } + bool hasMul64() const { return HasMul64; } + bool hasDiv() const { return HasDiv; } + bool hasBarrel() const { return HasBarrel; } + + bool isV400() const { return MBlazeArchVersion == V400; } + bool isV500() const { return MBlazeArchVersion == V500; } + bool isV600() const { return MBlazeArchVersion == V600; } + bool isV700() const { return MBlazeArchVersion == V700; } + bool isV710() const { return MBlazeArchVersion == V710; } +}; +} // End llvm namespace + +#endif diff --git a/lib/Target/MBlaze/MBlazeTargetMachine.cpp b/lib/Target/MBlaze/MBlazeTargetMachine.cpp new file mode 100644 index 0000000000..9eba2b3c47 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeTargetMachine.cpp @@ -0,0 +1,66 @@ +//===-- MBlazeTargetMachine.cpp - Define TargetMachine for MBlaze ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements the info about MBlaze target spec. +// +//===----------------------------------------------------------------------===// + +#include "MBlaze.h" +#include "MBlazeMCAsmInfo.h" +#include "MBlazeTargetMachine.h" +#include "llvm/PassManager.h" +#include "llvm/Target/TargetRegistry.h" +using namespace llvm; + +extern "C" void LLVMInitializeMBlazeTarget() { + // Register the target. + RegisterTargetMachine<MBlazeTargetMachine> X(TheMBlazeTarget); + RegisterAsmInfo<MBlazeMCAsmInfo> A(TheMBlazeTarget); +} + +// DataLayout --> Big-endian, 32-bit pointer/ABI/alignment +// The stack is always 8 byte aligned +// On function prologue, the stack is created by decrementing +// its pointer. Once decremented, all references are done with positive +// offset from the stack/frame pointer, using StackGrowsUp enables +// an easier handling. +MBlazeTargetMachine:: +MBlazeTargetMachine(const Target &T, const std::string &TT, + const std::string &FS): + LLVMTargetMachine(T, TT), + Subtarget(TT, FS), + DataLayout("E-p:32:32-i8:8:8-i16:16:16-i64:32:32-" + "f64:32:32-v64:32:32-v128:32:32-n32"), + InstrInfo(*this), + FrameInfo(TargetFrameInfo::StackGrowsUp, 8, 0), + TLInfo(*this) { + if (getRelocationModel() == Reloc::Default) { + setRelocationModel(Reloc::Static); + } + + if (getCodeModel() == CodeModel::Default) + setCodeModel(CodeModel::Small); +} + +// Install an instruction selector pass using +// the ISelDag to gen MBlaze code. +bool MBlazeTargetMachine:: +addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel) { + PM.add(createMBlazeISelDag(*this)); + return false; +} + +// Implemented by targets that want to run passes immediately before +// machine code is emitted. return true if -print-machineinstrs should +// print out the code after the passes. +bool MBlazeTargetMachine:: +addPreEmitPass(PassManagerBase &PM, CodeGenOpt::Level OptLevel) { + PM.add(createMBlazeDelaySlotFillerPass(*this)); + return true; +} diff --git a/lib/Target/MBlaze/MBlazeTargetMachine.h b/lib/Target/MBlaze/MBlazeTargetMachine.h new file mode 100644 index 0000000000..85c975cae9 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeTargetMachine.h @@ -0,0 +1,69 @@ +//===-- MBlazeTargetMachine.h - Define TargetMachine for MBlaze --- 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 MBlaze specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZE_TARGETMACHINE_H +#define MBLAZE_TARGETMACHINE_H + +#include "MBlazeSubtarget.h" +#include "MBlazeInstrInfo.h" +#include "MBlazeISelLowering.h" +#include "MBlazeIntrinsicInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameInfo.h" + +namespace llvm { + class formatted_raw_ostream; + + class MBlazeTargetMachine : public LLVMTargetMachine { + MBlazeSubtarget Subtarget; + const TargetData DataLayout; // Calculates type size & alignment + MBlazeInstrInfo InstrInfo; + TargetFrameInfo FrameInfo; + MBlazeTargetLowering TLInfo; + MBlazeIntrinsicInfo IntrinsicInfo; + public: + MBlazeTargetMachine(const Target &T, const std::string &TT, + const std::string &FS); + + virtual const MBlazeInstrInfo *getInstrInfo() const + { return &InstrInfo; } + + virtual const TargetFrameInfo *getFrameInfo() const + { return &FrameInfo; } + + virtual const MBlazeSubtarget *getSubtargetImpl() const + { return &Subtarget; } + + virtual const TargetData *getTargetData() const + { return &DataLayout;} + + virtual const MBlazeRegisterInfo *getRegisterInfo() const + { return &InstrInfo.getRegisterInfo(); } + + virtual MBlazeTargetLowering *getTargetLowering() const + { return const_cast<MBlazeTargetLowering*>(&TLInfo); } + + const TargetIntrinsicInfo *getIntrinsicInfo() const + { return &IntrinsicInfo; } + + // Pass Pipeline Configuration + virtual bool addInstSelector(PassManagerBase &PM, + CodeGenOpt::Level OptLevel); + + virtual bool addPreEmitPass(PassManagerBase &PM, + CodeGenOpt::Level OptLevel); + }; +} // End llvm namespace + +#endif diff --git a/lib/Target/MBlaze/MBlazeTargetObjectFile.cpp b/lib/Target/MBlaze/MBlazeTargetObjectFile.cpp new file mode 100644 index 0000000000..79c9494c4d --- /dev/null +++ b/lib/Target/MBlaze/MBlazeTargetObjectFile.cpp @@ -0,0 +1,88 @@ +//===-- MBlazeTargetObjectFile.cpp - MBlaze object files ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeTargetObjectFile.h" +#include "MBlazeSubtarget.h" +#include "llvm/DerivedTypes.h" +#include "llvm/GlobalVariable.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/CommandLine.h" +using namespace llvm; + +void MBlazeTargetObjectFile:: +Initialize(MCContext &Ctx, const TargetMachine &TM) { + TargetLoweringObjectFileELF::Initialize(Ctx, TM); + + SmallDataSection = + getELFSection(".sdata", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_WRITE | MCSectionELF::SHF_ALLOC, + SectionKind::getDataRel()); + + SmallBSSSection = + getELFSection(".sbss", MCSectionELF::SHT_NOBITS, + MCSectionELF::SHF_WRITE | MCSectionELF::SHF_ALLOC, + SectionKind::getBSS()); + +} + +// A address must be loaded from a small section if its size is less than the +// small section size threshold. Data in this section must be addressed using +// gp_rel operator. +static bool IsInSmallSection(uint64_t Size) { + return Size > 0 && Size <= 8; +} + +bool MBlazeTargetObjectFile:: +IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM) const { + if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage()) + return false; + + return IsGlobalInSmallSection(GV, TM, getKindForGlobal(GV, TM)); +} + +/// IsGlobalInSmallSection - Return true if this global address should be +/// placed into small data/bss section. +bool MBlazeTargetObjectFile:: +IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM, + SectionKind Kind) const { + // Only global variables, not functions. + const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GV); + if (!GVA) + return false; + + // We can only do this for datarel or BSS objects for now. + if (!Kind.isBSS() && !Kind.isDataRel()) + return false; + + // If this is a internal constant string, there is a special + // section for it, but not in small data/bss. + if (Kind.isMergeable1ByteCString()) + return false; + + const Type *Ty = GV->getType()->getElementType(); + return IsInSmallSection(TM.getTargetData()->getTypeAllocSize(Ty)); +} + +const MCSection *MBlazeTargetObjectFile:: +SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, + Mangler *Mang, const TargetMachine &TM) const { + // TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*" + // sections? + + // Handle Small Section classification here. + if (Kind.isBSS() && IsGlobalInSmallSection(GV, TM, Kind)) + return SmallBSSSection; + if (Kind.isDataNoRel() && IsGlobalInSmallSection(GV, TM, Kind)) + return SmallDataSection; + + // Otherwise, we work the same as ELF. + return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind, Mang,TM); +} diff --git a/lib/Target/MBlaze/MBlazeTargetObjectFile.h b/lib/Target/MBlaze/MBlazeTargetObjectFile.h new file mode 100644 index 0000000000..20e77026c6 --- /dev/null +++ b/lib/Target/MBlaze/MBlazeTargetObjectFile.h @@ -0,0 +1,41 @@ +//===-- llvm/Target/MBlazeTargetObjectFile.h - MBlaze Obj. Info -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_MBLAZE_TARGETOBJECTFILE_H +#define LLVM_TARGET_MBLAZE_TARGETOBJECTFILE_H + +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" + +namespace llvm { + + class MBlazeTargetObjectFile : public TargetLoweringObjectFileELF { + const MCSection *SmallDataSection; + const MCSection *SmallBSSSection; + public: + + void Initialize(MCContext &Ctx, const TargetMachine &TM); + + + /// IsGlobalInSmallSection - Return true if this global address should be + /// placed into small data/bss section. + bool IsGlobalInSmallSection(const GlobalValue *GV, + const TargetMachine &TM, + SectionKind Kind) const; + + bool IsGlobalInSmallSection(const GlobalValue *GV, + const TargetMachine &TM) const; + + const MCSection *SelectSectionForGlobal(const GlobalValue *GV, + SectionKind Kind, + Mangler *Mang, + const TargetMachine &TM) const; + }; +} // end namespace llvm + +#endif diff --git a/lib/Target/MBlaze/Makefile b/lib/Target/MBlaze/Makefile new file mode 100644 index 0000000000..19e508c532 --- /dev/null +++ b/lib/Target/MBlaze/Makefile @@ -0,0 +1,23 @@ +##===- lib/Target/MBlaze/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 = LLVMMBlazeCodeGen +TARGET = MBlaze + +# Make sure that tblgen is run, first thing. +BUILT_SOURCES = MBlazeGenRegisterInfo.h.inc MBlazeGenRegisterNames.inc \ + MBlazeGenRegisterInfo.inc MBlazeGenInstrNames.inc \ + MBlazeGenInstrInfo.inc MBlazeGenAsmWriter.inc \ + MBlazeGenDAGISel.inc MBlazeGenCallingConv.inc \ + MBlazeGenSubtarget.inc MBlazeGenIntrinsics.inc + +DIRS = AsmPrinter TargetInfo + +include $(LEVEL)/Makefile.common + diff --git a/lib/Target/MBlaze/TargetInfo/CMakeLists.txt b/lib/Target/MBlaze/TargetInfo/CMakeLists.txt new file mode 100644 index 0000000000..5afb14d09a --- /dev/null +++ b/lib/Target/MBlaze/TargetInfo/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMMBlazeInfo + MBlazeTargetInfo.cpp + ) + +add_dependencies(LLVMMBlazeInfo MBlazeCodeGenTable_gen) diff --git a/lib/Target/MBlaze/TargetInfo/MBlazeTargetInfo.cpp b/lib/Target/MBlaze/TargetInfo/MBlazeTargetInfo.cpp new file mode 100644 index 0000000000..16e01dbfde --- /dev/null +++ b/lib/Target/MBlaze/TargetInfo/MBlazeTargetInfo.cpp @@ -0,0 +1,19 @@ +//===-- MBlazeTargetInfo.cpp - MBlaze Target Implementation ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MBlaze.h" +#include "llvm/Module.h" +#include "llvm/Target/TargetRegistry.h" +using namespace llvm; + +Target llvm::TheMBlazeTarget; + +extern "C" void LLVMInitializeMBlazeTargetInfo() { + RegisterTarget<Triple::mblaze> X(TheMBlazeTarget, "mblaze", "MBlaze"); +} diff --git a/lib/Target/MBlaze/TargetInfo/Makefile b/lib/Target/MBlaze/TargetInfo/Makefile new file mode 100644 index 0000000000..fb7ea118a6 --- /dev/null +++ b/lib/Target/MBlaze/TargetInfo/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/MBlaze/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 = LLVMMBlazeInfo + +# 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/test/CodeGen/MBlaze/brind.ll b/test/CodeGen/MBlaze/brind.ll new file mode 100644 index 0000000000..7798e0f56a --- /dev/null +++ b/test/CodeGen/MBlaze/brind.ll @@ -0,0 +1,73 @@ +; Ensure that the select instruction is supported and is lowered to +; some sort of branch instruction. +; +; RUN: llc < %s -march=mblaze -mattr=+mul,+fpu,+barrel | FileCheck %s + +declare i32 @printf(i8*, ...) +@MSG = internal constant [13 x i8] c"Message: %d\0A\00" + +@BLKS = private constant [5 x i8*] + [ i8* blockaddress(@brind, %L1), + i8* blockaddress(@brind, %L2), + i8* blockaddress(@brind, %L3), + i8* blockaddress(@brind, %L4), + i8* blockaddress(@brind, %L5) ] + +define i32 @brind(i32 %a, i32 %b) +{ + ; CHECK: brind: +entry: + br label %loop + +loop: + %tmp.0 = phi i32 [ 0, %entry ], [ %tmp.8, %finish ] + %dst.0 = getelementptr [5 x i8*]* @BLKS, i32 0, i32 %tmp.0 + %dst.1 = load i8** %dst.0 + indirectbr i8* %dst.1, [ label %L1, + label %L2, + label %L3, + label %L4, + label %L5 ] + ; CHECK: br {{r[0-9]*}} + +L1: + %tmp.1 = add i32 %a, %b + br label %finish + ; CHECK: br + +L2: + %tmp.2 = sub i32 %a, %b + br label %finish + ; CHECK: br + +L3: + %tmp.3 = mul i32 %a, %b + br label %finish + ; CHECK: br + +L4: + %tmp.4 = sdiv i32 %a, %b + br label %finish + ; CHECK: br + +L5: + %tmp.5 = srem i32 %a, %b + br label %finish + ; CHECK: br + +finish: + %tmp.6 = phi i32 [ %tmp.1, %L1 ], + [ %tmp.2, %L2 ], + [ %tmp.3, %L3 ], + [ %tmp.4, %L4 ], + [ %tmp.5, %L5 ] + + call i32 (i8*,...)* @printf( i8* getelementptr([13 x i8]* @MSG,i32 0,i32 0), + i32 %tmp.6) + + %tmp.7 = add i32 %tmp.0, 1 + %tmp.8 = urem i32 %tmp.7, 5 + + br label %loop + ; CHECK: br +} diff --git a/test/CodeGen/MBlaze/callind.ll b/test/CodeGen/MBlaze/callind.ll new file mode 100644 index 0000000000..bfc8d001fd --- /dev/null +++ b/test/CodeGen/MBlaze/callind.ll @@ -0,0 +1,80 @@ +; Ensure that indirect calls work and that they are lowered to some +; sort of branch and link instruction. +; +; RUN: llc < %s -march=mblaze -mattr=+mul,+fpu,+barrel | FileCheck %s + +declare i32 @printf(i8*, ...) +@MSG = internal constant [13 x i8] c"Message: %d\0A\00" + +@FUNS = private constant [5 x i32 (i32,i32)*] + [ i32 (i32,i32)* @doadd, + i32 (i32,i32)* @dosub, + i32 (i32,i32)* @domul, + i32 (i32,i32)* @dodiv, + i32 (i32,i32)* @dorem ] + +define i32 @doadd(i32 %a, i32 %b) +{ + ; CHECK: doadd: + %tmp.0 = add i32 %a, %b + ret i32 %tmp.0 + ; CHECK: rtsd +} + +define i32 @dosub(i32 %a, i32 %b) +{ + ; CHECK: dosub: + %tmp.0 = sub i32 %a, %b + ret i32 %tmp.0 + ; CHECK: rtsd +} + +define i32 @domul(i32 %a, i32 %b) +{ + ; CHECK: domul: + %tmp.0 = mul i32 %a, %b + ret i32 %tmp.0 + ; CHECK: rtsd +} + +define i32 @dodiv(i32 %a, i32 %b) +{ + ; CHECK: dodiv: + %tmp.0 = sdiv i32 %a, %b + ret i32 %tmp.0 + ; CHECK: rtsd +} + +define i32 @dorem(i32 %a, i32 %b) +{ + ; CHECK: dorem: + %tmp.0 = srem i32 %a, %b + ret i32 %tmp.0 + ; CHECK: rtsd +} + +define i32 @callind(i32 %a, i32 %b) +{ + ; CHECK: callind: +entry: + br label %loop + +loop: + %tmp.0 = phi i32 [ 0, %entry ], [ %tmp.3, %loop ] + %dst.0 = getelementptr [5 x i32 (i32,i32)*]* @FUNS, i32 0, i32 %tmp.0 + %dst.1 = load i32 (i32,i32)** %dst.0 + %tmp.1 = call i32 %dst.1(i32 %a, i32 %b) + ; CHECK-NOT: brli + ; CHECK-NOT: brlai + ; CHECK: brl + + call i32 (i8*,...)* @printf( i8* getelementptr([13 x i8]* @MSG,i32 0,i32 0), + i32 %tmp.1) + ; CHECK: brl + + %tmp.2 = add i32 %tmp.0, 1 + %tmp.3 = urem i32 %tmp.2, 5 + + br label %loop + ; CHECK: br +} diff --git a/test/CodeGen/MBlaze/cc.ll b/test/CodeGen/MBlaze/cc.ll new file mode 100644 index 0000000000..de55728e24 --- /dev/null +++ b/test/CodeGen/MBlaze/cc.ll @@ -0,0 +1,315 @@ +; Test some of the calling convention lowering done by the MBlaze backend. +; We test that integer values are passed in the correct registers and +; returned in the correct registers. Additionally, we test that the stack +; is used as appropriate for passing arguments that cannot be placed into +; registers. +; +; RUN: llc < %s -march=mblaze | FileCheck %s + +declare i32 @printf(i8*, ...) +@MSG = internal constant [13 x i8] c"Message: %d\0A\00" + +define void @params0_noret() { + ; CHECK: params0_noret: + ret void + ; CHECK-NOT: {{.* r3, r0, 1}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i8 @params0_8bitret() { + ; CHECK: params0_8bitret: + ret i8 1 + ; CHECK: {{.* r3, r0, 1}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i16 @params0_16bitret() { + ; CHECK: params0_16bitret: + ret i16 1 + ; CHECK: {{.* r3, r0, 1}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i32 @params0_32bitret() { + ; CHECK: params0_32bitret: + ret i32 1 + ; CHECK: {{.* r3, r0, 1}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i64 @params0_64bitret() { + ; CHECK: params0_64bitret: + ret i64 1 + ; CHECK: {{.* r3, r0, .*}} + ; CHECK: {{.* r4, r0, 1}} + ; CHECK: rtsd +} + +define i32 @params1_32bitret(i32 %a) { + ; CHECK: params1_32bitret: + ret i32 %a + ; CHECK: {{.* r3, r5, r0}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i32 @params2_32bitret(i32 %a, i32 %b) { + ; CHECK: params2_32bitret: + ret i32 %b + ; CHECK: {{.* r3, r6, r0}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i32 @params3_32bitret(i32 %a, i32 %b, i32 %c) { + ; CHECK: params3_32bitret: + ret i32 %c + ; CHECK: {{.* r3, r7, r0}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i32 @params4_32bitret(i32 %a, i32 %b, i32 %c, i32 %d) { + ; CHECK: params4_32bitret: + ret i32 %d + ; CHECK: {{.* r3, r8, r0}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i32 @params5_32bitret(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) { + ; CHECK: params5_32bitret: + ret i32 %e + ; CHECK: {{.* r3, r9, r0}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i32 @params6_32bitret(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) { + ; CHECK: params6_32bitret: + ret i32 %f + ; CHECK: {{.* r3, r10, r0}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i32 @params7_32bitret(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, + i32 %g) { + ; CHECK: params7_32bitret: + ret i32 %g + ; CHECK: {{lwi? r3, r1, 8}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i32 @params8_32bitret(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, + i32 %g, i32 %h) { + ; CHECK: params8_32bitret: + ret i32 %h + ; CHECK: {{lwi? r3, r1, 12}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i32 @params9_32bitret(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, + i32 %g, i32 %h, i32 %i) { + ; CHECK: params9_32bitret: + ret i32 %i + ; CHECK: {{lwi? r3, r1, 16}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define i32 @params10_32bitret(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, + i32 %g, i32 %h, i32 %i, i32 %j) { + ; CHECK: params10_32bitret: + ret i32 %j + ; CHECK: {{lwi? r3, r1, 20}} + ; CHECK-NOT: {{.* r4, .*, .*}} + ; CHECK: rtsd +} + +define void @testing() { + %MSG.1 = getelementptr [13 x i8]* @MSG, i32 0, i32 0 + + call void @params0_noret() + ; CHECK: brlid + + %tmp.1 = call i8 @params0_8bitret() + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i8 %tmp.1) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + %tmp.2 = call i16 @params0_16bitret() + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i16 %tmp.2) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + %tmp.3 = call i32 @params0_32bitret() + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i32 %tmp.3) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + %tmp.4 = call i64 @params0_64bitret() + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i64 %tmp.4) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK: {{.* r7, r4, r0}} + ; CHECK: brlid + + %tmp.5 = call i32 @params1_32bitret(i32 1) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i32 %tmp.5) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + %tmp.6 = call i32 @params2_32bitret(i32 1, i32 2) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, .*, .*}} + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i32 %tmp.6) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + %tmp.7 = call i32 @params3_32bitret(i32 1, i32 2, i32 3) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, .*, .*}} + ; CHECK: {{.* r7, .*, .*}} + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i32 %tmp.7) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + %tmp.8 = call i32 @params4_32bitret(i32 1, i32 2, i32 3, i32 4) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, .*, .*}} + ; CHECK: {{.* r7, .*, .*}} + ; CHECK: {{.* r8, .*, .*}} + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i32 %tmp.8) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + %tmp.9 = call i32 @params5_32bitret(i32 1, i32 2, i32 3, i32 4, i32 5) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, .*, .*}} + ; CHECK: {{.* r7, .*, .*}} + ; CHECK: {{.* r8, .*, .*}} + ; CHECK: {{.* r9, .*, .*}} + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i32 %tmp.9) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + %tmp.10 = call i32 @params6_32bitret(i32 1, i32 2, i32 3, i32 4, i32 5, + i32 6) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, .*, .*}} + ; CHECK: {{.* r7, .*, .*}} + ; CHECK: {{.* r8, .*, .*}} + ; CHECK: {{.* r9, .*, .*}} + ; CHECK: {{.* r10, .*, .*}} + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i32 %tmp.10) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + %tmp.11 = call i32 @params7_32bitret(i32 1, i32 2, i32 3, i32 4, i32 5, + i32 6, i32 7) + ; CHECK: {{swi? .*, r1, 4}} + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, .*, .*}} + ; CHECK: {{.* r7, .*, .*}} + ; CHECK: {{.* r8, .*, .*}} + ; CHECK: {{.* r9, .*, .*}} + ; CHECK: {{.* r10, .*, .*}} + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i32 %tmp.11) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + %tmp.12 = call i32 @params8_32bitret(i32 1, i32 2, i32 3, i32 4, i32 5, + i32 6, i32 7, i32 8) + ; CHECK: {{swi? .*, r1, 4}} + ; CHECK: {{swi? .*, r1, 8}} + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, .*, .*}} + ; CHECK: {{.* r7, .*, .*}} + ; CHECK: {{.* r8, .*, .*}} + ; CHECK: {{.* r9, .*, .*}} + ; CHECK: {{.* r10, .*, .*}} + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i32 %tmp.12) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + %tmp.13 = call i32 @params9_32bitret(i32 1, i32 2, i32 3, i32 4, i32 5, + i32 6, i32 7, i32 8, i32 9) + ; CHECK: {{swi? .*, r1, 4}} + ; CHECK: {{swi? .*, r1, 8}} + ; CHECK: {{swi? .*, r1, 12}} + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, .*, .*}} + ; CHECK: {{.* r7, .*, .*}} + ; CHECK: {{.* r8, .*, .*}} + ; CHECK: {{.* r9, .*, .*}} + ; CHECK: {{.* r10, .*, .*}} + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i32 %tmp.13) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + %tmp.14 = call i32 @params10_32bitret(i32 1, i32 2, i32 3, i32 4, i32 5, + i32 6, i32 7, i32 8, i32 9, i32 10) + ; CHECK: {{swi? .*, r1, 4}} + ; CHECK: {{swi? .*, r1, 8}} + ; CHECK: {{swi? .*, r1, 12}} + ; CHECK: {{swi? .*, r1, 16}} + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, .*, .*}} + ; CHECK: {{.* r7, .*, .*}} + ; CHECK: {{.* r8, .*, .*}} + ; CHECK: {{.* r9, .*, .*}} + ; CHECK: {{.* r10, .*, .*}} + ; CHECK: brlid + call i32 (i8*,...)* @printf(i8* %MSG.1, i32 %tmp.14) + ; CHECK: {{.* r5, .*, .*}} + ; CHECK: {{.* r6, r3, r0}} + ; CHECK-NOT: {{.* r7, .*, .*}} + ; CHECK: brlid + + ret void +} diff --git a/test/CodeGen/MBlaze/dg.exp b/test/CodeGen/MBlaze/dg.exp new file mode 100644 index 0000000000..bfd5e47157 --- /dev/null +++ b/test/CodeGen/MBlaze/dg.exp @@ -0,0 +1,5 @@ +load_lib llvm.exp + +if { [llvm_supports_target MBlaze] } { + RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,c,cpp}]] +} diff --git a/test/CodeGen/MBlaze/div.ll b/test/CodeGen/MBlaze/div.ll new file mode 100644 index 0000000000..fae9830619 --- /dev/null +++ b/test/CodeGen/MBlaze/div.ll @@ -0,0 +1,75 @@ +; Ensure that multiplication is lowered to function calls when the multiplier +; unit is not available in the hardware and that function calls are not used +; when the multiplier unit is available in the hardware. +; +; RUN: llc < %s -march=mblaze | FileCheck -check-prefix=FUN %s +; RUN: llc < %s -march=mblaze -mattr=+div | FileCheck -check-prefix=DIV %s + +define i8 @test_i8(i8 %a, i8 %b) { + ; FUN: test_i8: + ; DIV: test_i8: + + %tmp.1 = udiv i8 %a, %b + ; FUN-NOT: idiv + ; FUN: brlid + ; DIV-NOT: brlid + ; DIV: idivu + + %tmp.2 = sdiv i8 %a, %b + ; FUN-NOT: idiv + ; FUN: brlid + ; DIV-NOT: brlid + ; DIV-NOT: idivu + ; DIV: idiv + + %tmp.3 = add i8 %tmp.1, %tmp.2 + ret i8 %tmp.3 + ; FUN: rtsd + ; DIV: rtsd +} + +define i16 @test_i16(i16 %a, i16 %b) { + ; FUN: test_i16: + ; DIV: test_i16: + + %tmp.1 = udiv i16 %a, %b + ; FUN-NOT: idiv + ; FUN: brlid + ; DIV-NOT: brlid + ; DIV: idivu + + %tmp.2 = sdiv i16 %a, %b + ; FUN-NOT: idiv + ; FUN: brlid + ; DIV-NOT: brlid + ; DIV-NOT: idivu + ; DIV: idiv + + %tmp.3 = add i16 %tmp.1, %tmp.2 + ret i16 %tmp.3 + ; FUN: rtsd + ; DIV: rtsd +} + +define i32 @test_i32(i32 %a, i32 %b) { + ; FUN: test_i32: + ; DIV: test_i32: + + %tmp.1 = udiv i32 %a, %b + ; FUN-NOT: idiv + ; FUN: brlid + ; DIV-NOT: brlid + ; DIV: idivu + + %tmp.2 = sdiv i32 %a, %b + ; FUN-NOT: idiv + ; FUN: brlid + ; DIV-NOT: brlid + ; DIV-NOT: idivu + ; DIV: idiv + + %tmp.3 = add i32 %tmp.1, %tmp.2 + ret i32 %tmp.3 + ; FUN: rtsd + ; DIV: rtsd +} diff --git a/test/CodeGen/MBlaze/fpu.ll b/test/CodeGen/MBlaze/fpu.ll new file mode 100644 index 0000000000..83f4d83124 --- /dev/null +++ b/test/CodeGen/MBlaze/fpu.ll @@ -0,0 +1,66 @@ +; Ensure that floating point operations are lowered to function calls when the +; FPU is not available in the hardware and that function calls are not used +; when the FPU is available in the hardware. +; +; RUN: llc < %s -march=mblaze | FileCheck -check-prefix=FUN %s +; RUN: llc < %s -march=mblaze -mattr=+fpu | FileCheck -check-prefix=FPU %s + +define float @test_add(float %a, float %b) { + ; FUN: test_add: + ; FPU: test_add: + + %tmp.1 = fadd float %a, %b + ; FUN-NOT: fadd + ; FUN: brlid + ; FPU-NOT: brlid + ; FPU: fadd + + ret float %tmp.1 + ; FUN: rtsd + ; FPU: rtsd +} + +define float @test_sub(float %a, float %b) { + ; FUN: test_sub: + ; FPU: test_sub: + + %tmp.1 = fsub float %a, %b + ; FUN-NOT: frsub + ; FUN: brlid + ; FPU-NOT: brlid + ; FPU: frsub + + ret float %tmp.1 + ; FUN: rtsd + ; FPU: rtsd +} + +define float @test_mul(float %a, float %b) { + ; FUN: test_mul: + ; FPU: test_mul: + + %tmp.1 = fmul float %a, %b + ; FUN-NOT: fmul + ; FUN: brlid + ; FPU-NOT: brlid + ; FPU: fmul + + ret float %tmp.1 + ; FUN: rtsd + ; FPU: rtsd +} + +define float @test_div(float %a, float %b) { + ; FUN: test_div: + ; FPU: test_div: + + %tmp.1 = fdiv float %a, %b + ; FUN-NOT: fdiv + ; FUN: brlid + ; FPU-NOT: brlid + ; FPU: fdiv + + ret float %tmp.1 + ; FUN: rtsd + ; FPU: rtsd +} diff --git a/test/CodeGen/MBlaze/fsl.ll b/test/CodeGen/MBlaze/fsl.ll new file mode 100644 index 0000000000..f9c6205bc1 --- /dev/null +++ b/test/CodeGen/MBlaze/fsl.ll @@ -0,0 +1,323 @@ +; Ensure that the FSL instrinsic instruction generate single FSL instructions +; at the machine level. Additionally, ensure that dynamic values use the +; dynamic version of the instructions and that constant values use the +; constant version of the instructions. +; +; RUN: llc < %s -march=mblaze | FileCheck %s + +declare i32 @llvm.mblaze.fsl.get(i32 %port) +declare i32 @llvm.mblaze.fsl.aget(i32 %port) +declare i32 @llvm.mblaze.fsl.cget(i32 %port) +declare i32 @llvm.mblaze.fsl.caget(i32 %port) +declare i32 @llvm.mblaze.fsl.eget(i32 %port) +declare i32 @llvm.mblaze.fsl.eaget(i32 %port) +declare i32 @llvm.mblaze.fsl.ecget(i32 %port) +declare i32 @llvm.mblaze.fsl.ecaget(i32 %port) +declare i32 @llvm.mblaze.fsl.nget(i32 %port) +declare i32 @llvm.mblaze.fsl.naget(i32 %port) +declare i32 @llvm.mblaze.fsl.ncget(i32 %port) +declare i32 @llvm.mblaze.fsl.ncaget(i32 %port) +declare i32 @llvm.mblaze.fsl.neget(i32 %port) +declare i32 @llvm.mblaze.fsl.neaget(i32 %port) +declare i32 @llvm.mblaze.fsl.necget(i32 %port) +declare i32 @llvm.mblaze.fsl.necaget(i32 %port) +declare i32 @llvm.mblaze.fsl.tget(i32 %port) +declare i32 @llvm.mblaze.fsl.taget(i32 %port) +declare i32 @llvm.mblaze.fsl.tcget(i32 %port) +declare i32 @llvm.mblaze.fsl.tcaget(i32 %port) +declare i32 @llvm.mblaze.fsl.teget(i32 %port) +declare i32 @llvm.mblaze.fsl.teaget(i32 %port) +declare i32 @llvm.mblaze.fsl.tecget(i32 %port) +declare i32 @llvm.mblaze.fsl.tecaget(i32 %port) +declare i32 @llvm.mblaze.fsl.tnget(i32 %port) +declare i32 @llvm.mblaze.fsl.tnaget(i32 %port) +declare i32 @llvm.mblaze.fsl.tncget(i32 %port) +declare i32 @llvm.mblaze.fsl.tncaget(i32 %port) +declare i32 @llvm.mblaze.fsl.tneget(i32 %port) +declare i32 @llvm.mblaze.fsl.tneaget(i32 %port) +declare i32 @llvm.mblaze.fsl.tnecget(i32 %port) +declare i32 @llvm.mblaze.fsl.tnecaget(i32 %port) + +declare void @llvm.mblaze.fsl.put(i32 %value, i32 %port) +declare void @llvm.mblaze.fsl.aput(i32 %value, i32 %port) +declare void @llvm.mblaze.fsl.cput(i32 %value, i32 %port) +declare void @llvm.mblaze.fsl.caput(i32 %value, i32 %port) +declare void @llvm.mblaze.fsl.nput(i32 %value, i32 %port) +declare void @llvm.mblaze.fsl.naput(i32 %value, i32 %port) +declare void @llvm.mblaze.fsl.ncput(i32 %value, i32 %port) +declare void @llvm.mblaze.fsl.ncaput(i32 %value, i32 %port) +declare void @llvm.mblaze.fsl.tput(i32 %port) +declare void @llvm.mblaze.fsl.taput(i32 %port) +declare void @llvm.mblaze.fsl.tcput(i32 %port) +declare void @llvm.mblaze.fsl.tcaput(i32 %port) +declare void @llvm.mblaze.fsl.tnput(i32 %port) +declare void @llvm.mblaze.fsl.tnaput(i32 %port) +declare void @llvm.mblaze.fsl.tncput(i32 %port) +declare void @llvm.mblaze.fsl.tncaput(i32 %port) + +define i32 @fsl_get(i32 %port) +{ + ; CHECK: fsl_get: + %v0 = call i32 @llvm.mblaze.fsl.get(i32 %port) + ; CHECK: getd + %v1 = call i32 @llvm.mblaze.fsl.aget(i32 %port) + ; CHECK-NEXT: agetd + %v2 = call i32 @llvm.mblaze.fsl.cget(i32 %port) + ; CHECK-NEXT: cgetd + %v3 = call i32 @llvm.mblaze.fsl.caget(i32 %port) + ; CHECK-NEXT: cagetd + %v4 = call i32 @llvm.mblaze.fsl.eget(i32 %port) + ; CHECK-NEXT: egetd + %v5 = call i32 @llvm.mblaze.fsl.eaget(i32 %port) + ; CHECK-NEXT: eagetd + %v6 = call i32 @llvm.mblaze.fsl.ecget(i32 %port) + ; CHECK-NEXT: ecgetd + %v7 = call i32 @llvm.mblaze.fsl.ecaget(i32 %port) + ; CHECK-NEXT: ecagetd + %v8 = call i32 @llvm.mblaze.fsl.nget(i32 %port) + ; CHECK-NEXT: ngetd + %v9 = call i32 @llvm.mblaze.fsl.naget(i32 %port) + ; CHECK-NEXT: nagetd + %v10 = call i32 @llvm.mblaze.fsl.ncget(i32 %port) + ; CHECK-NEXT: ncgetd + %v11 = call i32 @llvm.mblaze.fsl.ncaget(i32 %port) + ; CHECK-NEXT: ncagetd + %v12 = call i32 @llvm.mblaze.fsl.neget(i32 %port) + ; CHECK-NEXT: negetd + %v13 = call i32 @llvm.mblaze.fsl.neaget(i32 %port) + ; CHECK-NEXT: neagetd + %v14 = call i32 @llvm.mblaze.fsl.necget(i32 %port) + ; CHECK-NEXT: necgetd + %v15 = call i32 @llvm.mblaze.fsl.necaget(i32 %port) + ; CHECK-NEXT: necagetd + %v16 = call i32 @llvm.mblaze.fsl.tget(i32 %port) + ; CHECK-NEXT: tgetd + %v17 = call i32 @llvm.mblaze.fsl.taget(i32 %port) + ; CHECK-NEXT: tagetd + %v18 = call i32 @llvm.mblaze.fsl.tcget(i32 %port) + ; CHECK-NEXT: tcgetd + %v19 = call i32 @llvm.mblaze.fsl.tcaget(i32 %port) + ; CHECK-NEXT: tcagetd + %v20 = call i32 @llvm.mblaze.fsl.teget(i32 %port) + ; CHECK-NEXT: tegetd + %v21 = call i32 @llvm.mblaze.fsl.teaget(i32 %port) + ; CHECK-NEXT: teagetd + %v22 = call i32 @llvm.mblaze.fsl.tecget(i32 %port) + ; CHECK-NEXT: tecgetd + %v23 = call i32 @llvm.mblaze.fsl.tecaget(i32 %port) + ; CHECK-NEXT: tecagetd + %v24 = call i32 @llvm.mblaze.fsl.tnget(i32 %port) + ; CHECK-NEXT: tngetd + %v25 = call i32 @llvm.mblaze.fsl.tnaget(i32 %port) + ; CHECK-NEXT: tnagetd + %v26 = call i32 @llvm.mblaze.fsl.tncget(i32 %port) + ; CHECK-NEXT: tncgetd + %v27 = call i32 @llvm.mblaze.fsl.tncaget(i32 %port) + ; CHECK-NEXT: tncagetd + %v28 = call i32 @llvm.mblaze.fsl.tneget(i32 %port) + ; CHECK-NEXT: tnegetd + %v29 = call i32 @llvm.mblaze.fsl.tneaget(i32 %port) + ; CHECK-NEXT: tneagetd + %v30 = call i32 @llvm.mblaze.fsl.tnecget(i32 %port) + ; CHECK-NEXT: tnecgetd + %v31 = call i32 @llvm.mblaze.fsl.tnecaget(i32 %port) + ; CHECK-NEXT: tnecagetd + ret i32 1 + ; CHECK: rtsd +} + +define i32 @fslc_get() +{ + ; CHECK: fslc_get: + %v0 = call i32 @llvm.mblaze.fsl.get(i32 1) + ; CHECK: get + %v1 = call i32 @llvm.mblaze.fsl.aget(i32 1) + ; CHECK-NOT: agetd + ; CHECK: aget + %v2 = call i32 @llvm.mblaze.fsl.cget(i32 1) + ; CHECK-NOT: cgetd + ; CHECK: cget + %v3 = call i32 @llvm.mblaze.fsl.caget(i32 1) + ; CHECK-NOT: cagetd + ; CHECK: caget + %v4 = call i32 @llvm.mblaze.fsl.eget(i32 1) + ; CHECK-NOT: egetd + ; CHECK: eget + %v5 = call i32 @llvm.mblaze.fsl.eaget(i32 1) + ; CHECK-NOT: eagetd + ; CHECK: eaget + %v6 = call i32 @llvm.mblaze.fsl.ecget(i32 1) + ; CHECK-NOT: ecgetd + ; CHECK: ecget + %v7 = call i32 @llvm.mblaze.fsl.ecaget(i32 1) + ; CHECK-NOT: ecagetd + ; CHECK: ecaget + %v8 = call i32 @llvm.mblaze.fsl.nget(i32 1) + ; CHECK-NOT: ngetd + ; CHECK: nget + %v9 = call i32 @llvm.mblaze.fsl.naget(i32 1) + ; CHECK-NOT: nagetd + ; CHECK: naget + %v10 = call i32 @llvm.mblaze.fsl.ncget(i32 1) + ; CHECK-NOT: ncgetd + ; CHECK: ncget + %v11 = call i32 @llvm.mblaze.fsl.ncaget(i32 1) + ; CHECK-NOT: ncagetd + ; CHECK: ncaget + %v12 = call i32 @llvm.mblaze.fsl.neget(i32 1) + ; CHECK-NOT: negetd + ; CHECK: neget + %v13 = call i32 @llvm.mblaze.fsl.neaget(i32 1) + ; CHECK-NOT: neagetd + ; CHECK: neaget + %v14 = call i32 @llvm.mblaze.fsl.necget(i32 1) + ; CHECK-NOT: necgetd + ; CHECK: necget + %v15 = call i32 @llvm.mblaze.fsl.necaget(i32 1) + ; CHECK-NOT: necagetd + ; CHECK: necaget + %v16 = call i32 @llvm.mblaze.fsl.tget(i32 1) + ; CHECK-NOT: tgetd + ; CHECK: tget + %v17 = call i32 @llvm.mblaze.fsl.taget(i32 1) + ; CHECK-NOT: tagetd + ; CHECK: taget + %v18 = call i32 @llvm.mblaze.fsl.tcget(i32 1) + ; CHECK-NOT: tcgetd + ; CHECK: tcget + %v19 = call i32 @llvm.mblaze.fsl.tcaget(i32 1) + ; CHECK-NOT: tcagetd + ; CHECK: tcaget + %v20 = call i32 @llvm.mblaze.fsl.teget(i32 1) + ; CHECK-NOT: tegetd + ; CHECK: teget + %v21 = call i32 @llvm.mblaze.fsl.teaget(i32 1) + ; CHECK-NOT: teagetd + ; CHECK: teaget + %v22 = call i32 @llvm.mblaze.fsl.tecget(i32 1) + ; CHECK-NOT: tecgetd + ; CHECK: tecget + %v23 = call i32 @llvm.mblaze.fsl.tecaget(i32 1) + ; CHECK-NOT: tecagetd + ; CHECK: tecaget + %v24 = call i32 @llvm.mblaze.fsl.tnget(i32 1) + ; CHECK-NOT: tngetd + ; CHECK: tnget + %v25 = call i32 @llvm.mblaze.fsl.tnaget(i32 1) + ; CHECK-NOT: tnagetd + ; CHECK: tnaget + %v26 = call i32 @llvm.mblaze.fsl.tncget(i32 1) + ; CHECK-NOT: tncgetd + ; CHECK: tncget + %v27 = call i32 @llvm.mblaze.fsl.tncaget(i32 1) + ; CHECK-NOT: tncagetd + ; CHECK: tncaget + %v28 = call i32 @llvm.mblaze.fsl.tneget(i32 1) + ; CHECK-NOT: tnegetd + ; CHECK: tneget + %v29 = call i32 @llvm.mblaze.fsl.tneaget(i32 1) + ; CHECK-NOT: tneagetd + ; CHECK: tneaget + %v30 = call i32 @llvm.mblaze.fsl.tnecget(i32 1) + ; CHECK-NOT: tnecgetd + ; CHECK: tnecget + %v31 = call i32 @llvm.mblaze.fsl.tnecaget(i32 1) + ; CHECK-NOT: tnecagetd + ; CHECK: tnecaget + ret i32 1 + ; CHECK: rtsd +} + +define void @putfsl(i32 %value, i32 %port) +{ + ; CHECK: putfsl: + call void @llvm.mblaze.fsl.put(i32 %value, i32 %port) + ; CHECK: putd + call void @llvm.mblaze.fsl.aput(i32 %value, i32 %port) + ; CHECK-NEXT: aputd + call void @llvm.mblaze.fsl.cput(i32 %value, i32 %port) + ; CHECK-NEXT: cputd + call void @llvm.mblaze.fsl.caput(i32 %value, i32 %port) + ; CHECK-NEXT: caputd + call void @llvm.mblaze.fsl.nput(i32 %value, i32 %port) + ; CHECK-NEXT: nputd + call void @llvm.mblaze.fsl.naput(i32 %value, i32 %port) + ; CHECK-NEXT: naputd + call void @llvm.mblaze.fsl.ncput(i32 %value, i32 %port) + ; CHECK-NEXT: ncputd + call void @llvm.mblaze.fsl.ncaput(i32 %value, i32 %port) + ; CHECK-NEXT: ncaputd + call void @llvm.mblaze.fsl.tput(i32 %port) + ; CHECK-NEXT: tputd + call void @llvm.mblaze.fsl.taput(i32 %port) + ; CHECK-NEXT: taputd + call void @llvm.mblaze.fsl.tcput(i32 %port) + ; CHECK-NEXT: tcputd + call void @llvm.mblaze.fsl.tcaput(i32 %port) + ; CHECK-NEXT: tcaputd + call void @llvm.mblaze.fsl.tnput(i32 %port) + ; CHECK-NEXT: tnputd + call void @llvm.mblaze.fsl.tnaput(i32 %port) + ; CHECK-NEXT: tnaputd + call void @llvm.mblaze.fsl.tncput(i32 %port) + ; CHECK-NEXT: tncputd + call void @llvm.mblaze.fsl.tncaput(i32 %port) + ; CHECK-NEXT: tncaputd + ret void + ; CHECK: rtsd +} + +define void @putfsl_const(i32 %value) +{ + ; CHECK: putfsl_const: + call void @llvm.mblaze.fsl.put(i32 %value, i32 1) + ; CHECK-NOT: putd + ; CHECK: put + call void @llvm.mblaze.fsl.aput(i32 %value, i32 1) + ; CHECK-NOT: aputd + ; CHECK: aput + call void @llvm.mblaze.fsl.cput(i32 %value, i32 1) + ; CHECK-NOT: cputd + ; CHECK: cput + call void @llvm.mblaze.fsl.caput(i32 %value, i32 1) + ; CHECK-NOT: caputd + ; CHECK: caput + call void @llvm.mblaze.fsl.nput(i32 %value, i32 1) + ; CHECK-NOT: nputd + ; CHECK: nput + call void @llvm.mblaze.fsl.naput(i32 %value, i32 1) + ; CHECK-NOT: naputd + ; CHECK: naput + call void @llvm.mblaze.fsl.ncput(i32 %value, i32 1) + ; CHECK-NOT: ncputd + ; CHECK: ncput + call void @llvm.mblaze.fsl.ncaput(i32 %value, i32 1) + ; CHECK-NOT: ncaputd + ; CHECK: ncaput + call void @llvm.mblaze.fsl.tput(i32 1) + ; CHECK-NOT: tputd + ; CHECK: tput + call void @llvm.mblaze.fsl.taput(i32 1) + ; CHECK-NOT: taputd + ; CHECK: taput + call void @llvm.mblaze.fsl.tcput(i32 1) + ; CHECK-NOT: tcputd + ; CHECK: tcput + call void @llvm.mblaze.fsl.tcaput(i32 1) + ; CHECK-NOT: tcaputd + ; CHECK: tcaput + call void @llvm.mblaze.fsl.tnput(i32 1) + ; CHECK-NOT: tnputd + ; CHECK: tnput + call void @llvm.mblaze.fsl.tnaput(i32 1) + ; CHECK-NOT: tnaputd + ; CHECK: tnaput + call void @llvm.mblaze.fsl.tncput(i32 1) + ; CHECK-NOT: tncputd + ; CHECK: tncput + call void @llvm.mblaze.fsl.tncaput(i32 1) + ; CHECK-NOT: tncaputd + ; CHECK: tncaput + ret void + ; CHECK: rtsd +} diff --git a/test/CodeGen/MBlaze/imm.ll b/test/CodeGen/MBlaze/imm.ll new file mode 100644 index 0000000000..85fad175b7 --- /dev/null +++ b/test/CodeGen/MBlaze/imm.ll @@ -0,0 +1,70 @@ +; Ensure that all immediate values that are 32-bits or less can be loaded +; using a single instruction and that immediate values 64-bits or less can +; be loaded using two instructions. +; +; RUN: llc < %s -march=mblaze | FileCheck %s +; RUN: llc < %s -march=mblaze -mattr=+fpu | FileCheck -check-prefix=FPU %s + +define i8 @retimm_i8() { + ; CHECK: retimm_i8: + ; CHECK: add + ; CHECK-NEXT: rtsd + ; FPU: retimm_i8: + ; FPU: add + ; FPU-NEXT: rtsd + ret i8 123 +} + +define i16 @retimm_i16() { + ; CHECK: retimm_i16: + ; CHECK: add + ; CHECK-NEXT: rtsd + ; FPU: retimm_i16: + ; FPU: add + ; FPU-NEXT: rtsd + ret i16 38212 +} + +define i32 @retimm_i32() { + ; CHECK: retimm_i32: + ; CHECK: add + ; CHECK-NEXT: rtsd + ; FPU: retimm_i32: + ; FPU: add + ; FPU-NEXT: rtsd + ret i32 2938128 +} + +define i64 @retimm_i64() { + ; CHECK: retimm_i64: + ; CHECK: add + ; CHECK-NEXT: add + ; CHECK-NEXT: rtsd + ; FPU: retimm_i64: + ; FPU: add + ; FPU-NEXT: add + ; FPU-NEXT: rtsd + ret i64 94581823 +} + +define float @retimm_float() { + ; CHECK: retimm_float: + ; CHECK: add + ; CHECK-NEXT: rtsd + ; FPU: retimm_float: + ; FPU: or + ; FPU: rtsd + ret float 12.0 +} + +define double @retimm_double() { + ; CHECK: retimm_double: + ; CHECK: add + ; CHECK-NEXT: add + ; CHECK-NEXT: rtsd + ; FPU: retimm_double: + ; FPU: add + ; FPU-NEXT: add + ; FPU-NEXT: rtsd + ret double 598382.39283873 +} diff --git a/test/CodeGen/MBlaze/jumptable.ll b/test/CodeGen/MBlaze/jumptable.ll new file mode 100644 index 0000000000..3f27c12f19 --- /dev/null +++ b/test/CodeGen/MBlaze/jumptable.ll @@ -0,0 +1,79 @@ +; Ensure that jump tables can be handled by the mblaze backend. The +; jump table should be lowered to a "br" instruction using one of the +; available registers. +; +; RUN: llc < %s -march=mblaze | FileCheck %s + +define i32 @jmptable(i32 %arg) +{ + ; CHECK: jmptable: + switch i32 %arg, label %DEFAULT [ i32 0, label %L0 + i32 1, label %L1 + i32 2, label %L2 + i32 3, label %L3 + i32 4, label %L4 + i32 5, label %L5 + i32 6, label %L6 + i32 7, label %L7 + i32 8, label %L8 + i32 9, label %L9 ] + + ; CHECK: lw [[REG:r[0-9]*]] + ; CHECK: br [[REG]] +L0: + %var0 = add i32 %arg, 0 + br label %DONE + +L1: + %var1 = add i32 %arg, 1 + br label %DONE + +L2: + %var2 = add i32 %arg, 2 + br label %DONE + +L3: + %var3 = add i32 %arg, 3 + br label %DONE + +L4: + %var4 = add i32 %arg, 4 + br label %DONE + +L5: + %var5 = add i32 %arg, 5 + br label %DONE + +L6: + %var6 = add i32 %arg, 6 + br label %DONE + +L7: + %var7 = add i32 %arg, 7 + br label %DONE + +L8: + %var8 = add i32 %arg, 8 + br label %DONE + +L9: + %var9 = add i32 %arg, 9 + br label %DONE + +DEFAULT: + unreachable + +DONE: + %rval = phi i32 [ %var0, %L0 ], + [ %var1, %L1 ], + [ %var2, %L2 ], + [ %var3, %L3 ], + [ %var4, %L4 ], + [ %var5, %L5 ], + [ %var6, %L6 ], + [ %var7, %L7 ], + [ %var8, %L8 ], + [ %var9, %L9 ] + ret i32 %rval + ; CHECK: rtsd +} diff --git a/test/CodeGen/MBlaze/loop.ll b/test/CodeGen/MBlaze/loop.ll new file mode 100644 index 0000000000..b473020e66 --- /dev/null +++ b/test/CodeGen/MBlaze/loop.ll @@ -0,0 +1,47 @@ +; Test some complicated looping constructs to ensure that they +; compile successfully and that some sort of branching is used +; in the resulting code. +; +; RUN: llc < %s -march=mblaze -mattr=+mul,+fpu,+barrel | FileCheck %s + +declare i32 @printf(i8*, ...) +@MSG = internal constant [19 x i8] c"Message: %d %d %d\0A\00" + +define i32 @loop(i32 %a, i32 %b) +{ + ; CHECK: loop: +entry: + br label %loop_outer + +loop_outer: + %outer.0 = phi i32 [ 0, %entry ], [ %outer.2, %loop_outer_finish ] + br label %loop_inner + +loop_inner: + %inner.0 = phi i32 [ %a, %loop_outer ], [ %inner.3, %loop_inner_finish ] + %inner.1 = phi i32 [ %b, %loop_outer ], [ %inner.4, %loop_inner_finish ] + %inner.2 = phi i32 [ 0, %loop_outer ], [ %inner.5, %loop_inner_finish ] + %inner.3 = add i32 %inner.0, %inner.1 + %inner.4 = mul i32 %inner.2, 11 + br label %loop_inner_finish + +loop_inner_finish: + %inner.5 = add i32 %inner.2, 1 + ; CHECK: addi {{.*, 1}} + + call i32 (i8*,...)* @printf( i8* getelementptr([19 x i8]* @MSG,i32 0,i32 0), + i32 %inner.0, i32 %inner.1, i32 %inner.2 ) + ; CHECK: brlid + + %inner.6 = icmp eq i32 %inner.5, 100 + ; CHECK: cmp + + br i1 %inner.6, label %loop_inner, label %loop_outer_finish + ; CHECK: {{beq|bne}} + +loop_outer_finish: + %outer.1 = add i32 %outer.0, 1 + %outer.2 = urem i32 %outer.1, 1500 + br label %loop_outer + ; CHECK: br +} diff --git a/test/CodeGen/MBlaze/mul.ll b/test/CodeGen/MBlaze/mul.ll new file mode 100644 index 0000000000..65d3e22a3e --- /dev/null +++ b/test/CodeGen/MBlaze/mul.ll @@ -0,0 +1,51 @@ +; Ensure that multiplication is lowered to function calls when the multiplier +; unit is not available in the hardware and that function calls are not used +; when the multiplier unit is available in the hardware. +; +; RUN: llc < %s -march=mblaze | FileCheck -check-prefix=FUN %s +; RUN: llc < %s -march=mblaze -mattr=+mul | FileCheck -check-prefix=MUL %s + +define i8 @test_i8(i8 %a, i8 %b) { + ; FUN: test_i8: + ; MUL: test_i8: + + %tmp.1 = mul i8 %a, %b + ; FUN-NOT: mul + ; FUN: brlid + ; MUL-NOT: brlid + ; MUL: mul + + ret i8 %tmp.1 + ; FUN: rtsd + ; MUL: rtsd +} + +define i16 @test_i16(i16 %a, i16 %b) { + ; FUN: test_i16: + ; MUL: test_i16: + + %tmp.1 = mul i16 %a, %b + ; FUN-NOT: mul + ; FUN: brlid + ; MUL-NOT: brlid + ; MUL: mul + + ret i16 %tmp.1 + ; FUN: rtsd + ; MUL: rtsd +} + +define i32 @test_i32(i32 %a, i32 %b) { + ; FUN: test_i32: + ; MUL: test_i32: + + %tmp.1 = mul i32 %a, %b + ; FUN-NOT: mul + ; FUN: brlid + ; MUL-NOT: brlid + ; MUL: mul + + ret i32 %tmp.1 + ; FUN: rtsd + ; MUL: rtsd +} diff --git a/test/CodeGen/MBlaze/mul64.ll b/test/CodeGen/MBlaze/mul64.ll new file mode 100644 index 0000000000..e0ef4138af --- /dev/null +++ b/test/CodeGen/MBlaze/mul64.ll @@ -0,0 +1,23 @@ +; Ensure that multiplication is lowered to function calls when the 64-bit +; multiplier unit is not available in the hardware and that function calls +; are not used when the 64-bit multiplier unit is available in the hardware. +; +; RUN: llc < %s -march=mblaze | FileCheck -check-prefix=FUN %s +; RUN: llc < %s -march=mblaze -mattr=+mul,+mul64 | \ +; RUN: FileCheck -check-prefix=MUL %s + +define i64 @test_i64(i64 %a, i64 %b) { + ; FUN: test_i64: + ; MUL: test_i64: + + %tmp.1 = mul i64 %a, %b + ; FUN-NOT: mul + ; FUN: brlid + ; MUL-NOT: brlid + ; MUL: mulh + ; MUL: mul + + ret i64 %tmp.1 + ; FUN: rtsd + ; MUL: rtsd +} diff --git a/test/CodeGen/MBlaze/select.ll b/test/CodeGen/MBlaze/select.ll new file mode 100644 index 0000000000..47a88a1e3c --- /dev/null +++ b/test/CodeGen/MBlaze/select.ll @@ -0,0 +1,15 @@ +; Ensure that the select instruction is supported and is lowered to +; some sort of branch instruction. +; +; RUN: llc < %s -march=mblaze | FileCheck %s + +define i32 @testsel(i32 %a, i32 %b) +{ + ; CHECK: testsel: + %tmp.1 = icmp eq i32 %a, %b + ; CHECK: cmp + %tmp.2 = select i1 %tmp.1, i32 %a, i32 %b + ; CHECK: {{bne|beq}} + ret i32 %tmp.2 + ; CHECK: rtsd +} diff --git a/test/CodeGen/MBlaze/shift.ll b/test/CodeGen/MBlaze/shift.ll new file mode 100644 index 0000000000..186115ec19 --- /dev/null +++ b/test/CodeGen/MBlaze/shift.ll @@ -0,0 +1,117 @@ +; Ensure that shifts are lowered to loops when the barrel shifter unit is +; not available in the hardware and that loops are not used when the +; barrel shifter unit is available in the hardware. +; +; RUN: llc < %s -march=mblaze | FileCheck -check-prefix=FUN %s +; RUN: llc < %s -march=mblaze -mattr=+barrel | FileCheck -check-prefix=SHT %s + +define i8 @test_i8(i8 %a, i8 %b) { + ; FUN: test_i8: + ; SHT: test_i8: + + %tmp.1 = shl i8 %a, %b + ; FUN-NOT: bsll + ; FUN: andi + ; FUN: add + ; FUN: bnei + ; SHT-NOT: andi + ; SHT-NOT: bnei + ; SHT: bsll + + ret i8 %tmp.1 + ; FUN: rtsd + ; SHT: rtsd +} + +define i8 @testc_i8(i8 %a, i8 %b) { + ; FUN: testc_i8: + ; SHT: testc_i8: + + %tmp.1 = shl i8 %a, 5 + ; FUN-NOT: bsll + ; FUN: andi + ; FUN: add + ; FUN: bnei + ; SHT-NOT: andi + ; SHT-NOT: add + ; SHT-NOT: bnei + ; SHT: bslli + + ret i8 %tmp.1 + ; FUN: rtsd + ; SHT: rtsd +} + +define i16 @test_i16(i16 %a, i16 %b) { + ; FUN: test_i16: + ; SHT: test_i16: + + %tmp.1 = shl i16 %a, %b + ; FUN-NOT: bsll + ; FUN: andi + ; FUN: add + ; FUN: bnei + ; SHT-NOT: andi + ; SHT-NOT: bnei + ; SHT: bsll + + ret i16 %tmp.1 + ; FUN: rtsd + ; SHT: rtsd +} + +define i16 @testc_i16(i16 %a, i16 %b) { + ; FUN: testc_i16: + ; SHT: testc_i16: + + %tmp.1 = shl i16 %a, 5 + ; FUN-NOT: bsll + ; FUN: andi + ; FUN: add + ; FUN: bnei + ; SHT-NOT: andi + ; SHT-NOT: add + ; SHT-NOT: bnei + ; SHT: bslli + + ret i16 %tmp.1 + ; FUN: rtsd + ; SHT: rtsd +} + +define i32 @test_i32(i32 %a, i32 %b) { + ; FUN: test_i32: + ; SHT: test_i32: + + %tmp.1 = shl i32 %a, %b + ; FUN-NOT: bsll + ; FUN: andi + ; FUN: add + ; FUN: bnei + ; SHT-NOT: andi + ; SHT-NOT: bnei + ; SHT: bsll + + ret i32 %tmp.1 + ; FUN: rtsd + ; SHT: rtsd +} + +define i32 @testc_i32(i32 %a, i32 %b) { + ; FUN: testc_i32: + ; SHT: testc_i32: + + %tmp.1 = shl i32 %a, 5 + ; FUN-NOT: bsll + ; FUN: andi + ; FUN: add + ; FUN: bnei + ; SHT-NOT: andi + ; SHT-NOT: add + ; SHT-NOT: bnei + ; SHT: bslli + + ret i32 %tmp.1 + ; FUN: rtsd + ; SHT: rtsd +} |