Analog Devices Blackfin back-end.

Generate code for the Blackfin family of DSPs from Analog Devices:

  http://www.analog.com/en/embedded-processing-dsp/blackfin/processors/index.html
  
We aim to be compatible with the exsisting GNU toolchain found at:

  http://blackfin.uclinux.org/gf/project/toolchain
  
The back-end is experimental.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@77897 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jakob Stoklund Olesen 2009-08-02 17:32:10 +00:00
parent 4ea480499c
commit d950941e13
77 changed files with 5029 additions and 0 deletions

View File

@ -38,6 +38,7 @@ public:
alpha, // alpha
arm, // arm, armv.*
bfin, // blackfin
cellspu, // spu, cellspu
mips, // mips, mipsallegrex
mipsel, // mipsel, mipsallegrexel, psp

View File

@ -23,6 +23,7 @@ const char *Triple::getArchTypeName(ArchType Kind) {
case alpha: return "alpha";
case arm: return "arm";
case bfin: return "bfin";
case cellspu: return "cellspu";
case mips: return "mips";
case mipsel: return "mipsel";
@ -107,6 +108,8 @@ void Triple::Parse() const {
Arch = sparc;
else if (ArchName == "s390x")
Arch = systemz;
else if (ArchName == "bfin")
Arch = bfin;
else
Arch = UnknownArch;

View File

@ -0,0 +1,237 @@
//===-- BlackfinAsmPrinter.cpp - Blackfin LLVM assembly writer ------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a printer that converts from our internal representation
// of machine-dependent LLVM code to GAS-format BLACKFIN assembly language.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "asm-printer"
#include "Blackfin.h"
#include "BlackfinInstrInfo.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DwarfWriter.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetRegistry.h"
#include "llvm/Support/Mangler.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/FormattedStream.h"
using namespace llvm;
STATISTIC(EmittedInsts, "Number of machine instrs printed");
namespace {
class VISIBILITY_HIDDEN BlackfinAsmPrinter : public AsmPrinter {
public:
BlackfinAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
const TargetAsmInfo *TAI, bool V)
: AsmPrinter(O, TM, TAI, V) {}
virtual const char *getPassName() const {
return "Blackfin Assembly Printer";
}
void printOperand(const MachineInstr *MI, int opNum);
void printMemoryOperand(const MachineInstr *MI, int opNum);
bool printInstruction(const MachineInstr *MI); // autogenerated.
void emitLinkage(const std::string &n, GlobalValue::LinkageTypes l);
bool runOnMachineFunction(MachineFunction &F);
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode);
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode);
void PrintGlobalVariable(const GlobalVariable* GVar);
};
} // end of anonymous namespace
#include "BlackfinGenAsmWriter.inc"
extern "C" void LLVMInitializeBlackfinAsmPrinter() {
RegisterAsmPrinter<BlackfinAsmPrinter> X(TheBlackfinTarget);
}
void BlackfinAsmPrinter::emitLinkage(const std::string &name,
GlobalValue::LinkageTypes l) {
switch (l) {
default: llvm_unreachable("Unknown linkage type!");
case GlobalValue::InternalLinkage: // Symbols default to internal.
case GlobalValue::PrivateLinkage:
case GlobalValue::LinkerPrivateLinkage:
break;
case GlobalValue::ExternalLinkage:
O << TAI->getGlobalDirective() << name << "\n";
break;
case GlobalValue::LinkOnceAnyLinkage:
case GlobalValue::LinkOnceODRLinkage:
case GlobalValue::WeakAnyLinkage:
case GlobalValue::WeakODRLinkage:
O << TAI->getGlobalDirective() << name << "\n";
O << TAI->getWeakDefDirective() << name << "\n";
break;
}
}
void BlackfinAsmPrinter::PrintGlobalVariable(const GlobalVariable* GV) {
const TargetData *TD = TM.getTargetData();
if (!GV->hasInitializer() || EmitSpecialLLVMGlobal(GV))
return;
std::string name = Mang->getMangledName(GV);
Constant *C = GV->getInitializer();
SwitchToSection(getObjFileLowering().SectionForGlobal(GV, Mang, TM));
emitLinkage(name, GV->getLinkage());
EmitAlignment(TD->getPreferredAlignmentLog(GV), GV);
printVisibility(name, GV->getVisibility());
O << "\t.type " << name << ", STT_OBJECT\n";
O << "\t.size " << name << ',' << TD->getTypeAllocSize(C->getType()) << '\n';
O << name << ":\n";
EmitGlobalConstant(C);
}
/// runOnMachineFunction - This uses the printInstruction()
/// method to print assembly for each instruction.
///
bool BlackfinAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
SetupMachineFunction(MF);
EmitConstantPool(MF.getConstantPool());
EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
const Function *F = MF.getFunction();
SwitchToSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
EmitAlignment(2, F);
emitLinkage(CurrentFnName, F->getLinkage());
printVisibility(CurrentFnName, F->getVisibility());
O << "\t.type\t" << CurrentFnName << ", STT_FUNC\n"
<< CurrentFnName << ":\n";
if (DW)
DW->BeginFunction(&MF);
// Print out code for the function.
for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
I != E; ++I) {
// Print a label for the basic block.
if (!VerboseAsm && (I->pred_empty() || I->isOnlyReachableByFallthrough())) {
// This is an entry block or a block that's only reachable via a
// fallthrough edge. In non-VerboseAsm mode, don't print the label.
} else {
printBasicBlockLabel(I, true, true, VerboseAsm);
O << '\n';
}
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
II != E; ++II) {
// Print the assembly for the instruction.
printInstruction(II);
++EmittedInsts;
}
}
O << "\t.size " << CurrentFnName << ", .-" << CurrentFnName << "\n";
if (DW)
DW->EndFunction(&MF);
return false;
}
void BlackfinAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
const MachineOperand &MO = MI->getOperand (opNum);
const TargetRegisterInfo &RI = *TM.getRegisterInfo();
switch (MO.getType()) {
case MachineOperand::MO_Register:
assert (TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
"Virtual registers should be already mapped!");
O << RI.get(MO.getReg()).AsmName;
break;
case MachineOperand::MO_Immediate:
O << MO.getImm();
break;
case MachineOperand::MO_MachineBasicBlock:
printBasicBlockLabel(MO.getMBB(), false, false, false);
return;
case MachineOperand::MO_GlobalAddress:
O << Mang->getMangledName(MO.getGlobal());
printOffset(MO.getOffset());
break;
case MachineOperand::MO_ExternalSymbol:
O << Mang->makeNameProper(MO.getSymbolName());
break;
case MachineOperand::MO_ConstantPoolIndex:
O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
<< MO.getIndex();
break;
case MachineOperand::MO_JumpTableIndex:
O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
<< '_' << MO.getIndex();
break;
default:
llvm_unreachable("<unknown operand type>");
break;
}
}
void BlackfinAsmPrinter::printMemoryOperand(const MachineInstr *MI, int opNum) {
printOperand(MI, opNum);
if (MI->getOperand(opNum+1).isImm() && MI->getOperand(opNum+1).getImm() == 0)
return;
O << " + ";
printOperand(MI, opNum+1);
}
/// PrintAsmOperand - Print out an operand for an inline asm expression.
///
bool BlackfinAsmPrinter::PrintAsmOperand(const MachineInstr *MI,
unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode) {
if (ExtraCode && ExtraCode[0]) {
if (ExtraCode[1] != 0) return true; // Unknown modifier.
switch (ExtraCode[0]) {
default: return true; // Unknown modifier.
case 'r':
break;
}
}
printOperand(MI, OpNo);
return false;
}
bool BlackfinAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode) {
if (ExtraCode && ExtraCode[0])
return true; // Unknown modifier
O << '[';
printOperand(MI, OpNo);
O << ']';
return false;
}

View File

@ -0,0 +1,3 @@
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. )
add_llvm_library(LLVMBlackfinAsmPrinter BlackfinAsmPrinter.cpp)
add_dependencies(LLVMBlackfinAsmPrinter BlackfinCodeGenTable_gen)

View File

@ -0,0 +1,16 @@
##===- lib/Target/Blackfin/Makefile ------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
LIBRARYNAME = LLVMBlackfinAsmPrinter
# Hack: we need to include 'main' Blackfin target directory to grab private
# headers
CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,38 @@
//=== Blackfin.h - Top-level interface for Blackfin backend -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the entry points for global functions defined in the LLVM
// Blackfin back-end.
//
//===----------------------------------------------------------------------===//
#ifndef TARGET_BLACKFIN_H
#define TARGET_BLACKFIN_H
#include "llvm/Target/TargetMachine.h"
namespace llvm {
class FunctionPass;
class BlackfinTargetMachine;
FunctionPass *createBlackfinISelDag(BlackfinTargetMachine &TM,
CodeGenOpt::Level OptLevel);
extern Target TheBlackfinTarget;
} // end namespace llvm
// Defines symbolic names for Blackfin registers. This defines a mapping from
// register name to register number.
#include "BlackfinGenRegisterNames.inc"
// Defines symbolic names for the Blackfin instructions.
#include "BlackfinGenInstrNames.inc"
#endif

View File

@ -0,0 +1,52 @@
//===- Blackfin.td - Describe the Blackfin Target Machine --*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Target-independent interfaces which we are implementing
//===----------------------------------------------------------------------===//
include "llvm/Target/Target.td"
//===----------------------------------------------------------------------===//
// Blackfin Subtarget features.
//===----------------------------------------------------------------------===//
def FeatureSSYNC : SubtargetFeature<"ssync","ssyncWorkaround", "true",
"Work around SSYNC bugs">;
//===----------------------------------------------------------------------===//
// Register File, Calling Conv, Instruction Descriptions
//===----------------------------------------------------------------------===//
include "BlackfinRegisterInfo.td"
include "BlackfinCallingConv.td"
include "BlackfinInstrInfo.td"
def BlackfinInstrInfo : InstrInfo {}
//===----------------------------------------------------------------------===//
// Blackfin processors supported.
//===----------------------------------------------------------------------===//
class Proc<string Name, list<SubtargetFeature> Features>
: Processor<Name, NoItineraries, Features>;
def : Proc<"generic", [FeatureSSYNC]>;
//===----------------------------------------------------------------------===//
// Declare the target which we are implementing
//===----------------------------------------------------------------------===//
def Blackfin : Target {
// Pull in Instruction Info:
let InstructionSet = BlackfinInstrInfo;
}

View File

@ -0,0 +1,30 @@
//===--- BlackfinCallingConv.td - Calling Conventions ------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This describes the calling conventions for the Blackfin architectures.
//
//===----------------------------------------------------------------------===//
// Blackfin C Calling convention.
def CC_Blackfin : CallingConv<[
CCIfType<[i16], CCPromoteToType<i32>>,
CCIfSRet<CCAssignToReg<[P0]>>,
CCAssignToReg<[R0, R1, R2]>,
CCAssignToStack<4, 4>
]>;
//===----------------------------------------------------------------------===//
// Return Value Calling Conventions
//===----------------------------------------------------------------------===//
// Blackfin C return-value convention.
def RetCC_Blackfin : CallingConv<[
CCIfType<[i16], CCPromoteToType<i32>>,
CCAssignToReg<[R0, R1]>
]>;

View File

@ -0,0 +1,191 @@
//===- BlackfinISelDAGToDAG.cpp - A dag to dag inst selector for Blackfin -===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an instruction selector for the Blackfin target.
//
//===----------------------------------------------------------------------===//
#include "Blackfin.h"
#include "BlackfinISelLowering.h"
#include "BlackfinTargetMachine.h"
#include "BlackfinRegisterInfo.h"
#include "llvm/Intrinsics.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
//===----------------------------------------------------------------------===//
// Instruction Selector Implementation
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
/// BlackfinDAGToDAGISel - Blackfin specific code to select blackfin machine
/// instructions for SelectionDAG operations.
namespace {
class BlackfinDAGToDAGISel : public SelectionDAGISel {
/// Subtarget - Keep a pointer to the Blackfin Subtarget around so that we
/// can make the right decision when generating code for different targets.
//const BlackfinSubtarget &Subtarget;
public:
BlackfinDAGToDAGISel(BlackfinTargetMachine &TM, CodeGenOpt::Level OptLevel)
: SelectionDAGISel(TM, OptLevel) {}
virtual void InstructionSelect();
virtual const char *getPassName() const {
return "Blackfin DAG->DAG Pattern Instruction Selection";
}
// Include the pieces autogenerated from the target description.
#include "BlackfinGenDAGISel.inc"
private:
SDNode *Select(SDValue Op);
bool SelectADDRspii(SDValue Op, SDValue Addr,
SDValue &Base, SDValue &Offset);
// Walk the DAG after instruction selection, fixing register class issues.
void FixRegisterClasses(SelectionDAG &DAG);
const BlackfinInstrInfo &getInstrInfo() {
return *static_cast<const BlackfinTargetMachine&>(TM).getInstrInfo();
}
const BlackfinRegisterInfo *getRegisterInfo() {
return static_cast<const BlackfinTargetMachine&>(TM).getRegisterInfo();
}
};
} // end anonymous namespace
FunctionPass *llvm::createBlackfinISelDag(BlackfinTargetMachine &TM,
CodeGenOpt::Level OptLevel) {
return new BlackfinDAGToDAGISel(TM, OptLevel);
}
/// InstructionSelect - This callback is invoked by
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
void BlackfinDAGToDAGISel::InstructionSelect() {
// Select target instructions for the DAG.
SelectRoot(*CurDAG);
DOUT << "Selected selection DAG before regclass fixup:\n";
DEBUG(CurDAG->dump());
FixRegisterClasses(*CurDAG);
}
SDNode *BlackfinDAGToDAGISel::Select(SDValue Op) {
SDNode *N = Op.getNode();
DebugLoc dl = N->getDebugLoc();
if (N->isMachineOpcode())
return NULL; // Already selected.
switch (N->getOpcode()) {
default: break;
case ISD::FrameIndex: {
// Selects to ADDpp FI, 0 which in turn will become ADDimm7 SP, imm or ADDpp
// SP, Px
int FI = cast<FrameIndexSDNode>(N)->getIndex();
SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);
return CurDAG->SelectNodeTo(N, BF::ADDpp, MVT::i32, TFI,
CurDAG->getTargetConstant(0, MVT::i32));
}
}
return SelectCode(Op);
}
bool BlackfinDAGToDAGISel::SelectADDRspii(SDValue Op,
SDValue Addr,
SDValue &Base,
SDValue &Offset) {
FrameIndexSDNode *FIN = 0;
if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
Offset = CurDAG->getTargetConstant(0, MVT::i32);
return true;
}
if (Addr.getOpcode() == ISD::ADD) {
ConstantSDNode *CN = 0;
if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) &&
(CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) &&
(CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
// Constant positive word offset from frame index
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
return true;
}
}
return false;
}
static inline bool isCC(const TargetRegisterClass *RC) {
return RC == &BF::AnyCCRegClass || BF::AnyCCRegClass.hasSubClass(RC);
}
static inline bool isDCC(const TargetRegisterClass *RC) {
return RC == &BF::DRegClass || BF::DRegClass.hasSubClass(RC) || isCC(RC);
}
static void UpdateNodeOperand(SelectionDAG &DAG,
SDNode *N,
unsigned Num,
SDValue Val) {
SmallVector<SDValue, 8> ops(N->op_begin(), N->op_end());
ops[Num] = Val;
SDValue New = DAG.UpdateNodeOperands(SDValue(N, 0), ops.data(), ops.size());
DAG.ReplaceAllUsesWith(N, New.getNode());
}
// After instruction selection, insert COPY_TO_REGCLASS nodes to help in
// choosing the proper register classes.
void BlackfinDAGToDAGISel::FixRegisterClasses(SelectionDAG &DAG) {
const BlackfinInstrInfo &TII = getInstrInfo();
const BlackfinRegisterInfo *TRI = getRegisterInfo();
DAG.AssignTopologicalOrder();
HandleSDNode Dummy(DAG.getRoot());
for (SelectionDAG::allnodes_iterator NI = DAG.allnodes_begin();
NI != DAG.allnodes_end(); ++NI) {
if (NI->use_empty() || !NI->isMachineOpcode())
continue;
const TargetInstrDesc &DefTID = TII.get(NI->getMachineOpcode());
for (SDNode::use_iterator UI = NI->use_begin(); !UI.atEnd(); ++UI) {
if (!UI->isMachineOpcode())
continue;
if (UI.getUse().getResNo() >= DefTID.getNumDefs())
continue;
const TargetRegisterClass *DefRC =
DefTID.OpInfo[UI.getUse().getResNo()].getRegClass(TRI);
const TargetInstrDesc &UseTID = TII.get(UI->getMachineOpcode());
if (UseTID.getNumDefs()+UI.getOperandNo() >= UseTID.getNumOperands())
continue;
const TargetRegisterClass *UseRC =
UseTID.OpInfo[UseTID.getNumDefs()+UI.getOperandNo()].getRegClass(TRI);
if (!DefRC || !UseRC)
continue;
// We cannot copy CC <-> !(CC/D)
if ((isCC(DefRC) && !isDCC(UseRC)) || (isCC(UseRC) && !isDCC(DefRC))) {
SDNode *Copy =
DAG.getTargetNode(TargetInstrInfo::COPY_TO_REGCLASS,
NI->getDebugLoc(),
MVT::i32,
UI.getUse().get(),
DAG.getTargetConstant(BF::DRegClassID, MVT::i32));
UpdateNodeOperand(DAG, *UI, UI.getOperandNo(), SDValue(Copy, 0));
}
}
}
DAG.setRoot(Dummy.getValue());
}

View File

@ -0,0 +1,536 @@
//===- BlackfinISelLowering.cpp - Blackfin DAG Lowering Implementation ----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the interfaces that Blackfin uses to lower LLVM code
// into a selection DAG.
//
//===----------------------------------------------------------------------===//
#include "BlackfinISelLowering.h"
#include "BlackfinTargetMachine.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/ADT/VectorExtras.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
//===----------------------------------------------------------------------===//
// Calling Convention Implementation
//===----------------------------------------------------------------------===//
#include "BlackfinGenCallingConv.inc"
//===----------------------------------------------------------------------===//
// TargetLowering Implementation
//===----------------------------------------------------------------------===//
BlackfinTargetLowering::BlackfinTargetLowering(TargetMachine &TM)
: TargetLowering(TM, new TargetLoweringObjectFileELF()) {
setShiftAmountType(MVT::i16);
setBooleanContents(ZeroOrOneBooleanContent);
setStackPointerRegisterToSaveRestore(BF::SP);
setIntDivIsCheap(false);
// Set up the legal register classes.
addRegisterClass(MVT::i32, BF::DRegisterClass);
addRegisterClass(MVT::i16, BF::D16RegisterClass);
computeRegisterProperties();
// Blackfin doesn't have i1 loads or stores
setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote);
setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote);
setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote);
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
setOperationAction(ISD::JumpTable, MVT::i32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::Other, Expand);
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
setOperationAction(ISD::BR_CC, MVT::Other, Expand);
// i16 registers don't do much
setOperationAction(ISD::AND, MVT::i16, Promote);
setOperationAction(ISD::OR, MVT::i16, Promote);
setOperationAction(ISD::XOR, MVT::i16, Promote);
setOperationAction(ISD::CTPOP, MVT::i16, Promote);
// The expansion of CTLZ/CTTZ uses AND/OR, so we might as well promote
// immediately.
setOperationAction(ISD::CTLZ, MVT::i16, Promote);
setOperationAction(ISD::CTTZ, MVT::i16, Promote);
setOperationAction(ISD::SETCC, MVT::i16, Promote);
// Blackfin has no division
setOperationAction(ISD::SDIV, MVT::i16, Expand);
setOperationAction(ISD::SDIV, MVT::i32, Expand);
setOperationAction(ISD::SDIVREM, MVT::i16, Expand);
setOperationAction(ISD::SDIVREM, MVT::i32, Expand);
setOperationAction(ISD::SREM, MVT::i16, Expand);
setOperationAction(ISD::SREM, MVT::i32, Expand);
setOperationAction(ISD::UDIV, MVT::i16, Expand);
setOperationAction(ISD::UDIV, MVT::i32, Expand);
setOperationAction(ISD::UDIVREM, MVT::i16, Expand);
setOperationAction(ISD::UDIVREM, MVT::i32, Expand);
setOperationAction(ISD::UREM, MVT::i16, Expand);
setOperationAction(ISD::UREM, MVT::i32, Expand);
setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand);
setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
setOperationAction(ISD::MULHU, MVT::i32, Expand);
setOperationAction(ISD::MULHS, MVT::i32, Expand);
// No carry-in operations.
setOperationAction(ISD::ADDE, MVT::i32, Custom);
setOperationAction(ISD::SUBE, MVT::i32, Custom);
// Blackfin has no intrinsics for these particular operations.
setOperationAction(ISD::MEMBARRIER, MVT::Other, Expand);
setOperationAction(ISD::BSWAP, MVT::i32, Expand);
setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
// i32 has native CTPOP, but not CTLZ/CTTZ
setOperationAction(ISD::CTLZ, MVT::i32, Expand);
setOperationAction(ISD::CTTZ, MVT::i32, Expand);
// We don't have line number support yet.
setOperationAction(ISD::DBG_STOPPOINT, MVT::Other, Expand);
setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
setOperationAction(ISD::DBG_LABEL, MVT::Other, Expand);
setOperationAction(ISD::EH_LABEL, MVT::Other, Expand);
setOperationAction(ISD::DECLARE, MVT::Other, Expand);
// Use the default implementation.
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
setOperationAction(ISD::VAEND, MVT::Other, Expand);
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
// RET must be custom lowered, to meet ABI requirements
setOperationAction(ISD::RET, MVT::Other, Custom);
}
const char *BlackfinTargetLowering::getTargetNodeName(unsigned Opcode) const {
switch (Opcode) {
default: return 0;
case BFISD::CALL: return "BFISD::CALL";
case BFISD::RET_FLAG: return "BFISD::RET_FLAG";
case BFISD::Wrapper: return "BFISD::Wrapper";
}
}
MVT BlackfinTargetLowering::getSetCCResultType(MVT VT) const {
// SETCC always sets the CC register. Technically that is an i1 register, but
// that type is not legal, so we treat it as an i32 register.
return MVT::i32;
}
SDValue BlackfinTargetLowering::LowerGlobalAddress(SDValue Op,
SelectionDAG &DAG) {
DebugLoc DL = Op.getDebugLoc();
GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
Op = DAG.getTargetGlobalAddress(GV, MVT::i32);
return DAG.getNode(BFISD::Wrapper, DL, MVT::i32, Op);
}
SDValue BlackfinTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) {
DebugLoc DL = Op.getDebugLoc();
int JTI = cast<JumpTableSDNode>(Op)->getIndex();
Op = DAG.getTargetJumpTable(JTI, MVT::i32);
return DAG.getNode(BFISD::Wrapper, DL, MVT::i32, Op);
}
// FORMAL_ARGUMENTS(CHAIN, CC#, ISVARARG, FLAG0, ..., FLAGn) - This node
// represents the formal arguments for a function. CC# is a Constant value
// indicating the calling convention of the function, and ISVARARG is a
// flag that indicates whether the function is varargs or not. This node
// has one result value for each incoming argument, plus one for the output
// chain.
SDValue BlackfinTargetLowering::LowerFORMAL_ARGUMENTS(SDValue Op,
SelectionDAG &DAG) {
DebugLoc dl = Op.getDebugLoc();
SDValue Root = Op.getOperand(0);
unsigned CC = Op.getConstantOperandVal(1);
bool isVarArg = Op.getConstantOperandVal(2);
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs, *DAG.getContext());
CCInfo.AllocateStack(12, 4); // ABI requires 12 bytes stack space
CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_Blackfin);
SmallVector<SDValue, 8> ArgValues;
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
if (VA.isRegLoc()) {
MVT RegVT = VA.getLocVT();
TargetRegisterClass *RC = VA.getLocReg() == BF::P0 ?
BF::PRegisterClass : BF::DRegisterClass;
assert(RC->contains(VA.getLocReg()));
assert(RC->hasType(RegVT));
unsigned Reg = MF.getRegInfo().createVirtualRegister(RC);
MF.getRegInfo().addLiveIn(VA.getLocReg(), Reg);
SDValue ArgValue = DAG.getCopyFromReg(Root, dl, Reg, RegVT);
// If this is an 8 or 16-bit value, it is really passed promoted to 32
// bits. Insert an assert[sz]ext to capture this, then truncate to the
// right size.
if (VA.getLocInfo() == CCValAssign::SExt)
ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue,
DAG.getValueType(VA.getValVT()));
else if (VA.getLocInfo() == CCValAssign::ZExt)
ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue,
DAG.getValueType(VA.getValVT()));
if (VA.getLocInfo() != CCValAssign::Full)
ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
ArgValues.push_back(ArgValue);
} else {
assert(VA.isMemLoc());
unsigned ObjSize = VA.getLocVT().getStoreSizeInBits()/8;
int FI = MFI->CreateFixedObject(ObjSize, VA.getLocMemOffset());
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
ArgValues.push_back(DAG.getLoad(VA.getValVT(), dl, Root, FIN, NULL, 0));
}
}
ArgValues.push_back(Root);
// Return the new list of results.
return DAG.getNode(ISD::MERGE_VALUES, dl, Op.getNode()->getVTList(),
&ArgValues[0], ArgValues.size()).getValue(Op.getResNo());
}
SDValue BlackfinTargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) {
// CCValAssign - represent the assignment of the return value to locations.
SmallVector<CCValAssign, 16> RVLocs;
unsigned CC = DAG.getMachineFunction().getFunction()->getCallingConv();
bool isVarArg = DAG.getMachineFunction().getFunction()->isVarArg();
DebugLoc dl = Op.getDebugLoc();
// CCState - Info about the registers and stack slot.
CCState CCInfo(CC, isVarArg, DAG.getTarget(), RVLocs, *DAG.getContext());
// Analize return values of ISD::RET
CCInfo.AnalyzeReturn(Op.getNode(), RetCC_Blackfin);
// If this is the first return lowered for this function, add the regs to the
// liveout set for the function.
if (DAG.getMachineFunction().getRegInfo().liveout_empty()) {
for (unsigned i = 0; i != RVLocs.size(); ++i)
DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg());
}
SDValue Chain = Op.getOperand(0);
SDValue Flag;
// Copy the result values into the output registers.
for (unsigned i = 0; i != RVLocs.size(); ++i) {
CCValAssign &VA = RVLocs[i];
assert(VA.isRegLoc() && "Can only return in registers!");
SDValue Opi = Op.getOperand(i*2+1);
// Expand to i32 if necessary
switch (VA.getLocInfo()) {
default: llvm_unreachable("Unknown loc info!");
case CCValAssign::Full: break;
case CCValAssign::SExt:
Opi = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Opi);
break;
case CCValAssign::ZExt:
Opi = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Opi);
break;
case CCValAssign::AExt:
Opi = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Opi);
break;
}
// ISD::RET => ret chain, (regnum1,val1), ...
// So i*2+1 index only the regnums.
Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), Opi, SDValue());
// Guarantee that all emitted copies are stuck together with flags.
Flag = Chain.getValue(1);
}
if (Flag.getNode()) {
return DAG.getNode(BFISD::RET_FLAG, dl, MVT::Other, Chain, Flag);
} else {
return DAG.getNode(BFISD::RET_FLAG, dl, MVT::Other, Chain);
}
}
SDValue BlackfinTargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) {
CallSDNode *TheCall = cast<CallSDNode>(Op.getNode());
unsigned CallingConv = TheCall->getCallingConv();
SDValue Chain = TheCall->getChain();
SDValue Callee = TheCall->getCallee();
bool isVarArg = TheCall->isVarArg();
DebugLoc dl = TheCall->getDebugLoc();
// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
CCState CCInfo(CallingConv, isVarArg, DAG.getTarget(), ArgLocs,
*DAG.getContext());
CCInfo.AllocateStack(12, 4); // ABI requires 12 bytes stack space
CCInfo.AnalyzeCallOperands(TheCall, CC_Blackfin);
// Get the size of the outgoing arguments stack space requirement.
unsigned ArgsSize = CCInfo.getNextStackOffset();
Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, true));
SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
SmallVector<SDValue, 8> MemOpChains;
// Walk the register/memloc assignments, inserting copies/loads.
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
// Arguments start after the 5 first operands of ISD::CALL
SDValue Arg = TheCall->getArg(i);
// Promote the value if needed.
switch (VA.getLocInfo()) {
default: llvm_unreachable("Unknown loc info!");
case CCValAssign::Full: break;
case CCValAssign::SExt:
Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
break;
case CCValAssign::ZExt:
Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);
break;
case CCValAssign::AExt:
Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg);
break;
}
// Arguments that can be passed on register must be kept at
// RegsToPass vector
if (VA.isRegLoc()) {
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
} else {
assert(VA.isMemLoc());
int Offset = VA.getLocMemOffset();
assert(Offset%4 == 0);
assert(VA.getLocVT()==MVT::i32);
SDValue SPN = DAG.getCopyFromReg(Chain, dl, BF::SP, MVT::i32);
SDValue OffsetN = DAG.getIntPtrConstant(Offset);
OffsetN = DAG.getNode(ISD::ADD, dl, MVT::i32, SPN, OffsetN);
MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, OffsetN,
PseudoSourceValue::getStack(),
Offset));
}
}
// Transform all store nodes into one single node because
// all store nodes are independent of each other.
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
&MemOpChains[0], MemOpChains.size());
// Build a sequence of copy-to-reg nodes chained together with token
// chain and flag operands which copy the outgoing args into registers.
// The InFlag in necessary since all emited instructions must be
// stuck together.
SDValue InFlag;
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
RegsToPass[i].second, InFlag);
InFlag = Chain.getValue(1);
}
// If the callee is a GlobalAddress node (quite common, every direct call is)
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
// Likewise ExternalSymbol -> TargetExternalSymbol.
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i32);
else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32);
std::vector<MVT> NodeTys;
NodeTys.push_back(MVT::Other); // Returns a chain
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
SDValue Ops[] = { Chain, Callee, InFlag };
Chain = DAG.getNode(BFISD::CALL, dl, NodeTys, Ops,
InFlag.getNode() ? 3 : 2);
InFlag = Chain.getValue(1);
Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, true),
DAG.getIntPtrConstant(0, true), InFlag);
InFlag = Chain.getValue(1);
// Assign locations to each value returned by this call.
SmallVector<CCValAssign, 16> RVLocs;
CCState RVInfo(CallingConv, isVarArg, DAG.getTarget(), RVLocs,
*DAG.getContext());
RVInfo.AnalyzeCallResult(TheCall, RetCC_Blackfin);
SmallVector<SDValue, 8> ResultVals;
// Copy all of the result registers out of their specified physreg.
for (unsigned i = 0; i != RVLocs.size(); ++i) {
CCValAssign &RV = RVLocs[i];
unsigned Reg = RV.getLocReg();
Chain = DAG.getCopyFromReg(Chain, dl, Reg,
RVLocs[i].getLocVT(), InFlag);
SDValue Val = Chain.getValue(0);
InFlag = Chain.getValue(2);
Chain = Chain.getValue(1);
// Callee is responsible for extending any i16 return values.
switch (RV.getLocInfo()) {
case CCValAssign::SExt:
Val = DAG.getNode(ISD::AssertSext, dl, RV.getLocVT(), Val,
DAG.getValueType(RV.getValVT()));
break;
case CCValAssign::ZExt:
Val = DAG.getNode(ISD::AssertZext, dl, RV.getLocVT(), Val,
DAG.getValueType(RV.getValVT()));
break;
default:
break;
}
// Truncate to valtype
if (RV.getLocInfo() != CCValAssign::Full)
Val = DAG.getNode(ISD::TRUNCATE, dl, RV.getValVT(), Val);
ResultVals.push_back(Val);
}
ResultVals.push_back(Chain);
// Merge everything together with a MERGE_VALUES node.
SDValue merge = DAG.getNode(ISD::MERGE_VALUES, dl,
TheCall->getVTList(), &ResultVals[0],
ResultVals.size());
return merge;
}
// Expansion of ADDE / SUBE. This is a bit involved since blackfin doesn't have
// add-with-carry instructions.
SDValue BlackfinTargetLowering::LowerADDE(SDValue Op, SelectionDAG &DAG) {
// Operands: lhs, rhs, carry-in (AC0 flag)
// Results: sum, carry-out (AC0 flag)
DebugLoc dl = Op.getDebugLoc();
unsigned Opcode = Op.getOpcode()==ISD::ADDE ? BF::ADD : BF::SUB;
// zext incoming carry flag in AC0 to 32 bits
SDNode* CarryIn = DAG.getTargetNode(BF::MOVE_cc_ac0, dl, MVT::i32,
/* flag= */ Op.getOperand(2));
CarryIn = DAG.getTargetNode(BF::MOVECC_zext, dl, MVT::i32,
SDValue(CarryIn, 0));
// Add operands, produce sum and carry flag
SDNode *Sum = DAG.getTargetNode(Opcode, dl, MVT::i32, MVT::Flag,
Op.getOperand(0), Op.getOperand(1));
// Store intermediate carry from Sum
SDNode* Carry1 = DAG.getTargetNode(BF::MOVE_cc_ac0, dl, MVT::i32,
/* flag= */ SDValue(Sum, 1));
// Add incoming carry, again producing an output flag
Sum = DAG.getTargetNode(Opcode, dl, MVT::i32, MVT::Flag,
SDValue(Sum, 0), SDValue(CarryIn, 0));
// Update AC0 with the intermediate carry, producing a flag.
SDNode *CarryOut = DAG.getTargetNode(BF::OR_ac0_cc, dl, MVT::Flag,
SDValue(Carry1, 0));
// Compose (i32, flag) pair
SDValue ops[2] = { SDValue(Sum, 0), SDValue(CarryOut, 0) };
return DAG.getMergeValues(ops, 2, dl);
}
SDValue BlackfinTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) {
switch (Op.getOpcode()) {
default:
Op.getNode()->dump();
llvm_unreachable("Should not custom lower this!");
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
case ISD::GlobalTLSAddress:
llvm_unreachable("TLS not implemented for Blackfin.");
case ISD::JumpTable: return LowerJumpTable(Op, DAG);
// Frame & Return address. Currently unimplemented
case ISD::FRAMEADDR: return SDValue();
case ISD::RETURNADDR: return SDValue();
case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG);
case ISD::CALL: return LowerCALL(Op, DAG);
case ISD::RET: return LowerRET(Op, DAG);
case ISD::ADDE:
case ISD::SUBE: return LowerADDE(Op, DAG);
}
}
/// getFunctionAlignment - Return the Log2 alignment of this function.
unsigned BlackfinTargetLowering::getFunctionAlignment(const Function *F) const {
return 2;
}
//===----------------------------------------------------------------------===//
// Blackfin Inline Assembly Support
//===----------------------------------------------------------------------===//
/// getConstraintType - Given a constraint letter, return the type of
/// constraint it is for this target.
BlackfinTargetLowering::ConstraintType
BlackfinTargetLowering::getConstraintType(const std::string &Constraint) const {
if (Constraint.size() == 1) {
switch (Constraint[0]) {
default: break;
case 'r': return C_RegisterClass;
}
}
return TargetLowering::getConstraintType(Constraint);
}
std::pair<unsigned, const TargetRegisterClass*> BlackfinTargetLowering::
getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const {
if (Constraint.size() == 1) {
switch (Constraint[0]) {
case 'r':
return std::make_pair(0U, BF::DRegisterClass);
}
}
return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
}
std::vector<unsigned> BlackfinTargetLowering::
getRegClassForInlineAsmConstraint(const std::string &Constraint,
MVT VT) const {
if (Constraint.size() != 1)
return std::vector<unsigned>();
return std::vector<unsigned>();
}
bool BlackfinTargetLowering::
isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
// The Blackfin target isn't yet aware of offsets.
return false;
}

View File

@ -0,0 +1,61 @@
//===- BlackfinISelLowering.h - Blackfin DAG Lowering Interface -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interfaces that Blackfin uses to lower LLVM code into a
// selection DAG.
//
//===----------------------------------------------------------------------===//
#ifndef BLACKFIN_ISELLOWERING_H
#define BLACKFIN_ISELLOWERING_H
#include "llvm/Target/TargetLowering.h"
#include "Blackfin.h"
namespace llvm {
namespace BFISD {
enum {
FIRST_NUMBER = ISD::BUILTIN_OP_END,
CALL, // A call instruction.
RET_FLAG, // Return with a flag operand.
Wrapper // Address wrapper
};
}
class BlackfinTargetLowering : public TargetLowering {
int VarArgsFrameOffset; // Frame offset to start of varargs area.
public:
BlackfinTargetLowering(TargetMachine &TM);
virtual MVT getSetCCResultType(MVT VT) const;
virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG);
int getVarArgsFrameOffset() const { return VarArgsFrameOffset; }
ConstraintType getConstraintType(const std::string &Constraint) const;
std::pair<unsigned, const TargetRegisterClass*>
getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const;
std::vector<unsigned>
getRegClassForInlineAsmConstraint(const std::string &Constraint,
MVT VT) const;
virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const;
const char *getTargetNodeName(unsigned Opcode) const;
unsigned getFunctionAlignment(const Function *F) const;
private:
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG);
SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG);
SDValue LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG);
SDValue LowerRET(SDValue Op, SelectionDAG &DAG);
SDValue LowerCALL(SDValue Op, SelectionDAG &DAG);
SDValue LowerADDE(SDValue Op, SelectionDAG &DAG);
};
} // end namespace llvm
#endif // BLACKFIN_ISELLOWERING_H

View File

@ -0,0 +1,34 @@
//===--- BlackfinInstrFormats.td ---------------------------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Instruction format superclass
//===----------------------------------------------------------------------===//
class InstBfin<dag outs, dag ins, string asmstr, list<dag> pattern>
: Instruction {
field bits<32> Inst;
let Namespace = "BF";
dag OutOperandList = outs;
dag InOperandList = ins;
let AsmString = asmstr;
let Pattern = pattern;
}
// Single-word (16-bit) instructions
class F1<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstBfin<outs, ins, asmstr, pattern> {
}
// Double-word (32-bit) instructions
class F2<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstBfin<outs, ins, asmstr, pattern> {
}

View File

@ -0,0 +1,280 @@
//===- BlackfinInstrInfo.cpp - Blackfin Instruction Information -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Blackfin implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//
#include "BlackfinInstrInfo.h"
#include "BlackfinSubtarget.h"
#include "Blackfin.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Support/ErrorHandling.h"
#include "BlackfinGenInstrInfo.inc"
using namespace llvm;
BlackfinInstrInfo::BlackfinInstrInfo(BlackfinSubtarget &ST)
: TargetInstrInfoImpl(BlackfinInsts, array_lengthof(BlackfinInsts)),
RI(ST, *this),
Subtarget(ST) {}
/// Return true if the instruction is a register to register move and
/// leave the source and dest operands in the passed parameters.
bool BlackfinInstrInfo::isMoveInstr(const MachineInstr &MI,
unsigned &SrcReg,
unsigned &DstReg,
unsigned &SrcSR,
unsigned &DstSR) const {
SrcSR = DstSR = 0; // No sub-registers.
switch (MI.getOpcode()) {
case BF::MOVE:
case BF::MOVE_ncccc:
case BF::MOVE_ccncc:
case BF::MOVECC_zext:
case BF::MOVECC_nz:
DstReg = MI.getOperand(0).getReg();
SrcReg = MI.getOperand(1).getReg();
return true;
case BF::SLL16i:
if (MI.getOperand(2).getImm()!=0)
return false;
DstReg = MI.getOperand(0).getReg();
SrcReg = MI.getOperand(1).getReg();
return true;
default:
return false;
}
}
/// isLoadFromStackSlot - If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than loading from the stack slot.
unsigned BlackfinInstrInfo::isLoadFromStackSlot(const MachineInstr *MI,
int &FrameIndex) const {
switch (MI->getOpcode()) {
default: break;
case BF::LOAD32fi:
case BF::LOAD16fi:
if (MI->getOperand(1).isFI() &&
MI->getOperand(2).isImm() &&
MI->getOperand(2).getImm() == 0) {
FrameIndex = MI->getOperand(1).getIndex();
return MI->getOperand(0).getReg();
}
break;
}
return 0;
}
/// isStoreToStackSlot - If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than storing to the stack slot.
unsigned BlackfinInstrInfo::isStoreToStackSlot(const MachineInstr *MI,
int &FrameIndex) const {
switch (MI->getOpcode()) {
default: break;
case BF::STORE32fi:
case BF::STORE16fi:
if (MI->getOperand(1).isFI() &&
MI->getOperand(2).isImm() &&
MI->getOperand(2).getImm() == 0) {
FrameIndex = MI->getOperand(1).getIndex();
return MI->getOperand(0).getReg();
}
break;
}
return 0;
}
unsigned BlackfinInstrInfo::
InsertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
const SmallVectorImpl<MachineOperand> &Cond) const {
// FIXME this should probably have a DebugLoc operand
DebugLoc dl = DebugLoc::getUnknownLoc();
// Shouldn't be a fall through.
assert(TBB && "InsertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 1 || Cond.size() == 0) &&
"Branch conditions have one component!");
if (Cond.empty()) {
// Unconditional branch?
assert(!FBB && "Unconditional branch with multiple successors!");
BuildMI(&MBB, dl, get(BF::JUMPa)).addMBB(TBB);
return 1;
}
// Conditional branch.
llvm_unreachable("Implement conditional branches!");
}
static bool inClass(const TargetRegisterClass &Test,
unsigned Reg,
const TargetRegisterClass *RC) {
if (TargetRegisterInfo::isPhysicalRegister(Reg))
return Test.contains(Reg);
else
return &Test==RC || Test.hasSubClass(RC);
}
bool BlackfinInstrInfo::copyRegToReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned DestReg,
unsigned SrcReg,
const TargetRegisterClass *DestRC,
const TargetRegisterClass *SrcRC) const {
DebugLoc dl = DebugLoc::getUnknownLoc();
if (inClass(BF::ALLRegClass, DestReg, DestRC) &&
inClass(BF::ALLRegClass, SrcReg, SrcRC)) {
BuildMI(MBB, I, dl, get(BF::MOVE), DestReg).addReg(SrcReg);
return true;
}
if (inClass(BF::D16RegClass, DestReg, DestRC) &&
inClass(BF::D16RegClass, SrcReg, SrcRC)) {
BuildMI(MBB, I, dl, get(BF::SLL16i), DestReg).addReg(SrcReg).addImm(0);
return true;
}
if (inClass(BF::AnyCCRegClass, SrcReg, SrcRC) &&
inClass(BF::DRegClass, DestReg, DestRC)) {
if (inClass(BF::NotCCRegClass, SrcReg, SrcRC)) {
BuildMI(MBB, I, dl, get(BF::MOVENCC_z), DestReg).addReg(SrcReg);
BuildMI(MBB, I, dl, get(BF::BITTGL), DestReg).addReg(DestReg).addImm(0);
} else {
BuildMI(MBB, I, dl, get(BF::MOVECC_zext), DestReg).addReg(SrcReg);
}
return true;
}
if (inClass(BF::AnyCCRegClass, DestReg, DestRC) &&
inClass(BF::DRegClass, SrcReg, SrcRC)) {
if (inClass(BF::NotCCRegClass, DestReg, DestRC))
BuildMI(MBB, I, dl, get(BF::SETEQri_not), DestReg).addReg(SrcReg);
else
BuildMI(MBB, I, dl, get(BF::MOVECC_nz), DestReg).addReg(SrcReg);
return true;
}
if (inClass(BF::NotCCRegClass, DestReg, DestRC) &&
inClass(BF::JustCCRegClass, SrcReg, SrcRC)) {
BuildMI(MBB, I, dl, get(BF::MOVE_ncccc), DestReg).addReg(SrcReg);
return true;
}
if (inClass(BF::JustCCRegClass, DestReg, DestRC) &&
inClass(BF::NotCCRegClass, SrcReg, SrcRC)) {
BuildMI(MBB, I, dl, get(BF::MOVE_ccncc), DestReg).addReg(SrcReg);
return true;
}
llvm_unreachable((std::string("Bad regclasses for reg-to-reg copy: ")+
SrcRC->getName() + " -> " + DestRC->getName()).c_str());
return false;
}
void
BlackfinInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned SrcReg,
bool isKill,
int FI,
const TargetRegisterClass *RC) const {
DebugLoc DL = I != MBB.end() ?
I->getDebugLoc() : DebugLoc::getUnknownLoc();
if (inClass(BF::DPRegClass, SrcReg, RC)) {
BuildMI(MBB, I, DL, get(BF::STORE32fi))
.addReg(SrcReg, getKillRegState(isKill))
.addFrameIndex(FI)
.addImm(0);
return;
}
if (inClass(BF::D16RegClass, SrcReg, RC)) {
BuildMI(MBB, I, DL, get(BF::STORE16fi))
.addReg(SrcReg, getKillRegState(isKill))
.addFrameIndex(FI)
.addImm(0);
return;
}
if (inClass(BF::AnyCCRegClass, SrcReg, RC)) {
BuildMI(MBB, I, DL, get(BF::STORE8fi))
.addReg(SrcReg, getKillRegState(isKill))
.addFrameIndex(FI)
.addImm(0);
return;
}
llvm_unreachable((std::string("Cannot store regclass to stack slot: ")+
RC->getName()).c_str());
}
void BlackfinInstrInfo::
storeRegToAddr(MachineFunction &MF,
unsigned SrcReg,
bool isKill,
SmallVectorImpl<MachineOperand> &Addr,
const TargetRegisterClass *RC,
SmallVectorImpl<MachineInstr*> &NewMIs) const {
llvm_unreachable("storeRegToAddr not implemented");
}
void
BlackfinInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned DestReg,
int FI,
const TargetRegisterClass *RC) const {
DebugLoc DL = I != MBB.end() ?
I->getDebugLoc() : DebugLoc::getUnknownLoc();
if (inClass(BF::DPRegClass, DestReg, RC)) {
BuildMI(MBB, I, DL, get(BF::LOAD32fi), DestReg)
.addFrameIndex(FI)
.addImm(0);
return;
}
if (inClass(BF::D16RegClass, DestReg, RC)) {
BuildMI(MBB, I, DL, get(BF::LOAD16fi), DestReg)
.addFrameIndex(FI)
.addImm(0);
return;
}
if (inClass(BF::AnyCCRegClass, DestReg, RC)) {
BuildMI(MBB, I, DL, get(BF::LOAD8fi), DestReg)
.addFrameIndex(FI)
.addImm(0);
return;
}
llvm_unreachable("Cannot load regclass from stack slot");
}
void BlackfinInstrInfo::
loadRegFromAddr(MachineFunction &MF,
unsigned DestReg,
SmallVectorImpl<MachineOperand> &Addr,
const TargetRegisterClass *RC,
SmallVectorImpl<MachineInstr*> &NewMIs) const {
llvm_unreachable("loadRegFromAddr not implemented");
}

View File

@ -0,0 +1,80 @@
//===- BlackfinInstrInfo.h - Blackfin Instruction Information ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Blackfin implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//
#ifndef BLACKFININSTRUCTIONINFO_H
#define BLACKFININSTRUCTIONINFO_H
#include "llvm/Target/TargetInstrInfo.h"
#include "BlackfinRegisterInfo.h"
namespace llvm {
class BlackfinInstrInfo : public TargetInstrInfoImpl {
const BlackfinRegisterInfo RI;
const BlackfinSubtarget& Subtarget;
public:
explicit BlackfinInstrInfo(BlackfinSubtarget &ST);
/// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
/// such, whenever a client has an instance of instruction info, it should
/// always be able to get register info as well (through this method).
virtual const BlackfinRegisterInfo &getRegisterInfo() const { return RI; }
virtual bool isMoveInstr(const MachineInstr &MI,
unsigned &SrcReg, unsigned &DstReg,
unsigned &SrcSubIdx, unsigned &DstSubIdx) const;
virtual unsigned isLoadFromStackSlot(const MachineInstr *MI,
int &FrameIndex) const;
virtual unsigned isStoreToStackSlot(const MachineInstr *MI,
int &FrameIndex) const;
virtual unsigned
InsertBranch(MachineBasicBlock &MBB,
MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
const SmallVectorImpl<MachineOperand> &Cond) const;
virtual bool copyRegToReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned DestReg, unsigned SrcReg,
const TargetRegisterClass *DestRC,
const TargetRegisterClass *SrcRC) const;
virtual void storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned SrcReg, bool isKill,
int FrameIndex,
const TargetRegisterClass *RC) const;
virtual void storeRegToAddr(MachineFunction &MF,
unsigned SrcReg, bool isKill,
SmallVectorImpl<MachineOperand> &Addr,
const TargetRegisterClass *RC,
SmallVectorImpl<MachineInstr*> &NewMIs) const;
virtual void loadRegFromStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned DestReg, int FrameIndex,
const TargetRegisterClass *RC) const;
virtual void loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
SmallVectorImpl<MachineOperand> &Addr,
const TargetRegisterClass *RC,
SmallVectorImpl<MachineInstr*> &NewMIs) const;
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,838 @@
//===- BlackfinInstrInfo.td - Target Description for Blackfin Target ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the Blackfin instructions in TableGen format.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Instruction format superclass
//===----------------------------------------------------------------------===//
include "BlackfinInstrFormats.td"
// These are target-independent nodes, but have target-specific formats.
def SDT_BfinCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>;
def SDT_BfinCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>,
SDTCisVT<1, i32> ]>;
def BfinCallseqStart : SDNode<"ISD::CALLSEQ_START", SDT_BfinCallSeqStart,
[SDNPHasChain, SDNPOutFlag]>;
def BfinCallseqEnd : SDNode<"ISD::CALLSEQ_END", SDT_BfinCallSeqEnd,
[SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
def SDT_BfinCall : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>;
def BfinCall : SDNode<"BFISD::CALL", SDT_BfinCall,
[SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
def BfinRet: SDNode<"BFISD::RET_FLAG", SDTNone,
[SDNPHasChain, SDNPOptInFlag]>;
def BfinWrapper: SDNode<"BFISD::Wrapper", SDTIntUnaryOp>;
//===----------------------------------------------------------------------===//
// Transformations
//===----------------------------------------------------------------------===//
def trailingZeros_xform : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant(N->getAPIntValue().countTrailingZeros(),
MVT::i32);
}]>;
def trailingOnes_xform : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant(N->getAPIntValue().countTrailingOnes(),
MVT::i32);
}]>;
def LO16 : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant((unsigned short)N->getZExtValue(), MVT::i16);
}]>;
def HI16 : SDNodeXForm<imm, [{
// Transformation function: shift the immediate value down into the low bits.
return CurDAG->getTargetConstant((unsigned)N->getZExtValue() >> 16, MVT::i16);
}]>;
//===----------------------------------------------------------------------===//
// Immediates
//===----------------------------------------------------------------------===//
def imm3 : PatLeaf<(imm), [{return isImm<3>(N->getSExtValue());}]>;
def uimm3 : PatLeaf<(imm), [{return isUimm<3>(N->getZExtValue());}]>;
def uimm4 : PatLeaf<(imm), [{return isUimm<4>(N->getZExtValue());}]>;
def uimm5 : PatLeaf<(imm), [{return isUimm<5>(N->getZExtValue());}]>;
def uimm5m2 : PatLeaf<(imm), [{
uint64_t value = N->getZExtValue();
return value % 2 == 0 && isUimm<5>(value);
}]>;
def uimm6m4 : PatLeaf<(imm), [{
uint64_t value = N->getZExtValue();
return value % 4 == 0 && isUimm<6>(value);
}]>;
def imm7 : PatLeaf<(imm), [{return isImm<7>(N->getSExtValue());}]>;
def imm16 : PatLeaf<(imm), [{return isImm<16>(N->getSExtValue());}]>;
def uimm16 : PatLeaf<(imm), [{return isUimm<16>(N->getZExtValue());}]>;
def ximm16 : PatLeaf<(imm), [{
int64_t value = N->getSExtValue();
return value < (1<<16) && value >= -(1<<15);
}]>;
def imm17m2 : PatLeaf<(imm), [{
int64_t value = N->getSExtValue();
return value % 2 == 0 && isImm<17>(value);
}]>;
def imm18m4 : PatLeaf<(imm), [{
int64_t value = N->getSExtValue();
return value % 4 == 0 && isImm<18>(value);
}]>;
// 32-bit bitmask transformed to a bit number
def uimm5mask : Operand<i32>, PatLeaf<(imm), [{
return isPowerOf2_32(N->getZExtValue());
}], trailingZeros_xform>;
// 32-bit inverse bitmask transformed to a bit number
def uimm5imask : Operand<i32>, PatLeaf<(imm), [{
return isPowerOf2_32(~N->getZExtValue());
}], trailingOnes_xform>;
//===----------------------------------------------------------------------===//
// Operands
//===----------------------------------------------------------------------===//
def calltarget : Operand<iPTR>;
def brtarget : Operand<OtherVT>;
// Addressing modes
def ADDRspii : ComplexPattern<i32, 2, "SelectADDRspii", [add, frameindex], []>;
// Address operands
def MEMii : Operand<i32> {
let PrintMethod = "printMemoryOperand";
let MIOperandInfo = (ops i32imm, i32imm);
}
//===----------------------------------------------------------------------===//
// Instructions
//===----------------------------------------------------------------------===//
// Pseudo instructions.
class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstBfin<outs, ins, asmstr, pattern>;
let Defs = [SP], Uses = [SP] in {
def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt),
"${:comment}ADJCALLSTACKDOWN $amt",
[(BfinCallseqStart timm:$amt)]>;
def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
"${:comment}ADJCALLSTACKUP $amt1 $amt2",
[(BfinCallseqEnd timm:$amt1, timm:$amt2)]>;
}
//===----------------------------------------------------------------------===//
// Table C-9. Program Flow Control Instructions
//===----------------------------------------------------------------------===//
let isBranch = 1, isTerminator = 1 in {
let isIndirectBranch = 1 in
def JUMPp : F1<(outs), (ins P:$target),
"JUMP ($target);",
[(brind P:$target)]>;
// TODO JUMP (PC-P)
// NOTE: assembler chooses between JUMP.S and JUMP.L
def JUMPa : F1<(outs), (ins brtarget:$target),
"jump $target;",
[(br bb:$target)]>;
def JUMPcc : F1<(outs), (ins AnyCC:$cc, brtarget:$target),
"if $cc jump $target;",
[(brcond AnyCC:$cc, bb:$target)]>;
}
let isCall = 1,
Defs = [R0, R1, R2, R3, P0, P1, P2, LB0, LB1, LC0, LC1, RETS, ASTAT] in {
def CALLa: F1<(outs), (ins calltarget:$func, variable_ops),
"call $func;", []>;
def CALLp: F1<(outs), (ins P:$func, variable_ops),
"call ($func);", [(BfinCall P:$func)]>;
}
let isReturn = 1,
isTerminator = 1,
Uses = [RETS] in
def RTS: F1<(outs), (ins), "rts;", [(BfinRet)]>;
//===----------------------------------------------------------------------===//
// Table C-10. Load / Store Instructions
//===----------------------------------------------------------------------===//
// Immediate constant loads
// sext immediate, i32 D/P regs
def LOADimm7: F1<(outs DP:$dst), (ins i32imm:$src),
"$dst = $src (x);",
[(set DP:$dst, imm7:$src)]>;
// zext immediate, i32 reg groups 0-3
def LOADuimm16: F2<(outs GR:$dst), (ins i32imm:$src),
"$dst = $src (z);",
[(set GR:$dst, uimm16:$src)]>;
// sext immediate, i32 reg groups 0-3
def LOADimm16: F2<(outs GR:$dst), (ins i32imm:$src),
"$dst = $src (x);",
[(set GR:$dst, imm16:$src)]>;
// Pseudo-instruction for loading a general 32-bit constant.
def LOAD32imm: Pseudo<(outs GR:$dst), (ins i32imm:$src),
"$dst.h = ($src >> 16); $dst.l = ($src & 0xffff);",
[(set GR:$dst, imm:$src)]>;
def LOAD32sym: Pseudo<(outs GR:$dst), (ins i32imm:$src),
"$dst.h = $src; $dst.l = $src;", []>;
// 16-bit immediate, i16 reg groups 0-3
def LOAD16i: F2<(outs GR16:$dst), (ins i16imm:$src),
"$dst = $src;", []>;
def : Pat<(BfinWrapper (i32 tglobaladdr:$addr)),
(LOAD32sym tglobaladdr:$addr)>;
def : Pat<(BfinWrapper (i32 tjumptable:$addr)),
(LOAD32sym tjumptable:$addr)>;
// We cannot copy from GR16 to D16, and codegen wants to insert copies if we
// emit GR16 instructions. As a hack, we use this fake instruction instead.
def LOAD16i_d16: F2<(outs D16:$dst), (ins i16imm:$src),
"$dst = $src;",
[(set D16:$dst, ximm16:$src)]>;
// Memory loads with patterns
def LOAD32p: F1<(outs DP:$dst), (ins P:$ptr),
"$dst = [$ptr];",
[(set DP:$dst, (load P:$ptr))]>;
// Pseudo-instruction for loading a stack slot
def LOAD32fi: Pseudo<(outs DP:$dst), (ins MEMii:$mem),
"${:comment}FI $dst = [$mem];",
[(set DP:$dst, (load ADDRspii:$mem))]>;
// Note: Expands to multiple insns
def LOAD16fi: Pseudo<(outs D16:$dst), (ins MEMii:$mem),
"${:comment}FI $dst = [$mem];",
[(set D16:$dst, (load ADDRspii:$mem))]>;
// Pseudo-instruction for loading a stack slot, used for AnyCC regs.
// Replaced with Load D + CC=D
def LOAD8fi: Pseudo<(outs AnyCC:$dst), (ins MEMii:$mem),
"${:comment}FI $dst = B[$mem];",
[(set AnyCC:$dst, (load ADDRspii:$mem))]>;
def LOAD32p_uimm6m4: F1<(outs DP:$dst), (ins P:$ptr, i32imm:$off),
"$dst = [$ptr + $off];",
[(set DP:$dst, (load (add P:$ptr, uimm6m4:$off)))]>;
def LOAD32p_imm18m4: F2<(outs DP:$dst), (ins P:$ptr, i32imm:$off),
"$dst = [$ptr + $off];",
[(set DP:$dst, (load (add P:$ptr, imm18m4:$off)))]>;
def LOAD32p_16z: F1<(outs D:$dst), (ins P:$ptr),
"$dst = W[$ptr] (z);",
[(set D:$dst, (zextloadi16 P:$ptr))]>;
def : Pat<(i32 (extloadi16 P:$ptr)),(LOAD32p_16z P:$ptr)>;
def LOAD32p_uimm5m2_16z: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off),
"$dst = w[$ptr + $off] (z);",
[(set D:$dst, (zextloadi16 (add P:$ptr,
uimm5m2:$off)))]>;
def : Pat<(i32 (extloadi16 (add P:$ptr, uimm5m2:$off))),
(LOAD32p_uimm5m2_16z P:$ptr, imm:$off)>;
def LOAD32p_imm17m2_16z: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off),
"$dst = w[$ptr + $off] (z);",
[(set D:$dst,
(zextloadi16 (add P:$ptr, imm17m2:$off)))]>;
def : Pat<(i32 (extloadi16 (add P:$ptr, imm17m2:$off))),
(LOAD32p_imm17m2_16z P:$ptr, imm:$off)>;
def LOAD32p_16s: F1<(outs D:$dst), (ins P:$ptr),
"$dst = w[$ptr] (x);",
[(set D:$dst, (sextloadi16 P:$ptr))]>;
def LOAD32p_uimm5m2_16s: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off),
"$dst = w[$ptr + $off] (x);",
[(set D:$dst,
(sextloadi16 (add P:$ptr, uimm5m2:$off)))]>;
def LOAD32p_imm17m2_16s: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off),
"$dst = w[$ptr + $off] (x);",
[(set D:$dst,
(sextloadi16 (add P:$ptr, imm17m2:$off)))]>;
def LOAD16pi: F1<(outs D16:$dst), (ins PI:$ptr),
"$dst = w[$ptr];",
[(set D16:$dst, (load PI:$ptr))]>;
def LOAD32p_8z: F1<(outs D:$dst), (ins P:$ptr),
"$dst = B[$ptr] (z);",
[(set D:$dst, (zextloadi8 P:$ptr))]>;
def : Pat<(i32 (extloadi8 P:$ptr)), (LOAD32p_8z P:$ptr)>;
def : Pat<(i16 (extloadi8 P:$ptr)),
(EXTRACT_SUBREG (LOAD32p_8z P:$ptr), bfin_subreg_lo16)>;
def : Pat<(i16 (zextloadi8 P:$ptr)),
(EXTRACT_SUBREG (LOAD32p_8z P:$ptr), bfin_subreg_lo16)>;
def LOAD32p_imm16_8z: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off),
"$dst = b[$ptr + $off] (z);",
[(set D:$dst, (zextloadi8 (add P:$ptr, imm16:$off)))]>;
def : Pat<(i32 (extloadi8 (add P:$ptr, imm16:$off))),
(LOAD32p_imm16_8z P:$ptr, imm:$off)>;
def : Pat<(i16 (extloadi8 (add P:$ptr, imm16:$off))),
(EXTRACT_SUBREG (LOAD32p_imm16_8z P:$ptr, imm:$off),
bfin_subreg_lo16)>;
def : Pat<(i16 (zextloadi8 (add P:$ptr, imm16:$off))),
(EXTRACT_SUBREG (LOAD32p_imm16_8z P:$ptr, imm:$off),
bfin_subreg_lo16)>;
def LOAD32p_8s: F1<(outs D:$dst), (ins P:$ptr),
"$dst = b[$ptr] (x);",
[(set D:$dst, (sextloadi8 P:$ptr))]>;
def : Pat<(i16 (sextloadi8 P:$ptr)),
(EXTRACT_SUBREG (LOAD32p_8s P:$ptr), bfin_subreg_lo16)>;
def LOAD32p_imm16_8s: F1<(outs D:$dst), (ins P:$ptr, i32imm:$off),
"$dst = b[$ptr + $off] (x);",
[(set D:$dst, (sextloadi8 (add P:$ptr, imm16:$off)))]>;
def : Pat<(i16 (sextloadi8 (add P:$ptr, imm16:$off))),
(EXTRACT_SUBREG (LOAD32p_imm16_8s P:$ptr, imm:$off),
bfin_subreg_lo16)>;
// Memory loads without patterns
let mayLoad = 1 in {
multiclass LOAD_incdec<RegisterClass drc, RegisterClass prc,
string mem="", string suf=";"> {
def _inc : F1<(outs drc:$dst, prc:$ptr_wb), (ins prc:$ptr),
!strconcat(!subst("M", mem, "$dst = M[$ptr++]"), suf), []>;
def _dec : F1<(outs drc:$dst, prc:$ptr_wb), (ins prc:$ptr),
!strconcat(!subst("M", mem, "$dst = M[$ptr--]"), suf), []>;
}
multiclass LOAD_incdecpost<RegisterClass drc, RegisterClass prc,
string mem="", string suf=";">
: LOAD_incdec<drc, prc, mem, suf> {
def _post : F1<(outs drc:$dst, prc:$ptr_wb), (ins prc:$ptr, prc:$off),
!strconcat(!subst("M", mem, "$dst = M[$ptr++$off]"), suf), []>;
}
defm LOAD32p: LOAD_incdec<DP, P>;
defm LOAD32i: LOAD_incdec<D, I>;
defm LOAD8z32p: LOAD_incdec<D, P, "b", " (z);">;
defm LOAD8s32p: LOAD_incdec<D, P, "b", " (x);">;
defm LOADhi: LOAD_incdec<D16, I, "w">;
defm LOAD16z32p: LOAD_incdecpost<D, P, "w", " (z);">;
defm LOAD16s32p: LOAD_incdecpost<D, P, "w", " (x);">;
def LOAD32p_post: F1<(outs D:$dst, P:$ptr_wb), (ins P:$ptr, P:$off),
"$dst = [$ptr ++ $off];", []>;
// Note: $fp MUST be FP
def LOAD32fp_nimm7m4: F1<(outs DP:$dst), (ins P:$fp, i32imm:$off),
"$dst = [$fp - $off];", []>;
def LOAD32i: F1<(outs D:$dst), (ins I:$ptr),
"$dst = [$ptr];", []>;
def LOAD32i_post: F1<(outs D:$dst, I:$ptr_wb), (ins I:$ptr, M:$off),
"$dst = [$ptr ++ $off];", []>;
def LOADhp_post: F1<(outs D16:$dst, P:$ptr_wb), (ins P:$ptr, P:$off),
"$dst = w[$ptr ++ $off];", []>;
}
// Memory stores with patterns
def STORE32p: F1<(outs), (ins DP:$val, P:$ptr),
"[$ptr] = $val;",
[(store DP:$val, P:$ptr)]>;
// Pseudo-instructions for storing to a stack slot
def STORE32fi: Pseudo<(outs), (ins DP:$val, MEMii:$mem),
"${:comment}FI [$mem] = $val;",
[(store DP:$val, ADDRspii:$mem)]>;
// Note: This stack-storing pseudo-instruction is expanded to multiple insns
def STORE16fi: Pseudo<(outs), (ins D16:$val, MEMii:$mem),
"${:comment}FI [$mem] = $val;",
[(store D16:$val, ADDRspii:$mem)]>;
// Pseudo-instructions for storing AnyCC register to a stack slot.
// Replaced with D=CC + STORE byte
def STORE8fi: Pseudo<(outs), (ins AnyCC:$val, MEMii:$mem),
"${:comment}FI b[$mem] = $val;",
[(store AnyCC:$val, ADDRspii:$mem)]>;
def STORE32p_uimm6m4: F1<(outs), (ins DP:$val, P:$ptr, i32imm:$off),
"[$ptr + $off] = $val;",
[(store DP:$val, (add P:$ptr, uimm6m4:$off))]>;
def STORE32p_imm18m4: F1<(outs), (ins DP:$val, P:$ptr, i32imm:$off),
"[$ptr + $off] = $val;",
[(store DP:$val, (add P:$ptr, imm18m4:$off))]>;
def STORE16pi: F1<(outs), (ins D16:$val, PI:$ptr),
"w[$ptr] = $val;",
[(store D16:$val, PI:$ptr)]>;
def STORE8p: F1<(outs), (ins D:$val, P:$ptr),
"b[$ptr] = $val;",
[(truncstorei8 D:$val, P:$ptr)]>;
def STORE8p_imm16: F1<(outs), (ins D:$val, P:$ptr, i32imm:$off),
"b[$ptr + $off] = $val;",
[(truncstorei8 D:$val, (add P:$ptr, imm16:$off))]>;
let Constraints = "$ptr = $ptr_wb" in {
multiclass STORE_incdec<RegisterClass drc, RegisterClass prc,
int off=4, string pre=""> {
def _inc : F1<(outs prc:$ptr_wb), (ins drc:$val, prc:$ptr),
!strconcat(pre, "[$ptr++] = $val;"),
[(set prc:$ptr_wb, (post_store drc:$val, prc:$ptr, off))]>;
def _dec : F1<(outs prc:$ptr_wb), (ins drc:$val, prc:$ptr),
!strconcat(pre, "[$ptr--] = $val;"),
[(set prc:$ptr_wb, (post_store drc:$val, prc:$ptr,
(ineg off)))]>;
}
defm STORE32p: STORE_incdec<DP, P>;
defm STORE16i: STORE_incdec<D16, I, 2, "w">;
defm STORE8p: STORE_incdec<D, P, 1, "b">;
def STORE32p_post: F1<(outs P:$ptr_wb), (ins D:$val, P:$ptr, P:$off),
"[$ptr ++ $off] = $val;",
[(set P:$ptr_wb, (post_store D:$val, P:$ptr, P:$off))]>;
def STORE16p_post: F1<(outs P:$ptr_wb), (ins D16:$val, P:$ptr, P:$off),
"w[$ptr ++ $off] = $val;",
[(set P:$ptr_wb, (post_store D16:$val, P:$ptr, P:$off))]>;
}
// Memory stores without patterns
let mayStore = 1 in {
// Note: only works for $fp == FP
def STORE32fp_nimm7m4: F1<(outs), (ins DP:$val, P:$fp, i32imm:$off),
"[$fp - $off] = $val;", []>;
def STORE32i: F1<(outs), (ins D:$val, I:$ptr),
"[$ptr] = $val;", []>;
def STORE32i_inc: F1<(outs I:$ptr_wb), (ins D:$val, I:$ptr),
"[$ptr++] = $val;", []>;
def STORE32i_dec: F1<(outs I:$ptr_wb), (ins D:$val, I:$ptr),
"[$ptr--] = $val;", []>;
def STORE32i_post: F1<(outs I:$ptr_wb), (ins D:$val, I:$ptr, M:$off),
"[$ptr ++ $off] = $val;", []>;
}
def : Pat<(truncstorei16 D:$val, PI:$ptr),
(STORE16pi (EXTRACT_SUBREG (COPY_TO_REGCLASS D:$val, D),
bfin_subreg_lo16), PI:$ptr)>;
def : Pat<(truncstorei16 (srl D:$val, (i16 16)), PI:$ptr),
(STORE16pi (EXTRACT_SUBREG (COPY_TO_REGCLASS D:$val, D),
bfin_subreg_hi16), PI:$ptr)>;
def : Pat<(truncstorei8 D16L:$val, P:$ptr),
(STORE8p (INSERT_SUBREG (i32 (IMPLICIT_DEF)),
(COPY_TO_REGCLASS D16L:$val, D16L),
bfin_subreg_lo16),
P:$ptr)>;
//===----------------------------------------------------------------------===//
// Table C-11. Move Instructions.
//===----------------------------------------------------------------------===//
def MOVE: F1<(outs ALL:$dst), (ins ALL:$src),
"$dst = $src;",
[]>;
let isTwoAddress = 1 in
def MOVEcc: F1<(outs DP:$dst), (ins DP:$src1, DP:$src2, AnyCC:$cc),
"if $cc $dst = $src2;",
[(set DP:$dst, (select AnyCC:$cc, DP:$src2, DP:$src1))]>;
let Defs = [AZ, AN, AC0, V] in {
def MOVEzext: F1<(outs D:$dst), (ins D16L:$src),
"$dst = $src (z);",
[(set D:$dst, (zext D16L:$src))]>;
def MOVEsext: F1<(outs D:$dst), (ins D16L:$src),
"$dst = $src (x);",
[(set D:$dst, (sext D16L:$src))]>;
def MOVEzext8: F1<(outs D:$dst), (ins D:$src),
"$dst = $src.b (z);",
[(set D:$dst, (and D:$src, 0xff))]>;
def MOVEsext8: F1<(outs D:$dst), (ins D:$src),
"$dst = $src.b (x);",
[(set D:$dst, (sext_inreg D:$src, i8))]>;
}
def : Pat<(sext_inreg D16L:$src, i8),
(EXTRACT_SUBREG (MOVEsext8
(INSERT_SUBREG (i32 (IMPLICIT_DEF)),
D16L:$src,
bfin_subreg_lo16)),
bfin_subreg_lo16)>;
def : Pat<(sext_inreg D:$src, i16),
(MOVEsext (EXTRACT_SUBREG D:$src, bfin_subreg_lo16))>;
def : Pat<(and D:$src, 0xffff),
(MOVEzext (EXTRACT_SUBREG D:$src, bfin_subreg_lo16))>;
def : Pat<(i32 (anyext D16L:$src)),
(INSERT_SUBREG (i32 (IMPLICIT_DEF)),
(COPY_TO_REGCLASS D16L:$src, D16L),
bfin_subreg_lo16)>;
// TODO Dreg = Dreg_byte (X/Z)
// TODO Accumulator moves
//===----------------------------------------------------------------------===//
// Table C-12. Stack Control Instructions
//===----------------------------------------------------------------------===//
let Uses = [SP], Defs = [SP] in {
def PUSH: F1<(outs), (ins ALL:$src),
"[--sp] = $src;", []> { let mayStore = 1; }
// NOTE: POP does not work for DP regs, use LOAD instead
def POP: F1<(outs ALL:$dst), (ins),
"$dst = [sp++];", []> { let mayLoad = 1; }
}
// TODO: push/pop multiple
def LINK: F2<(outs), (ins i32imm:$amount),
"link $amount;", []>;
def UNLINK: F2<(outs), (ins),
"unlink;", []>;
//===----------------------------------------------------------------------===//
// Table C-13. Control Code Bit Management Instructions
//===----------------------------------------------------------------------===//
multiclass SETCC<PatFrag opnode, PatFrag invnode, string cond, string suf=";"> {
def dd : F1<(outs JustCC:$cc), (ins D:$a, D:$b),
!strconcat(!subst("XX", cond, "cc = $a XX $b"), suf),
[(set JustCC:$cc, (opnode D:$a, D:$b))]>;
def ri : F1<(outs JustCC:$cc), (ins DP:$a, i32imm:$b),
!strconcat(!subst("XX", cond, "cc = $a XX $b"), suf),
[(set JustCC:$cc, (opnode DP:$a, imm3:$b))]>;
def pp : F1<(outs JustCC:$cc), (ins P:$a, P:$b),
!strconcat(!subst("XX", cond, "cc = $a XX $b"), suf),
[]>;
def ri_not : F1<(outs NotCC:$cc), (ins DP:$a, i32imm:$b),
!strconcat(!subst("XX", cond, "cc = $a XX $b"), suf),
[(set NotCC:$cc, (invnode DP:$a, imm3:$b))]>;
}
defm SETEQ : SETCC<seteq, setne, "==">;
defm SETLT : SETCC<setlt, setge, "<">;
defm SETLE : SETCC<setle, setgt, "<=">;
defm SETULT : SETCC<setult, setuge, "<", " (iu);">;
defm SETULE : SETCC<setule, setugt, "<=", " (iu);">;
def SETNEdd : F1<(outs NotCC:$cc), (ins D:$a, D:$b),
"cc = $a == $b;",
[(set NotCC:$cc, (setne D:$a, D:$b))]>;
def : Pat<(setgt D:$a, D:$b), (SETLTdd D:$b, D:$a)>;
def : Pat<(setge D:$a, D:$b), (SETLEdd D:$b, D:$a)>;
def : Pat<(setugt D:$a, D:$b), (SETULTdd D:$b, D:$a)>;
def : Pat<(setuge D:$a, D:$b), (SETULEdd D:$b, D:$a)>;
// TODO: compare pointer for P-P comparisons
// TODO: compare accumulator
let Defs = [AC0] in
def OR_ac0_cc : F1<(outs), (ins JustCC:$cc),
"ac0 \\|= cc;", []>;
let Uses = [AC0] in
def MOVE_cc_ac0 : F1<(outs JustCC:$cc), (ins),
"cc = ac0;", []>;
def MOVE_ccncc : F1<(outs JustCC:$cc), (ins NotCC:$sb),
"cc = !cc;", []>;
def MOVE_ncccc : F1<(outs NotCC:$cc), (ins JustCC:$sb),
"cc = !cc;", []>;
def MOVECC_zext : F1<(outs D:$dst), (ins JustCC:$cc),
"$dst = $cc;",
[(set D:$dst, (zext JustCC:$cc))]>;
def MOVENCC_z : F1<(outs D:$dst), (ins NotCC:$cc),
"$dst = cc;", []>;
def MOVECC_nz : F1<(outs AnyCC:$cc), (ins D:$src),
"cc = $src;",
[(set AnyCC:$cc, (setne D:$src, 0))]>;
//===----------------------------------------------------------------------===//
// Table C-14. Logical Operations Instructions
//===----------------------------------------------------------------------===//
def AND: F1<(outs D:$dst), (ins D:$src1, D:$src2),
"$dst = $src1 & $src2;",
[(set D:$dst, (and D:$src1, D:$src2))]>;
def NOT: F1<(outs D:$dst), (ins D:$src),
"$dst = ~$src;",
[(set D:$dst, (not D:$src))]>;
def OR: F1<(outs D:$dst), (ins D:$src1, D:$src2),
"$dst = $src1 \\| $src2;",
[(set D:$dst, (or D:$src1, D:$src2))]>;
def XOR: F1<(outs D:$dst), (ins D:$src1, D:$src2),
"$dst = $src1 ^ $src2;",
[(set D:$dst, (xor D:$src1, D:$src2))]>;
// missing: BXOR, BXORSHIFT
//===----------------------------------------------------------------------===//
// Table C-15. Bit Operations Instructions
//===----------------------------------------------------------------------===//
let isTwoAddress = 1 in {
def BITCLR: F1<(outs D:$dst), (ins D:$src1, uimm5imask:$src2),
"bitclr($dst, $src2);",
[(set D:$dst, (and D:$src1, uimm5imask:$src2))]>;
def BITSET: F1<(outs D:$dst), (ins D:$src1, uimm5mask:$src2),
"bitset($dst, $src2);",
[(set D:$dst, (or D:$src1, uimm5mask:$src2))]>;
def BITTGL: F1<(outs D:$dst), (ins D:$src1, uimm5mask:$src2),
"bittgl($dst, $src2);",
[(set D:$dst, (xor D:$src1, uimm5mask:$src2))]>;
}
def BITTST: F1<(outs JustCC:$cc), (ins D:$src1, uimm5mask:$src2),
"cc = bittst($src1, $src2);",
[(set JustCC:$cc, (setne (and D:$src1, uimm5mask:$src2),
(i32 0)))]>;
def NBITTST: F1<(outs JustCC:$cc), (ins D:$src1, uimm5mask:$src2),
"cc = !bittst($src1, $src2);",
[(set JustCC:$cc, (seteq (and D:$src1, uimm5mask:$src2),
(i32 0)))]>;
// TODO: DEPOSIT, EXTRACT, BITMUX
def ONES: F2<(outs D16L:$dst), (ins D:$src),
"$dst = ones $src;",
[(set D16L:$dst, (trunc (ctpop D:$src)))]>;
def : Pat<(ctpop D:$src), (MOVEzext (ONES D:$src))>;
//===----------------------------------------------------------------------===//
// Table C-16. Shift / Rotate Instructions
//===----------------------------------------------------------------------===//
multiclass SHIFT32<SDNode opnode, string ops> {
def i : F1<(outs D:$dst), (ins D:$src, i16imm:$amount),
!subst("XX", ops, "$dst XX= $amount;"),
[(set D:$dst, (opnode D:$src, (i16 uimm5:$amount)))]>;
def r : F1<(outs D:$dst), (ins D:$src, D:$amount),
!subst("XX", ops, "$dst XX= $amount;"),
[(set D:$dst, (opnode D:$src, D:$amount))]>;
}
let Defs = [AZ, AN, V, VS],
isTwoAddress = 1 in {
defm SRA : SHIFT32<sra, ">>>">;
defm SRL : SHIFT32<srl, ">>">;
defm SLL : SHIFT32<shl, "<<">;
}
// TODO: automatic switching between 2-addr and 3-addr (?)
let Defs = [AZ, AN, V, VS] in {
def SLLr16: F2<(outs D:$dst), (ins D:$src, D16L:$amount),
"$dst = lshift $src by $amount;",
[(set D:$dst, (shl D:$src, D16L:$amount))]>;
// Arithmetic left-shift = saturing overflow.
def SLAr16: F2<(outs D:$dst), (ins D:$src, D16L:$amount),
"$dst = ashift $src by $amount;",
[(set D:$dst, (sra D:$src, (ineg D16L:$amount)))]>;
def SRA16i: F1<(outs D16:$dst), (ins D16:$src, i16imm:$amount),
"$dst = $src >>> $amount;",
[(set D16:$dst, (sra D16:$src, (i16 uimm4:$amount)))]>;
def SRL16i: F1<(outs D16:$dst), (ins D16:$src, i16imm:$amount),
"$dst = $src >> $amount;",
[(set D16:$dst, (srl D16:$src, (i16 uimm4:$amount)))]>;
// Arithmetic left-shift = saturing overflow.
def SLA16r: F1<(outs D16:$dst), (ins D16:$src, D16L:$amount),
"$dst = ashift $src BY $amount;",
[(set D16:$dst, (srl D16:$src, (ineg D16L:$amount)))]>;
def SLL16i: F1<(outs D16:$dst), (ins D16:$src, i16imm:$amount),
"$dst = $src << $amount;",
[(set D16:$dst, (shl D16:$src, (i16 uimm4:$amount)))]>;
def SLL16r: F1<(outs D16:$dst), (ins D16:$src, D16L:$amount),
"$dst = lshift $src by $amount;",
[(set D16:$dst, (shl D16:$src, D16L:$amount))]>;
}
//===----------------------------------------------------------------------===//
// Table C-17. Arithmetic Operations Instructions
//===----------------------------------------------------------------------===//
// TODO: ABS
let Defs = [AZ, AN, AC0, V, VS] in {
def ADD: F1<(outs D:$dst), (ins D:$src1, D:$src2),
"$dst = $src1 + $src2;",
[(set D:$dst, (add D:$src1, D:$src2))]>;
def ADD16: F2<(outs D16:$dst), (ins D16:$src1, D16:$src2),
"$dst = $src1 + $src2;",
[(set D16:$dst, (add D16:$src1, D16:$src2))]>;
let isTwoAddress = 1 in
def ADDimm7: F1<(outs D:$dst), (ins D:$src1, i32imm:$src2),
"$dst += $src2;",
[(set D:$dst, (add D:$src1, imm7:$src2))]>;
def SUB: F1<(outs D:$dst), (ins D:$src1, D:$src2),
"$dst = $src1 - $src2;",
[(set D:$dst, (sub D:$src1, D:$src2))]>;
def SUB16: F2<(outs D16:$dst), (ins D16:$src1, D16:$src2),
"$dst = $src1 - $src2;",
[(set D16:$dst, (sub D16:$src1, D16:$src2))]>;
}
def : Pat<(addc D:$src1, D:$src2), (ADD D:$src1, D:$src2)>;
def : Pat<(subc D:$src1, D:$src2), (SUB D:$src1, D:$src2)>;
let Defs = [AZ, AN, V, VS] in
def NEG: F1<(outs D:$dst), (ins D:$src),
"$dst = -$src;",
[(set D:$dst, (ineg D:$src))]>;
// No pattern, it would confuse isel to have two i32 = i32+i32 patterns
def ADDpp: F1<(outs P:$dst), (ins P:$src1, P:$src2),
"$dst = $src1 + $src2;", []>;
let isTwoAddress = 1 in
def ADDpp_imm7: F1<(outs P:$dst), (ins P:$src1, i32imm:$src2),
"$dst += $src2;", []>;
let Defs = [AZ, AN, V] in
def ADD_RND20: F2<(outs D16:$dst), (ins D:$src1, D:$src2),
"$dst = $src1 + $src2 (rnd20);", []>;
let Defs = [V, VS] in {
def MUL16: F2<(outs D16:$dst), (ins D16:$src1, D16:$src2),
"$dst = $src1 * $src2 (is);",
[(set D16:$dst, (mul D16:$src1, D16:$src2))]>;
def MULHS16: F2<(outs D16:$dst), (ins D16:$src1, D16:$src2),
"$dst = $src1 * $src2 (ih);",
[(set D16:$dst, (mulhs D16:$src1, D16:$src2))]>;
def MULhh32s: F2<(outs D:$dst), (ins D16:$src1, D16:$src2),
"$dst = $src1 * $src2 (is);",
[(set D:$dst, (mul (sext D16:$src1), (sext D16:$src2)))]>;
def MULhh32u: F2<(outs D:$dst), (ins D16:$src1, D16:$src2),
"$dst = $src1 * $src2 (is);",
[(set D:$dst, (mul (zext D16:$src1), (zext D16:$src2)))]>;
}
let isTwoAddress = 1 in
def MUL32: F1<(outs D:$dst), (ins D:$src1, D:$src2),
"$dst *= $src2;",
[(set D:$dst, (mul D:$src1, D:$src2))]>;
//===----------------------------------------------------------------------===//
// Table C-18. External Exent Management Instructions
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Table C-19. Cache Control Instructions
//===----------------------------------------------------------------------===//
// Table C-20. Video Pixel Operations Instructions
// Table C-21. Vector Operations Instructions
// Patterns
def : Pat<(BfinCall (i32 tglobaladdr:$dst)),
(CALLa tglobaladdr:$dst)>;
def : Pat<(BfinCall (i32 texternalsym:$dst)),
(CALLa texternalsym:$dst)>;
def : Pat<(sext JustCC:$cc),
(NEG (MOVECC_zext JustCC:$cc))>;
def : Pat<(anyext JustCC:$cc),
(MOVECC_zext JustCC:$cc)>;
def : Pat<(i16 (zext JustCC:$cc)),
(EXTRACT_SUBREG (MOVECC_zext JustCC:$cc), bfin_subreg_lo16)>;
def : Pat<(i16 (sext JustCC:$cc)),
(EXTRACT_SUBREG (NEG (MOVECC_zext JustCC:$cc)), bfin_subreg_lo16)>;
def : Pat<(i16 (anyext JustCC:$cc)),
(EXTRACT_SUBREG (MOVECC_zext JustCC:$cc), bfin_subreg_lo16)>;
def : Pat<(i16 (trunc D:$src)),
(EXTRACT_SUBREG (COPY_TO_REGCLASS D:$src, D), bfin_subreg_lo16)>;

View File

@ -0,0 +1,462 @@
//===- BlackfinRegisterInfo.cpp - Blackfin Register Information -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Blackfin implementation of the TargetRegisterInfo
// class.
//
//===----------------------------------------------------------------------===//
#include "Blackfin.h"
#include "BlackfinRegisterInfo.h"
#include "BlackfinSubtarget.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineLocation.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Type.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
using namespace llvm;
BlackfinRegisterInfo::BlackfinRegisterInfo(BlackfinSubtarget &st,
const TargetInstrInfo &tii)
: BlackfinGenRegisterInfo(BF::ADJCALLSTACKDOWN, BF::ADJCALLSTACKUP),
Subtarget(st),
TII(tii) {}
const unsigned*
BlackfinRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
using namespace BF;
static const unsigned CalleeSavedRegs[] = {
FP,
R4, R5, R6, R7,
P3, P4, P5,
0 };
return CalleeSavedRegs;
}
const TargetRegisterClass* const *BlackfinRegisterInfo::
getCalleeSavedRegClasses(const MachineFunction *MF) const {
using namespace BF;
static const TargetRegisterClass * const CalleeSavedRegClasses[] = {
&PRegClass,
&DRegClass, &DRegClass, &DRegClass, &DRegClass,
&PRegClass, &PRegClass, &PRegClass,
0 };
return CalleeSavedRegClasses;
}
BitVector
BlackfinRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
using namespace BF;
BitVector Reserved(getNumRegs());
Reserved.set(L0);
Reserved.set(L1);
Reserved.set(L2);
Reserved.set(L3);
Reserved.set(SP);
Reserved.set(RETS);
if (hasFP(MF))
Reserved.set(FP);
return Reserved;
}
const TargetRegisterClass*
BlackfinRegisterInfo::getPhysicalRegisterRegClass(unsigned reg, MVT VT) const {
assert(isPhysicalRegister(reg) && "reg must be a physical register");
// Pick the smallest register class of the right type that contains
// this physreg.
const TargetRegisterClass* BestRC = 0;
for (regclass_iterator I = regclass_begin(), E = regclass_end();
I != E; ++I) {
const TargetRegisterClass* RC = *I;
if ((VT == MVT::Other || RC->hasType(VT)) && RC->contains(reg) &&
(!BestRC || RC->getNumRegs() < BestRC->getNumRegs()))
BestRC = RC;
}
assert(BestRC && "Couldn't find the register class");
return BestRC;
}
// hasFP - Return true if the specified function should have a dedicated frame
// pointer register. This is true if the function has variable sized allocas or
// if frame pointer elimination is disabled.
bool BlackfinRegisterInfo::hasFP(const MachineFunction &MF) const {
const MachineFrameInfo *MFI = MF.getFrameInfo();
return NoFramePointerElim || MFI->hasCalls() || MFI->hasVarSizedObjects();
}
bool BlackfinRegisterInfo::
requiresRegisterScavenging(const MachineFunction &MF) const {
return true;
}
// Emit instructions to add delta to D/P register. ScratchReg must be of the
// same class as Reg (P).
void BlackfinRegisterInfo::adjustRegister(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
DebugLoc DL,
unsigned Reg,
unsigned ScratchReg,
int delta) const {
if (!delta)
return;
if (isImm<7>(delta)) {
BuildMI(MBB, I, DL, TII.get(BF::ADDpp_imm7), Reg)
.addReg(Reg) // No kill on two-addr operand
.addImm(delta);
return;
}
// We must load delta into ScratchReg and add that.
loadConstant(MBB, I, DL, ScratchReg, delta);
if (BF::PRegClass.contains(Reg)) {
assert (BF::PRegClass.contains(ScratchReg));
BuildMI(MBB, I, DL, TII.get(BF::ADDpp), Reg)
.addReg(Reg, RegState::Kill)
.addReg(ScratchReg, RegState::Kill);
} else {
assert (BF::DRegClass.contains(Reg));
assert (BF::DRegClass.contains(ScratchReg));
BuildMI(MBB, I, DL, TII.get(BF::ADD), Reg)
.addReg(Reg, RegState::Kill)
.addReg(ScratchReg, RegState::Kill);
}
}
// Emit instructions to load a constant into D/P register
void BlackfinRegisterInfo::loadConstant(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
DebugLoc DL,
unsigned Reg,
int value) const {
if (isImm<7>(value)) {
BuildMI(MBB, I, DL, TII.get(BF::LOADimm7), Reg).addImm(value);
return;
}
if (isUimm<16>(value)) {
BuildMI(MBB, I, DL, TII.get(BF::LOADuimm16), Reg).addImm(value);
return;
}
if (isImm<16>(value)) {
BuildMI(MBB, I, DL, TII.get(BF::LOADimm16), Reg).addImm(value);
return;
}
// We must split into halves
BuildMI(MBB, I, DL,
TII.get(BF::LOAD16i), getSubReg(Reg, bfin_subreg_hi16))
.addImm((value >> 16) & 0xffff)
.addReg(Reg, RegState::ImplicitDefine);
BuildMI(MBB, I, DL,
TII.get(BF::LOAD16i), getSubReg(Reg, bfin_subreg_lo16))
.addImm(value & 0xffff)
.addReg(Reg, RegState::ImplicitKill)
.addReg(Reg, RegState::ImplicitDefine);
}
void BlackfinRegisterInfo::
eliminateCallFramePseudoInstr(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
if (!hasReservedCallFrame(MF)) {
int64_t Amount = I->getOperand(0).getImm();
if (Amount != 0) {
assert(Amount%4 == 0);
if (I->getOpcode() == BF::ADJCALLSTACKDOWN) {
adjustRegister(MBB, I, I->getDebugLoc(), BF::SP, BF::P1, -Amount);
} else {
assert(I->getOpcode() == BF::ADJCALLSTACKUP);
adjustRegister(MBB, I, I->getDebugLoc(), BF::SP, BF::P1, Amount);
}
}
}
MBB.erase(I);
}
/// findScratchRegister - Find a 'free' register. Try for a call-clobbered
/// register first and then a spilled callee-saved register if that fails.
static unsigned findScratchRegister(MachineBasicBlock::iterator II,
RegScavenger *RS,
const TargetRegisterClass *RC,
int SPAdj) {
assert(RS && "Register scavenging must be on");
unsigned Reg = RS->FindUnusedReg(RC, true);
if (Reg == 0)
Reg = RS->scavengeRegister(RC, II, SPAdj);
return Reg;
}
void BlackfinRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj,
RegScavenger *RS) const {
unsigned i;
MachineInstr &MI = *II;
MachineBasicBlock &MBB = *MI.getParent();
MachineFunction &MF = *MBB.getParent();
DebugLoc DL = MI.getDebugLoc();
for (i=0; !MI.getOperand(i).isFI(); i++) {
assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
}
int FrameIndex = MI.getOperand(i).getIndex();
assert(i+1 < MI.getNumOperands() && MI.getOperand(i+1).isImm());
int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex)
+ MI.getOperand(i+1).getImm();
unsigned BaseReg = BF::FP;
if (hasFP(MF)) {
assert(SPAdj==0);
} else {
BaseReg = BF::SP;
Offset += MF.getFrameInfo()->getStackSize() + SPAdj;
}
bool isStore = false;
switch (MI.getOpcode()) {
case BF::STORE32fi:
isStore = true;
case BF::LOAD32fi: {
assert(Offset%4 == 0 && "Badly aligned i32 stack access");
assert(i==1);
MI.getOperand(i).ChangeToRegister(BaseReg, false);
MI.getOperand(i+1).setImm(Offset);
if (isUimm<6>(Offset)) {
MI.setDesc(TII.get(isStore
? BF::STORE32p_uimm6m4
: BF::LOAD32p_uimm6m4));
return;
}
if (BaseReg == BF::FP && isUimm<7>(-Offset)) {
MI.setDesc(TII.get(isStore
? BF::STORE32fp_nimm7m4
: BF::LOAD32fp_nimm7m4));
MI.getOperand(i+1).setImm(-Offset);
return;
}
if (isImm<18>(Offset)) {
MI.setDesc(TII.get(isStore
? BF::STORE32p_imm18m4
: BF::LOAD32p_imm18m4));
return;
}
// Use RegScavenger to calculate proper offset...
MI.dump();
llvm_unreachable("Stack frame offset too big");
break;
}
case BF::ADDpp: {
assert(MI.getOperand(0).isReg());
unsigned DestReg = MI.getOperand(0).getReg();
// We need to produce a stack offset in a P register. We emit:
// P0 = offset;
// P0 = BR + P0;
assert(i==1);
loadConstant(MBB, II, DL, DestReg, Offset);
MI.getOperand(1).ChangeToRegister(DestReg, false, false, true);
MI.getOperand(2).ChangeToRegister(BaseReg, false);
break;
}
case BF::STORE16fi:
isStore = true;
case BF::LOAD16fi: {
assert(Offset%2 == 0 && "Badly aligned i16 stack access");
assert(i==1);
// We need a P register to use as an address
unsigned ScratchReg = findScratchRegister(II, RS, &BF::PRegClass, SPAdj);
assert(ScratchReg);
loadConstant(MBB, II, DL, ScratchReg, Offset);
BuildMI(MBB, II, DL, TII.get(BF::ADDpp), ScratchReg)
.addReg(ScratchReg, RegState::Kill)
.addReg(BaseReg);
MI.setDesc(TII.get(isStore ? BF::STORE16pi : BF::LOAD16pi));
MI.getOperand(1).ChangeToRegister(ScratchReg, false, false, true);
MI.RemoveOperand(2);
break;
}
case BF::STORE8fi: {
// This is an AnyCC spill, we need a scratch register.
assert(i==1);
MachineOperand SpillReg = MI.getOperand(0);
unsigned ScratchReg = findScratchRegister(II, RS, &BF::DRegClass, SPAdj);
assert(ScratchReg);
if (SpillReg.getReg()==BF::NCC) {
BuildMI(MBB, II, DL, TII.get(BF::MOVENCC_z), ScratchReg)
.addOperand(SpillReg);
BuildMI(MBB, II, DL, TII.get(BF::BITTGL), ScratchReg)
.addReg(ScratchReg).addImm(0);
} else {
BuildMI(MBB, II, DL, TII.get(BF::MOVECC_zext), ScratchReg)
.addOperand(SpillReg);
}
// STORE D
MI.setDesc(TII.get(BF::STORE8p_imm16));
MI.getOperand(0).ChangeToRegister(ScratchReg, false, false, true);
MI.getOperand(i).ChangeToRegister(BaseReg, false);
MI.getOperand(i+1).setImm(Offset);
break;
}
case BF::LOAD8fi: {
// This is an restore, we need a scratch register.
assert(i==1);
MachineOperand SpillReg = MI.getOperand(0);
unsigned ScratchReg = findScratchRegister(II, RS, &BF::DRegClass, SPAdj);
assert(ScratchReg);
MI.setDesc(TII.get(BF::LOAD32p_imm16_8z));
MI.getOperand(0).ChangeToRegister(ScratchReg, true);
MI.getOperand(i).ChangeToRegister(BaseReg, false);
MI.getOperand(i+1).setImm(Offset);
++II;
if (SpillReg.getReg()==BF::CC) {
// CC = D
BuildMI(MBB, II, DL, TII.get(BF::MOVECC_nz), BF::CC)
.addReg(ScratchReg, RegState::Kill);
} else {
// Restore NCC (CC = D==0)
BuildMI(MBB, II, DL, TII.get(BF::SETEQri_not), BF::NCC)
.addReg(ScratchReg, RegState::Kill)
.addImm(0);
}
break;
}
default:
llvm_unreachable("Cannot eliminate frame index");
break;
}
}
void BlackfinRegisterInfo::
processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
RegScavenger *RS) const {
MachineFrameInfo *MFI = MF.getFrameInfo();
const TargetRegisterClass *RC = BF::DPRegisterClass;
if (requiresRegisterScavenging(MF)) {
// Reserve a slot close to SP or frame pointer.
RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
RC->getAlignment()));
}
}
void BlackfinRegisterInfo::
processFunctionBeforeFrameFinalized(MachineFunction &MF) const {
}
// Emit a prologue that sets up a stack frame.
// On function entry, R0-R2 and P0 may hold arguments.
// R3, P1, and P2 may be used as scratch registers
void BlackfinRegisterInfo::emitPrologue(MachineFunction &MF) const {
MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB
MachineBasicBlock::iterator MBBI = MBB.begin();
MachineFrameInfo *MFI = MF.getFrameInfo();
DebugLoc dl = (MBBI != MBB.end()
? MBBI->getDebugLoc()
: DebugLoc::getUnknownLoc());
int FrameSize = MFI->getStackSize();
if (FrameSize%4) {
FrameSize = (FrameSize+3) & ~3;
MFI->setStackSize(FrameSize);
}
if (!hasFP(MF)) {
// So far we only support FP elimination on leaf functions
assert(!MFI->hasCalls());
adjustRegister(MBB, MBBI, dl, BF::SP, BF::P1, -FrameSize);
return;
}
// emit a LINK instruction
if (FrameSize <= 0x3ffff) {
BuildMI(MBB, MBBI, dl, TII.get(BF::LINK)).addImm(FrameSize);
return;
}
// Frame is too big, do a manual LINK:
// [--SP] = RETS;
// [--SP] = FP;
// FP = SP;
// P1 = -FrameSize;
// SP = SP + P1;
BuildMI(MBB, MBBI, dl, TII.get(BF::PUSH))
.addReg(BF::RETS, RegState::Kill);
BuildMI(MBB, MBBI, dl, TII.get(BF::PUSH))
.addReg(BF::FP, RegState::Kill);
BuildMI(MBB, MBBI, dl, TII.get(BF::MOVE), BF::FP)
.addReg(BF::SP);
loadConstant(MBB, MBBI, dl, BF::P1, -FrameSize);
BuildMI(MBB, MBBI, dl, TII.get(BF::ADDpp), BF::SP)
.addReg(BF::SP, RegState::Kill)
.addReg(BF::P1, RegState::Kill);
}
void BlackfinRegisterInfo::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineFrameInfo *MFI = MF.getFrameInfo();
MachineBasicBlock::iterator MBBI = prior(MBB.end());
DebugLoc dl = MBBI->getDebugLoc();
int FrameSize = MFI->getStackSize();
assert(FrameSize%4 == 0 && "Misaligned frame size");
if (!hasFP(MF)) {
// So far we only support FP elimination on leaf functions
assert(!MFI->hasCalls());
adjustRegister(MBB, MBBI, dl, BF::SP, BF::P1, FrameSize);
return;
}
// emit an UNLINK instruction
BuildMI(MBB, MBBI, dl, TII.get(BF::UNLINK));
}
unsigned BlackfinRegisterInfo::getRARegister() const {
return BF::RETS;
}
unsigned BlackfinRegisterInfo::getFrameRegister(MachineFunction &MF) const {
return hasFP(MF) ? BF::FP : BF::SP;
}
int
BlackfinRegisterInfo::getFrameIndexOffset(MachineFunction &MF, int FI) const {
const TargetFrameInfo &TFI = *MF.getTarget().getFrameInfo();
MachineFrameInfo *MFI = MF.getFrameInfo();
return MFI->getObjectOffset(FI) + MFI->getStackSize() -
TFI.getOffsetOfLocalArea() + MFI->getOffsetAdjustment();
}
unsigned BlackfinRegisterInfo::getEHExceptionRegister() const {
llvm_unreachable("What is the exception register");
return 0;
}
unsigned BlackfinRegisterInfo::getEHHandlerRegister() const {
llvm_unreachable("What is the exception handler register");
return 0;
}
int BlackfinRegisterInfo::getDwarfRegNum(unsigned RegNum, bool isEH) const {
llvm_unreachable("What is the dwarf register number");
return -1;
}
#include "BlackfinGenRegisterInfo.inc"

View File

@ -0,0 +1,114 @@
//===- BlackfinRegisterInfo.h - Blackfin Register Information ..-*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Blackfin implementation of the TargetRegisterInfo
// class.
//
//===----------------------------------------------------------------------===//
#ifndef BLACKFINREGISTERINFO_H
#define BLACKFINREGISTERINFO_H
#include "llvm/Target/TargetRegisterInfo.h"
#include "BlackfinGenRegisterInfo.h.inc"
namespace llvm {
class BlackfinSubtarget;
class TargetInstrInfo;
class Type;
template<unsigned N>
static inline bool isImm(int x) {
return x >= -(1<<(N-1)) && x < (1<<(N-1));
}
template<unsigned N>
static inline bool isUimm(unsigned x) {
return x < (1<<N);
}
// Subregister indices, keep in sync with BlackfinRegisterInfo.td
enum BfinSubregIdx {
bfin_subreg_lo16 = 1,
bfin_subreg_hi16 = 2,
bfin_subreg_lo32 = 3
};
struct BlackfinRegisterInfo : public BlackfinGenRegisterInfo {
BlackfinSubtarget &Subtarget;
const TargetInstrInfo &TII;
BlackfinRegisterInfo(BlackfinSubtarget &st, const TargetInstrInfo &tii);
/// Code Generation virtual methods...
const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const;
const TargetRegisterClass* const*
getCalleeSavedRegClasses(const MachineFunction *MF = 0) const;
BitVector getReservedRegs(const MachineFunction &MF) const;
// getSubReg implemented by tablegen
const TargetRegisterClass *getPointerRegClass(unsigned Kind = 0) const {
return &BF::PRegClass;
}
const TargetRegisterClass *getPhysicalRegisterRegClass(unsigned reg,
MVT VT) const;
bool hasFP(const MachineFunction &MF) const;
// bool hasReservedCallFrame(MachineFunction &MF) const;
bool requiresRegisterScavenging(const MachineFunction &MF) const;
void eliminateCallFramePseudoInstr(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const;
void eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, RegScavenger *RS = NULL) const;
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
RegScavenger *RS) const;
void processFunctionBeforeFrameFinalized(MachineFunction &MF) const;
void emitPrologue(MachineFunction &MF) const;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const;
unsigned getFrameRegister(MachineFunction &MF) const;
int getFrameIndexOffset(MachineFunction &MF, int FI) const;
unsigned getRARegister() const;
// Exception handling queries.
unsigned getEHExceptionRegister() const;
unsigned getEHHandlerRegister() const;
int getDwarfRegNum(unsigned RegNum, bool isEH) const;
// Utility functions
void adjustRegister(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
DebugLoc DL,
unsigned Reg,
unsigned ScratchReg,
int delta) const;
void loadConstant(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
DebugLoc DL,
unsigned Reg,
int value) const;
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,380 @@
//===- BlackfinRegisterInfo.td - Blackfin Register defs ----*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Declarations that describe the Blackfin register file
//===----------------------------------------------------------------------===//
// Registers are identified with 3-bit group and 3-bit ID numbers.
class BlackfinReg<string n> : Register<n> {
field bits<3> Group;
field bits<3> Num;
let Namespace = "BF";
}
// Rc - 1-bit registers
class Rc<bits<5> bitno, string n> : BlackfinReg<n> {
field bits<5> BitNum = bitno;
}
// Rs - 16-bit integer registers
class Rs<bits<3> group, bits<3> num, bits<1> hi, string n> : BlackfinReg<n> {
let Group = group;
let Num = num;
field bits<1> High = hi;
}
// Ri - 32-bit integer registers with subregs
class Ri<bits<3> group, bits<3> num, string n> : BlackfinReg<n> {
let Group = group;
let Num = num;
}
// Ra 40-bit accumulator registers
class Ra<bits<3> num, string n, list<Register> subs> : BlackfinReg<n> {
let SubRegs = subs;
let Group = 4;
let Num = num;
}
// Ywo halves of 32-bit register
multiclass Rss<bits<3> group, bits<3> num, string n> {
def H : Rs<group, num, 1, !strconcat(n, ".h")>;
def L : Rs<group, num, 0, !strconcat(n, ".l")>;
}
// Rii - 32-bit integer registers with subregs
class Rii<bits<3> group, bits<3> num, string n, list<Register> subs>
: BlackfinReg<n> {
let SubRegs = subs;
let Group = group;
let Num = num;
}
// Status bits are all part of ASTAT
def AZ : Rc<0, "az">;
def AN : Rc<1, "an">;
def CC : Rc<5, "cc">, DwarfRegNum<[34]>;
def NCC : Rc<5, "!cc"> { let Aliases = [CC]; }
def AQ : Rc<6, "aq">;
def AC0 : Rc<12, "ac0">;
def AC1 : Rc<13, "ac1">;
def AV0 : Rc<16, "av0">;
def AV0S : Rc<17, "av0s">;
def AV1 : Rc<18, "av1">;
def AV1S : Rc<19, "av1s">;
def V : Rc<24, "v">;
def VS : Rc<25, "vs">;
// Skipped non-status bits: AC0_COPY, V_COPY, RND_MOD
// Group 0: Integer registers
defm R0 : Rss<0, 0, "r0">;
def R0 : Rii<0, 0, "r0", [R0H, R0L]>, DwarfRegNum<[0]>;
defm R1 : Rss<0, 1, "r1">;
def R1 : Rii<0, 1, "r1", [R1H, R1L]>, DwarfRegNum<[1]>;
defm R2 : Rss<0, 2, "r2">;
def R2 : Rii<0, 2, "r2", [R2H, R2L]>, DwarfRegNum<[2]>;
defm R3 : Rss<0, 3, "r3">;
def R3 : Rii<0, 3, "r3", [R3H, R3L]>, DwarfRegNum<[3]>;
defm R4 : Rss<0, 4, "r4">;
def R4 : Rii<0, 4, "r4", [R4H, R4L]>, DwarfRegNum<[4]>;
defm R5 : Rss<0, 5, "r5">;
def R5 : Rii<0, 5, "r5", [R5H, R5L]>, DwarfRegNum<[5]>;
defm R6 : Rss<0, 6, "r6">;
def R6 : Rii<0, 6, "r6", [R6H, R6L]>, DwarfRegNum<[6]>;
defm R7 : Rss<0, 7, "r7">;
def R7 : Rii<0, 7, "r7", [R7H, R7L]>, DwarfRegNum<[7]>;
// Group 1: Pointer registers
defm P0 : Rss<1, 0, "p0">;
def P0 : Rii<1, 0, "p0", [P0H, P0L]>, DwarfRegNum<[8]>;
defm P1 : Rss<1, 1, "p1">;
def P1 : Rii<1, 1, "p1", [P1H, P1L]>, DwarfRegNum<[9]>;
defm P2 : Rss<1, 2, "p2">;
def P2 : Rii<1, 2, "p2", [P2H, P2L]>, DwarfRegNum<[10]>;
defm P3 : Rss<1, 3, "p3">;
def P3 : Rii<1, 3, "p3", [P3H, P3L]>, DwarfRegNum<[11]>;
defm P4 : Rss<1, 4, "p4">;
def P4 : Rii<1, 4, "p4", [P4H, P4L]>, DwarfRegNum<[12]>;
defm P5 : Rss<1, 5, "p5">;
def P5 : Rii<1, 5, "p5", [P5H, P5L]>, DwarfRegNum<[13]>;
defm SP : Rss<1, 6, "sp">;
def SP : Rii<1, 6, "sp", [SPH, SPL]>, DwarfRegNum<[14]>;
defm FP : Rss<1, 7, "fp">;
def FP : Rii<1, 7, "fp", [FPH, FPL]>, DwarfRegNum<[15]>;
// Group 2: Index registers
defm I0 : Rss<2, 0, "i0">;
def I0 : Rii<2, 0, "i0", [I0H, I0L]>, DwarfRegNum<[16]>;
defm I1 : Rss<2, 1, "i1">;
def I1 : Rii<2, 1, "i1", [I1H, I1L]>, DwarfRegNum<[17]>;
defm I2 : Rss<2, 2, "i2">;
def I2 : Rii<2, 2, "i2", [I2H, I2L]>, DwarfRegNum<[18]>;
defm I3 : Rss<2, 3, "i3">;
def I3 : Rii<2, 3, "i3", [I3H, I3L]>, DwarfRegNum<[19]>;
defm M0 : Rss<2, 4, "m0">;
def M0 : Rii<2, 4, "m0", [M0H, M0L]>, DwarfRegNum<[20]>;
defm M1 : Rss<2, 5, "m1">;
def M1 : Rii<2, 5, "m1", [M1H, M1L]>, DwarfRegNum<[21]>;
defm M2 : Rss<2, 6, "m2">;
def M2 : Rii<2, 6, "m2", [M2H, M2L]>, DwarfRegNum<[22]>;
defm M3 : Rss<2, 7, "m3">;
def M3 : Rii<2, 7, "m3", [M3H, M3L]>, DwarfRegNum<[23]>;
// Group 3: Cyclic indexing registers
defm B0 : Rss<3, 0, "b0">;
def B0 : Rii<3, 0, "b0", [B0H, B0L]>, DwarfRegNum<[24]>;
defm B1 : Rss<3, 1, "b1">;
def B1 : Rii<3, 1, "b1", [B1H, B1L]>, DwarfRegNum<[25]>;
defm B2 : Rss<3, 2, "b2">;
def B2 : Rii<3, 2, "b2", [B2H, B2L]>, DwarfRegNum<[26]>;
defm B3 : Rss<3, 3, "b3">;
def B3 : Rii<3, 3, "b3", [B3H, B3L]>, DwarfRegNum<[27]>;
defm L0 : Rss<3, 4, "l0">;
def L0 : Rii<3, 4, "l0", [L0H, L0L]>, DwarfRegNum<[28]>;
defm L1 : Rss<3, 5, "l1">;
def L1 : Rii<3, 5, "l1", [L1H, L1L]>, DwarfRegNum<[29]>;
defm L2 : Rss<3, 6, "l2">;
def L2 : Rii<3, 6, "l2", [L2H, L2L]>, DwarfRegNum<[30]>;
defm L3 : Rss<3, 7, "l3">;
def L3 : Rii<3, 7, "l3", [L3H, L3L]>, DwarfRegNum<[31]>;
// Accumulators
def A0X : Ri <4, 0, "a0.x">;
defm A0 : Rss<4, 1, "a0">;
def A0W : Rii<4, 1, "a0.w", [A0H, A0L]>, DwarfRegNum<[32]>;
def A0 : Ra <0, "a0", [A0X, A0W]>;
def A1X : Ri <4, 2, "a1.x">;
defm A1 : Rss<4, 3, "a1">;
def A1W : Rii<4, 3, "a1.w", [A1H, A1L]>, DwarfRegNum<[33]>;
def A1 : Ra <2, "a1", [A1X, A1W]>;
def RETS : Ri<4, 7, "rets">, DwarfRegNum<[35]>;
def RETI : Ri<7, 3, "reti">, DwarfRegNum<[36]>;
def RETX : Ri<7, 4, "retx">, DwarfRegNum<[37]>;
def RETN : Ri<7, 5, "retn">, DwarfRegNum<[38]>;
def RETE : Ri<7, 6, "rete">, DwarfRegNum<[39]>;
def ASTAT : Ri<4, 6, "astat">, DwarfRegNum<[40]> {
let SubRegs = [AZ, AN, CC, NCC, AQ, AC0, AC1, AV0, AV0S, AV1, AV1S, V, VS];
}
def SEQSTAT : Ri<7, 1, "seqstat">, DwarfRegNum<[41]>;
def USP : Ri<7, 0, "usp">, DwarfRegNum<[42]>;
def EMUDAT : Ri<7, 7, "emudat">, DwarfRegNum<[43]>;
def SYSCFG : Ri<7, 2, "syscfg">;
def CYCLES : Ri<6, 6, "cycles">;
def CYCLES2 : Ri<6, 7, "cycles2">;
// Hardware loops
def LT0 : Ri<6, 1, "lt0">, DwarfRegNum<[44]>;
def LT1 : Ri<6, 4, "lt1">, DwarfRegNum<[45]>;
def LC0 : Ri<6, 0, "lc0">, DwarfRegNum<[46]>;
def LC1 : Ri<6, 3, "lc1">, DwarfRegNum<[47]>;
def LB0 : Ri<6, 2, "lb0">, DwarfRegNum<[48]>;
def LB1 : Ri<6, 5, "lb1">, DwarfRegNum<[49]>;
// Subregs are:
// 1: .L
// 2: .H
// 3: .W (32 low bits of 40-bit accu)
// Keep in sync with enum in BlackfinRegisterInfo.h
def bfin_subreg_lo16 : PatLeaf<(i32 1)>;
def bfin_subreg_hi16 : PatLeaf<(i32 2)>;
def bfin_subreg_32bit : PatLeaf<(i32 3)>;
def : SubRegSet<1,
[R0, R1, R2, R3, R4, R5, R6, R7,
P0, P1, P2, P3, P4, P5, SP, FP,
I0, I1, I2, I3, M0, M1, M2, M3,
B0, B1, B2, B3, L0, L1, L2, L3],
[R0L, R1L, R2L, R3L, R4L, R5L, R6L, R7L,
P0L, P1L, P2L, P3L, P4L, P5L, SPL, FPL,
I0L, I1L, I2L, I3L, M0L, M1L, M2L, M3L,
B0L, B1L, B2L, B3L, L0L, L1L, L2L, L3L]>;
def : SubRegSet<2,
[R0, R1, R2, R3, R4, R5, R6, R7,
P0, P1, P2, P3, P4, P5, SP, FP,
I0, I1, I2, I3, M0, M1, M2, M3,
B0, B1, B2, B3, L0, L1, L2, L3],
[R0H, R1H, R2H, R3H, R4H, R5H, R6H, R7H,
P0H, P1H, P2H, P3H, P4H, P5H, SPH, FPH,
I0H, I1H, I2H, I3H, M0H, M1H, M2H, M3H,
B0H, B1H, B2H, B3H, L0H, L1H, L2H, L3H]>;
def : SubRegSet<1, [A0, A0W, A1, A1W], [A0L, A0L, A1L, A1L]>;
def : SubRegSet<2, [A0, A0W, A1, A1W], [A0H, A0H, A1H, A1H]>;
// Register classes.
def D16 : RegisterClass<"BF", [i16], 16,
[R0H, R0L, R1H, R1L, R2H, R2L, R3H, R3L,
R4H, R4L, R5H, R5L, R6H, R6L, R7H, R7L]>;
def D16L : RegisterClass<"BF", [i16], 16,
[R0L, R1L, R2L, R3L, R4L, R5L, R6L, R7L]>;
def D16H : RegisterClass<"BF", [i16], 16,
[R0H, R1H, R2H, R3H, R4H, R5H, R6H, R7H]>;
def P16 : RegisterClass<"BF", [i16], 16,
[P0H, P0L, P1H, P1L, P2H, P2L, P3H, P3L,
P4H, P4L, P5H, P5L, SPH, SPL, FPH, FPL]>;
def P16L : RegisterClass<"BF", [i16], 16,
[P0L, P1L, P2L, P3L, P4L, P5L, SPL, FPL]>;
def P16H : RegisterClass<"BF", [i16], 16,
[P0H, P1H, P2H, P3H, P4H, P5H, SPH, FPH]>;
def DP16 : RegisterClass<"BF", [i16], 16,
[R0H, R0L, R1H, R1L, R2H, R2L, R3H, R3L,
R4H, R4L, R5H, R5L, R6H, R6L, R7H, R7L,
P0H, P0L, P1H, P1L, P2H, P2L, P3H, P3L,
P4H, P4L, P5H, P5L, SPH, SPL, FPH, FPL]>;
def DP16L : RegisterClass<"BF", [i16], 16,
[R0L, R1L, R2L, R3L, R4L, R5L, R6L, R7L,
P0L, P1L, P2L, P3L, P4L, P5L, SPL, FPL]>;
def DP16H : RegisterClass<"BF", [i16], 16,
[R0H, R1H, R2H, R3H, R4H, R5H, R6H, R7H,
P0H, P1H, P2H, P3H, P4H, P5H, SPH, FPH]>;
def GR16 : RegisterClass<"BF", [i16], 16,
[R0H, R0L, R1H, R1L, R2H, R2L, R3H, R3L,
R4H, R4L, R5H, R5L, R6H, R6L, R7H, R7L,
P0H, P0L, P1H, P1L, P2H, P2L, P3H, P3L,
P4H, P4L, P5H, P5L, SPH, SPL, FPH, FPL,
I0H, I0L, I1H, I1L, I2H, I2L, I3H, I3L,
M0H, M0L, M1H, M1L, M2H, M2L, M3H, M3L,
B0H, B0L, B1H, B1L, B2H, B2L, B3H, B3L,
L0H, L0L, L1H, L1L, L2H, L2L, L3H, L3L]>;
def D : RegisterClass<"BF", [i32], 32, [R0, R1, R2, R3, R4, R5, R6, R7]> {
let SubRegClassList = [D16L, D16H];
}
def P : RegisterClass<"BF", [i32], 32, [P0, P1, P2, P3, P4, P5, FP, SP]> {
let SubRegClassList = [P16L, P16H];
let MethodProtos = [{
iterator allocation_order_end(const MachineFunction &MF) const;
}];
let MethodBodies = [{
PClass::iterator
PClass::allocation_order_end(const MachineFunction &MF) const {
const TargetMachine &TM = MF.getTarget();
const TargetRegisterInfo *RI = TM.getRegisterInfo();
return allocation_order_begin(MF)
+ (RI->hasFP(MF) ? 7 : 6);
}
}];
}
def I : RegisterClass<"BF", [i32], 32, [I0, I1, I2, I3]>;
def M : RegisterClass<"BF", [i32], 32, [M0, M1, M2, M3]>;
def DP : RegisterClass<"BF", [i32], 32,
[R0, R1, R2, R3, R4, R5, R6, R7,
P0, P1, P2, P3, P4, P5, FP, SP]> {
let SubRegClassList = [DP16L, DP16H];
let MethodProtos = [{
iterator allocation_order_end(const MachineFunction &MF) const;
}];
let MethodBodies = [{
DPClass::iterator
DPClass::allocation_order_end(const MachineFunction &MF) const {
const TargetMachine &TM = MF.getTarget();
const TargetRegisterInfo *RI = TM.getRegisterInfo();
return allocation_order_begin(MF)
+ (RI->hasFP(MF) ? 15 : 14);
}
}];
}
def GR : RegisterClass<"BF", [i32], 32,
[R0, R1, R2, R3, R4, R5, R6, R7,
P0, P1, P2, P3, P4, P5,
I0, I1, I2, I3, M0, M1, M2, M3,
B0, B1, B2, B3, L0, L1, L2, L3,
FP, SP]> {
let MethodProtos = [{
iterator allocation_order_end(const MachineFunction &MF) const;
}];
let MethodBodies = [{
GRClass::iterator
GRClass::allocation_order_end(const MachineFunction &MF) const {
const TargetMachine &TM = MF.getTarget();
const TargetRegisterInfo *RI = TM.getRegisterInfo();
return allocation_order_begin(MF)
+ (RI->hasFP(MF) ? 31 : 30);
}
}];
}
def ALL : RegisterClass<"BF", [i32], 32,
[R0, R1, R2, R3, R4, R5, R6, R7,
P0, P1, P2, P3, P4, P5,
I0, I1, I2, I3, M0, M1, M2, M3,
B0, B1, B2, B3, L0, L1, L2, L3,
FP, SP,
A0X, A0W, A1X, A1W, ASTAT, RETS,
LC0, LT0, LB0, LC1, LT1, LB1, CYCLES, CYCLES2,
USP, SEQSTAT, SYSCFG, RETI, RETX, RETN, RETE, EMUDAT]> {
let MethodProtos = [{
iterator allocation_order_end(const MachineFunction &MF) const;
}];
let MethodBodies = [{
ALLClass::iterator
ALLClass::allocation_order_end(const MachineFunction &MF) const {
const TargetMachine &TM = MF.getTarget();
const TargetRegisterInfo *RI = TM.getRegisterInfo();
return allocation_order_begin(MF)
+ (RI->hasFP(MF) ? 31 : 30);
}
}];
}
def PI : RegisterClass<"BF", [i32], 32,
[P0, P1, P2, P3, P4, P5, I0, I1, I2, I3, FP, SP]> {
let MethodProtos = [{
iterator allocation_order_end(const MachineFunction &MF) const;
}];
let MethodBodies = [{
PIClass::iterator
PIClass::allocation_order_end(const MachineFunction &MF) const {
const TargetMachine &TM = MF.getTarget();
const TargetRegisterInfo *RI = TM.getRegisterInfo();
return allocation_order_begin(MF)
+ (RI->hasFP(MF) ? 11 : 10);
}
}];
}
// We are going to pretend that CC and !CC are 32-bit registers, even though
// they only can hold 1 bit.
let CopyCost = -1, Size = 8 in {
def JustCC : RegisterClass<"BF", [i32], 8, [CC]>;
def NotCC : RegisterClass<"BF", [i32], 8, [NCC]>;
def AnyCC : RegisterClass<"BF", [i32], 8, [CC, NCC]> {
let MethodProtos = [{
iterator allocation_order_end(const MachineFunction &MF) const;
}];
let MethodBodies = [{
AnyCCClass::iterator
AnyCCClass::allocation_order_end(const MachineFunction &MF) const {
return allocation_order_begin(MF)+1;
}
}];
}
def StatBit : RegisterClass<"BF", [i1], 8,
[AZ, AN, CC, AQ, AC0, AC1, AV0, AV0S, AV1, AV1S, V, VS]>;
}

View File

@ -0,0 +1,26 @@
//===- BlackfinSubtarget.cpp - BLACKFIN Subtarget Information -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the blackfin specific subclass of TargetSubtarget.
//
//===----------------------------------------------------------------------===//
#include "BlackfinSubtarget.h"
#include "BlackfinGenSubtarget.inc"
using namespace llvm;
BlackfinSubtarget::BlackfinSubtarget(const TargetMachine &TM,
const Module &M,
const std::string &FS) {
std::string CPU = "generic";
// Parse features string.
ParseSubtargetFeatures(FS, CPU);
}

View File

@ -0,0 +1,39 @@
//===- BlackfinSubtarget.h - Define Subtarget for the Blackfin -*- C++ -*-====//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the BLACKFIN specific subclass of TargetSubtarget.
//
//===----------------------------------------------------------------------===//
#ifndef BLACKFIN_SUBTARGET_H
#define BLACKFIN_SUBTARGET_H
#include "llvm/Target/TargetSubtarget.h"
#include <string>
namespace llvm {
class TargetMachine;
class Module;
class BlackfinSubtarget : public TargetSubtarget {
bool ssyncWorkaround;
public:
BlackfinSubtarget(const TargetMachine &TM, const Module &M,
const std::string &FS);
/// ParseSubtargetFeatures - Parses features string setting specified
/// subtarget options. Definition of function is auto generated by tblgen.
std::string ParseSubtargetFeatures(const std::string &FS,
const std::string &CPU);
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,23 @@
//===-- BlackfinTargetAsmInfo.cpp - Blackfin asm properties -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the declarations of the BlackfinTargetAsmInfo properties.
//
//===----------------------------------------------------------------------===//
#include "BlackfinTargetAsmInfo.h"
using namespace llvm;
BlackfinTargetAsmInfo::BlackfinTargetAsmInfo() {
GlobalPrefix = "_";
CommentString = "//";
InlineAsmStart = "// APP";
InlineAsmEnd = "// NO_APP";
}

View File

@ -0,0 +1,27 @@
//===-- BlackfinTargetAsmInfo.h - Blackfin asm properties -----*- C++ -*--====//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the declaration of the BlackfinTargetAsmInfo class.
//
//===----------------------------------------------------------------------===//
#ifndef BLACKFINTARGETASMINFO_H
#define BLACKFINTARGETASMINFO_H
#include "llvm/Target/TargetAsmInfo.h"
namespace llvm {
struct BlackfinTargetAsmInfo : public TargetAsmInfo {
explicit BlackfinTargetAsmInfo();
};
} // namespace llvm
#endif

View File

@ -0,0 +1,54 @@
//===-- BlackfinTargetMachine.cpp - Define TargetMachine for Blackfin -----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
#include "BlackfinTargetMachine.h"
#include "Blackfin.h"
#include "BlackfinTargetAsmInfo.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Target/TargetRegistry.h"
using namespace llvm;
extern "C" void LLVMInitializeBlackfinTarget() {
RegisterTargetMachine<BlackfinTargetMachine> X(TheBlackfinTarget);
}
const TargetAsmInfo* BlackfinTargetMachine::createTargetAsmInfo() const {
return new BlackfinTargetAsmInfo();
}
BlackfinTargetMachine::BlackfinTargetMachine(const Target &T,
const Module &M,
const std::string &FS)
: LLVMTargetMachine(T),
DataLayout("e-p:32:32-i64:32-f64:32"),
Subtarget(*this, M, FS),
TLInfo(*this),
InstrInfo(Subtarget),
FrameInfo(TargetFrameInfo::StackGrowsDown, 4, 0) {
}
unsigned BlackfinTargetMachine::getModuleMatchQuality(const Module &M) {
std::string TT = M.getTargetTriple();
if (TT.size() >= 5 && std::string(TT.begin(), TT.begin()+5) == "bfin-")
return 20;
// Otherwise we don't match.
return 0;
}
bool BlackfinTargetMachine::addInstSelector(PassManagerBase &PM,
CodeGenOpt::Level OptLevel) {
PM.add(createBlackfinISelDag(*this, OptLevel));
return false;
}

View File

@ -0,0 +1,61 @@
//===-- BlackfinTargetMachine.h - TargetMachine for Blackfin ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the Blackfin specific subclass of TargetMachine.
//
//===----------------------------------------------------------------------===//
#ifndef BLACKFINTARGETMACHINE_H
#define BLACKFINTARGETMACHINE_H
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "BlackfinInstrInfo.h"
#include "BlackfinSubtarget.h"
#include "BlackfinISelLowering.h"
namespace llvm {
class Module;
class BlackfinTargetMachine : public LLVMTargetMachine {
const TargetData DataLayout;
BlackfinSubtarget Subtarget;
BlackfinTargetLowering TLInfo;
BlackfinInstrInfo InstrInfo;
TargetFrameInfo FrameInfo;
protected:
virtual const TargetAsmInfo *createTargetAsmInfo() const;
public:
BlackfinTargetMachine(const Target &T, const Module &M,
const std::string &FS);
virtual const BlackfinInstrInfo *getInstrInfo() const { return &InstrInfo; }
virtual const TargetFrameInfo *getFrameInfo() const { return &FrameInfo; }
virtual const BlackfinSubtarget *getSubtargetImpl() const {
return &Subtarget;
}
virtual const BlackfinRegisterInfo *getRegisterInfo() const {
return &InstrInfo.getRegisterInfo();
}
virtual BlackfinTargetLowering* getTargetLowering() const {
return const_cast<BlackfinTargetLowering*>(&TLInfo);
}
virtual const TargetData *getTargetData() const { return &DataLayout; }
static unsigned getModuleMatchQuality(const Module &M);
virtual bool addInstSelector(PassManagerBase &PM,
CodeGenOpt::Level OptLevel);
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,21 @@
set(LLVM_TARGET_DEFINITIONS Blackfin.td)
tablegen(BlackfinGenRegisterInfo.h.inc -gen-register-desc-header)
tablegen(BlackfinGenRegisterNames.inc -gen-register-enums)
tablegen(BlackfinGenRegisterInfo.inc -gen-register-desc)
tablegen(BlackfinGenInstrNames.inc -gen-instr-enums)
tablegen(BlackfinGenInstrInfo.inc -gen-instr-desc)
tablegen(BlackfinGenAsmWriter.inc -gen-asm-writer)
tablegen(BlackfinGenDAGISel.inc -gen-dag-isel)
tablegen(BlackfinGenSubtarget.inc -gen-subtarget)
tablegen(BlackfinGenCallingConv.inc -gen-callingconv)
add_llvm_target(BlackfinCodeGen
BlackfinInstrInfo.cpp
BlackfinISelDAGToDAG.cpp
BlackfinISelLowering.cpp
BlackfinRegisterInfo.cpp
BlackfinSubtarget.cpp
BlackfinTargetAsmInfo.cpp
BlackfinTargetMachine.cpp
)

View File

@ -0,0 +1,23 @@
##===- lib/Target/Blackfin/Makefile ------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../..
LIBRARYNAME = LLVMBlackfinCodeGen
TARGET = Blackfin
# Make sure that tblgen is run, first thing.
BUILT_SOURCES = BlackfinGenRegisterInfo.h.inc BlackfinGenRegisterNames.inc \
BlackfinGenRegisterInfo.inc BlackfinGenInstrNames.inc \
BlackfinGenInstrInfo.inc BlackfinGenAsmWriter.inc \
BlackfinGenDAGISel.inc BlackfinGenSubtarget.inc \
BlackfinGenCallingConv.inc
DIRS = AsmPrinter TargetInfo
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,122 @@
//===-- README.txt - Notes for Blackfin Target ------------------*- org -*-===//
* Condition codes
** DONE Problem with asymmetric SETCC operations
The instruction
CC = R0 < 2
is not symmetric - there is no R0 > 2 instruction. On the other hand, IF CC
JUMP can take both CC and !CC as a condition. We cannot pattern-match (brcond
(not cc), target), the DAG optimizer removes that kind of thing.
This is handled by creating a pseudo-register NCC that aliases CC. Register
classes JustCC and NotCC are used to control the inversion of CC.
** DONE CC as an i32 register
The AnyCC register class pretends to hold i32 values. It can only represent the
values 0 and 1, but we can copy to and from the D class. This hack makes it
possible to represent the setcc instruction without having i1 as a legal type.
In most cases, the CC register is set by a "CC = .." or BITTST instruction, and
then used in a conditional branch or move. The code generator thinks it is
moving 32 bits, but the value stays in CC. In other cases, the result of a
comparison is actually used as am i32 number, and CC will be copied to a D
register.
* Stack frames
** TODO Use Push/Pop instructions
We should use the push/pop instructions when saving callee-saved
registers. The are smaller, and we may even use push multiple instructions.
** TODO requiresRegisterScavenging
We need more intelligence in determining when the scavenger is needed. We
should keep track of:
- Spilling D16 registers
- Spilling AnyCC registers
* Assembler
** TODO Implement PrintGlobalVariable
** TODO Remove LOAD32sym
It's a hack combining two instructions by concatenation.
* Inline Assembly
** TODO Support all register classes
* DAG combiner
** Create test case for each Illegal SETCC case
The DAG combiner may someimes produce illegal i16 SETCC instructions.
*** TODO SETCC (ctlz x), 5) == const
*** TODO SETCC (and load, const) == const
*** DONE SETCC (zext x) == const
*** TODO SETCC (sext x) == const
* Instruction selection
** TODO Better imediate constants
Like ARM, build constants as small imm + shift.
** TODO Implement cycle counter
We have CYCLES and CYCLES2 registers, but the readcyclecounter intrinsic wants
to return i64, and the code generator doesn't know how to legalize that.
** TODO Instruction alternatives
Some instructions come in different variants for example:
D = D + D
P = P + P
Cross combinations are not allowed:
P = D + D (bad)
Similarly for the subreg pseudo-instructions:
D16L = EXTRACT_SUBREG D16, bfin_subreg_lo16
P16L = EXTRACT_SUBREG P16, bfin_subreg_lo16
We want to take advantage of the alternative instructions. This could be done by
changing the DAG after instruction selection.
** Multipatterns for load/store
We should try to identify multipatterns for load and store instructions. The
available instruction matrix is a bit irregular.
Loads:
| Addr | D | P | D 16z | D 16s | D16 | D 8z | D 8s |
|------------+---+---+-------+-------+-----+------+------|
| P | * | * | * | * | * | * | * |
| P++ | * | * | * | * | | * | * |
| P-- | * | * | * | * | | * | * |
| P+uimm5m2 | | | * | * | | | |
| P+uimm6m4 | * | * | | | | | |
| P+imm16 | | | | | | * | * |
| P+imm17m2 | | | * | * | | | |
| P+imm18m4 | * | * | | | | | |
| P++P | * | | * | * | * | | |
| FP-uimm7m4 | * | * | | | | | |
| I | * | | | | * | | |
| I++ | * | | | | * | | |
| I-- | * | | | | * | | |
| I++M | * | | | | | | |
Stores:
| Addr | D | P | D16H | D16L | D 8 |
|------------+---+---+------+------+-----|
| P | * | * | * | * | * |
| P++ | * | * | | * | * |
| P-- | * | * | | * | * |
| P+uimm5m2 | | | | * | |
| P+uimm6m4 | * | * | | | |
| P+imm16 | | | | | * |
| P+imm17m2 | | | | * | |
| P+imm18m4 | * | * | | | |
| P++P | * | | * | * | |
| FP-uimm7m4 | * | * | | | |
| I | * | | * | * | |
| I++ | * | | * | * | |
| I-- | * | | * | * | |
| I++M | * | | | | |

View File

@ -0,0 +1,21 @@
//===-- BlackfinTargetInfo.cpp - Blackfin Target Implementation -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Blackfin.h"
#include "llvm/Module.h"
#include "llvm/Target/TargetRegistry.h"
using namespace llvm;
Target llvm::TheBlackfinTarget;
extern "C" void LLVMInitializeBlackfinTargetInfo() {
RegisterTarget<Triple::bfin> X(TheBlackfinTarget, "bfin",
"Analog Devices Blackfin [experimental]");
}

View File

@ -0,0 +1,3 @@
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. )
add_llvm_library(LLVMBlackfinInfo BlackfinTargetInfo.cpp)
add_dependencies(LLVMBlackfinInfo BlackfinCodeGenTable_gen)

View File

@ -0,0 +1,15 @@
##===- lib/Target/Blackfin/TargetInfo/Makefile -------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
LIBRARYNAME = LLVMBlackfinInfo
# Hack: we need to include 'main' target directory to grab private headers
CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,18 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
type { i24, i1 } ; type %0
define i1 @func2(i24 zeroext %v1, i24 zeroext %v2) nounwind {
entry:
%t = call %0 @llvm.uadd.with.overflow.i24(i24 %v1, i24 %v2) ; <%0> [#uses=1]
%obit = extractvalue %0 %t, 1 ; <i1> [#uses=1]
br i1 %obit, label %carry, label %normal
normal: ; preds = %entry
ret i1 true
carry: ; preds = %entry
ret i1 false
}
declare %0 @llvm.uadd.with.overflow.i24(i24, i24) nounwind

View File

@ -0,0 +1,5 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
define i32 @add(i32 %A, i32 %B) {
%R = add i32 %A, %B ; <i32> [#uses=1]
ret i32 %R
}

View File

@ -0,0 +1,42 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
; XFAIL: *
; Assertion failed: (isUsed(Reg) && "Using an undefined register!"),
; function forward, file RegisterScavenging.cpp, line 182.
define void @test_add(i64 %AL, i64 %AH, i64 %BL, i64 %BH, i64* %RL, i64* %RH) {
entry:
%tmp1 = zext i64 %AL to i128 ; <i128> [#uses=1]
%tmp23 = zext i64 %AH to i128 ; <i128> [#uses=1]
%tmp4 = shl i128 %tmp23, 64 ; <i128> [#uses=1]
%tmp5 = or i128 %tmp4, %tmp1 ; <i128> [#uses=1]
%tmp67 = zext i64 %BL to i128 ; <i128> [#uses=1]
%tmp89 = zext i64 %BH to i128 ; <i128> [#uses=1]
%tmp11 = shl i128 %tmp89, 64 ; <i128> [#uses=1]
%tmp12 = or i128 %tmp11, %tmp67 ; <i128> [#uses=1]
%tmp15 = add i128 %tmp12, %tmp5 ; <i128> [#uses=2]
%tmp1617 = trunc i128 %tmp15 to i64 ; <i64> [#uses=1]
store i64 %tmp1617, i64* %RL
%tmp21 = lshr i128 %tmp15, 64 ; <i128> [#uses=1]
%tmp2122 = trunc i128 %tmp21 to i64 ; <i64> [#uses=1]
store i64 %tmp2122, i64* %RH
ret void
}
define void @test_sub(i64 %AL, i64 %AH, i64 %BL, i64 %BH, i64* %RL, i64* %RH) {
entry:
%tmp1 = zext i64 %AL to i128 ; <i128> [#uses=1]
%tmp23 = zext i64 %AH to i128 ; <i128> [#uses=1]
%tmp4 = shl i128 %tmp23, 64 ; <i128> [#uses=1]
%tmp5 = or i128 %tmp4, %tmp1 ; <i128> [#uses=1]
%tmp67 = zext i64 %BL to i128 ; <i128> [#uses=1]
%tmp89 = zext i64 %BH to i128 ; <i128> [#uses=1]
%tmp11 = shl i128 %tmp89, 64 ; <i128> [#uses=1]
%tmp12 = or i128 %tmp11, %tmp67 ; <i128> [#uses=1]
%tmp15 = sub i128 %tmp5, %tmp12 ; <i128> [#uses=2]
%tmp1617 = trunc i128 %tmp15 to i64 ; <i64> [#uses=1]
store i64 %tmp1617, i64* %RL
%tmp21 = lshr i128 %tmp15, 64 ; <i128> [#uses=1]
%tmp2122 = trunc i128 %tmp21 to i64 ; <i64> [#uses=1]
store i64 %tmp2122, i64* %RH
ret void
}

View File

@ -0,0 +1,51 @@
; RUN: llvm-as < %s | llc -march=bfin > %t
define i1 @add(i1 %A, i1 %B) {
%R = add i1 %A, %B ; <i1> [#uses=1]
ret i1 %R
}
define i1 @sub(i1 %A, i1 %B) {
%R = sub i1 %A, %B ; <i1> [#uses=1]
ret i1 %R
}
define i1 @mul(i1 %A, i1 %B) {
%R = mul i1 %A, %B ; <i1> [#uses=1]
ret i1 %R
}
define i1 @sdiv(i1 %A, i1 %B) {
%R = sdiv i1 %A, %B ; <i1> [#uses=1]
ret i1 %R
}
define i1 @udiv(i1 %A, i1 %B) {
%R = udiv i1 %A, %B ; <i1> [#uses=1]
ret i1 %R
}
define i1 @srem(i1 %A, i1 %B) {
%R = srem i1 %A, %B ; <i1> [#uses=1]
ret i1 %R
}
define i1 @urem(i1 %A, i1 %B) {
%R = urem i1 %A, %B ; <i1> [#uses=1]
ret i1 %R
}
define i1 @and(i1 %A, i1 %B) {
%R = and i1 %A, %B ; <i1> [#uses=1]
ret i1 %R
}
define i1 @or(i1 %A, i1 %B) {
%R = or i1 %A, %B ; <i1> [#uses=1]
ret i1 %R
}
define i1 @xor(i1 %A, i1 %B) {
%R = xor i1 %A, %B ; <i1> [#uses=1]
ret i1 %R
}

View File

@ -0,0 +1,36 @@
; RUN: llvm-as < %s | llc -march=bfin
define i16 @add(i16 %A, i16 %B) {
%R = add i16 %A, %B ; <i16> [#uses=1]
ret i16 %R
}
define i16 @sub(i16 %A, i16 %B) {
%R = sub i16 %A, %B ; <i16> [#uses=1]
ret i16 %R
}
define i16 @mul(i16 %A, i16 %B) {
%R = mul i16 %A, %B ; <i16> [#uses=1]
ret i16 %R
}
define i16 @sdiv(i16 %A, i16 %B) {
%R = sdiv i16 %A, %B ; <i16> [#uses=1]
ret i16 %R
}
define i16 @udiv(i16 %A, i16 %B) {
%R = udiv i16 %A, %B ; <i16> [#uses=1]
ret i16 %R
}
define i16 @srem(i16 %A, i16 %B) {
%R = srem i16 %A, %B ; <i16> [#uses=1]
ret i16 %R
}
define i16 @urem(i16 %A, i16 %B) {
%R = urem i16 %A, %B ; <i16> [#uses=1]
ret i16 %R
}

View File

@ -0,0 +1,51 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
define i32 @add(i32 %A, i32 %B) {
%R = add i32 %A, %B ; <i32> [#uses=1]
ret i32 %R
}
define i32 @sub(i32 %A, i32 %B) {
%R = sub i32 %A, %B ; <i32> [#uses=1]
ret i32 %R
}
define i32 @mul(i32 %A, i32 %B) {
%R = mul i32 %A, %B ; <i32> [#uses=1]
ret i32 %R
}
define i32 @sdiv(i32 %A, i32 %B) {
%R = sdiv i32 %A, %B ; <i32> [#uses=1]
ret i32 %R
}
define i32 @udiv(i32 %A, i32 %B) {
%R = udiv i32 %A, %B ; <i32> [#uses=1]
ret i32 %R
}
define i32 @srem(i32 %A, i32 %B) {
%R = srem i32 %A, %B ; <i32> [#uses=1]
ret i32 %R
}
define i32 @urem(i32 %A, i32 %B) {
%R = urem i32 %A, %B ; <i32> [#uses=1]
ret i32 %R
}
define i32 @and(i32 %A, i32 %B) {
%R = and i32 %A, %B ; <i32> [#uses=1]
ret i32 %R
}
define i32 @or(i32 %A, i32 %B) {
%R = or i32 %A, %B ; <i32> [#uses=1]
ret i32 %R
}
define i32 @xor(i32 %A, i32 %B) {
%R = xor i32 %A, %B ; <i32> [#uses=1]
ret i32 %R
}

View File

@ -0,0 +1,51 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
define i64 @add(i64 %A, i64 %B) {
%R = add i64 %A, %B ; <i64> [#uses=1]
ret i64 %R
}
define i64 @sub(i64 %A, i64 %B) {
%R = sub i64 %A, %B ; <i64> [#uses=1]
ret i64 %R
}
define i64 @mul(i64 %A, i64 %B) {
%R = mul i64 %A, %B ; <i64> [#uses=1]
ret i64 %R
}
define i64 @sdiv(i64 %A, i64 %B) {
%R = sdiv i64 %A, %B ; <i64> [#uses=1]
ret i64 %R
}
define i64 @udiv(i64 %A, i64 %B) {
%R = udiv i64 %A, %B ; <i64> [#uses=1]
ret i64 %R
}
define i64 @srem(i64 %A, i64 %B) {
%R = srem i64 %A, %B ; <i64> [#uses=1]
ret i64 %R
}
define i64 @urem(i64 %A, i64 %B) {
%R = urem i64 %A, %B ; <i64> [#uses=1]
ret i64 %R
}
define i64 @and(i64 %A, i64 %B) {
%R = and i64 %A, %B ; <i64> [#uses=1]
ret i64 %R
}
define i64 @or(i64 %A, i64 %B) {
%R = or i64 %A, %B ; <i64> [#uses=1]
ret i64 %R
}
define i64 @xor(i64 %A, i64 %B) {
%R = xor i64 %A, %B ; <i64> [#uses=1]
ret i64 %R
}

View File

@ -0,0 +1,51 @@
; RUN: llvm-as < %s | llc -march=bfin
define i8 @add(i8 %A, i8 %B) {
%R = add i8 %A, %B ; <i8> [#uses=1]
ret i8 %R
}
define i8 @sub(i8 %A, i8 %B) {
%R = sub i8 %A, %B ; <i8> [#uses=1]
ret i8 %R
}
define i8 @mul(i8 %A, i8 %B) {
%R = mul i8 %A, %B ; <i8> [#uses=1]
ret i8 %R
}
define i8 @sdiv(i8 %A, i8 %B) {
%R = sdiv i8 %A, %B ; <i8> [#uses=1]
ret i8 %R
}
define i8 @udiv(i8 %A, i8 %B) {
%R = udiv i8 %A, %B ; <i8> [#uses=1]
ret i8 %R
}
define i8 @srem(i8 %A, i8 %B) {
%R = srem i8 %A, %B ; <i8> [#uses=1]
ret i8 %R
}
define i8 @urem(i8 %A, i8 %B) {
%R = urem i8 %A, %B ; <i8> [#uses=1]
ret i8 %R
}
define i8 @and(i8 %A, i8 %B) {
%R = and i8 %A, %B ; <i8> [#uses=1]
ret i8 %R
}
define i8 @or(i8 %A, i8 %B) {
%R = or i8 %A, %B ; <i8> [#uses=1]
ret i8 %R
}
define i8 @xor(i8 %A, i8 %B) {
%R = xor i8 %A, %B ; <i8> [#uses=1]
ret i8 %R
}

View File

@ -0,0 +1,19 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
define void @void(i32, i32) {
add i32 0, 0 ; <i32>:3 [#uses=2]
sub i32 0, 4 ; <i32>:4 [#uses=2]
br label %5
; <label>:5 ; preds = %5, %2
add i32 %0, %1 ; <i32>:6 [#uses=2]
sub i32 %6, %4 ; <i32>:7 [#uses=1]
icmp sle i32 %7, %3 ; <i1>:8 [#uses=1]
br i1 %8, label %9, label %5
; <label>:9 ; preds = %5
add i32 %0, %1 ; <i32>:10 [#uses=0]
sub i32 %6, %4 ; <i32>:11 [#uses=1]
icmp sle i32 %11, %3 ; <i1>:12 [#uses=0]
ret void
}

View File

@ -0,0 +1,19 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
%IntList = type %struct.intlist*
%ReadFn = type i32 ()*
%YYSTYPE = type { %IntList }
%struct.intlist = type { i32, %IntList }
@yyval = external global %YYSTYPE ; <%YYSTYPE*> [#uses=1]
define i32 @yyparse() {
bb0:
%reg254 = load i16* null ; <i16> [#uses=1]
%reg254-idxcast = sext i16 %reg254 to i64 ; <i64> [#uses=1]
%reg254-idxcast-scale = mul i64 %reg254-idxcast, -1 ; <i64> [#uses=1]
%reg254-idxcast-scale-offset = add i64 %reg254-idxcast-scale, 1 ; <i64> [#uses=1]
%reg261.idx1 = getelementptr %YYSTYPE* null, i64 %reg254-idxcast-scale-offset, i32 0 ; <%IntList*> [#uses=1]
%reg261 = load %IntList* %reg261.idx1 ; <%IntList> [#uses=1]
store %IntList %reg261, %IntList* getelementptr (%YYSTYPE* @yyval, i64 0, i32 0)
unreachable
}

View File

@ -0,0 +1,9 @@
; RUN: llvm-as < %s | llc -march=bfin > %t
; XFAIL: *
; Assertion failed: (isUsed(Reg) && "Using an undefined register!")
; function forward, file RegisterScavenging.cpp, line 259.
define i1 @cmp3(i32 %A) {
%R = icmp uge i32 %A, 2
ret i1 %R
}

View File

@ -0,0 +1,17 @@
; RUN: llvm-as < %s | llc -march=bfin
; This test tries to use a JustCC register as a data operand for MOVEcc. It
; calls copyRegToReg(JustCC -> DP), failing because JustCC can only be copied to
; D. The proper solution would be to restrict the virtual register to D only.
define i32 @main() {
entry:
br label %loopentry
loopentry:
%done = icmp sle i64 undef, 5
br i1 %done, label %loopentry, label %exit.1
exit.1:
ret i32 0
}

View File

@ -0,0 +1,20 @@
; RUN: llvm-as < %s | llc -march=bfin
declare i32 @llvm.ctlz.i32(i32)
declare i32 @llvm.cttz.i32(i32)
declare i32 @llvm.ctpop.i32(i32)
define i32 @ctlztest(i32 %B) {
%b = call i32 @llvm.ctlz.i32( i32 %B )
ret i32 %b;
}
define i32 @cttztest(i32 %B) {
%b = call i32 @llvm.cttz.i32( i32 %B )
ret i32 %b;
}
define i32 @ctpoptest(i32 %B) {
%b = call i32 @llvm.ctpop.i32( i32 %B )
ret i32 %b;
}

View File

@ -0,0 +1,20 @@
; RUN: llvm-as < %s | llc -march=bfin
declare i64 @llvm.ctlz.i64(i64)
declare i64 @llvm.cttz.i64(i64)
declare i64 @llvm.ctpop.i64(i64)
define i64 @ctlztest(i64 %B) {
%b = call i64 @llvm.ctlz.i64( i64 %B )
ret i64 %b;
}
define i64 @cttztest(i64 %B) {
%b = call i64 @llvm.cttz.i64( i64 %B )
ret i64 %b;
}
define i64 @ctpoptest(i64 %B) {
%b = call i64 @llvm.ctpop.i64( i64 %B )
ret i64 %b;
}

View File

@ -0,0 +1,18 @@
; RUN: llvm-as < %s | llc -march=bfin
declare i16 @llvm.ctlz.i16(i16)
define i16 @ctlztest(i16 %B) {
%b = call i16 @llvm.ctlz.i16( i16 %B ) ; <i16> [#uses=1]
ret i16 %b;
}
define i16 @ctlztest_z(i16 zeroext %B) {
%b = call i16 @llvm.ctlz.i16( i16 %B ) ; <i16> [#uses=1]
ret i16 %b;
}
define i16 @ctlztest_s(i16 signext %B) {
%b = call i16 @llvm.ctlz.i16( i16 %B ) ; <i16> [#uses=1]
ret i16 %b;
}

View File

@ -0,0 +1,15 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
@.str = external constant [14 x i8] ; <[14 x i8]*> [#uses=1]
define i32 @main(i64 %arg) nounwind {
entry:
%tmp47 = tail call i64 @llvm.cttz.i64(i64 %arg) ; <i64> [#uses=1]
%tmp48 = trunc i64 %tmp47 to i32 ; <i32> [#uses=1]
%tmp40 = tail call i32 (i8*, ...)* @printf(i8* noalias getelementptr ([14 x i8]* @.str, i32 0, i32 0), i64 %arg, i32 0, i32 %tmp48, i32 0) nounwind ; <i32> [#uses=0]
ret i32 0
}
declare i32 @printf(i8* noalias, ...) nounwind
declare i64 @llvm.cttz.i64(i64) nounwind readnone

View File

@ -0,0 +1,18 @@
; RUN: llvm-as < %s | llc -march=bfin
declare i16 @llvm.ctpop.i16(i16)
define i16 @ctpoptest(i16 %B) {
%b = call i16 @llvm.ctpop.i16( i16 %B ) ; <i16> [#uses=1]
ret i16 %b;
}
define i16 @ctpoptest_z(i16 zeroext %B) {
%b = call i16 @llvm.ctpop.i16( i16 %B ) ; <i16> [#uses=1]
ret i16 %b;
}
define i16 @ctpoptest_s(i16 signext %B) {
%b = call i16 @llvm.ctpop.i16( i16 %B ) ; <i16> [#uses=1]
ret i16 %b;
}

View File

@ -0,0 +1,18 @@
; RUN: llvm-as < %s | llc -march=bfin
declare i16 @llvm.cttz.i16(i16)
define i16 @cttztest(i16 %B) {
%b = call i16 @llvm.cttz.i16( i16 %B ) ; <i16> [#uses=1]
ret i16 %b;
}
define i16 @cttztest_z(i16 zeroext %B) {
%b = call i16 @llvm.cttz.i16( i16 %B ) ; <i16> [#uses=1]
ret i16 %b;
}
define i16 @cttztest_s(i16 signext %B) {
%b = call i16 @llvm.cttz.i16( i16 %B ) ; <i16> [#uses=1]
ret i16 %b;
}

View File

@ -0,0 +1,11 @@
; RUN: llvm-as < %s | llc -march=bfin | grep cycles
; XFAIL: *
; ExpandIntegerResult #0: 0x181a60c: i64,ch = ReadCycleCounter 0x1104b08
; Do not know how to expand the result of this operator!
declare i64 @llvm.readcyclecounter()
define i64 @foo() {
%tmp.1 = call i64 @llvm.readcyclecounter()
ret i64 %tmp.1
}

View File

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

View File

@ -0,0 +1,8 @@
; RUN: llvm-as < %s | llc -march=bfin
declare i32 @printf(i8*, ...)
define i32 @main() {
%1 = call i32 (i8*, ...)* @printf(i8* undef, double undef)
ret i32 0
}

View File

@ -0,0 +1,10 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
declare i32 @SIM(i8*, i8*, i32, i32, i32, [256 x i32]*, i32, i32, i32)
define void @foo() {
bb0:
%V = alloca [256 x i32], i32 256 ; <[256 x i32]*> [#uses=1]
%0 = call i32 @SIM(i8* null, i8* null, i32 0, i32 0, i32 0, [256 x i32]* %V, i32 0, i32 0, i32 2) ; <i32> [#uses=0]
ret void
}

View File

@ -0,0 +1,9 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
@i17_l = external global i17 ; <i17*> [#uses=1]
@i17_s = external global i17 ; <i17*> [#uses=1]
define void @i17_ls() nounwind {
%tmp = load i17* @i17_l ; <i17> [#uses=1]
store i17 %tmp, i17* @i17_s
ret void
}

View File

@ -0,0 +1,9 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
@i1_l = external global i1 ; <i1*> [#uses=1]
@i1_s = external global i1 ; <i1*> [#uses=1]
define void @i1_ls() nounwind {
%tmp = load i1* @i1_l ; <i1> [#uses=1]
store i1 %tmp, i1* @i1_s
ret void
}

View File

@ -0,0 +1,10 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
define i32 @adj(i32 %d.1, i32 %ct.1) {
entry:
%tmp.22.not = trunc i32 %ct.1 to i1 ; <i1> [#uses=1]
%tmp.221 = xor i1 %tmp.22.not, true ; <i1> [#uses=1]
%tmp.26 = or i1 false, %tmp.221 ; <i1> [#uses=1]
%tmp.27 = zext i1 %tmp.26 to i32 ; <i32> [#uses=1]
ret i32 %tmp.27
}

View File

@ -0,0 +1,9 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
@i216_l = external global i216 ; <i216*> [#uses=1]
@i216_s = external global i216 ; <i216*> [#uses=1]
define void @i216_ls() nounwind {
%tmp = load i216* @i216_l ; <i216> [#uses=1]
store i216 %tmp, i216* @i216_s
ret void
}

View File

@ -0,0 +1,9 @@
; RUN: llvm-as < %s | llc -march=bfin
@i248_l = external global i248 ; <i248*> [#uses=1]
@i248_s = external global i248 ; <i248*> [#uses=1]
define void @i248_ls() nounwind {
%tmp = load i248* @i248_l ; <i248> [#uses=1]
store i248 %tmp, i248* @i248_s
ret void
}

View File

@ -0,0 +1,9 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
@i17_l = external global i17 ; <i17*> [#uses=1]
@i17_s = external global i17 ; <i17*> [#uses=1]
define void @i17_ls() nounwind {
%tmp = load i17* @i17_l ; <i17> [#uses=1]
store i17 %tmp, i17* @i17_s
ret void
}

View File

@ -0,0 +1,7 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
@i256_s = external global i256 ; <i256*> [#uses=1]
define void @i256_ls(i256 %x) nounwind {
store i256 %x, i256* @i256_s
ret void
}

View File

@ -0,0 +1,8 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
@i56_l = external global i56 ; <i56*> [#uses=1]
@i56_s = external global i56 ; <i56*> [#uses=1]
define void @i56_ls(i56 %x) nounwind {
store i56 %x, i56* @i56_s
ret void
}

View File

@ -0,0 +1,10 @@
; RUN: llvm-as < %s | llc -march=bfin
@i8_l = external global i8 ; <i8*> [#uses=1]
@i8_s = external global i8 ; <i8*> [#uses=1]
define void @i8_ls() nounwind {
%tmp = load i8* @i8_l ; <i8> [#uses=1]
store i8 %tmp, i8* @i8_s
ret void
}

View File

@ -0,0 +1,80 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
define fastcc void @Evaluate() {
entry:
br i1 false, label %cond_false186, label %cond_true
cond_true: ; preds = %entry
ret void
cond_false186: ; preds = %entry
br i1 false, label %cond_true293, label %bb203
bb203: ; preds = %cond_false186
ret void
cond_true293: ; preds = %cond_false186
br i1 false, label %cond_true298, label %cond_next317
cond_true298: ; preds = %cond_true293
br i1 false, label %cond_next518, label %cond_true397.preheader
cond_next317: ; preds = %cond_true293
ret void
cond_true397.preheader: ; preds = %cond_true298
ret void
cond_next518: ; preds = %cond_true298
br i1 false, label %bb1069, label %cond_true522
cond_true522: ; preds = %cond_next518
ret void
bb1069: ; preds = %cond_next518
br i1 false, label %cond_next1131, label %bb1096
bb1096: ; preds = %bb1069
ret void
cond_next1131: ; preds = %bb1069
br i1 false, label %cond_next1207, label %cond_true1150
cond_true1150: ; preds = %cond_next1131
ret void
cond_next1207: ; preds = %cond_next1131
br i1 false, label %cond_next1219, label %cond_true1211
cond_true1211: ; preds = %cond_next1207
ret void
cond_next1219: ; preds = %cond_next1207
br i1 false, label %cond_true1223, label %cond_next1283
cond_true1223: ; preds = %cond_next1219
br i1 false, label %cond_true1254, label %cond_true1264
cond_true1254: ; preds = %cond_true1223
br i1 false, label %bb1567, label %cond_true1369.preheader
cond_true1264: ; preds = %cond_true1223
ret void
cond_next1283: ; preds = %cond_next1219
ret void
cond_true1369.preheader: ; preds = %cond_true1254
ret void
bb1567: ; preds = %cond_true1254
%tmp1605 = load i8* null ; <i8> [#uses=1]
%tmp1606 = icmp eq i8 %tmp1605, 0 ; <i1> [#uses=1]
br i1 %tmp1606, label %cond_next1637, label %cond_true1607
cond_true1607: ; preds = %bb1567
ret void
cond_next1637: ; preds = %bb1567
ret void
}

View File

@ -0,0 +1,15 @@
; RUN: llvm-as < %s | llc -march=bfin
; Assertion failed: (width < BitWidth && "Invalid APInt Truncate request"),
; function trunc, file APInt.cpp, line 956.
@str2 = external global [29 x i8]
define void @printArgsNoRet(i32 %a1, float %a2, i8 %a3, double %a4, i8* %a5, i32 %a6, float %a7, i8 %a8, double %a9, i8* %a10, i32 %a11, float %a12, i8 %a13, double %a14, i8* %a15) {
entry:
%tmp17 = sext i8 %a13 to i32
%tmp23 = call i32 (i8*, ...)* @printf(i8* getelementptr ([29 x i8]* @str2, i32 0, i64 0), i32 %a11, double 0.000000e+00, i32 %tmp17, double %a14, i32 0)
ret void
}
declare i32 @printf(i8*, ...)

View File

@ -0,0 +1,53 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs | FileCheck %s
; CHECK: .section .rodata
; CHECK: JTI1_0:
; CHECK: .long .BB1_1
define i32 @oper(i32 %op, i32 %A, i32 %B) {
entry:
switch i32 %op, label %bbx [
i32 1 , label %bb1
i32 2 , label %bb2
i32 3 , label %bb3
i32 4 , label %bb4
i32 5 , label %bb5
i32 6 , label %bb6
i32 7 , label %bb7
i32 8 , label %bb8
i32 9 , label %bb9
i32 10, label %bb10
]
bb1:
%R1 = add i32 %A, %B ; <i32> [#uses=1]
ret i32 %R1
bb2:
%R2 = sub i32 %A, %B ; <i32> [#uses=1]
ret i32 %R2
bb3:
%R3 = mul i32 %A, %B ; <i32> [#uses=1]
ret i32 %R3
bb4:
%R4 = sdiv i32 %A, %B ; <i32> [#uses=1]
ret i32 %R4
bb5:
%R5 = udiv i32 %A, %B ; <i32> [#uses=1]
ret i32 %R5
bb6:
%R6 = srem i32 %A, %B ; <i32> [#uses=1]
ret i32 %R6
bb7:
%R7 = urem i32 %A, %B ; <i32> [#uses=1]
ret i32 %R7
bb8:
%R8 = and i32 %A, %B ; <i32> [#uses=1]
ret i32 %R8
bb9:
%R9 = or i32 %A, %B ; <i32> [#uses=1]
ret i32 %R9
bb10:
%R10 = xor i32 %A, %B ; <i32> [#uses=1]
ret i32 %R10
bbx:
ret i32 0
}

View File

@ -0,0 +1,187 @@
; RUN: llvm-as < %s | llc -march=bfin
; The switch expansion uses a dynamic shl, and it produces a jumptable
define void @athlon_fp_unit_ready_cost() {
entry:
switch i32 0, label %UnifiedReturnBlock [
i32 -1, label %bb2063
i32 19, label %bb2035
i32 20, label %bb2035
i32 21, label %bb2035
i32 23, label %bb2035
i32 24, label %bb2035
i32 27, label %bb2035
i32 32, label %bb2035
i32 33, label %bb1994
i32 35, label %bb2035
i32 36, label %bb1994
i32 90, label %bb1948
i32 94, label %bb1948
i32 95, label %bb1948
i32 133, label %bb1419
i32 135, label %bb1238
i32 136, label %bb1238
i32 137, label %bb1238
i32 138, label %bb1238
i32 139, label %bb1201
i32 140, label %bb1201
i32 141, label %bb1154
i32 142, label %bb1126
i32 144, label %bb1201
i32 145, label %bb1126
i32 146, label %bb1201
i32 147, label %bb1126
i32 148, label %bb1201
i32 149, label %bb1126
i32 150, label %bb1201
i32 151, label %bb1126
i32 152, label %bb1096
i32 153, label %bb1096
i32 154, label %bb1096
i32 157, label %bb1096
i32 158, label %bb1096
i32 159, label %bb1096
i32 162, label %bb1096
i32 163, label %bb1096
i32 164, label %bb1096
i32 167, label %bb1201
i32 168, label %bb1201
i32 170, label %bb1201
i32 171, label %bb1201
i32 173, label %bb1201
i32 174, label %bb1201
i32 176, label %bb1201
i32 177, label %bb1201
i32 179, label %bb993
i32 180, label %bb993
i32 181, label %bb993
i32 182, label %bb993
i32 183, label %bb993
i32 184, label %bb993
i32 365, label %bb1126
i32 366, label %bb1126
i32 367, label %bb1126
i32 368, label %bb1126
i32 369, label %bb1126
i32 370, label %bb1126
i32 371, label %bb1126
i32 372, label %bb1126
i32 373, label %bb1126
i32 384, label %bb1126
i32 385, label %bb1126
i32 386, label %bb1126
i32 387, label %bb1126
i32 388, label %bb1126
i32 389, label %bb1126
i32 390, label %bb1126
i32 391, label %bb1126
i32 392, label %bb1126
i32 525, label %bb919
i32 526, label %bb839
i32 528, label %bb919
i32 529, label %bb839
i32 532, label %cond_next6.i97
i32 533, label %cond_next6.i81
i32 534, label %bb495
i32 536, label %cond_next6.i81
i32 537, label %cond_next6.i81
i32 538, label %bb396
i32 539, label %bb288
i32 541, label %bb396
i32 542, label %bb396
i32 543, label %bb396
i32 544, label %bb396
i32 545, label %bb189
i32 546, label %cond_next6.i
i32 547, label %bb189
i32 548, label %cond_next6.i
i32 549, label %bb189
i32 550, label %cond_next6.i
i32 551, label %bb189
i32 552, label %cond_next6.i
i32 553, label %bb189
i32 554, label %cond_next6.i
i32 555, label %bb189
i32 556, label %cond_next6.i
i32 557, label %bb189
i32 558, label %cond_next6.i
i32 618, label %bb40
i32 619, label %bb18
i32 620, label %bb40
i32 621, label %bb10
i32 622, label %bb10
]
bb10:
ret void
bb18:
ret void
bb40:
ret void
cond_next6.i:
ret void
bb189:
ret void
bb288:
ret void
bb396:
ret void
bb495:
ret void
cond_next6.i81:
ret void
cond_next6.i97:
ret void
bb839:
ret void
bb919:
ret void
bb993:
ret void
bb1096:
ret void
bb1126:
ret void
bb1154:
ret void
bb1201:
ret void
bb1238:
ret void
bb1419:
ret void
bb1948:
ret void
bb1994:
ret void
bb2035:
ret void
bb2063:
ret void
UnifiedReturnBlock:
ret void
}

View File

@ -0,0 +1,13 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
; This somewhat contrived function heavily exercises register classes
; It can trick -join-cross-class-copies into making illegal joins
define void @f(i16** nocapture %p) nounwind readonly {
entry:
%tmp1 = load i16** %p ; <i16*> [#uses=1]
%tmp2 = load i16* %tmp1 ; <i16> [#uses=1]
%ptr = getelementptr i16* %tmp1, i16 %tmp2
store i16 %tmp2, i16* %ptr
ret void
}

View File

@ -0,0 +1,16 @@
; RUN: llvm-as < %s | llc -march=bfin
define i16 @and(i16 %A, i16 %B) {
%R = and i16 %A, %B ; <i16> [#uses=1]
ret i16 %R
}
define i16 @or(i16 %A, i16 %B) {
%R = or i16 %A, %B ; <i16> [#uses=1]
ret i16 %R
}
define i16 @xor(i16 %A, i16 %B) {
%R = xor i16 %A, %B ; <i16> [#uses=1]
ret i16 %R
}

View File

@ -0,0 +1,23 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
type { i32, float, float, float, float, float, float, float, float, float, float } ; type %0
%struct..s_segment_inf = type { float, i32, i16, i16, float, float, i32, float, float }
define i32 @main(i32 %argc.1, i8** %argv.1) {
entry:
%tmp.218 = load float* null ; <float> [#uses=1]
%tmp.219 = getelementptr %0* null, i64 0, i32 6 ; <float*> [#uses=1]
%tmp.220 = load float* %tmp.219 ; <float> [#uses=1]
%tmp.221 = getelementptr %0* null, i64 0, i32 7 ; <float*> [#uses=1]
%tmp.222 = load float* %tmp.221 ; <float> [#uses=1]
%tmp.223 = getelementptr %0* null, i64 0, i32 8 ; <float*> [#uses=1]
%tmp.224 = load float* %tmp.223 ; <float> [#uses=1]
%tmp.225 = getelementptr %0* null, i64 0, i32 9 ; <float*> [#uses=1]
%tmp.226 = load float* %tmp.225 ; <float> [#uses=1]
%tmp.227 = getelementptr %0* null, i64 0, i32 10 ; <float*> [#uses=1]
%tmp.228 = load float* %tmp.227 ; <float> [#uses=1]
call void @place_and_route(i32 0, i32 0, float 0.000000e+00, i32 0, i32 0, i8* null, i32 0, i32 0, i8* null, i8* null, i8* null, i8* null, i32 0, i32 0, i32 0, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, i32 0, i32 0, i32 0, i32 0, i32 0, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, i32 0, i32 0, i16 0, i16 0, i16 0, float 0.000000e+00, float 0.000000e+00, %struct..s_segment_inf* null, i32 0, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float %tmp.218, float %tmp.220, float %tmp.222, float %tmp.224, float %tmp.226, float %tmp.228)
ret i32 0
}
declare void @place_and_route(i32, i32, float, i32, i32, i8*, i32, i32, i8*, i8*, i8*, i8*, i32, i32, i32, float, float, float, float, float, float, float, float, float, i32, i32, i32, i32, i32, float, float, float, i32, i32, i16, i16, i16, float, float, %struct..s_segment_inf*, i32, float, float, float, float, float, float, float, float, float, float)

View File

@ -0,0 +1,106 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
%struct.CUMULATIVE_ARGS = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }
%struct.VEC_edge = type { i32, i32, [1 x %struct.edge_def*] }
%struct._obstack_chunk = type { i8*, %struct._obstack_chunk*, [4 x i8] }
%struct.basic_block_def = type { %struct.rtx_def*, %struct.rtx_def*, %struct.tree_node*, %struct.VEC_edge*, %struct.VEC_edge*, %struct.bitmap_head_def*, %struct.bitmap_head_def*, i8*, %struct.loop*, [2 x %struct.et_node*], %struct.basic_block_def*, %struct.basic_block_def*, %struct.reorder_block_def*, %struct.bb_ann_d*, i64, i32, i32, i32, i32 }
%struct.bb_ann_d = type { %struct.tree_node*, i8, %struct.edge_prediction* }
%struct.bitmap_element_def = type { %struct.bitmap_element_def*, %struct.bitmap_element_def*, i32, [4 x i32] }
%struct.bitmap_head_def = type { %struct.bitmap_element_def*, %struct.bitmap_element_def*, i32, %struct.bitmap_obstack* }
%struct.bitmap_obstack = type { %struct.bitmap_element_def*, %struct.bitmap_head_def*, %struct.obstack }
%struct.cost_pair = type { %struct.iv_cand*, i32, %struct.bitmap_head_def* }
%struct.dataflow_d = type { %struct.varray_head_tag*, [2 x %struct.tree_node*] }
%struct.def_operand_ptr = type { %struct.tree_node** }
%struct.def_optype_d = type { i32, [1 x %struct.def_operand_ptr] }
%struct.edge_def = type { %struct.basic_block_def*, %struct.basic_block_def*, %struct.edge_def_insns, i8*, %struct.location_t*, i32, i32, i64, i32 }
%struct.edge_def_insns = type { %struct.rtx_def* }
%struct.edge_prediction = type { %struct.edge_prediction*, %struct.edge_def*, i32, i32 }
%struct.eh_status = type opaque
%struct.emit_status = type { i32, i32, %struct.rtx_def*, %struct.rtx_def*, %struct.sequence_stack*, i32, %struct.location_t, i32, i8*, %struct.rtx_def** }
%struct.et_node = type opaque
%struct.expr_status = type { i32, i32, i32, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def* }
%struct.function = type { %struct.eh_status*, %struct.expr_status*, %struct.emit_status*, %struct.varasm_status*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.function*, i32, i32, i32, i32, %struct.rtx_def*, %struct.CUMULATIVE_ARGS, %struct.rtx_def*, %struct.rtx_def*, %struct.initial_value_struct*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, i8, i32, i64, %struct.tree_node*, %struct.tree_node*, %struct.rtx_def*, %struct.varray_head_tag*, %struct.temp_slot*, i32, %struct.var_refs_queue*, i32, i32, %struct.rtvec_def*, %struct.tree_node*, i32, i32, i32, %struct.machine_function*, i32, i32, i1, i1, %struct.language_function*, %struct.rtx_def*, i32, i32, i32, i32, %struct.location_t, %struct.varray_head_tag*, %struct.tree_node*, i8, i8, i8 }
%struct.htab = type { i32 (i8*)*, i32 (i8*, i8*)*, void (i8*)*, i8**, i32, i32, i32, i32, i32, i8* (i32, i32)*, void (i8*)*, i8*, i8* (i8*, i32, i32)*, void (i8*, i8*)*, i32 }
%struct.initial_value_struct = type opaque
%struct.iv = type { %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, i1, i1, i32 }
%struct.iv_cand = type { i32, i1, i32, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.iv*, i32 }
%struct.iv_use = type { i32, i32, %struct.iv*, %struct.tree_node*, %struct.tree_node**, %struct.bitmap_head_def*, i32, %struct.cost_pair*, %struct.iv_cand* }
%struct.ivopts_data = type { %struct.loop*, %struct.htab*, i32, %struct.version_info*, %struct.bitmap_head_def*, i32, %struct.varray_head_tag*, %struct.varray_head_tag*, %struct.bitmap_head_def*, i1 }
%struct.lang_decl = type opaque
%struct.language_function = type opaque
%struct.location_t = type { i8*, i32 }
%struct.loop = type { i32, %struct.basic_block_def*, %struct.basic_block_def*, %struct.basic_block_def*, %struct.lpt_decision, i32, i32, %struct.edge_def**, i32, %struct.basic_block_def*, %struct.basic_block_def*, i32, %struct.edge_def**, i32, %struct.edge_def**, i32, %struct.simple_bitmap_def*, i32, %struct.loop**, i32, %struct.loop*, %struct.loop*, %struct.loop*, %struct.loop*, i32, i8*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, %struct.rtx_def*, i32, %struct.tree_node*, %struct.tree_node*, %struct.nb_iter_bound*, %struct.edge_def*, i1 }
%struct.lpt_decision = type { i32, i32 }
%struct.machine_function = type { %struct.stack_local_entry*, i8*, %struct.rtx_def*, i32, i32, i32, i32, i32 }
%struct.nb_iter_bound = type { %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.nb_iter_bound* }
%struct.obstack = type { i32, %struct._obstack_chunk*, i8*, i8*, i8*, i32, i32, %struct._obstack_chunk* (i8*, i32)*, void (i8*, %struct._obstack_chunk*)*, i8*, i8 }
%struct.reorder_block_def = type { %struct.rtx_def*, %struct.rtx_def*, %struct.basic_block_def*, %struct.basic_block_def*, %struct.basic_block_def*, i32, i32, i32 }
%struct.rtvec_def = type { i32, [1 x %struct.rtx_def*] }
%struct.rtx_def = type { i16, i8, i8, %struct.u }
%struct.sequence_stack = type { %struct.rtx_def*, %struct.rtx_def*, %struct.sequence_stack* }
%struct.simple_bitmap_def = type { i32, i32, i32, [1 x i64] }
%struct.stack_local_entry = type opaque
%struct.stmt_ann_d = type { %struct.tree_ann_common_d, i8, %struct.basic_block_def*, %struct.stmt_operands_d, %struct.dataflow_d*, %struct.bitmap_head_def*, i32 }
%struct.stmt_operands_d = type { %struct.def_optype_d*, %struct.def_optype_d*, %struct.v_may_def_optype_d*, %struct.vuse_optype_d*, %struct.v_may_def_optype_d* }
%struct.temp_slot = type opaque
%struct.tree_ann_common_d = type { i32, i8*, %struct.tree_node* }
%struct.tree_ann_d = type { %struct.stmt_ann_d }
%struct.tree_common = type { %struct.tree_node*, %struct.tree_node*, %struct.tree_ann_d*, i8, i8, i8, i8, i8 }
%struct.tree_decl = type { %struct.tree_common, %struct.location_t, i32, %struct.tree_node*, i8, i8, i8, i8, i8, i8, i8, i32, %struct.tree_decl_u1, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.tree_node*, %struct.rtx_def*, i32, %struct.tree_decl_u2, %struct.tree_node*, %struct.tree_node*, i64, %struct.lang_decl* }
%struct.tree_decl_u1 = type { i64 }
%struct.tree_decl_u2 = type { %struct.function* }
%struct.tree_node = type { %struct.tree_decl }
%struct.u = type { [1 x i64] }
%struct.v_def_use_operand_type_t = type { %struct.tree_node*, %struct.tree_node* }
%struct.v_may_def_optype_d = type { i32, [1 x %struct.v_def_use_operand_type_t] }
%struct.var_refs_queue = type { %struct.rtx_def*, i32, i32, %struct.var_refs_queue* }
%struct.varasm_status = type opaque
%struct.varray_head_tag = type { i32, i32, i32, i8*, %struct.u }
%struct.version_info = type { %struct.tree_node*, %struct.iv*, i1, i32, i1 }
%struct.vuse_optype_d = type { i32, [1 x %struct.tree_node*] }
define i1 @determine_use_iv_cost(%struct.ivopts_data* %data, %struct.iv_use* %use, %struct.iv_cand* %cand) {
entry:
switch i32 0, label %bb91 [
i32 0, label %bb
i32 1, label %bb6
i32 3, label %cond_next135
]
bb: ; preds = %entry
ret i1 false
bb6: ; preds = %entry
br i1 false, label %bb87, label %cond_next27
cond_next27: ; preds = %bb6
br i1 false, label %cond_true30, label %cond_next55
cond_true30: ; preds = %cond_next27
br i1 false, label %cond_next41, label %cond_true35
cond_true35: ; preds = %cond_true30
ret i1 false
cond_next41: ; preds = %cond_true30
%tmp44 = call i32 @force_var_cost(%struct.ivopts_data* %data, %struct.tree_node* null, %struct.bitmap_head_def** null) ; <i32> [#uses=1]
%tmp46 = udiv i32 %tmp44, 5 ; <i32> [#uses=1]
call void @set_use_iv_cost(%struct.ivopts_data* %data, %struct.iv_use* %use, %struct.iv_cand* %cand, i32 %tmp46, %struct.bitmap_head_def* null)
br label %bb87
cond_next55: ; preds = %cond_next27
ret i1 false
bb87: ; preds = %cond_next41, %bb6
ret i1 false
bb91: ; preds = %entry
ret i1 false
cond_next135: ; preds = %entry
ret i1 false
}
declare void @set_use_iv_cost(%struct.ivopts_data*, %struct.iv_use*, %struct.iv_cand*, i32, %struct.bitmap_head_def*)
declare i32 @force_var_cost(%struct.ivopts_data*, %struct.tree_node*, %struct.bitmap_head_def**)

View File

@ -0,0 +1,10 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
@.str_1 = external constant [42 x i8] ; <[42 x i8]*> [#uses=1]
declare i32 @printf(i8*, ...)
define i32 @main(i32 %argc.1, i8** %argv.1) {
entry:
%tmp.16 = call i32 (i8*, ...)* @printf(i8* getelementptr ([42 x i8]* @.str_1, i64 0, i64 0), i32 0, i32 0, i64 0, i64 0)
ret i32 0
}

View File

@ -0,0 +1,11 @@
; RUN: llvm-as < %s | llc -march=bfin
; XFAIL: *
; Assertion failed: (isUsed(Reg) && "Using an undefined register!"),
; function forward, file RegisterScavenging.cpp, line 182.
declare i32 @printf(i8*, ...)
define i32 @main() {
%1 = call i32 (i8*, ...)* @printf(i8* undef, i1 undef)
ret i32 0
}

View File

@ -0,0 +1,42 @@
; RUN: llvm-as < %s | llc -march=bfin > %t
; XFAIL: *
; DAG combiner can produce an illegal i16 OR operation after LegalizeOps.
define void @mng_display_bgr565() {
entry:
br i1 false, label %bb.preheader, label %return
bb.preheader:
br i1 false, label %cond_true48, label %cond_next80
cond_true48:
%tmp = load i8* null
%tmp51 = zext i8 %tmp to i16
%tmp99 = load i8* null
%tmp54 = bitcast i8 %tmp99 to i8
%tmp54.upgrd.1 = zext i8 %tmp54 to i32
%tmp55 = lshr i32 %tmp54.upgrd.1, 3
%tmp55.upgrd.2 = trunc i32 %tmp55 to i16
%tmp52 = shl i16 %tmp51, 5
%tmp56 = and i16 %tmp55.upgrd.2, 28
%tmp57 = or i16 %tmp56, %tmp52
%tmp60 = zext i16 %tmp57 to i32
%tmp62 = xor i32 0, 65535
%tmp63 = mul i32 %tmp60, %tmp62
%tmp65 = add i32 0, %tmp63
%tmp69 = add i32 0, %tmp65
%tmp70 = lshr i32 %tmp69, 16
%tmp70.upgrd.3 = trunc i32 %tmp70 to i16
%tmp75 = lshr i16 %tmp70.upgrd.3, 8
%tmp75.upgrd.4 = trunc i16 %tmp75 to i8
%tmp76 = lshr i8 %tmp75.upgrd.4, 5
store i8 %tmp76, i8* null
ret void
cond_next80:
ret void
return:
ret void
}

View File

@ -0,0 +1,40 @@
; RUN: llvm-as < %s | llc -march=bfin > %t
; XFAIL: *
; Assertion failed: (isUsed(Reg) && "Using an undefined register!"),
; function forward, file RegisterScavenging.cpp, line 259.
; The DAG combiner may sometimes create illegal i16 SETCC operations when run
; after LegalizeOps. Try to tease out all the optimizations in
; TargetLowering::SimplifySetCC.
@x = external global i16
@y = external global i16
declare i16 @llvm.ctlz.i16(i16)
; Case (srl (ctlz x), 5) == const
; Note: ctlz is promoted, so this test does not catch the DAG combiner
define i1 @srl_ctlz_const() {
%x = load i16* @x
%c = call i16 @llvm.ctlz.i16(i16 %x)
%s = lshr i16 %c, 4
%r = icmp eq i16 %s, 1
ret i1 %r
}
; Case (zext x) == const
define i1 @zext_const() {
%x = load i16* @x
%r = icmp ugt i16 %x, 1
ret i1 %r
}
; Case (sext x) == const
define i1 @sext_const() {
%x = load i16* @x
%y = add i16 %x, 1
%x2 = sext i16 %y to i32
%r = icmp ne i32 %x2, -1
ret i1 %r
}

View File

@ -0,0 +1,5 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs
define i32 @sdiv(i32 %A, i32 %B) {
%R = sdiv i32 %A, %B ; <i32> [#uses=1]
ret i32 %R
}

View File

@ -0,0 +1,11 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
declare i1 @foo()
define i32 @test(i32* %A, i32* %B) {
%a = load i32* %A
%b = load i32* %B
%cond = call i1 @foo()
%c = select i1 %cond, i32 %a, i32 %b
ret i32 %c
}

View File

@ -0,0 +1,18 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
define i32 @foo(i32 %A, i32 %B, i32 %C) {
entry:
switch i32 %A, label %out [
i32 1, label %bb
i32 0, label %bb13
]
bb: ; preds = %entry
ret i32 1
bb13: ; preds = %entry
ret i32 1
out: ; preds = %entry
ret i32 0
}

View File

@ -0,0 +1,16 @@
; RUN: llvm-as < %s | llc -march=bfin -verify-machineinstrs > %t
define i8* @FindChar(i8* %CurPtr) {
entry:
br label %bb
bb: ; preds = %bb, %entry
%tmp = load i8* null ; <i8> [#uses=1]
switch i8 %tmp, label %bb [
i8 0, label %bb7
i8 120, label %bb7
]
bb7: ; preds = %bb, %bb
ret i8* null
}