More of the Cell SPU code drop from "Team Aerospace".

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@44582 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Scott Michel 2007-12-04 22:23:35 +00:00
parent 35a3e4abb9
commit 266bc8f777
11 changed files with 4792 additions and 0 deletions

View File

@ -0,0 +1,654 @@
//===-- SPUAsmPrinter.cpp - Print machine instrs to Cell SPU assembly -------=//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by a team from the Computer Systems Research
// Department at The Aerospace Corporation.
//
// See README.txt for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a printer that converts from our internal representation
// of machine-dependent LLVM code to Cell SPU assembly language. This printer
// is the output mechanism used by `llc'.
//
// Documentation at http://developer.apple.com/documentation/DeveloperTools/
// Reference/Assembler/ASMIntroduction/chapter_1_section_1.html
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "asmprinter"
#include "SPU.h"
#include "SPUTargetMachine.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DwarfWriter.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Support/Mangler.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Target/TargetAsmInfo.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include <set>
using namespace llvm;
namespace {
STATISTIC(EmittedInsts, "Number of machine instrs printed");
const std::string bss_section(".bss");
struct VISIBILITY_HIDDEN SPUAsmPrinter : public AsmPrinter {
std::set<std::string> FnStubs, GVStubs;
SPUAsmPrinter(std::ostream &O, TargetMachine &TM, const TargetAsmInfo *T) :
AsmPrinter(O, TM, T)
{
}
virtual const char *getPassName() const {
return "STI CBEA SPU Assembly Printer";
}
SPUTargetMachine &getTM() {
return static_cast<SPUTargetMachine&>(TM);
}
/// printInstruction - This method is automatically generated by tablegen
/// from the instruction set description. This method returns true if the
/// machine instruction was sufficiently described to print it, otherwise it
/// returns false.
bool printInstruction(const MachineInstr *MI);
void printMachineInstruction(const MachineInstr *MI);
void printOp(const MachineOperand &MO);
/// printRegister - Print register according to target requirements.
///
void printRegister(const MachineOperand &MO, bool R0AsZero) {
unsigned RegNo = MO.getReg();
assert(MRegisterInfo::isPhysicalRegister(RegNo) && "Not physreg??");
O << TM.getRegisterInfo()->get(RegNo).Name;
}
void printOperand(const MachineInstr *MI, unsigned OpNo) {
const MachineOperand &MO = MI->getOperand(OpNo);
if (MO.isRegister()) {
assert(MRegisterInfo::isPhysicalRegister(MO.getReg())&&"Not physreg??");
O << TM.getRegisterInfo()->get(MO.getReg()).Name;
} else if (MO.isImmediate()) {
O << MO.getImmedValue();
} else {
printOp(MO);
}
}
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
printS7ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
int value = MI->getOperand(OpNo).getImmedValue();
value = (value << (32 - 7)) >> (32 - 7);
assert((value >= -(1 << 8) && value <= (1 << 7) - 1)
&& "Invalid s7 argument");
O << value;
}
void
printU7ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
unsigned int value = MI->getOperand(OpNo).getImmedValue();
assert(value < (1 << 8) && "Invalid u7 argument");
O << value;
}
void
printMemRegImmS7(const MachineInstr *MI, unsigned OpNo)
{
char value = MI->getOperand(OpNo).getImmedValue();
O << (int) value;
O << "(";
printOperand(MI, OpNo+1);
O << ")";
}
void
printS16ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
O << (short) MI->getOperand(OpNo).getImmedValue();
}
void
printU16ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
O << (unsigned short)MI->getOperand(OpNo).getImmedValue();
}
void
printU32ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
O << (unsigned)MI->getOperand(OpNo).getImmedValue();
}
void
printMemRegReg(const MachineInstr *MI, unsigned OpNo) {
// When used as the base register, r0 reads constant zero rather than
// the value contained in the register. For this reason, the darwin
// assembler requires that we print r0 as 0 (no r) when used as the base.
const MachineOperand &MO = MI->getOperand(OpNo);
O << TM.getRegisterInfo()->get(MO.getReg()).Name;
O << ", ";
printOperand(MI, OpNo+1);
}
void
printU18ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
unsigned int value = MI->getOperand(OpNo).getImmedValue();
assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
O << value;
}
void
printS10ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
short value = (short) (((int) MI->getOperand(OpNo).getImmedValue() << 16)
>> 16);
assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
&& "Invalid s10 argument");
O << value;
}
void
printU10ImmOperand(const MachineInstr *MI, unsigned OpNo)
{
short value = (short) (((int) MI->getOperand(OpNo).getImmedValue() << 16)
>> 16);
assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
O << value;
}
void
printMemRegImmS10(const MachineInstr *MI, unsigned OpNo)
{
const MachineOperand &MO = MI->getOperand(OpNo);
assert(MO.isImmediate()
&& "printMemRegImmS10 first operand is not immedate");
printS10ImmOperand(MI, OpNo);
O << "(";
printOperand(MI, OpNo+1);
O << ")";
}
void
printAddr256K(const MachineInstr *MI, unsigned OpNo)
{
/* Note: operand 1 is an offset or symbol name. Operand 2 is
ignored. */
if (MI->getOperand(OpNo).isImmediate()) {
printS16ImmOperand(MI, OpNo);
} else {
printOp(MI->getOperand(OpNo));
}
}
void printCallOperand(const MachineInstr *MI, unsigned OpNo) {
printOp(MI->getOperand(OpNo));
}
void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo) {
printOp(MI->getOperand(OpNo));
O << "-.";
}
void printSymbolHi(const MachineInstr *MI, unsigned OpNo) {
if (MI->getOperand(OpNo).isImmediate()) {
printS16ImmOperand(MI, OpNo);
} else {
printOp(MI->getOperand(OpNo));
O << "@h";
}
}
void printSymbolLo(const MachineInstr *MI, unsigned OpNo) {
if (MI->getOperand(OpNo).isImmediate()) {
printS16ImmOperand(MI, OpNo);
} else {
printOp(MI->getOperand(OpNo));
O << "@l";
}
}
/// Print local store address
void printSymbolLSA(const MachineInstr *MI, unsigned OpNo) {
printOp(MI->getOperand(OpNo));
}
void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
if (MI->getOperand(OpNo).isImmediate()) {
int value = (int) MI->getOperand(OpNo).getImmedValue();
assert((value >= 0 && value < 16)
&& "Invalid negated immediate rotate 7-bit argument");
O << -value;
} else {
assert(0 && "Invalid/non-immediate rotate amount in printRotateNeg7Imm");
}
}
void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo) {
if (MI->getOperand(OpNo).isImmediate()) {
int value = (int) MI->getOperand(OpNo).getImmedValue();
assert((value >= 0 && value < 32)
&& "Invalid negated immediate rotate 7-bit argument");
O << -value;
} else {
assert(0 && "Invalid/non-immediate rotate amount in printRotateNeg7Imm");
}
}
virtual bool runOnMachineFunction(MachineFunction &F) = 0;
virtual bool doFinalization(Module &M) = 0;
};
/// LinuxAsmPrinter - SPU assembly printer, customized for Linux
struct VISIBILITY_HIDDEN LinuxAsmPrinter : public SPUAsmPrinter {
DwarfWriter DW;
LinuxAsmPrinter(std::ostream &O, SPUTargetMachine &TM,
const TargetAsmInfo *T) :
SPUAsmPrinter(O, TM, T),
DW(O, this, T)
{ }
virtual const char *getPassName() const {
return "STI CBEA SPU Assembly Printer";
}
bool runOnMachineFunction(MachineFunction &F);
bool doInitialization(Module &M);
bool doFinalization(Module &M);
void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<MachineModuleInfo>();
SPUAsmPrinter::getAnalysisUsage(AU);
}
/// getSectionForFunction - Return the section that we should emit the
/// specified function body into.
virtual std::string getSectionForFunction(const Function &F) const;
};
} // end of anonymous namespace
// Include the auto-generated portion of the assembly writer
#include "SPUGenAsmWriter.inc"
void SPUAsmPrinter::printOp(const MachineOperand &MO) {
switch (MO.getType()) {
case MachineOperand::MO_Immediate:
cerr << "printOp() does not handle immediate values\n";
abort();
return;
case MachineOperand::MO_MachineBasicBlock:
printBasicBlockLabel(MO.getMachineBasicBlock());
return;
case MachineOperand::MO_JumpTableIndex:
O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
<< '_' << MO.getJumpTableIndex();
// FIXME: PIC relocation model
return;
case MachineOperand::MO_ConstantPoolIndex:
O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
<< '_' << MO.getConstantPoolIndex();
return;
case MachineOperand::MO_ExternalSymbol:
// Computing the address of an external symbol, not calling it.
if (TM.getRelocationModel() != Reloc::Static) {
std::string Name(TAI->getGlobalPrefix()); Name += MO.getSymbolName();
GVStubs.insert(Name);
O << "L" << Name << "$non_lazy_ptr";
return;
}
O << TAI->getGlobalPrefix() << MO.getSymbolName();
return;
case MachineOperand::MO_GlobalAddress: {
// Computing the address of a global symbol, not calling it.
GlobalValue *GV = MO.getGlobal();
std::string Name = Mang->getValueName(GV);
// External or weakly linked global variables need non-lazily-resolved
// stubs
if (TM.getRelocationModel() != Reloc::Static) {
if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
GV->hasLinkOnceLinkage()))) {
GVStubs.insert(Name);
O << "L" << Name << "$non_lazy_ptr";
return;
}
}
O << Name;
if (GV->hasExternalWeakLinkage())
ExtWeakSymbols.insert(GV);
return;
}
default:
O << "<unknown operand type: " << MO.getType() << ">";
return;
}
}
/// PrintAsmOperand - Print out an operand for an inline asm expression.
///
bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode) {
// Does this asm operand have a single letter operand modifier?
if (ExtraCode && ExtraCode[0]) {
if (ExtraCode[1] != 0) return true; // Unknown modifier.
switch (ExtraCode[0]) {
default: return true; // Unknown modifier.
case 'L': // Write second word of DImode reference.
// Verify that this operand has two consecutive registers.
if (!MI->getOperand(OpNo).isRegister() ||
OpNo+1 == MI->getNumOperands() ||
!MI->getOperand(OpNo+1).isRegister())
return true;
++OpNo; // Return the high-part.
break;
}
}
printOperand(MI, OpNo);
return false;
}
bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode) {
if (ExtraCode && ExtraCode[0])
return true; // Unknown modifier.
printMemRegReg(MI, OpNo);
return false;
}
/// printMachineInstruction -- Print out a single PowerPC MI in Darwin syntax
/// to the current output stream.
///
void SPUAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
++EmittedInsts;
printInstruction(MI);
}
std::string LinuxAsmPrinter::getSectionForFunction(const Function &F) const {
switch (F.getLinkage()) {
default: assert(0 && "Unknown linkage type!");
case Function::ExternalLinkage:
case Function::InternalLinkage: return TAI->getTextSection();
case Function::WeakLinkage:
case Function::LinkOnceLinkage:
return ""; // Print nothing for the time being...
}
}
/// runOnMachineFunction - This uses the printMachineInstruction()
/// method to print assembly for each instruction.
///
bool
LinuxAsmPrinter::runOnMachineFunction(MachineFunction &MF)
{
DW.SetModuleInfo(&getAnalysis<MachineModuleInfo>());
SetupMachineFunction(MF);
O << "\n\n";
// Print out constants referenced by the function
EmitConstantPool(MF.getConstantPool());
// Print out labels for the function.
const Function *F = MF.getFunction();
SwitchToTextSection(getSectionForFunction(*F).c_str(), F);
EmitAlignment(3, F);
switch (F->getLinkage()) {
default: assert(0 && "Unknown linkage type!");
case Function::InternalLinkage: // Symbols default to internal.
break;
case Function::ExternalLinkage:
O << "\t.global\t" << CurrentFnName << "\n"
<< "\t.type\t" << CurrentFnName << ", @function\n";
break;
case Function::WeakLinkage:
case Function::LinkOnceLinkage:
O << "\t.global\t" << CurrentFnName << "\n";
O << "\t.weak_definition\t" << CurrentFnName << "\n";
break;
}
O << CurrentFnName << ":\n";
// Emit pre-function debug information.
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 (I != MF.begin()) {
printBasicBlockLabel(I, true);
O << '\n';
}
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
II != E; ++II) {
// Print the assembly for the instruction.
O << "\t";
printMachineInstruction(II);
}
}
O << "\t.size\t" << CurrentFnName << ",.-" << CurrentFnName << "\n";
// Print out jump tables referenced by the function.
EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
// Emit post-function debug information.
DW.EndFunction();
// We didn't modify anything.
return false;
}
bool LinuxAsmPrinter::doInitialization(Module &M) {
bool Result = AsmPrinter::doInitialization(M);
SwitchToTextSection(TAI->getTextSection());
// Emit initial debug information.
DW.BeginModule(&M);
return Result;
}
bool LinuxAsmPrinter::doFinalization(Module &M) {
const TargetData *TD = TM.getTargetData();
// Print out module-level global variables here.
for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
I != E; ++I) {
if (!I->hasInitializer()) continue; // External global require no code
// Check to see if this is a special global used by LLVM, if so, emit it.
if (EmitSpecialLLVMGlobal(I))
continue;
std::string name = Mang->getValueName(I);
Constant *C = I->getInitializer();
unsigned Size = TD->getTypeStoreSize(C->getType());
unsigned Align = TD->getPreferredAlignmentLog(I);
if (C->isNullValue() && /* FIXME: Verify correct */
(I->hasInternalLinkage() || I->hasWeakLinkage() ||
I->hasLinkOnceLinkage() ||
(I->hasExternalLinkage() && !I->hasSection()))) {
if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
if (I->hasExternalLinkage()) {
// External linkage globals -> .bss section
// FIXME: Want to set the global variable's section so that
// SwitchToDataSection emits the ".section" directive
SwitchToDataSection("\t.section\t.bss", I);
O << "\t.global\t" << name << '\n';
O << "\t.align\t" << Align << '\n';
O << "\t.type\t" << name << ", @object\n";
O << "\t.size\t" << name << ", " << Size << '\n';
O << name << ":\n";
O << "\t.zero\t" << Size;
} else if (I->hasInternalLinkage()) {
SwitchToDataSection("\t.data", I);
O << TAI->getLCOMMDirective() << name << "," << Size << "," << Align;
} else {
SwitchToDataSection("\t.data", I);
O << ".comm " << name << "," << Size;
}
O << "\t\t# '" << I->getName() << "'\n";
} else {
switch (I->getLinkage()) {
case GlobalValue::LinkOnceLinkage:
case GlobalValue::WeakLinkage:
O << "\t.global " << name << '\n'
<< "\t.weak_definition " << name << '\n';
SwitchToDataSection(".section __DATA,__datacoal_nt,coalesced", I);
break;
case GlobalValue::AppendingLinkage:
// FIXME: appending linkage variables should go into a section of
// their name or something. For now, just emit them as external.
case GlobalValue::ExternalLinkage:
// If external or appending, declare as a global symbol
O << "\t.global " << name << "\n";
// FALL THROUGH
case GlobalValue::InternalLinkage:
if (I->isConstant()) {
const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
if (TAI->getCStringSection() && CVA && CVA->isCString()) {
SwitchToDataSection(TAI->getCStringSection(), I);
break;
}
}
SwitchToDataSection("\t.data", I);
break;
default:
cerr << "Unknown linkage type!";
abort();
}
EmitAlignment(Align, I);
O << name << ":\t\t\t\t# '" << I->getName() << "'\n";
// If the initializer is a extern weak symbol, remember to emit the weak
// reference!
if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
if (GV->hasExternalWeakLinkage())
ExtWeakSymbols.insert(GV);
EmitGlobalConstant(C);
O << '\n';
}
}
// Output stubs for dynamically-linked functions
if (TM.getRelocationModel() == Reloc::PIC_) {
for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
i != e; ++i) {
SwitchToTextSection(".section __TEXT,__picsymbolstub1,symbol_stubs,"
"pure_instructions,32");
EmitAlignment(4);
O << "L" << *i << "$stub:\n";
O << "\t.indirect_symbol " << *i << "\n";
O << "\tmflr r0\n";
O << "\tbcl 20,31,L0$" << *i << "\n";
O << "L0$" << *i << ":\n";
O << "\tmflr r11\n";
O << "\taddis r11,r11,ha16(L" << *i << "$lazy_ptr-L0$" << *i << ")\n";
O << "\tmtlr r0\n";
O << "\tlwzu r12,lo16(L" << *i << "$lazy_ptr-L0$" << *i << ")(r11)\n";
O << "\tmtctr r12\n";
O << "\tbctr\n";
SwitchToDataSection(".lazy_symbol_pointer");
O << "L" << *i << "$lazy_ptr:\n";
O << "\t.indirect_symbol " << *i << "\n";
O << "\t.long dyld_stub_binding_helper\n";
}
} else {
for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end();
i != e; ++i) {
SwitchToTextSection(".section __TEXT,__symbol_stub1,symbol_stubs,"
"pure_instructions,16");
EmitAlignment(4);
O << "L" << *i << "$stub:\n";
O << "\t.indirect_symbol " << *i << "\n";
O << "\tlis r11,ha16(L" << *i << "$lazy_ptr)\n";
O << "\tlwzu r12,lo16(L" << *i << "$lazy_ptr)(r11)\n";
O << "\tmtctr r12\n";
O << "\tbctr\n";
SwitchToDataSection(".lazy_symbol_pointer");
O << "L" << *i << "$lazy_ptr:\n";
O << "\t.indirect_symbol " << *i << "\n";
O << "\t.long dyld_stub_binding_helper\n";
}
}
O << "\n";
// Output stubs for external and common global variables.
if (GVStubs.begin() != GVStubs.end()) {
SwitchToDataSection(".non_lazy_symbol_pointer");
for (std::set<std::string>::iterator I = GVStubs.begin(),
E = GVStubs.end(); I != E; ++I) {
O << "L" << *I << "$non_lazy_ptr:\n";
O << "\t.indirect_symbol " << *I << "\n";
O << "\t.long\t0\n";
}
}
// Emit initial debug information.
DW.EndModule();
// Emit ident information
O << "\t.ident\t\"(llvm 1.9+) STI CBEA Cell SPU backend\"\n";
return AsmPrinter::doFinalization(M);
}
/// createSPUCodePrinterPass - Returns a pass that prints the Cell SPU
/// assembly code for a MachineFunction to the given output stream, in a format
/// that the Linux SPU assembler can deal with.
///
FunctionPass *llvm::createSPUAsmPrinterPass(std::ostream &o,
SPUTargetMachine &tm) {
return new LinuxAsmPrinter(o, tm, tm.getTargetAsmInfo());
}

View File

@ -0,0 +1,62 @@
//===- SPUCallingConv.td - Calling Conventions for CellSPU ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by a team from the Computer Systems Research
// Department at The Aerospace Corporation.
//
// See README.txt for details.
//
//===----------------------------------------------------------------------===//
//
// This describes the calling conventions for the STI Cell SPU architecture.
//
//===----------------------------------------------------------------------===//
/// CCIfSubtarget - Match if the current subtarget has a feature F.
class CCIfSubtarget<string F, CCAction A>
: CCIf<!strconcat("State.getTarget().getSubtarget<PPCSubtarget>().", F), A>;
//===----------------------------------------------------------------------===//
// Return Value Calling Convention
//===----------------------------------------------------------------------===//
// Return-value convention for Cell SPU: Everything can be passed back via $3:
def RetCC_SPU : CallingConv<[
CCIfType<[i32], CCAssignToReg<[R3]>>,
CCIfType<[i64], CCAssignToReg<[R3]>>,
CCIfType<[f32, f64], CCAssignToReg<[R3]>>,
CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], CCAssignToReg<[R3]>>
]>;
//===----------------------------------------------------------------------===//
// CellSPU Argument Calling Conventions
// FIXME
//===----------------------------------------------------------------------===//
/*
def CC_SPU : CallingConv<[
// The first 8 integer arguments are passed in integer registers.
CCIfType<[i32], CCAssignToReg<[R3, R4, R5, R6, R7, R8, R9, R10]>>,
CCIfType<[i64], CCAssignToReg<[X3, X4, X5, X6, X7, X8, X9, X10]>>,
// SPU can pass back arguments in all
CCIfType<[f32, f64], CCIfSubtarget<"isMachoABI()",
CCAssignToReg<[F1, F2, F3, F4, F5, F6, F7, F8,F9,F10,F11,F12,F13]>>>,
// Other sub-targets pass FP values in F1-10.
CCIfType<[f32, f64], CCAssignToReg<[F1, F2, F3, F4, F5, F6, F7, F8, F9,F10]>>,
// The first 12 Vector arguments are passed in altivec registers.
CCIfType<[v16i8, v8i16, v4i32, v4f32],
CCAssignToReg<[V2, V3, V4, V5, V6, V7, V8, V9, V10,V11,V12,V13]>>
*/
/*
// Integer/FP values get stored in stack slots that are 8 bytes in size and
// 8-byte aligned if there are no more registers to hold them.
CCIfType<[i32, i64, f32, f64], CCAssignToStack<8, 8>>,
// Vectors get 16-byte stack slots that are 16-byte aligned.
CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],
CCAssignToStack<16, 16>>*/
]>;
*/

View File

@ -0,0 +1,32 @@
//===-- SPUTargetMachine.cpp - Define TargetMachine for Cell SPU ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by a team from the Computer Systems Research
// Department at The Aerospace Corporation.
//
// See README.txt for details.
//
//===----------------------------------------------------------------------===//
//
// Top-level implementation for the Cell SPU target.
//
//===----------------------------------------------------------------------===//
#include "SPU.h"
#include "SPUFrameInfo.h"
#include "SPURegisterNames.h"
using namespace llvm;
//===----------------------------------------------------------------------===//
// SPUFrameInfo:
//===----------------------------------------------------------------------===//
SPUFrameInfo::SPUFrameInfo(const TargetMachine &tm):
TargetFrameInfo(TargetFrameInfo::StackGrowsDown, 16, 0),
TM(tm)
{
LR[0].first = SPU::R0;
LR[0].second = 16;
}

View File

@ -0,0 +1,77 @@
//===-- SPUFrameInfo.h - Top-level interface for Cell SPU Target -*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by a team from the Computer Systems Research
// Department at The Aerospace Corporation.
//
// See README.txt for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains CellSPU frame information that doesn't fit anywhere else
// cleanly...
//
//===----------------------------------------------------------------------===//
#if !defined(SPUFRAMEINFO_H)
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "SPURegisterInfo.h"
namespace llvm {
class SPUFrameInfo: public TargetFrameInfo {
const TargetMachine &TM;
std::pair<unsigned, int> LR[1];
public:
SPUFrameInfo(const TargetMachine &tm);
//! Return a function's saved spill slots
/*!
For CellSPU, a function's saved spill slots is just the link register.
*/
const std::pair<unsigned, int> *
getCalleeSaveSpillSlots(unsigned &NumEntries) const;
//! Stack slot size (16 bytes)
static const int stackSlotSize() {
return 16;
}
//! Maximum frame offset representable by a signed 10-bit integer
/*!
This is the maximum frame offset that can be expressed as a 10-bit
integer, used in D-form addresses.
*/
static const int maxFrameOffset() {
return ((1 << 9) - 1) * stackSlotSize();
}
//! Minimum frame offset representable by a signed 10-bit integer
static const int minFrameOffset() {
return -(1 << 9) * stackSlotSize();
}
//! Minimum frame size (enough to spill LR + SP)
static const int minStackSize() {
return (2 * stackSlotSize());
}
//! Frame size required to spill all registers plus frame info
static const int fullSpillSize() {
return (SPURegisterInfo::getNumArgRegs() * stackSlotSize());
}
//! Number of instructions required to overcome hint-for-branch latency
/*!
HBR (hint-for-branch) instructions can be inserted when, for example,
we know that a given function is going to be called, such as printf(),
in the control flow graph. HBRs are only inserted if a sufficient number
of instructions occurs between the HBR and the target. Currently, HBRs
take 6 cycles, ergo, the magic number 6.
*/
static const int branchHintPenalty() {
return 6;
}
};
}
#define SPUFRAMEINFO_H 1
#endif

View File

@ -0,0 +1,137 @@
//===-- SPUHazardRecognizers.cpp - Cell Hazard Recognizer Impls -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by a team from the Computer Systems Research
// Department at The Aerospace Corporation.
//
// See README.txt for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements hazard recognizers for scheduling on Cell SPU
// processors.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "sched"
#include "SPUHazardRecognizers.h"
#include "SPU.h"
#include "SPUInstrInfo.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
//===----------------------------------------------------------------------===//
// Cell SPU hazard recognizer
//
// This is the pipeline hazard recognizer for the Cell SPU processor. It does
// very little right now.
//===----------------------------------------------------------------------===//
SPUHazardRecognizer::SPUHazardRecognizer(const TargetInstrInfo &tii) :
TII(tii),
EvenOdd(0)
{
}
/// Return the pipeline hazard type encountered or generated by this
/// instruction. Currently returns NoHazard.
///
/// \return NoHazard
HazardRecognizer::HazardType
SPUHazardRecognizer::getHazardType(SDNode *Node)
{
// Initial thoughts on how to do this, but this code cannot work unless the
// function's prolog and epilog code are also being scheduled so that we can
// accurately determine which pipeline is being scheduled.
#if 0
HazardRecognizer::HazardType retval = NoHazard;
bool mustBeOdd = false;
switch (Node->getOpcode()) {
case SPU::LQDv16i8:
case SPU::LQDv8i16:
case SPU::LQDv4i32:
case SPU::LQDv4f32:
case SPU::LQDv2f64:
case SPU::LQDr128:
case SPU::LQDr64:
case SPU::LQDr32:
case SPU::LQDr16:
case SPU::LQAv16i8:
case SPU::LQAv8i16:
case SPU::LQAv4i32:
case SPU::LQAv4f32:
case SPU::LQAv2f64:
case SPU::LQAr128:
case SPU::LQAr64:
case SPU::LQAr32:
case SPU::LQXv4i32:
case SPU::LQXr128:
case SPU::LQXr64:
case SPU::LQXr32:
case SPU::LQXr16:
case SPU::STQDv16i8:
case SPU::STQDv8i16:
case SPU::STQDv4i32:
case SPU::STQDv4f32:
case SPU::STQDv2f64:
case SPU::STQDr128:
case SPU::STQDr64:
case SPU::STQDr32:
case SPU::STQDr16:
case SPU::STQDr8:
case SPU::STQAv16i8:
case SPU::STQAv8i16:
case SPU::STQAv4i32:
case SPU::STQAv4f32:
case SPU::STQAv2f64:
case SPU::STQAr128:
case SPU::STQAr64:
case SPU::STQAr32:
case SPU::STQAr16:
case SPU::STQAr8:
case SPU::STQXv16i8:
case SPU::STQXv8i16:
case SPU::STQXv4i32:
case SPU::STQXv4f32:
case SPU::STQXv2f64:
case SPU::STQXr128:
case SPU::STQXr64:
case SPU::STQXr32:
case SPU::STQXr16:
case SPU::STQXr8:
case SPU::RET:
mustBeOdd = true;
break;
default:
// Assume that this instruction can be on the even pipe
break;
}
if (mustBeOdd && !EvenOdd)
retval = Hazard;
DOUT << "SPUHazardRecognizer EvenOdd " << EvenOdd << " Hazard " << retval << "\n";
EvenOdd ^= 1;
return retval;
#else
return NoHazard;
#endif
}
void SPUHazardRecognizer::EmitInstruction(SDNode *Node)
{
}
void SPUHazardRecognizer::AdvanceCycle()
{
DOUT << "SPUHazardRecognizer::AdvanceCycle\n";
}
void SPUHazardRecognizer::EmitNoop()
{
AdvanceCycle();
}

View File

@ -0,0 +1,43 @@
//===-- SPUHazardRecognizers.h - Cell SPU Hazard Recognizer -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by a team from the Computer Systems Research
// Department at The Aerospace Corporation.
//
// See README.txt for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines hazard recognizers for scheduling on the Cell SPU
// processor.
//
//===----------------------------------------------------------------------===//
#ifndef SPUHAZRECS_H
#define SPUHAZRECS_H
#include "llvm/CodeGen/ScheduleDAG.h"
#include "SPUInstrInfo.h"
namespace llvm {
/// SPUHazardRecognizer
class SPUHazardRecognizer : public HazardRecognizer
{
private:
const TargetInstrInfo &TII;
int EvenOdd;
public:
SPUHazardRecognizer(const TargetInstrInfo &TII);
virtual HazardType getHazardType(SDNode *Node);
virtual void EmitInstruction(SDNode *Node);
virtual void AdvanceCycle();
virtual void EmitNoop();
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,615 @@
//===-- SPUISelDAGToDAG.cpp - CellSPU -pattern matching inst selector -----===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by a team from the Computer Systems Research
// Department at The Aerospace Corporation.
//
// See README.txt for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a pattern matching instruction selector for the Cell SPU,
// converting from a legalized dag to a SPU-target dag.
//
//===----------------------------------------------------------------------===//
#include "SPU.h"
#include "SPUTargetMachine.h"
#include "SPUISelLowering.h"
#include "SPUHazardRecognizers.h"
#include "SPUFrameInfo.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Constants.h"
#include "llvm/GlobalValue.h"
#include "llvm/Intrinsics.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Compiler.h"
#include <iostream>
#include <queue>
#include <set>
using namespace llvm;
namespace {
//! ConstantSDNode predicate for i32 sign-extended, 10-bit immediates
bool
isI64IntS10Immediate(ConstantSDNode *CN)
{
return isS10Constant(CN->getValue());
}
//! ConstantSDNode predicate for i32 sign-extended, 10-bit immediates
bool
isI32IntS10Immediate(ConstantSDNode *CN)
{
return isS10Constant((int) CN->getValue());
}
#if 0
//! SDNode predicate for sign-extended, 10-bit immediate values
bool
isI32IntS10Immediate(SDNode *N)
{
return (N->getOpcode() == ISD::Constant
&& isI32IntS10Immediate(cast<ConstantSDNode>(N)));
}
#endif
//! ConstantSDNode predicate for i16 sign-extended, 10-bit immediate values
bool
isI16IntS10Immediate(ConstantSDNode *CN)
{
return isS10Constant((short) CN->getValue());
}
//! SDNode predicate for i16 sign-extended, 10-bit immediate values
bool
isI16IntS10Immediate(SDNode *N)
{
return (N->getOpcode() == ISD::Constant
&& isI16IntS10Immediate(cast<ConstantSDNode>(N)));
}
//! ConstantSDNode predicate for signed 16-bit values
/*!
\arg CN The constant SelectionDAG node holding the value
\arg Imm The returned 16-bit value, if returning true
This predicate tests the value in \a CN to see whether it can be
represented as a 16-bit, sign-extended quantity. Returns true if
this is the case.
*/
bool
isIntS16Immediate(ConstantSDNode *CN, short &Imm)
{
MVT::ValueType vt = CN->getValueType(0);
Imm = (short) CN->getValue();
if (vt >= MVT::i1 && vt <= MVT::i16) {
return true;
} else if (vt == MVT::i32) {
int32_t i_val = (int32_t) CN->getValue();
short s_val = (short) i_val;
return i_val == s_val;
} else {
int64_t i_val = (int64_t) CN->getValue();
short s_val = (short) i_val;
return i_val == s_val;
}
return false;
}
//! SDNode predicate for signed 16-bit values.
bool
isIntS16Immediate(SDNode *N, short &Imm)
{
return (N->getOpcode() == ISD::Constant
&& isIntS16Immediate(cast<ConstantSDNode>(N), Imm));
}
//! ConstantFPSDNode predicate for representing floats as 16-bit sign ext.
static bool
isFPS16Immediate(ConstantFPSDNode *FPN, short &Imm)
{
MVT::ValueType vt = FPN->getValueType(0);
if (vt == MVT::f32) {
const APFloat &apf = FPN->getValueAPF();
float fval = apf.convertToFloat();
int val = *((int *) &fval);
int sval = (int) ((val << 16) >> 16);
Imm = (short) val;
return val == sval;
}
return false;
}
//===------------------------------------------------------------------===//
//! MVT::ValueType to useful stuff structure:
struct valtype_map_s {
MVT::ValueType VT;
unsigned ldresult_ins; /// LDRESULT instruction (0 = undefined)
int prefslot_byte; /// Byte offset of the "preferred" slot
unsigned brcc_eq_ins; /// br_cc equal instruction
unsigned brcc_neq_ins; /// br_cc not equal instruction
};
const valtype_map_s valtype_map[] = {
{ MVT::i1, 0, 3, 0, 0 },
{ MVT::i8, 0, 3, 0, 0 },
{ MVT::i16, SPU::ORHIr16, 2, SPU::BRHZ, SPU::BRHNZ },
{ MVT::i32, SPU::ORIr32, 0, SPU::BRZ, SPU::BRNZ },
{ MVT::i64, SPU::ORIr64, 0, 0, 0 },
{ MVT::f32, SPU::ORIf32, 0, 0, 0 },
{ MVT::f64, SPU::ORIf64, 0, 0, 0 }
};
const size_t n_valtype_map = sizeof(valtype_map) / sizeof(valtype_map[0]);
const valtype_map_s *getValueTypeMapEntry(MVT::ValueType VT)
{
const valtype_map_s *retval = 0;
for (size_t i = 0; i < n_valtype_map; ++i) {
if (valtype_map[i].VT == VT) {
retval = valtype_map + i;
break;
}
}
#ifndef NDEBUG
if (retval == 0) {
cerr << "SPUISelDAGToDAG.cpp: getValueTypeMapEntry returns NULL for "
<< MVT::getValueTypeString(VT)
<< "\n";
abort();
}
#endif
return retval;
}
}
//===--------------------------------------------------------------------===//
/// SPUDAGToDAGISel - Cell SPU-specific code to select SPU machine
/// instructions for SelectionDAG operations.
///
class SPUDAGToDAGISel :
public SelectionDAGISel
{
SPUTargetMachine &TM;
SPUTargetLowering &SPUtli;
unsigned GlobalBaseReg;
public:
SPUDAGToDAGISel(SPUTargetMachine &tm) :
SelectionDAGISel(*tm.getTargetLowering()),
TM(tm),
SPUtli(*tm.getTargetLowering())
{}
virtual bool runOnFunction(Function &Fn) {
// Make sure we re-emit a set of the global base reg if necessary
GlobalBaseReg = 0;
SelectionDAGISel::runOnFunction(Fn);
return true;
}
/// getI32Imm - Return a target constant with the specified value, of type
/// i32.
inline SDOperand getI32Imm(uint32_t Imm) {
return CurDAG->getTargetConstant(Imm, MVT::i32);
}
/// getI64Imm - Return a target constant with the specified value, of type
/// i64.
inline SDOperand getI64Imm(uint64_t Imm) {
return CurDAG->getTargetConstant(Imm, MVT::i64);
}
/// getSmallIPtrImm - Return a target constant of pointer type.
inline SDOperand getSmallIPtrImm(unsigned Imm) {
return CurDAG->getTargetConstant(Imm, SPUtli.getPointerTy());
}
/// Select - Convert the specified operand from a target-independent to a
/// target-specific node if it hasn't already been changed.
SDNode *Select(SDOperand Op);
/// Return true if the address N is a RI7 format address [r+imm]
bool SelectDForm2Addr(SDOperand Op, SDOperand N, SDOperand &Disp,
SDOperand &Base);
//! Returns true if the address N is an A-form (local store) address
bool SelectAFormAddr(SDOperand Op, SDOperand N, SDOperand &Base,
SDOperand &Index);
//! D-form address predicate
bool SelectDFormAddr(SDOperand Op, SDOperand N, SDOperand &Base,
SDOperand &Index);
//! Address predicate if N can be expressed as an indexed [r+r] operation.
bool SelectXFormAddr(SDOperand Op, SDOperand N, SDOperand &Base,
SDOperand &Index);
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
/// inline asm expressions.
virtual bool SelectInlineAsmMemoryOperand(const SDOperand &Op,
char ConstraintCode,
std::vector<SDOperand> &OutOps,
SelectionDAG &DAG) {
SDOperand Op0, Op1;
switch (ConstraintCode) {
default: return true;
case 'm': // memory
if (!SelectDFormAddr(Op, Op, Op0, Op1)
&& !SelectAFormAddr(Op, Op, Op0, Op1))
SelectXFormAddr(Op, Op, Op0, Op1);
break;
case 'o': // offsetable
if (!SelectDFormAddr(Op, Op, Op0, Op1)
&& !SelectAFormAddr(Op, Op, Op0, Op1)) {
Op0 = Op;
AddToISelQueue(Op0); // r+0.
Op1 = getSmallIPtrImm(0);
}
break;
case 'v': // not offsetable
#if 1
assert(0 && "InlineAsmMemoryOperand 'v' constraint not handled.");
#else
SelectAddrIdxOnly(Op, Op, Op0, Op1);
#endif
break;
}
OutOps.push_back(Op0);
OutOps.push_back(Op1);
return false;
}
/// InstructionSelectBasicBlock - This callback is invoked by
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
virtual void InstructionSelectBasicBlock(SelectionDAG &DAG);
virtual const char *getPassName() const {
return "Cell SPU DAG->DAG Pattern Instruction Selection";
}
/// CreateTargetHazardRecognizer - Return the hazard recognizer to use for
/// this target when scheduling the DAG.
virtual HazardRecognizer *CreateTargetHazardRecognizer() {
const TargetInstrInfo *II = SPUtli.getTargetMachine().getInstrInfo();
assert(II && "No InstrInfo?");
return new SPUHazardRecognizer(*II);
}
// Include the pieces autogenerated from the target description.
#include "SPUGenDAGISel.inc"
};
/// InstructionSelectBasicBlock - This callback is invoked by
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
void
SPUDAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG)
{
DEBUG(BB->dump());
// Select target instructions for the DAG.
DAG.setRoot(SelectRoot(DAG.getRoot()));
DAG.RemoveDeadNodes();
// Emit machine code to BB.
ScheduleAndEmitDAG(DAG);
}
bool
SPUDAGToDAGISel::SelectDForm2Addr(SDOperand Op, SDOperand N, SDOperand &Disp,
SDOperand &Base) {
unsigned Opc = N.getOpcode();
unsigned VT = N.getValueType();
MVT::ValueType PtrVT = SPUtli.getPointerTy();
ConstantSDNode *CN = 0;
int Imm;
if (Opc == ISD::ADD) {
SDOperand Op0 = N.getOperand(0);
SDOperand Op1 = N.getOperand(1);
if (Op1.getOpcode() == ISD::Constant ||
Op1.getOpcode() == ISD::TargetConstant) {
CN = cast<ConstantSDNode>(Op1);
Imm = int(CN->getValue());
if (Imm <= 0xff) {
Disp = CurDAG->getTargetConstant(Imm, SPUtli.getPointerTy());
Base = Op0;
return true;
}
}
} else if (Opc == ISD::GlobalAddress
|| Opc == ISD::TargetGlobalAddress
|| Opc == ISD::Register) {
// Plain old local store address:
Disp = CurDAG->getTargetConstant(0, VT);
Base = N;
return true;
} else if (Opc == SPUISD::DFormAddr) {
// D-Form address: This is pretty straightforward, naturally...
CN = cast<ConstantSDNode>(N.getOperand(1));
assert(CN != 0 && "SelectDFormAddr/SPUISD::DForm2Addr expecting constant");
Imm = unsigned(CN->getValue());
if (Imm < 0xff) {
Disp = CurDAG->getTargetConstant(CN->getValue(), PtrVT);
Base = N.getOperand(0);
return true;
}
}
return false;
}
/*!
\arg Op The ISD instructio operand
\arg N The address to be tested
\arg Base The base address
\arg Index The base address index
*/
bool
SPUDAGToDAGISel::SelectAFormAddr(SDOperand Op, SDOperand N, SDOperand &Base,
SDOperand &Index) {
// These match the addr256k operand type:
MVT::ValueType PtrVT = SPUtli.getPointerTy();
MVT::ValueType OffsVT = MVT::i16;
switch (N.getOpcode()) {
case ISD::Constant:
case ISD::TargetConstant: {
// Loading from a constant address.
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N);
int Imm = (int)CN->getValue();
if (Imm < 0x3ffff && (Imm & 0x3) == 0) {
Base = CurDAG->getTargetConstant(Imm, PtrVT);
// Note that this operand will be ignored by the assembly printer...
Index = CurDAG->getTargetConstant(0, OffsVT);
return true;
}
}
case ISD::ConstantPool:
case ISD::TargetConstantPool: {
// The constant pool address is N. Base is a dummy that will be ignored by
// the assembly printer.
Base = N;
Index = CurDAG->getTargetConstant(0, OffsVT);
return true;
}
case ISD::GlobalAddress:
case ISD::TargetGlobalAddress: {
// The global address is N. Base is a dummy that is ignored by the
// assembly printer.
Base = N;
Index = CurDAG->getTargetConstant(0, OffsVT);
return true;
}
}
return false;
}
/*!
\arg Op The ISD instruction (ignored)
\arg N The address to be tested
\arg Base Base address register/pointer
\arg Index Base address index
Examine the input address by a base register plus a signed 10-bit
displacement, [r+I10] (D-form address).
\return true if \a N is a D-form address with \a Base and \a Index set
to non-empty SDOperand instances.
*/
bool
SPUDAGToDAGISel::SelectDFormAddr(SDOperand Op, SDOperand N, SDOperand &Base,
SDOperand &Index) {
unsigned Opc = N.getOpcode();
unsigned PtrTy = SPUtli.getPointerTy();
if (Opc == ISD::Register) {
Base = N;
Index = CurDAG->getTargetConstant(0, PtrTy);
return true;
} else if (Opc == ISD::FrameIndex) {
// Stack frame index must be less than 512 (divided by 16):
FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N);
DEBUG(cerr << "SelectDFormAddr: ISD::FrameIndex = "
<< FI->getIndex() << "\n");
if (FI->getIndex() < SPUFrameInfo::maxFrameOffset()) {
Base = CurDAG->getTargetConstant(0, PtrTy);
Index = CurDAG->getTargetFrameIndex(FI->getIndex(), PtrTy);
return true;
}
} else if (Opc == ISD::ADD) {
// Generated by getelementptr
const SDOperand Op0 = N.getOperand(0); // Frame index/base
const SDOperand Op1 = N.getOperand(1); // Offset within base
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op1);
// Not a constant?
if (CN == 0)
return false;
int32_t offset = (int32_t) CN->getSignExtended();
unsigned Opc0 = Op0.getOpcode();
if ((offset & 0xf) != 0) {
cerr << "SelectDFormAddr: unaligned offset = " << offset << "\n";
abort();
/*NOTREACHED*/
}
if (Opc0 == ISD::FrameIndex) {
FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Op0);
DEBUG(cerr << "SelectDFormAddr: ISD::ADD offset = " << offset
<< " frame index = " << FI->getIndex() << "\n");
if (FI->getIndex() < SPUFrameInfo::maxFrameOffset()) {
Base = CurDAG->getTargetConstant(offset, PtrTy);
Index = CurDAG->getTargetFrameIndex(FI->getIndex(), PtrTy);
return true;
}
} else if (offset > SPUFrameInfo::minFrameOffset()
&& offset < SPUFrameInfo::maxFrameOffset()) {
Base = CurDAG->getTargetConstant(offset, PtrTy);
if (Opc0 == ISD::GlobalAddress) {
// Convert global address to target global address
GlobalAddressSDNode *GV = dyn_cast<GlobalAddressSDNode>(Op0);
Index = CurDAG->getTargetGlobalAddress(GV->getGlobal(), PtrTy);
return true;
} else {
// Otherwise, just take operand 0
Index = Op0;
return true;
}
}
} else if (Opc == SPUISD::DFormAddr) {
// D-Form address: This is pretty straightforward, naturally...
ConstantSDNode *CN = cast<ConstantSDNode>(N.getOperand(1));
assert(CN != 0 && "SelectDFormAddr/SPUISD::DFormAddr expecting constant");
Base = CurDAG->getTargetConstant(CN->getValue(), PtrTy);
Index = N.getOperand(0);
return true;
}
return false;
}
/*!
\arg Op The ISD instruction operand
\arg N The address operand
\arg Base The base pointer operand
\arg Index The offset/index operand
If the address \a N can be expressed as a [r + s10imm] address, returns false.
Otherwise, creates two operands, Base and Index that will become the [r+r]
address.
*/
bool
SPUDAGToDAGISel::SelectXFormAddr(SDOperand Op, SDOperand N, SDOperand &Base,
SDOperand &Index) {
if (SelectAFormAddr(Op, N, Base, Index)
|| SelectDFormAddr(Op, N, Base, Index))
return false;
unsigned Opc = N.getOpcode();
if (Opc == ISD::ADD) {
SDOperand N1 = N.getOperand(0);
SDOperand N2 = N.getOperand(1);
unsigned N1Opc = N1.getOpcode();
unsigned N2Opc = N2.getOpcode();
if ((N1Opc == SPUISD::Hi && N2Opc == SPUISD::Lo)
|| (N1Opc == SPUISD::Lo && N2Opc == SPUISD::Hi)) {
Base = N.getOperand(0);
Index = N.getOperand(1);
return true;
} else {
cerr << "SelectXFormAddr: Unhandled ADD operands:\n";
N1.Val->dump();
cerr << "\n";
N2.Val->dump();
cerr << "\n";
abort();
/*UNREACHED*/
}
} else if (N.getNumOperands() == 2) {
SDOperand N1 = N.getOperand(0);
SDOperand N2 = N.getOperand(1);
unsigned N1Opc = N1.getOpcode();
unsigned N2Opc = N2.getOpcode();
if ((N1Opc == ISD::CopyToReg || N1Opc == ISD::Register)
&& (N2Opc == ISD::CopyToReg || N2Opc == ISD::Register)) {
Base = N.getOperand(0);
Index = N.getOperand(1);
return true;
/*UNREACHED*/
} else {
cerr << "SelectXFormAddr: 2-operand unhandled operand:\n";
N.Val->dump();
cerr << "\n";
abort();
/*UNREACHED*/
}
} else {
cerr << "SelectXFormAddr: Unhandled operand type:\n";
N.Val->dump();
cerr << "\n";
abort();
/*UNREACHED*/
}
return false;
}
//! Convert the operand from a target-independent to a target-specific node
/*!
*/
SDNode *
SPUDAGToDAGISel::Select(SDOperand Op) {
SDNode *N = Op.Val;
unsigned Opc = N->getOpcode();
if (Opc >= ISD::BUILTIN_OP_END && Opc < SPUISD::FIRST_NUMBER) {
return NULL; // Already selected.
} else if (Opc == ISD::FrameIndex) {
// Selects to AIr32 FI, 0 which in turn will become AIr32 SP, imm.
int FI = cast<FrameIndexSDNode>(N)->getIndex();
SDOperand TFI = CurDAG->getTargetFrameIndex(FI, SPUtli.getPointerTy());
DEBUG(cerr << "SPUDAGToDAGISel: Replacing FrameIndex with AI32 TFI, 0\n");
return CurDAG->SelectNodeTo(N, SPU::AIr32, Op.getValueType(), TFI,
CurDAG->getTargetConstant(0, MVT::i32));
} else if (Opc == SPUISD::LDRESULT) {
// Custom select instructions for LDRESULT
unsigned VT = N->getValueType(0);
SDOperand Arg = N->getOperand(0);
SDOperand Chain = N->getOperand(1);
SDOperand Zero = CurDAG->getTargetConstant(0, VT);
SDNode *Result;
const valtype_map_s *vtm = getValueTypeMapEntry(VT);
if (vtm->ldresult_ins == 0) {
cerr << "LDRESULT for unsupported type: "
<< MVT::getValueTypeString(VT)
<< "\n";
abort();
} else
Opc = vtm->ldresult_ins;
AddToISelQueue(Arg);
AddToISelQueue(Zero);
AddToISelQueue(Chain);
Result = CurDAG->SelectNodeTo(N, Opc, VT, MVT::Other, Arg, Zero, Chain);
Chain = SDOperand(Result, 1);
return Result;
}
return SelectCode(Op);
}
/// createPPCISelDag - This pass converts a legalized DAG into a
/// SPU-specific DAG, ready for instruction scheduling.
///
FunctionPass *llvm::createSPUISelDag(SPUTargetMachine &TM) {
return new SPUDAGToDAGISel(TM);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,139 @@
//===-- SPUISelLowering.h - Cell SPU DAG Lowering Interface -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by a team from the Computer Systems Research
// Department at The Aerospace Corporation.
//
// See README.txt for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interfaces that Cell SPU uses to lower LLVM code into
// a selection DAG.
//
//===----------------------------------------------------------------------===//
#ifndef SPU_ISELLOWERING_H
#define SPU_ISELLOWERING_H
#include "llvm/Target/TargetLowering.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "SPU.h"
namespace llvm {
namespace SPUISD {
enum NodeType {
// Start the numbering where the builting ops and target ops leave off.
FIRST_NUMBER = ISD::BUILTIN_OP_END+SPU::INSTRUCTION_LIST_END,
// Pseudo instructions:
RET_FLAG, ///< Return with flag, matched by bi instruction
Hi, ///< High address component (upper 16)
Lo, ///< Low address component (lower 16)
PCRelAddr, ///< Program counter relative address
DFormAddr, ///< D-Form address "imm($r)"
XFormAddr, ///< X-Form address "$r1($r2)"
LDRESULT, ///< Load result (value, chain)
CALL, ///< CALL instruction
SHUFB, ///< Vector shuffle (permute)
INSERT_MASK, ///< Insert element shuffle mask
CNTB, ///< Count leading ones in bytes
PROMOTE_SCALAR, ///< Promote scalar->vector
EXTRACT_ELT0, ///< Extract element 0
EXTRACT_ELT0_CHAINED, ///< Extract element 0, with chain
EXTRACT_I1_ZEXT, ///< Extract element 0 as i1, zero extend
EXTRACT_I1_SEXT, ///< Extract element 0 as i1, sign extend
EXTRACT_I8_ZEXT, ///< Extract element 0 as i8, zero extend
EXTRACT_I8_SEXT, ///< Extract element 0 as i8, sign extend
MPY, ///< 16-bit Multiply (low parts of a 32-bit)
MPYU, ///< Multiply Unsigned
MPYH, ///< Multiply High
MPYHH, ///< Multiply High-High
VEC_SHL, ///< Vector shift left
VEC_SRL, ///< Vector shift right (logical)
VEC_SRA, ///< Vector shift right (arithmetic)
VEC_ROTL, ///< Vector rotate left
VEC_ROTR, ///< Vector rotate right
ROTBYTES_RIGHT_Z, ///< Vector rotate right, by bytes, zero fill
ROTBYTES_RIGHT_S, ///< Vector rotate right, by bytes, sign fill
ROTBYTES_LEFT, ///< Rotate bytes (loads -> ROTQBYI)
ROTBYTES_LEFT_CHAINED, ///< Rotate bytes (loads -> ROTQBYI), with chain
FSMBI, ///< Form Select Mask for Bytes, Immediate
SELB, ///< Select bits -> (b & mask) | (a & ~mask)
SFPConstant, ///< Single precision floating point constant
FPInterp, ///< Floating point interpolate
FPRecipEst, ///< Floating point reciprocal estimate
SEXT32TO64, ///< Sign-extended 32-bit const -> 64-bits
LAST_SPUISD ///< Last user-defined instruction
};
}
/// Predicates that are used for node matching:
namespace SPU {
SDOperand get_vec_u18imm(SDNode *N, SelectionDAG &DAG,
MVT::ValueType ValueType);
SDOperand get_vec_i16imm(SDNode *N, SelectionDAG &DAG,
MVT::ValueType ValueType);
SDOperand get_vec_i10imm(SDNode *N, SelectionDAG &DAG,
MVT::ValueType ValueType);
SDOperand get_vec_i8imm(SDNode *N, SelectionDAG &DAG,
MVT::ValueType ValueType);
SDOperand get_ILHUvec_imm(SDNode *N, SelectionDAG &DAG,
MVT::ValueType ValueType);
SDOperand get_v4i32_imm(SDNode *N, SelectionDAG &DAG);
SDOperand get_v2i64_imm(SDNode *N, SelectionDAG &DAG);
}
class SPUTargetMachine; // forward dec'l.
class SPUTargetLowering :
public TargetLowering
{
int VarArgsFrameIndex; // FrameIndex for start of varargs area.
int ReturnAddrIndex; // FrameIndex for return slot.
SPUTargetMachine &SPUTM;
public:
SPUTargetLowering(SPUTargetMachine &TM);
/// getTargetNodeName() - This method returns the name of a target specific
/// DAG node.
virtual const char *getTargetNodeName(unsigned Opcode) const;
/// LowerOperation - Provide custom lowering hooks for some operations.
///
virtual SDOperand LowerOperation(SDOperand Op, SelectionDAG &DAG);
virtual SDOperand PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const;
virtual void computeMaskedBitsForTargetNode(const SDOperand Op,
uint64_t Mask,
uint64_t &KnownZero,
uint64_t &KnownOne,
const SelectionDAG &DAG,
unsigned Depth = 0) const;
virtual MachineBasicBlock *InsertAtEndOfBasicBlock(MachineInstr *MI,
MachineBasicBlock *MBB);
ConstraintType getConstraintType(const std::string &ConstraintLetter) const;
std::pair<unsigned, const TargetRegisterClass*>
getRegForInlineAsmConstraint(const std::string &Constraint,
MVT::ValueType VT) const;
void LowerAsmOperandForConstraint(SDOperand Op, char ConstraintLetter,
std::vector<SDOperand> &Ops,
SelectionDAG &DAG);
/// isLegalAddressImmediate - Return true if the integer value can be used
/// as the offset of the target addressing mode.
virtual bool isLegalAddressImmediate(int64_t V, const Type *Ty) const;
virtual bool isLegalAddressImmediate(GlobalValue *) const;
};
}
#endif

View File

@ -0,0 +1,52 @@
//==-- SPUInstrBuilder.h - Aides for building Cell SPU insts -----*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
//===----------------------------------------------------------------------===//
//
// This file exposes functions that may be used with BuildMI from the
// MachineInstrBuilder.h file to simplify generating frame and constant pool
// references.
//
// For reference, the order of operands for memory references is:
// (Operand), Dest Reg, Base Reg, and either Reg Index or Immediate
// Displacement.
//
//===----------------------------------------------------------------------===//
#ifndef SPU_INSTRBUILDER_H
#define SPU_INSTRBUILDER_H
#include "llvm/CodeGen/MachineInstrBuilder.h"
namespace llvm {
/// addFrameReference - This function is used to add a reference to the base of
/// an abstract object on the stack frame of the current function. This
/// reference has base register as the FrameIndex offset until it is resolved.
/// This allows a constant offset to be specified as well...
///
inline const MachineInstrBuilder&
addFrameReference(const MachineInstrBuilder &MIB, int FI, int Offset = 0,
bool mem = true) {
if (mem)
return MIB.addImm(Offset).addFrameIndex(FI);
else
return MIB.addFrameIndex(FI).addImm(Offset);
}
/// addConstantPoolReference - This function is used to add a reference to the
/// base of a constant value spilled to the per-function constant pool. The
/// reference has base register ConstantPoolIndex offset which is retained until
/// either machine code emission or assembly output. This allows an optional
/// offset to be added as well.
///
inline const MachineInstrBuilder&
addConstantPoolReference(const MachineInstrBuilder &MIB, unsigned CPI,
int Offset = 0) {
return MIB.addImm(Offset).addConstantPoolIndex(CPI);
}
} // End llvm namespace
#endif

View File

@ -0,0 +1,308 @@
//==== SPUInstrFormats.td - Cell SPU Instruction Formats ---*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by The Aerospace Corporation....
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
//
// Cell SPU instruction formats. Note that these are notationally similar to
// PowerPC, like "A-Form". But the sizes of operands and fields differ.
// This was kiped from the PPC instruction formats (seemed like a good idea...)
class I<dag OOL, dag IOL, string asmstr, InstrItinClass itin>
: Instruction {
field bits<32> Inst;
let Name = "";
let Namespace = "SPU";
let OutOperandList = OOL;
let InOperandList = IOL;
let AsmString = asmstr;
let Itinerary = itin;
}
// RR Format
class RRForm<bits<11> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: I<OOL, IOL, asmstr, itin> {
bits<7> RA;
bits<7> RB;
bits<7> RT;
let Pattern = pattern;
let Inst{0-10} = opcode;
let Inst{11-17} = RB;
let Inst{18-24} = RA;
let Inst{25-31} = RT;
}
let RB = 0 in {
// RR Format, where RB is zeroed (dont care):
class RRForm_1<bits<11> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: RRForm<opcode, OOL, IOL, asmstr, itin, pattern>
{ }
let RA = 0 in {
// RR Format, where RA and RB are zeroed (dont care):
// Used for reads from status control registers (see FPSCRRr32)
class RRForm_2<bits<11> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: RRForm<opcode, OOL, IOL, asmstr, itin, pattern>
{ }
}
}
let RT = 0 in {
// RR Format, where RT is zeroed (don't care), or as the instruction handbook
// says, "RT is a false target." Used in "Halt if" instructions
class RRForm_3<bits<11> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: RRForm<opcode, OOL, IOL, asmstr, itin, pattern>
{ }
}
// RRR Format
class RRRForm<bits<4> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: I<OOL, IOL, asmstr, itin>
{
bits<7> RA;
bits<7> RB;
bits<7> RC;
bits<7> RT;
let Pattern = pattern;
let Inst{0-3} = opcode;
let Inst{4-10} = RT;
let Inst{11-17} = RB;
let Inst{18-24} = RA;
let Inst{25-31} = RC;
}
// RI7 Format
class RI7Form<bits<11> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: I<OOL, IOL, asmstr, itin>
{
bits<7> i7;
bits<7> RA;
bits<7> RT;
let Pattern = pattern;
let Inst{0-10} = opcode;
let Inst{11-17} = i7;
let Inst{18-24} = RA;
let Inst{25-31} = RT;
}
// CVTIntFp Format
class CVTIntFPForm<bits<10> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: I<OOL, IOL, asmstr, itin>
{
bits<7> RA;
bits<7> RT;
let Pattern = pattern;
let Inst{0-9} = opcode;
let Inst{10-17} = 0;
let Inst{18-24} = RA;
let Inst{25-31} = RT;
}
let RA = 0 in {
class BICondForm<bits<11> opcode, string asmstr, list<dag> pattern>
: RRForm<opcode, (outs), (ins R32C:$rA, R32C:$func), asmstr,
BranchResolv, pattern>
{ }
let RT = 0 in {
// Branch instruction format (without D/E flag settings)
class BRForm<bits<11> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: RRForm<opcode, OOL, IOL, asmstr, itin, pattern>
{ }
class BIForm<bits<11> opcode, string asmstr, list<dag> pattern>
: RRForm<opcode, (outs), (ins R32C:$func), asmstr, BranchResolv,
pattern>
{ }
let RB = 0 in {
// Return instruction (bi, branch indirect), RA is zero (LR):
class RETForm<string asmstr, list<dag> pattern>
: BRForm<0b00010101100, (outs), (ins), asmstr, BranchResolv,
pattern>
{ }
}
}
}
// Branch indirect external data forms:
class BISLEDForm<bits<2> DE_flag, string asmstr, list<dag> pattern>
: I<(outs), (ins indcalltarget:$func), asmstr, BranchResolv>
{
bits<7> Rcalldest;
let Pattern = pattern;
let Inst{0-10} = 0b11010101100;
let Inst{11} = 0;
let Inst{12-13} = DE_flag;
let Inst{14-17} = 0b0000;
let Inst{18-24} = Rcalldest;
let Inst{25-31} = 0b0000000;
}
// RI10 Format
class RI10Form<bits<8> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: I<OOL, IOL, asmstr, itin>
{
bits<10> i10;
bits<7> RA;
bits<7> RT;
let Pattern = pattern;
let Inst{0-7} = opcode;
let Inst{8-17} = i10;
let Inst{18-24} = RA;
let Inst{25-31} = RT;
}
// RI10 Format, where the constant is zero (or effectively ignored by the
// SPU)
class RI10Form_1<bits<8> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: I<OOL, IOL, asmstr, itin>
{
bits<7> RA;
bits<7> RT;
let Pattern = pattern;
let Inst{0-7} = opcode;
let Inst{8-17} = 0;
let Inst{18-24} = RA;
let Inst{25-31} = RT;
}
// RI10 Format, where RT is ignored.
// This format is used primarily by the Halt If ... Immediate set of
// instructions
class RI10Form_2<bits<8> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: I<OOL, IOL, asmstr, itin>
{
bits<10> i10;
bits<7> RA;
let Pattern = pattern;
let Inst{0-7} = opcode;
let Inst{8-17} = i10;
let Inst{18-24} = RA;
let Inst{25-31} = 0;
}
// RI16 Format
class RI16Form<bits<9> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: I<OOL, IOL, asmstr, itin>
{
bits<16> i16;
bits<7> RT;
let Pattern = pattern;
let Inst{0-8} = opcode;
let Inst{9-24} = i16;
let Inst{25-31} = RT;
}
// Specialized version of the RI16 Format for unconditional branch relative and
// branch absolute, branch and set link. Note that for branch and set link, the
// link register doesn't have to be $lr, but this is actually hard coded into
// the instruction pattern.
let RT = 0 in {
class UncondBranch<bits<9> opcode, dag OOL, dag IOL, string asmstr,
list<dag> pattern>
: RI16Form<opcode, OOL, IOL, asmstr, BranchResolv, pattern>
{ }
class BranchSetLink<bits<9> opcode, dag OOL, dag IOL, string asmstr,
list<dag> pattern>
: RI16Form<opcode, OOL, IOL, asmstr, BranchResolv, pattern>
{ }
}
// RI18 Format
class RI18Form<bits<7> opcode, dag OOL, dag IOL, string asmstr,
InstrItinClass itin, list<dag> pattern>
: I<OOL, IOL, asmstr, itin>
{
bits<18> i18;
bits<7> RT;
let Pattern = pattern;
let Inst{0-6} = opcode;
let Inst{7-24} = i18;
let Inst{25-31} = RT;
}
//===----------------------------------------------------------------------===//
// Instruction formats for intrinsics:
//===----------------------------------------------------------------------===//
// RI10 Format for v8i16 intrinsics
class RI10_Int_v8i16<bits<8> opcode, string opc, InstrItinClass itin,
Intrinsic IntID> :
RI10Form<opcode, (outs VECREG:$rT), (ins s10imm:$val, VECREG:$rA),
!strconcat(opc, " $rT, $rA, $val"), itin,
[(set (v8i16 VECREG:$rT), (IntID (v8i16 VECREG:$rA),
i16ImmSExt10:$val))] >;
class RI10_Int_v4i32<bits<8> opcode, string opc, InstrItinClass itin,
Intrinsic IntID> :
RI10Form<opcode, (outs VECREG:$rT), (ins s10imm:$val, VECREG:$rA),
!strconcat(opc, " $rT, $rA, $val"), itin,
[(set (v4i32 VECREG:$rT), (IntID (v4i32 VECREG:$rA),
i32ImmSExt10:$val))] >;
// RR Format for v8i16 intrinsics
class RR_Int_v8i16<bits<11> opcode, string opc, InstrItinClass itin,
Intrinsic IntID> :
RRForm<opcode, (outs VECREG:$rT), (ins VECREG:$rA, VECREG:$rB),
!strconcat(opc, " $rT, $rA, $rB"), itin,
[(set (v8i16 VECREG:$rT), (IntID (v8i16 VECREG:$rA),
(v8i16 VECREG:$rB)))] >;
// RR Format for v4i32 intrinsics
class RR_Int_v4i32<bits<11> opcode, string opc, InstrItinClass itin,
Intrinsic IntID> :
RRForm<opcode, (outs VECREG:$rT), (ins VECREG:$rA, VECREG:$rB),
!strconcat(opc, " $rT, $rA, $rB"), itin,
[(set (v4i32 VECREG:$rT), (IntID (v4i32 VECREG:$rA),
(v4i32 VECREG:$rB)))] >;
//===----------------------------------------------------------------------===//
// Pseudo instructions, like call frames:
//===----------------------------------------------------------------------===//
class Pseudo<dag OOL, dag IOL, string asmstr, list<dag> pattern>
: I<OOL, IOL, asmstr, NoItinerary> {
let Pattern = pattern;
let Inst{31-0} = 0;
}