1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

Adding the MicroBlaze backend.

The MicroBlaze is a highly configurable 32-bit soft-microprocessor for
use on Xilinx FPGAs. For more information see:
http://www.xilinx.com/tools/microblaze.htm
http://en.wikipedia.org/wiki/MicroBlaze

The current LLVM MicroBlaze backend generates assembly which can be
compiled using the an appropriate binutils assembler.

llvm-svn: 96969
This commit is contained in:
Wesley Peck 2010-02-23 19:15:24 +00:00
parent 45a2c36ddc
commit 94cdac52e5
56 changed files with 6736 additions and 2 deletions

View File

@ -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

View File

@ -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" ;;

7
configure vendored
View File

@ -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
@ -4794,6 +4795,8 @@ else
SystemZ) TARGET_HAS_JIT=0
;;
Blackfin) TARGET_HAS_JIT=0
;;
MBlaze) TARGET_HAS_JIT=0
;;
*) TARGET_HAS_JIT=0
;;
@ -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" ;;

View File

@ -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
};

View File

@ -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")

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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]>>
]>;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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)>;

View File

@ -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>;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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"

View File

@ -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));
}

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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;
}
}];
}

View File

@ -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]>]>
]>;

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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");
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

315
test/CodeGen/MBlaze/cc.ll Normal file
View File

@ -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
}

View File

@ -0,0 +1,5 @@
load_lib llvm.exp
if { [llvm_supports_target MBlaze] } {
RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,c,cpp}]]
}

View File

@ -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
}

View File

@ -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
}

323
test/CodeGen/MBlaze/fsl.ll Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}