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:
parent
45a2c36ddc
commit
94cdac52e5
@ -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
|
||||
|
@ -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
7
configure
vendored
@ -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" ;;
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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")
|
||||
|
9
lib/Target/MBlaze/AsmPrinter/CMakeLists.txt
Normal file
9
lib/Target/MBlaze/AsmPrinter/CMakeLists.txt
Normal 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)
|
302
lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp
Normal file
302
lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp
Normal 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);
|
||||
}
|
17
lib/Target/MBlaze/AsmPrinter/Makefile
Normal file
17
lib/Target/MBlaze/AsmPrinter/Makefile
Normal 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
|
27
lib/Target/MBlaze/CMakeLists.txt
Normal file
27
lib/Target/MBlaze/CMakeLists.txt
Normal 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)
|
39
lib/Target/MBlaze/MBlaze.h
Normal file
39
lib/Target/MBlaze/MBlaze.h
Normal 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
|
85
lib/Target/MBlaze/MBlaze.td
Normal file
85
lib/Target/MBlaze/MBlaze.td
Normal 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;
|
||||
}
|
41
lib/Target/MBlaze/MBlazeCallingConv.td
Normal file
41
lib/Target/MBlaze/MBlazeCallingConv.td
Normal 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]>>
|
||||
]>;
|
75
lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp
Normal file
75
lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp
Normal 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);
|
||||
}
|
||||
|
368
lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp
Normal file
368
lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp
Normal 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);
|
||||
}
|
882
lib/Target/MBlaze/MBlazeISelLowering.cpp
Normal file
882
lib/Target/MBlaze/MBlazeISelLowering.cpp
Normal 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;
|
||||
}
|
146
lib/Target/MBlaze/MBlazeISelLowering.h
Normal file
146
lib/Target/MBlaze/MBlazeISelLowering.h
Normal 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
|
223
lib/Target/MBlaze/MBlazeInstrFPU.td
Normal file
223
lib/Target/MBlaze/MBlazeInstrFPU.td
Normal 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)>;
|
153
lib/Target/MBlaze/MBlazeInstrFSL.td
Normal file
153
lib/Target/MBlaze/MBlazeInstrFSL.td
Normal 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>;
|
246
lib/Target/MBlaze/MBlazeInstrFormats.td
Normal file
246
lib/Target/MBlaze/MBlazeInstrFormats.td
Normal 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;
|
||||
}
|
222
lib/Target/MBlaze/MBlazeInstrInfo.cpp
Normal file
222
lib/Target/MBlaze/MBlazeInstrInfo.cpp
Normal 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;
|
||||
}
|
242
lib/Target/MBlaze/MBlazeInstrInfo.h
Normal file
242
lib/Target/MBlaze/MBlazeInstrInfo.h
Normal 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
|
672
lib/Target/MBlaze/MBlazeInstrInfo.td
Normal file
672
lib/Target/MBlaze/MBlazeInstrInfo.td
Normal 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"
|
101
lib/Target/MBlaze/MBlazeIntrinsicInfo.cpp
Normal file
101
lib/Target/MBlaze/MBlazeIntrinsicInfo.cpp
Normal 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));
|
||||
}
|
32
lib/Target/MBlaze/MBlazeIntrinsicInfo.h
Normal file
32
lib/Target/MBlaze/MBlazeIntrinsicInfo.h
Normal 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
|
137
lib/Target/MBlaze/MBlazeIntrinsics.td
Normal file
137
lib/Target/MBlaze/MBlazeIntrinsics.td
Normal 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;
|
27
lib/Target/MBlaze/MBlazeMCAsmInfo.cpp
Normal file
27
lib/Target/MBlaze/MBlazeMCAsmInfo.cpp
Normal 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;
|
||||
}
|
30
lib/Target/MBlaze/MBlazeMCAsmInfo.h
Normal file
30
lib/Target/MBlaze/MBlazeMCAsmInfo.h
Normal 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
|
140
lib/Target/MBlaze/MBlazeMachineFunction.h
Normal file
140
lib/Target/MBlaze/MBlazeMachineFunction.h
Normal 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
|
378
lib/Target/MBlaze/MBlazeRegisterInfo.cpp
Normal file
378
lib/Target/MBlaze/MBlazeRegisterInfo.cpp
Normal 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"
|
||||
|
90
lib/Target/MBlaze/MBlazeRegisterInfo.h
Normal file
90
lib/Target/MBlaze/MBlazeRegisterInfo.h
Normal 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
|
186
lib/Target/MBlaze/MBlazeRegisterInfo.td
Normal file
186
lib/Target/MBlaze/MBlazeRegisterInfo.td
Normal 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;
|
||||
}
|
||||
}];
|
||||
}
|
63
lib/Target/MBlaze/MBlazeSchedule.td
Normal file
63
lib/Target/MBlaze/MBlazeSchedule.td
Normal 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]>]>
|
||||
]>;
|
31
lib/Target/MBlaze/MBlazeSubtarget.cpp
Normal file
31
lib/Target/MBlaze/MBlazeSubtarget.cpp
Normal 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);
|
||||
}
|
79
lib/Target/MBlaze/MBlazeSubtarget.h
Normal file
79
lib/Target/MBlaze/MBlazeSubtarget.h
Normal 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
|
66
lib/Target/MBlaze/MBlazeTargetMachine.cpp
Normal file
66
lib/Target/MBlaze/MBlazeTargetMachine.cpp
Normal 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;
|
||||
}
|
69
lib/Target/MBlaze/MBlazeTargetMachine.h
Normal file
69
lib/Target/MBlaze/MBlazeTargetMachine.h
Normal 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
|
88
lib/Target/MBlaze/MBlazeTargetObjectFile.cpp
Normal file
88
lib/Target/MBlaze/MBlazeTargetObjectFile.cpp
Normal 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);
|
||||
}
|
41
lib/Target/MBlaze/MBlazeTargetObjectFile.h
Normal file
41
lib/Target/MBlaze/MBlazeTargetObjectFile.h
Normal 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
|
23
lib/Target/MBlaze/Makefile
Normal file
23
lib/Target/MBlaze/Makefile
Normal 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
|
||||
|
7
lib/Target/MBlaze/TargetInfo/CMakeLists.txt
Normal file
7
lib/Target/MBlaze/TargetInfo/CMakeLists.txt
Normal 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)
|
19
lib/Target/MBlaze/TargetInfo/MBlazeTargetInfo.cpp
Normal file
19
lib/Target/MBlaze/TargetInfo/MBlazeTargetInfo.cpp
Normal 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");
|
||||
}
|
15
lib/Target/MBlaze/TargetInfo/Makefile
Normal file
15
lib/Target/MBlaze/TargetInfo/Makefile
Normal 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
|
73
test/CodeGen/MBlaze/brind.ll
Normal file
73
test/CodeGen/MBlaze/brind.ll
Normal 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
|
||||
}
|
80
test/CodeGen/MBlaze/callind.ll
Normal file
80
test/CodeGen/MBlaze/callind.ll
Normal 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
315
test/CodeGen/MBlaze/cc.ll
Normal 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
|
||||
}
|
5
test/CodeGen/MBlaze/dg.exp
Normal file
5
test/CodeGen/MBlaze/dg.exp
Normal file
@ -0,0 +1,5 @@
|
||||
load_lib llvm.exp
|
||||
|
||||
if { [llvm_supports_target MBlaze] } {
|
||||
RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,c,cpp}]]
|
||||
}
|
75
test/CodeGen/MBlaze/div.ll
Normal file
75
test/CodeGen/MBlaze/div.ll
Normal 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
|
||||
}
|
66
test/CodeGen/MBlaze/fpu.ll
Normal file
66
test/CodeGen/MBlaze/fpu.ll
Normal 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
323
test/CodeGen/MBlaze/fsl.ll
Normal 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
|
||||
}
|
70
test/CodeGen/MBlaze/imm.ll
Normal file
70
test/CodeGen/MBlaze/imm.ll
Normal 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
|
||||
}
|
79
test/CodeGen/MBlaze/jumptable.ll
Normal file
79
test/CodeGen/MBlaze/jumptable.ll
Normal 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
|
||||
}
|
47
test/CodeGen/MBlaze/loop.ll
Normal file
47
test/CodeGen/MBlaze/loop.ll
Normal 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
|
||||
}
|
51
test/CodeGen/MBlaze/mul.ll
Normal file
51
test/CodeGen/MBlaze/mul.ll
Normal 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
|
||||
}
|
23
test/CodeGen/MBlaze/mul64.ll
Normal file
23
test/CodeGen/MBlaze/mul64.ll
Normal 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
|
||||
}
|
15
test/CodeGen/MBlaze/select.ll
Normal file
15
test/CodeGen/MBlaze/select.ll
Normal 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
|
||||
}
|
117
test/CodeGen/MBlaze/shift.ll
Normal file
117
test/CodeGen/MBlaze/shift.ll
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user