aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target/CellSPU
diff options
context:
space:
mode:
authorScott Michel <scottm@aero.org>2007-12-04 22:23:35 +0000
committerScott Michel <scottm@aero.org>2007-12-04 22:23:35 +0000
commit266bc8f7774b153401e54ed537db299159840981 (patch)
treede355be7f16914c2c6f21f597b71bc6cf9dceb78 /lib/Target/CellSPU
parent35a3e4abb96a6947ec66254b72e788bacc3aadd6 (diff)
downloadexternal_llvm-266bc8f7774b153401e54ed537db299159840981.zip
external_llvm-266bc8f7774b153401e54ed537db299159840981.tar.gz
external_llvm-266bc8f7774b153401e54ed537db299159840981.tar.bz2
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
Diffstat (limited to 'lib/Target/CellSPU')
-rw-r--r--lib/Target/CellSPU/SPUAsmPrinter.cpp654
-rw-r--r--lib/Target/CellSPU/SPUCallingConv.td62
-rw-r--r--lib/Target/CellSPU/SPUFrameInfo.cpp32
-rw-r--r--lib/Target/CellSPU/SPUFrameInfo.h77
-rw-r--r--lib/Target/CellSPU/SPUHazardRecognizers.cpp137
-rw-r--r--lib/Target/CellSPU/SPUHazardRecognizers.h43
-rw-r--r--lib/Target/CellSPU/SPUISelDAGToDAG.cpp615
-rw-r--r--lib/Target/CellSPU/SPUISelLowering.cpp2673
-rw-r--r--lib/Target/CellSPU/SPUISelLowering.h139
-rw-r--r--lib/Target/CellSPU/SPUInstrBuilder.h52
-rw-r--r--lib/Target/CellSPU/SPUInstrFormats.td308
11 files changed, 4792 insertions, 0 deletions
diff --git a/lib/Target/CellSPU/SPUAsmPrinter.cpp b/lib/Target/CellSPU/SPUAsmPrinter.cpp
new file mode 100644
index 0000000..6fdb14c
--- /dev/null
+++ b/lib/Target/CellSPU/SPUAsmPrinter.cpp
@@ -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());
+}
+
diff --git a/lib/Target/CellSPU/SPUCallingConv.td b/lib/Target/CellSPU/SPUCallingConv.td
new file mode 100644
index 0000000..cc1a9d6
--- /dev/null
+++ b/lib/Target/CellSPU/SPUCallingConv.td
@@ -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>>*/
+]>;
+ */
diff --git a/lib/Target/CellSPU/SPUFrameInfo.cpp b/lib/Target/CellSPU/SPUFrameInfo.cpp
new file mode 100644
index 0000000..c110db9
--- /dev/null
+++ b/lib/Target/CellSPU/SPUFrameInfo.cpp
@@ -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;
+}
diff --git a/lib/Target/CellSPU/SPUFrameInfo.h b/lib/Target/CellSPU/SPUFrameInfo.h
new file mode 100644
index 0000000..2fe7b35
--- /dev/null
+++ b/lib/Target/CellSPU/SPUFrameInfo.h
@@ -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
diff --git a/lib/Target/CellSPU/SPUHazardRecognizers.cpp b/lib/Target/CellSPU/SPUHazardRecognizers.cpp
new file mode 100644
index 0000000..e4787eb
--- /dev/null
+++ b/lib/Target/CellSPU/SPUHazardRecognizers.cpp
@@ -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();
+}
diff --git a/lib/Target/CellSPU/SPUHazardRecognizers.h b/lib/Target/CellSPU/SPUHazardRecognizers.h
new file mode 100644
index 0000000..ce602fd
--- /dev/null
+++ b/lib/Target/CellSPU/SPUHazardRecognizers.h
@@ -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
+
diff --git a/lib/Target/CellSPU/SPUISelDAGToDAG.cpp b/lib/Target/CellSPU/SPUISelDAGToDAG.cpp
new file mode 100644
index 0000000..7d5c8ca
--- /dev/null
+++ b/lib/Target/CellSPU/SPUISelDAGToDAG.cpp
@@ -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);
+}
diff --git a/lib/Target/CellSPU/SPUISelLowering.cpp b/lib/Target/CellSPU/SPUISelLowering.cpp
new file mode 100644
index 0000000..91c0024
--- /dev/null
+++ b/lib/Target/CellSPU/SPUISelLowering.cpp
@@ -0,0 +1,2673 @@
+//===-- SPUISelLowering.cpp - Cell SPU DAG Lowering Implementation --------===//
+//
+// 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 the SPUTargetLowering class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SPURegisterNames.h"
+#include "SPUISelLowering.h"
+#include "SPUTargetMachine.h"
+#include "llvm/ADT/VectorExtras.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/SSARegMap.h"
+#include "llvm/Constants.h"
+#include "llvm/Function.h"
+#include "llvm/Intrinsics.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Target/TargetOptions.h"
+
+#include <map>
+
+using namespace llvm;
+
+// Used in getTargetNodeName() below
+namespace {
+ std::map<unsigned, const char *> node_names;
+
+ //! MVT::ValueType mapping to useful data for Cell SPU
+ struct valtype_map_s {
+ const MVT::ValueType valtype;
+ const int prefslot_byte;
+ };
+
+ const valtype_map_s valtype_map[] = {
+ { MVT::i1, 3 },
+ { MVT::i8, 3 },
+ { MVT::i16, 2 },
+ { MVT::i32, 0 },
+ { MVT::f32, 0 },
+ { MVT::i64, 0 },
+ { MVT::f64, 0 },
+ { MVT::i128, 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].valtype == VT) {
+ retval = valtype_map + i;
+ break;
+ }
+ }
+
+#ifndef NDEBUG
+ if (retval == 0) {
+ cerr << "getValueTypeMapEntry returns NULL for "
+ << MVT::getValueTypeString(VT)
+ << "\n";
+ abort();
+ }
+#endif
+
+ return retval;
+ }
+
+ //! Predicate that returns true if operand is a memory target
+ /*!
+ \arg Op Operand to test
+ \return true if the operand is a memory target (i.e., global
+ address, external symbol, constant pool) or an existing D-Form
+ address.
+ */
+ bool isMemoryOperand(const SDOperand &Op)
+ {
+ const unsigned Opc = Op.getOpcode();
+ return (Opc == ISD::GlobalAddress
+ || Opc == ISD::GlobalTLSAddress
+ || Opc == ISD::FrameIndex
+ || Opc == ISD::JumpTable
+ || Opc == ISD::ConstantPool
+ || Opc == ISD::ExternalSymbol
+ || Opc == ISD::TargetGlobalAddress
+ || Opc == ISD::TargetGlobalTLSAddress
+ || Opc == ISD::TargetFrameIndex
+ || Opc == ISD::TargetJumpTable
+ || Opc == ISD::TargetConstantPool
+ || Opc == ISD::TargetExternalSymbol
+ || Opc == SPUISD::DFormAddr);
+ }
+}
+
+SPUTargetLowering::SPUTargetLowering(SPUTargetMachine &TM)
+ : TargetLowering(TM),
+ SPUTM(TM)
+{
+ // Fold away setcc operations if possible.
+ setPow2DivIsCheap();
+
+ // Use _setjmp/_longjmp instead of setjmp/longjmp.
+ setUseUnderscoreSetJmp(true);
+ setUseUnderscoreLongJmp(true);
+
+ // Set up the SPU's register classes:
+ // NOTE: i8 register class is not registered because we cannot determine when
+ // we need to zero or sign extend for custom-lowered loads and stores.
+ addRegisterClass(MVT::i16, SPU::R16CRegisterClass);
+ addRegisterClass(MVT::i32, SPU::R32CRegisterClass);
+ addRegisterClass(MVT::i64, SPU::R64CRegisterClass);
+ addRegisterClass(MVT::f32, SPU::R32FPRegisterClass);
+ addRegisterClass(MVT::f64, SPU::R64FPRegisterClass);
+ addRegisterClass(MVT::i128, SPU::GPRCRegisterClass);
+
+ // SPU has no sign or zero extended loads for i1, i8, i16:
+ setLoadXAction(ISD::EXTLOAD, MVT::i1, Custom);
+ setLoadXAction(ISD::SEXTLOAD, MVT::i1, Promote);
+ setLoadXAction(ISD::ZEXTLOAD, MVT::i1, Promote);
+ setStoreXAction(MVT::i1, Custom);
+
+ setLoadXAction(ISD::EXTLOAD, MVT::i8, Custom);
+ setLoadXAction(ISD::SEXTLOAD, MVT::i8, Custom);
+ setLoadXAction(ISD::ZEXTLOAD, MVT::i8, Custom);
+ setStoreXAction(MVT::i8, Custom);
+
+ setLoadXAction(ISD::EXTLOAD, MVT::i16, Custom);
+ setLoadXAction(ISD::SEXTLOAD, MVT::i16, Custom);
+ setLoadXAction(ISD::ZEXTLOAD, MVT::i16, Custom);
+
+ // SPU constant load actions are custom lowered:
+ setOperationAction(ISD::Constant, MVT::i64, Custom);
+ setOperationAction(ISD::ConstantFP, MVT::f32, Custom);
+ setOperationAction(ISD::ConstantFP, MVT::f64, Custom);
+
+ // SPU's loads and stores have to be custom lowered:
+ for (unsigned sctype = (unsigned) MVT::i1; sctype < (unsigned) MVT::f128;
+ ++sctype) {
+ setOperationAction(ISD::LOAD, sctype, Custom);
+ setOperationAction(ISD::STORE, sctype, Custom);
+ }
+
+ // SPU supports BRCOND, although DAGCombine will convert BRCONDs
+ // into BR_CCs. BR_CC instructions are custom selected in
+ // SPUDAGToDAGISel.
+ setOperationAction(ISD::BRCOND, MVT::Other, Legal);
+
+ // Expand the jumptable branches
+ setOperationAction(ISD::BR_JT, MVT::Other, Expand);
+ setOperationAction(ISD::BR_CC, MVT::Other, Expand);
+ setOperationAction(ISD::SELECT_CC, MVT::Other, Expand);
+
+ // SPU has no intrinsics for these particular operations:
+ setOperationAction(ISD::MEMMOVE, MVT::Other, Expand);
+ setOperationAction(ISD::MEMSET, MVT::Other, Expand);
+ setOperationAction(ISD::MEMCPY, MVT::Other, Expand);
+
+ // PowerPC has no SREM/UREM instructions
+ setOperationAction(ISD::SREM, MVT::i32, Expand);
+ setOperationAction(ISD::UREM, MVT::i32, Expand);
+ setOperationAction(ISD::SREM, MVT::i64, Expand);
+ setOperationAction(ISD::UREM, MVT::i64, Expand);
+
+ // We don't support sin/cos/sqrt/fmod
+ setOperationAction(ISD::FSIN , MVT::f64, Expand);
+ setOperationAction(ISD::FCOS , MVT::f64, Expand);
+ setOperationAction(ISD::FREM , MVT::f64, Expand);
+ setOperationAction(ISD::FSIN , MVT::f32, Expand);
+ setOperationAction(ISD::FCOS , MVT::f32, Expand);
+ setOperationAction(ISD::FREM , MVT::f32, Expand);
+
+ // If we're enabling GP optimizations, use hardware square root
+ setOperationAction(ISD::FSQRT, MVT::f64, Expand);
+ setOperationAction(ISD::FSQRT, MVT::f32, Expand);
+
+ setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand);
+ setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand);
+
+ // SPU can do rotate right and left, so legalize it... but customize for i8
+ // because instructions don't exist.
+ setOperationAction(ISD::ROTR, MVT::i32, Legal);
+ setOperationAction(ISD::ROTR, MVT::i16, Legal);
+ setOperationAction(ISD::ROTR, MVT::i8, Custom);
+ setOperationAction(ISD::ROTL, MVT::i32, Legal);
+ setOperationAction(ISD::ROTL, MVT::i16, Legal);
+ setOperationAction(ISD::ROTL, MVT::i8, Custom);
+ // SPU has no native version of shift left/right for i8
+ setOperationAction(ISD::SHL, MVT::i8, Custom);
+ setOperationAction(ISD::SRL, MVT::i8, Custom);
+ setOperationAction(ISD::SRA, MVT::i8, Custom);
+
+ // Custom lower i32 multiplications
+ setOperationAction(ISD::MUL, MVT::i32, Custom);
+
+ // Need to custom handle (some) common i8 math ops
+ setOperationAction(ISD::SUB, MVT::i8, Custom);
+ setOperationAction(ISD::MUL, MVT::i8, Custom);
+
+ // SPU does not have BSWAP. It does have i32 support CTLZ.
+ // CTPOP has to be custom lowered.
+ setOperationAction(ISD::BSWAP, MVT::i32, Expand);
+ setOperationAction(ISD::BSWAP, MVT::i64, Expand);
+
+ setOperationAction(ISD::CTPOP, MVT::i8, Custom);
+ setOperationAction(ISD::CTPOP, MVT::i16, Custom);
+ setOperationAction(ISD::CTPOP, MVT::i32, Custom);
+ setOperationAction(ISD::CTPOP, MVT::i64, Custom);
+
+ setOperationAction(ISD::CTTZ , MVT::i32, Expand);
+ setOperationAction(ISD::CTTZ , MVT::i64, Expand);
+
+ setOperationAction(ISD::CTLZ , MVT::i32, Legal);
+
+ // SPU does not have select or setcc
+ setOperationAction(ISD::SELECT, MVT::i1, Expand);
+ setOperationAction(ISD::SELECT, MVT::i8, Expand);
+ setOperationAction(ISD::SELECT, MVT::i16, Expand);
+ setOperationAction(ISD::SELECT, MVT::i32, Expand);
+ setOperationAction(ISD::SELECT, MVT::i64, Expand);
+ setOperationAction(ISD::SELECT, MVT::f32, Expand);
+ setOperationAction(ISD::SELECT, MVT::f64, Expand);
+
+ setOperationAction(ISD::SETCC, MVT::i1, Expand);
+ setOperationAction(ISD::SETCC, MVT::i8, Expand);
+ setOperationAction(ISD::SETCC, MVT::i16, Expand);
+ setOperationAction(ISD::SETCC, MVT::i32, Expand);
+ setOperationAction(ISD::SETCC, MVT::i64, Expand);
+ setOperationAction(ISD::SETCC, MVT::f32, Expand);
+ setOperationAction(ISD::SETCC, MVT::f64, Expand);
+
+ // SPU has a legal FP -> signed INT instruction
+ setOperationAction(ISD::FP_TO_SINT, MVT::i32, Legal);
+ setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom);
+ setOperationAction(ISD::FP_TO_UINT, MVT::i32, Legal);
+ setOperationAction(ISD::FP_TO_UINT, MVT::i64, Custom);
+
+ // FDIV on SPU requires custom lowering
+ setOperationAction(ISD::FDIV, MVT::f32, Custom);
+ //setOperationAction(ISD::FDIV, MVT::f64, Custom);
+
+ // SPU has [U|S]INT_TO_FP
+ setOperationAction(ISD::SINT_TO_FP, MVT::i32, Legal);
+ setOperationAction(ISD::SINT_TO_FP, MVT::i16, Promote);
+ setOperationAction(ISD::SINT_TO_FP, MVT::i8, Promote);
+ setOperationAction(ISD::UINT_TO_FP, MVT::i32, Legal);
+ setOperationAction(ISD::UINT_TO_FP, MVT::i16, Promote);
+ setOperationAction(ISD::UINT_TO_FP, MVT::i8, Promote);
+ setOperationAction(ISD::SINT_TO_FP, MVT::i64, Custom);
+ setOperationAction(ISD::UINT_TO_FP, MVT::i64, Custom);
+
+ setOperationAction(ISD::BIT_CONVERT, MVT::f32, Expand);
+ setOperationAction(ISD::BIT_CONVERT, MVT::i32, Expand);
+ setOperationAction(ISD::BIT_CONVERT, MVT::i64, Expand);
+ setOperationAction(ISD::BIT_CONVERT, MVT::f64, Expand);
+
+ // We cannot sextinreg(i1). Expand to shifts.
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
+
+ // Support label based line numbers.
+ setOperationAction(ISD::LOCATION, MVT::Other, Expand);
+ setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
+
+ // We want to legalize GlobalAddress and ConstantPool nodes into the
+ // appropriate instructions to materialize the address.
+ setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
+ setOperationAction(ISD::ConstantPool, MVT::i32, Custom);
+ setOperationAction(ISD::ConstantPool, MVT::f32, Custom);
+ setOperationAction(ISD::JumpTable, MVT::i32, Custom);
+ setOperationAction(ISD::GlobalAddress, MVT::i64, Custom);
+ setOperationAction(ISD::ConstantPool, MVT::i64, Custom);
+ setOperationAction(ISD::ConstantPool, MVT::f64, Custom);
+ setOperationAction(ISD::JumpTable, MVT::i64, Custom);
+
+ // RET must be custom lowered, to meet ABI requirements
+ setOperationAction(ISD::RET, MVT::Other, Custom);
+
+ // VASTART needs to be custom lowered to use the VarArgsFrameIndex
+ setOperationAction(ISD::VASTART , MVT::Other, Custom);
+
+ // Use the default implementation.
+ setOperationAction(ISD::VAARG , MVT::Other, Expand);
+ setOperationAction(ISD::VACOPY , MVT::Other, Expand);
+ setOperationAction(ISD::VAEND , MVT::Other, Expand);
+ setOperationAction(ISD::STACKSAVE , MVT::Other, Expand);
+ setOperationAction(ISD::STACKRESTORE , MVT::Other, Expand);
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32 , Expand);
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64 , Expand);
+
+ // Cell SPU has instructions for converting between i64 and fp.
+ setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom);
+ setOperationAction(ISD::SINT_TO_FP, MVT::i64, Custom);
+
+ // To take advantage of the above i64 FP_TO_SINT, promote i32 FP_TO_UINT
+ setOperationAction(ISD::FP_TO_UINT, MVT::i32, Promote);
+
+ // BUILD_PAIR can't be handled natively, and should be expanded to shl/or
+ setOperationAction(ISD::BUILD_PAIR, MVT::i64, Expand);
+
+ // First set operation action for all vector types to expand. Then we
+ // will selectively turn on ones that can be effectively codegen'd.
+ addRegisterClass(MVT::v16i8, SPU::VECREGRegisterClass);
+ addRegisterClass(MVT::v8i16, SPU::VECREGRegisterClass);
+ addRegisterClass(MVT::v4i32, SPU::VECREGRegisterClass);
+ addRegisterClass(MVT::v2i64, SPU::VECREGRegisterClass);
+ addRegisterClass(MVT::v4f32, SPU::VECREGRegisterClass);
+ addRegisterClass(MVT::v2f64, SPU::VECREGRegisterClass);
+
+ for (unsigned VT = (unsigned)MVT::FIRST_VECTOR_VALUETYPE;
+ VT <= (unsigned)MVT::LAST_VECTOR_VALUETYPE; ++VT) {
+ // add/sub are legal for all supported vector VT's.
+ setOperationAction(ISD::ADD , (MVT::ValueType)VT, Legal);
+ setOperationAction(ISD::SUB , (MVT::ValueType)VT, Legal);
+ // mul has to be custom lowered.
+ setOperationAction(ISD::MUL , (MVT::ValueType)VT, Custom);
+
+ setOperationAction(ISD::AND , (MVT::ValueType)VT, Legal);
+ setOperationAction(ISD::OR , (MVT::ValueType)VT, Legal);
+ setOperationAction(ISD::XOR , (MVT::ValueType)VT, Legal);
+ setOperationAction(ISD::LOAD , (MVT::ValueType)VT, Legal);
+ setOperationAction(ISD::SELECT, (MVT::ValueType)VT, Legal);
+ setOperationAction(ISD::STORE, (MVT::ValueType)VT, Legal);
+
+ // These operations need to be expanded:
+ setOperationAction(ISD::SDIV, (MVT::ValueType)VT, Expand);
+ setOperationAction(ISD::SREM, (MVT::ValueType)VT, Expand);
+ setOperationAction(ISD::UDIV, (MVT::ValueType)VT, Expand);
+ setOperationAction(ISD::UREM, (MVT::ValueType)VT, Expand);
+ setOperationAction(ISD::FDIV, (MVT::ValueType)VT, Custom);
+
+ // Custom lower build_vector, constant pool spills, insert and
+ // extract vector elements:
+ setOperationAction(ISD::BUILD_VECTOR, (MVT::ValueType)VT, Custom);
+ setOperationAction(ISD::ConstantPool, (MVT::ValueType)VT, Custom);
+ setOperationAction(ISD::SCALAR_TO_VECTOR, (MVT::ValueType)VT, Custom);
+ setOperationAction(ISD::EXTRACT_VECTOR_ELT, (MVT::ValueType)VT, Custom);
+ setOperationAction(ISD::INSERT_VECTOR_ELT, (MVT::ValueType)VT, Custom);
+ setOperationAction(ISD::VECTOR_SHUFFLE, (MVT::ValueType)VT, Custom);
+ }
+
+ setOperationAction(ISD::MUL, MVT::v16i8, Custom);
+ setOperationAction(ISD::AND, MVT::v16i8, Custom);
+ setOperationAction(ISD::OR, MVT::v16i8, Custom);
+ setOperationAction(ISD::XOR, MVT::v16i8, Custom);
+ setOperationAction(ISD::SCALAR_TO_VECTOR, MVT::v4f32, Custom);
+
+ setSetCCResultType(MVT::i32);
+ setShiftAmountType(MVT::i32);
+ setSetCCResultContents(ZeroOrOneSetCCResult);
+
+ setStackPointerRegisterToSaveRestore(SPU::R1);
+
+ // We have target-specific dag combine patterns for the following nodes:
+ // e.g., setTargetDAGCombine(ISD::SUB);
+
+ computeRegisterProperties();
+}
+
+const char *
+SPUTargetLowering::getTargetNodeName(unsigned Opcode) const
+{
+ if (node_names.empty()) {
+ node_names[(unsigned) SPUISD::RET_FLAG] = "SPUISD::RET_FLAG";
+ node_names[(unsigned) SPUISD::Hi] = "SPUISD::Hi";
+ node_names[(unsigned) SPUISD::Lo] = "SPUISD::Lo";
+ node_names[(unsigned) SPUISD::PCRelAddr] = "SPUISD::PCRelAddr";
+ node_names[(unsigned) SPUISD::DFormAddr] = "SPUISD::DFormAddr";
+ node_names[(unsigned) SPUISD::XFormAddr] = "SPUISD::XFormAddr";
+ node_names[(unsigned) SPUISD::LDRESULT] = "SPUISD::LDRESULT";
+ node_names[(unsigned) SPUISD::CALL] = "SPUISD::CALL";
+ node_names[(unsigned) SPUISD::SHUFB] = "SPUISD::SHUFB";
+ node_names[(unsigned) SPUISD::INSERT_MASK] = "SPUISD::INSERT_MASK";
+ node_names[(unsigned) SPUISD::CNTB] = "SPUISD::CNTB";
+ node_names[(unsigned) SPUISD::PROMOTE_SCALAR] = "SPUISD::PROMOTE_SCALAR";
+ node_names[(unsigned) SPUISD::EXTRACT_ELT0] = "SPUISD::EXTRACT_ELT0";
+ node_names[(unsigned) SPUISD::EXTRACT_ELT0_CHAINED] = "SPUISD::EXTRACT_ELT0_CHAINED";
+ node_names[(unsigned) SPUISD::EXTRACT_I1_ZEXT] = "SPUISD::EXTRACT_I1_ZEXT";
+ node_names[(unsigned) SPUISD::EXTRACT_I1_SEXT] = "SPUISD::EXTRACT_I1_SEXT";
+ node_names[(unsigned) SPUISD::EXTRACT_I8_ZEXT] = "SPUISD::EXTRACT_I8_ZEXT";
+ node_names[(unsigned) SPUISD::EXTRACT_I8_SEXT] = "SPUISD::EXTRACT_I8_SEXT";
+ node_names[(unsigned) SPUISD::MPY] = "SPUISD::MPY";
+ node_names[(unsigned) SPUISD::MPYU] = "SPUISD::MPYU";
+ node_names[(unsigned) SPUISD::MPYH] = "SPUISD::MPYH";
+ node_names[(unsigned) SPUISD::MPYHH] = "SPUISD::MPYHH";
+ node_names[(unsigned) SPUISD::VEC_SHL] = "SPUISD::VEC_SHL";
+ node_names[(unsigned) SPUISD::VEC_SRL] = "SPUISD::VEC_SRL";
+ node_names[(unsigned) SPUISD::VEC_SRA] = "SPUISD::VEC_SRA";
+ node_names[(unsigned) SPUISD::VEC_ROTL] = "SPUISD::VEC_ROTL";
+ node_names[(unsigned) SPUISD::VEC_ROTR] = "SPUISD::VEC_ROTR";
+ node_names[(unsigned) SPUISD::ROTBYTES_RIGHT_Z] =
+ "SPUISD::ROTBYTES_RIGHT_Z";
+ node_names[(unsigned) SPUISD::ROTBYTES_RIGHT_S] =
+ "SPUISD::ROTBYTES_RIGHT_S";
+ node_names[(unsigned) SPUISD::ROTBYTES_LEFT] = "SPUISD::ROTBYTES_LEFT";
+ node_names[(unsigned) SPUISD::ROTBYTES_LEFT_CHAINED] =
+ "SPUISD::ROTBYTES_LEFT_CHAINED";
+ node_names[(unsigned) SPUISD::FSMBI] = "SPUISD::FSMBI";
+ node_names[(unsigned) SPUISD::SELB] = "SPUISD::SELB";
+ node_names[(unsigned) SPUISD::SFPConstant] = "SPUISD::SFPConstant";
+ node_names[(unsigned) SPUISD::FPInterp] = "SPUISD::FPInterp";
+ node_names[(unsigned) SPUISD::FPRecipEst] = "SPUISD::FPRecipEst";
+ node_names[(unsigned) SPUISD::SEXT32TO64] = "SPUISD::SEXT32TO64";
+ }
+
+ std::map<unsigned, const char *>::iterator i = node_names.find(Opcode);
+
+ return ((i != node_names.end()) ? i->second : 0);
+}
+
+//===----------------------------------------------------------------------===//
+// Calling convention code:
+//===----------------------------------------------------------------------===//
+
+#include "SPUGenCallingConv.inc"
+
+//===----------------------------------------------------------------------===//
+// LowerOperation implementation
+//===----------------------------------------------------------------------===//
+
+/// Custom lower loads for CellSPU
+/*!
+ All CellSPU loads and stores are aligned to 16-byte boundaries, so for elements
+ within a 16-byte block, we have to rotate to extract the requested element.
+ */
+static SDOperand
+LowerLOAD(SDOperand Op, SelectionDAG &DAG, const SPUSubtarget *ST) {
+ LoadSDNode *LN = cast<LoadSDNode>(Op);
+ SDOperand basep = LN->getBasePtr();
+ SDOperand the_chain = LN->getChain();
+ MVT::ValueType VT = LN->getLoadedVT();
+ MVT::ValueType OpVT = Op.Val->getValueType(0);
+ MVT::ValueType PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
+ ISD::LoadExtType ExtType = LN->getExtensionType();
+ unsigned alignment = LN->getAlignment();
+ const valtype_map_s *vtm = getValueTypeMapEntry(VT);
+ SDOperand Ops[8];
+
+ // For an extending load of an i1 variable, just call it i8 (or whatever we
+ // were passed) and make it zero-extended:
+ if (VT == MVT::i1) {
+ VT = OpVT;
+ ExtType = ISD::ZEXTLOAD;
+ }
+
+ switch (LN->getAddressingMode()) {
+ case ISD::UNINDEXED: {
+ SDOperand result;
+ SDOperand rot_op, rotamt;
+ SDOperand ptrp;
+ int c_offset;
+ int c_rotamt;
+
+ // The vector type we really want to be when we load the 16-byte chunk
+ MVT::ValueType vecVT, opVecVT;
+
+ if (VT != MVT::i1)
+ vecVT = MVT::getVectorType(VT, (128 / MVT::getSizeInBits(VT)));
+ else
+ vecVT = MVT::v16i8;
+
+ opVecVT = MVT::getVectorType(OpVT, (128 / MVT::getSizeInBits(OpVT)));
+
+ if (basep.getOpcode() == ISD::ADD) {
+ const ConstantSDNode *CN = cast<ConstantSDNode>(basep.Val->getOperand(1));
+
+ assert(CN != NULL
+ && "LowerLOAD: ISD::ADD operand 1 is not constant");
+
+ c_offset = (int) CN->getValue();
+ c_rotamt = (int) (c_offset & 0xf);
+
+ // Adjust the rotation amount to ensure that the final result ends up in
+ // the preferred slot:
+ c_rotamt -= vtm->prefslot_byte;
+ ptrp = basep.getOperand(0);
+ } else {
+ c_offset = 0;
+ c_rotamt = -vtm->prefslot_byte;
+ ptrp = basep;
+ }
+
+ if (alignment == 16) {
+ // 16-byte aligned load into preferred slot, no rotation
+ if (c_rotamt == 0) {
+ if (isMemoryOperand(ptrp))
+ // Return unchanged
+ return SDOperand();
+ else {
+ // Return modified D-Form address for pointer:
+ ptrp = DAG.getNode(SPUISD::DFormAddr, PtrVT,
+ ptrp, DAG.getConstant((c_offset & ~0xf), PtrVT));
+ if (VT == OpVT)
+ return DAG.getLoad(VT, LN->getChain(), ptrp,
+ LN->getSrcValue(), LN->getSrcValueOffset(),
+ LN->isVolatile(), 16);
+ else
+ return DAG.getExtLoad(ExtType, VT, LN->getChain(), ptrp, LN->getSrcValue(),
+ LN->getSrcValueOffset(), OpVT,
+ LN->isVolatile(), 16);
+ }
+ } else {
+ // Need to rotate...
+ if (c_rotamt < 0)
+ c_rotamt += 16;
+ // Realign the base pointer, with a D-Form address
+ if ((c_offset & ~0xf) != 0 || !isMemoryOperand(ptrp))
+ basep = DAG.getNode(SPUISD::DFormAddr, PtrVT,
+ ptrp, DAG.getConstant((c_offset & ~0xf), MVT::i32));
+ else
+ basep = ptrp;
+
+ // Rotate the load:
+ rot_op = DAG.getLoad(MVT::v16i8, the_chain, basep,
+ LN->getSrcValue(), LN->getSrcValueOffset(),
+ LN->isVolatile(), 16);
+ the_chain = rot_op.getValue(1);
+ rotamt = DAG.getConstant(c_rotamt, MVT::i16);
+
+ SDVTList vecvts = DAG.getVTList(MVT::v16i8, MVT::Other);
+ Ops[0] = the_chain;
+ Ops[1] = rot_op;
+ Ops[2] = rotamt;
+
+ result = DAG.getNode(SPUISD::ROTBYTES_LEFT_CHAINED, vecvts, Ops, 3);
+ the_chain = result.getValue(1);
+
+ if (VT == OpVT || ExtType == ISD::EXTLOAD) {
+ SDVTList scalarvts;
+ Ops[0] = the_chain;
+ Ops[1] = result;
+ if (OpVT == VT) {
+ scalarvts = DAG.getVTList(VT, MVT::Other);
+ } else {
+ scalarvts = DAG.getVTList(OpVT, MVT::Other);
+ }
+
+ result = DAG.getNode(ISD::BIT_CONVERT, (OpVT == VT ? vecVT : opVecVT),
+ result);
+ Ops[0] = the_chain;
+ Ops[1] = result;
+ result = DAG.getNode(SPUISD::EXTRACT_ELT0_CHAINED, scalarvts, Ops, 2);
+ the_chain = result.getValue(1);
+ } else {
+ // Handle the sign and zero-extending loads for i1 and i8:
+ unsigned NewOpC;
+
+ if (ExtType == ISD::SEXTLOAD) {
+ NewOpC = (OpVT == MVT::i1
+ ? SPUISD::EXTRACT_I1_SEXT
+ : SPUISD::EXTRACT_I8_SEXT);
+ } else if (ExtType == ISD::ZEXTLOAD) {
+ NewOpC = (OpVT == MVT::i1
+ ? SPUISD::EXTRACT_I1_ZEXT
+ : SPUISD::EXTRACT_I8_ZEXT);
+ }
+
+ result = DAG.getNode(NewOpC, OpVT, result);
+ }
+
+ SDVTList retvts = DAG.getVTList(OpVT, MVT::Other);
+ SDOperand retops[2] = { result, the_chain };
+
+ result = DAG.getNode(SPUISD::LDRESULT, retvts, retops, 2);
+ return result;
+ /*UNREACHED*/
+ }
+ } else {
+ // Misaligned 16-byte load:
+ if (basep.getOpcode() == ISD::LOAD) {
+ LN = cast<LoadSDNode>(basep);
+ if (LN->getAlignment() == 16) {
+ // We can verify that we're really loading from a 16-byte aligned
+ // chunk. Encapsulate basep as a D-Form address and return a new
+ // load:
+ basep = DAG.getNode(SPUISD::DFormAddr, PtrVT, basep,
+ DAG.getConstant(0, PtrVT));
+ if (OpVT == VT)
+ return DAG.getLoad(VT, LN->getChain(), basep,
+ LN->getSrcValue(), LN->getSrcValueOffset(),
+ LN->isVolatile(), 16);
+ else
+ return DAG.getExtLoad(ExtType, VT, LN->getChain(), basep,
+ LN->getSrcValue(), LN->getSrcValueOffset(),
+ OpVT, LN->isVolatile(), 16);
+ }
+ }
+
+ // Catch all other cases where we can't guarantee that we have a
+ // 16-byte aligned entity, which means resorting to an X-form
+ // address scheme:
+
+ SDOperand ZeroOffs = DAG.getConstant(0, PtrVT);
+ SDOperand loOp = DAG.getNode(SPUISD::Lo, VT, basep, ZeroOffs);
+ SDOperand hiOp = DAG.getNode(SPUISD::Hi, VT, basep, ZeroOffs);
+
+ ptrp = DAG.getNode(ISD::ADD, PtrVT, loOp, hiOp);
+
+ SDOperand alignLoad =
+ DAG.getLoad(opVecVT, LN->getChain(), ptrp,
+ LN->getSrcValue(), LN->getSrcValueOffset(),
+ LN->isVolatile(), 16);
+
+ SDOperand insertEltOp =
+ DAG.getNode(SPUISD::INSERT_MASK, vecVT, ptrp);
+
+ result = DAG.getNode(SPUISD::SHUFB, opVecVT,
+ alignLoad,
+ alignLoad,
+ DAG.getNode(ISD::BIT_CONVERT, opVecVT, insertEltOp));
+
+ result = DAG.getNode(SPUISD::EXTRACT_ELT0, OpVT, result);
+
+ SDVTList retvts = DAG.getVTList(OpVT, MVT::Other);
+ SDOperand retops[2] = { result, the_chain };
+
+ result = DAG.getNode(SPUISD::LDRESULT, retvts, retops, 2);
+ return result;
+ }
+ break;
+ }
+ case ISD::PRE_INC:
+ case ISD::PRE_DEC:
+ case ISD::POST_INC:
+ case ISD::POST_DEC:
+ case ISD::LAST_INDEXED_MODE:
+ cerr << "LowerLOAD: Got a LoadSDNode with an addr mode other than "
+ "UNINDEXED\n";
+ cerr << (unsigned) LN->getAddressingMode() << "\n";
+ abort();
+ /*NOTREACHED*/
+ }
+
+ return SDOperand();
+}
+
+/// Custom lower stores for CellSPU
+/*!
+ All CellSPU stores are aligned to 16-byte boundaries, so for elements
+ within a 16-byte block, we have to generate a shuffle to insert the
+ requested element into its place, then store the resulting block.
+ */
+static SDOperand
+LowerSTORE(SDOperand Op, SelectionDAG &DAG, const SPUSubtarget *ST) {
+ StoreSDNode *SN = cast<StoreSDNode>(Op);
+ SDOperand Value = SN->getValue();
+ MVT::ValueType VT = Value.getValueType();
+ MVT::ValueType StVT = (!SN->isTruncatingStore() ? VT : SN->getStoredVT());
+ MVT::ValueType PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
+ SDOperand the_chain = SN->getChain();
+ unsigned alignment = SN->getAlignment();
+ const valtype_map_s *vtm = getValueTypeMapEntry(VT);
+
+ switch (SN->getAddressingMode()) {
+ case ISD::UNINDEXED: {
+ SDOperand basep = SN->getBasePtr();
+ SDOperand ptrOp;
+ int offset;
+
+ if (basep.getOpcode() == ISD::ADD) {
+ const ConstantSDNode *CN = cast<ConstantSDNode>(basep.Val->getOperand(1));
+ assert(CN != NULL
+ && "LowerSTORE: ISD::ADD operand 1 is not constant");
+ offset = unsigned(CN->getValue());
+ ptrOp = basep.getOperand(0);
+ DEBUG(cerr << "LowerSTORE: StoreSDNode ISD:ADD offset = "
+ << offset
+ << "\n");
+ } else {
+ ptrOp = basep;
+ offset = 0;
+ }
+
+ // The vector type we really want to load from the 16-byte chunk, except
+ // in the case of MVT::i1, which has to be v16i8.
+ unsigned vecVT, stVecVT;
+
+ if (StVT != MVT::i1)
+ stVecVT = MVT::getVectorType(StVT, (128 / MVT::getSizeInBits(StVT)));
+ else
+ stVecVT = MVT::v16i8;
+ vecVT = MVT::getVectorType(VT, (128 / MVT::getSizeInBits(VT)));
+
+ // Realign the pointer as a D-Form address (ptrOp is the pointer,
+ // to force a register load with the address; basep is the actual
+ // dform addr offs($reg).
+ ptrOp = DAG.getNode(SPUISD::DFormAddr, PtrVT, ptrOp,
+ DAG.getConstant(0, PtrVT));
+ basep = DAG.getNode(SPUISD::DFormAddr, PtrVT,
+ ptrOp, DAG.getConstant((offset & ~0xf), PtrVT));
+
+ // Create the 16-byte aligned vector load
+ SDOperand alignLoad =
+ DAG.getLoad(vecVT, the_chain, basep,
+ SN->getSrcValue(), SN->getSrcValueOffset(),
+ SN->isVolatile(), 16);
+ the_chain = alignLoad.getValue(1);
+
+ LoadSDNode *LN = cast<LoadSDNode>(alignLoad);
+ SDOperand theValue = SN->getValue();
+ SDOperand result;
+
+ if (StVT != VT
+ && (theValue.getOpcode() == ISD::AssertZext
+ || theValue.getOpcode() == ISD::AssertSext)) {
+ // Drill down and get the value for zero- and sign-extended
+ // quantities
+ theValue = theValue.getOperand(0);
+ }
+
+ SDOperand insertEltOp =
+ DAG.getNode(SPUISD::INSERT_MASK, stVecVT,
+ DAG.getNode(SPUISD::DFormAddr, PtrVT,
+ ptrOp,
+ DAG.getConstant((offset & 0xf), PtrVT)));
+
+ result = DAG.getNode(SPUISD::SHUFB, vecVT,
+ DAG.getNode(ISD::SCALAR_TO_VECTOR, vecVT, theValue),
+ alignLoad,
+ DAG.getNode(ISD::BIT_CONVERT, vecVT, insertEltOp));
+
+ result = DAG.getStore(the_chain, result, basep,
+ LN->getSrcValue(), LN->getSrcValueOffset(),
+ LN->isVolatile(), LN->getAlignment());
+
+ return result;
+ /*UNREACHED*/
+ }
+ case ISD::PRE_INC:
+ case ISD::PRE_DEC:
+ case ISD::POST_INC:
+ case ISD::POST_DEC:
+ case ISD::LAST_INDEXED_MODE:
+ cerr << "LowerLOAD: Got a LoadSDNode with an addr mode other than "
+ "UNINDEXED\n";
+ cerr << (unsigned) SN->getAddressingMode() << "\n";
+ abort();
+ /*NOTREACHED*/
+ }
+
+ return SDOperand();
+}
+
+/// Generate the address of a constant pool entry.
+static SDOperand
+LowerConstantPool(SDOperand Op, SelectionDAG &DAG, const SPUSubtarget *ST) {
+ MVT::ValueType PtrVT = Op.getValueType();
+ ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op);
+ Constant *C = CP->getConstVal();
+ SDOperand CPI = DAG.getTargetConstantPool(C, PtrVT, CP->getAlignment());
+ const TargetMachine &TM = DAG.getTarget();
+ SDOperand Zero = DAG.getConstant(0, PtrVT);
+
+ if (TM.getRelocationModel() == Reloc::Static) {
+ if (!ST->usingLargeMem()) {
+ // Just return the SDOperand with the constant pool address in it.
+ return CPI;
+ } else {
+ // Generate hi/lo address pair
+ SDOperand Hi = DAG.getNode(SPUISD::Hi, PtrVT, CPI, Zero);
+ SDOperand Lo = DAG.getNode(SPUISD::Lo, PtrVT, CPI, Zero);
+
+ return DAG.getNode(ISD::ADD, PtrVT, Lo, Hi);
+ }
+ }
+
+ assert(0 &&
+ "LowerConstantPool: Relocation model other than static not supported.");
+ return SDOperand();
+}
+
+static SDOperand
+LowerJumpTable(SDOperand Op, SelectionDAG &DAG, const SPUSubtarget *ST) {
+ MVT::ValueType PtrVT = Op.getValueType();
+ JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
+ SDOperand JTI = DAG.getTargetJumpTable(JT->getIndex(), PtrVT);
+ SDOperand Zero = DAG.getConstant(0, PtrVT);
+ const TargetMachine &TM = DAG.getTarget();
+
+ if (TM.getRelocationModel() == Reloc::Static) {
+ if (!ST->usingLargeMem()) {
+ // Just return the SDOperand with the jump table address in it.
+ return JTI;
+ } else {
+ // Generate hi/lo address pair
+ SDOperand Hi = DAG.getNode(SPUISD::Hi, PtrVT, JTI, Zero);
+ SDOperand Lo = DAG.getNode(SPUISD::Lo, PtrVT, JTI, Zero);
+
+ return DAG.getNode(ISD::ADD, PtrVT, Lo, Hi);
+ }
+ }
+
+ assert(0 &&
+ "LowerJumpTable: Relocation model other than static not supported.");
+ return SDOperand();
+}
+
+static SDOperand
+LowerGlobalAddress(SDOperand Op, SelectionDAG &DAG, const SPUSubtarget *ST) {
+ MVT::ValueType PtrVT = Op.getValueType();
+ GlobalAddressSDNode *GSDN = cast<GlobalAddressSDNode>(Op);
+ GlobalValue *GV = GSDN->getGlobal();
+ SDOperand GA = DAG.getTargetGlobalAddress(GV, PtrVT, GSDN->getOffset());
+ SDOperand Zero = DAG.getConstant(0, PtrVT);
+ const TargetMachine &TM = DAG.getTarget();
+
+ if (TM.getRelocationModel() == Reloc::Static) {
+ if (!ST->usingLargeMem()) {
+ // Generate a local store address
+ return GA;
+ } else {
+ // Generate hi/lo address pair
+ SDOperand Hi = DAG.getNode(SPUISD::Hi, PtrVT, GA, Zero);
+ SDOperand Lo = DAG.getNode(SPUISD::Lo, PtrVT, GA, Zero);
+
+ return DAG.getNode(ISD::ADD, PtrVT, Lo, Hi);
+ }
+ } else {
+ cerr << "LowerGlobalAddress: Relocation model other than static not "
+ << "supported.\n";
+ abort();
+ /*NOTREACHED*/
+ }
+
+ return SDOperand();
+}
+
+//! Custom lower i64 integer constants
+/*!
+ This code inserts all of the necessary juggling that needs to occur to load
+ a 64-bit constant into a register.
+ */
+static SDOperand
+LowerConstant(SDOperand Op, SelectionDAG &DAG) {
+ unsigned VT = Op.getValueType();
+ ConstantSDNode *CN = cast<ConstantSDNode>(Op.Val);
+
+ if (VT == MVT::i64) {
+ SDOperand T = DAG.getConstant(CN->getValue(), MVT::i64);
+ return DAG.getNode(SPUISD::EXTRACT_ELT0, VT,
+ DAG.getNode(ISD::BUILD_VECTOR, MVT::v2i64, T, T));
+
+ } else {
+ cerr << "LowerConstant: unhandled constant type "
+ << MVT::getValueTypeString(VT)
+ << "\n";
+ abort();
+ /*NOTREACHED*/
+ }
+
+ return SDOperand();
+}
+
+//! Custom lower single precision floating point constants
+/*!
+ "float" immediates can be lowered as if they were unsigned 32-bit integers.
+ The SPUISD::SFPConstant pseudo-instruction handles this in the instruction
+ target description.
+ */
+static SDOperand
+LowerConstantFP(SDOperand Op, SelectionDAG &DAG) {
+ unsigned VT = Op.getValueType();
+ ConstantFPSDNode *FP = cast<ConstantFPSDNode>(Op.Val);
+
+ assert((FP != 0) &&
+ "LowerConstantFP: Node is not ConstantFPSDNode");
+
+ const APFloat &apf = FP->getValueAPF();
+
+ if (VT == MVT::f32) {
+ return DAG.getNode(SPUISD::SFPConstant, VT,
+ DAG.getTargetConstantFP(apf.convertToFloat(), VT));
+ } else if (VT == MVT::f64) {
+ uint64_t dbits = DoubleToBits(apf.convertToDouble());
+ return DAG.getNode(ISD::BIT_CONVERT, VT,
+ LowerConstant(DAG.getConstant(dbits, MVT::i64), DAG));
+ }
+
+ return SDOperand();
+}
+
+static SDOperand
+LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG, int &VarArgsFrameIndex)
+{
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ SSARegMap *RegMap = MF.getSSARegMap();
+ SmallVector<SDOperand, 8> ArgValues;
+ SDOperand Root = Op.getOperand(0);
+ bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
+
+ const unsigned *ArgRegs = SPURegisterInfo::getArgRegs();
+ const unsigned NumArgRegs = SPURegisterInfo::getNumArgRegs();
+
+ unsigned ArgOffset = SPUFrameInfo::minStackSize();
+ unsigned ArgRegIdx = 0;
+ unsigned StackSlotSize = SPUFrameInfo::stackSlotSize();
+
+ MVT::ValueType PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
+
+ // Add DAG nodes to load the arguments or copy them out of registers.
+ for (unsigned ArgNo = 0, e = Op.Val->getNumValues()-1; ArgNo != e; ++ArgNo) {
+ SDOperand ArgVal;
+ bool needsLoad = false;
+ MVT::ValueType ObjectVT = Op.getValue(ArgNo).getValueType();
+ unsigned ObjSize = MVT::getSizeInBits(ObjectVT)/8;
+
+ switch (ObjectVT) {
+ default: {
+ cerr << "LowerFORMAL_ARGUMENTS Unhandled argument type: "
+ << MVT::getValueTypeString(ObjectVT)
+ << "\n";
+ abort();
+ }
+ case MVT::i8:
+ if (!isVarArg && ArgRegIdx < NumArgRegs) {
+ unsigned VReg = RegMap->createVirtualRegister(&SPU::R16CRegClass);
+ MF.addLiveIn(ArgRegs[ArgRegIdx], VReg);
+ ArgVal = DAG.getCopyFromReg(Root, VReg, MVT::i8);
+ ++ArgRegIdx;
+ } else {
+ needsLoad = true;
+ }
+ break;
+ case MVT::i16:
+ if (!isVarArg && ArgRegIdx < NumArgRegs) {
+ unsigned VReg = RegMap->createVirtualRegister(&SPU::R16CRegClass);
+ MF.addLiveIn(ArgRegs[ArgRegIdx], VReg);
+ ArgVal = DAG.getCopyFromReg(Root, VReg, MVT::i16);
+ ++ArgRegIdx;
+ } else {
+ needsLoad = true;
+ }
+ break;
+ case MVT::i32:
+ if (!isVarArg && ArgRegIdx < NumArgRegs) {
+ unsigned VReg = RegMap->createVirtualRegister(&SPU::R32CRegClass);
+ MF.addLiveIn(ArgRegs[ArgRegIdx], VReg);
+ ArgVal = DAG.getCopyFromReg(Root, VReg, MVT::i32);
+ ++ArgRegIdx;
+ } else {
+ needsLoad = true;
+ }
+ break;
+ case MVT::i64:
+ if (!isVarArg && ArgRegIdx < NumArgRegs) {
+ unsigned VReg = RegMap->createVirtualRegister(&SPU::R64CRegClass);
+ MF.addLiveIn(ArgRegs[ArgRegIdx], VReg);
+ ArgVal = DAG.getCopyFromReg(Root, VReg, MVT::i64);
+ ++ArgRegIdx;
+ } else {
+ needsLoad = true;
+ }
+ break;
+ case MVT::f32:
+ if (!isVarArg && ArgRegIdx < NumArgRegs) {
+ unsigned VReg = RegMap->createVirtualRegister(&SPU::R32FPRegClass);
+ MF.addLiveIn(ArgRegs[ArgRegIdx], VReg);
+ ArgVal = DAG.getCopyFromReg(Root, VReg, MVT::f32);
+ ++ArgRegIdx;
+ } else {
+ needsLoad = true;
+ }
+ break;
+ case MVT::f64:
+ if (!isVarArg && ArgRegIdx < NumArgRegs) {
+ unsigned VReg = RegMap->createVirtualRegister(&SPU::R64FPRegClass);
+ MF.addLiveIn(ArgRegs[ArgRegIdx], VReg);
+ ArgVal = DAG.getCopyFromReg(Root, VReg, MVT::f64);
+ ++ArgRegIdx;
+ } else {
+ needsLoad = true;
+ }
+ break;
+ case MVT::v2f64:
+ case MVT::v4f32:
+ case MVT::v4i32:
+ case MVT::v8i16:
+ case MVT::v16i8:
+ if (!isVarArg && ArgRegIdx < NumArgRegs) {
+ unsigned VReg = RegMap->createVirtualRegister(&SPU::VECREGRegClass);
+ MF.addLiveIn(ArgRegs[ArgRegIdx], VReg);
+ ArgVal = DAG.getCopyFromReg(Root, VReg, ObjectVT);
+ ++ArgRegIdx;
+ } else {
+ needsLoad = true;
+ }
+ break;
+ }
+
+ // We need to load the argument to a virtual register if we determined above
+ // that we ran out of physical registers of the appropriate type
+ if (needsLoad) {
+ // If the argument is actually used, emit a load from the right stack
+ // slot.
+ if (!Op.Val->hasNUsesOfValue(0, ArgNo)) {
+ int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
+ SDOperand FIN = DAG.getFrameIndex(FI, PtrVT);
+ ArgVal = DAG.getLoad(ObjectVT, Root, FIN, NULL, 0);
+ } else {
+ // Don't emit a dead load.
+ ArgVal = DAG.getNode(ISD::UNDEF, ObjectVT);
+ }
+
+ ArgOffset += StackSlotSize;
+ }
+
+ ArgValues.push_back(ArgVal);
+ }
+
+ // If the function takes variable number of arguments, make a frame index for
+ // the start of the first vararg value... for expansion of llvm.va_start.
+ if (isVarArg) {
+ VarArgsFrameIndex = MFI->CreateFixedObject(MVT::getSizeInBits(PtrVT)/8,
+ ArgOffset);
+ SDOperand FIN = DAG.getFrameIndex(VarArgsFrameIndex, PtrVT);
+ // If this function is vararg, store any remaining integer argument regs to
+ // their spots on the stack so that they may be loaded by deferencing the
+ // result of va_next.
+ SmallVector<SDOperand, 8> MemOps;
+ for (; ArgRegIdx != NumArgRegs; ++ArgRegIdx) {
+ unsigned VReg = RegMap->createVirtualRegister(&SPU::GPRCRegClass);
+ MF.addLiveIn(ArgRegs[ArgRegIdx], VReg);
+ SDOperand Val = DAG.getCopyFromReg(Root, VReg, PtrVT);
+ SDOperand Store = DAG.getStore(Val.getValue(1), Val, FIN, NULL, 0);
+ MemOps.push_back(Store);
+ // Increment the address by four for the next argument to store
+ SDOperand PtrOff = DAG.getConstant(MVT::getSizeInBits(PtrVT)/8, PtrVT);
+ FIN = DAG.getNode(ISD::ADD, PtrOff.getValueType(), FIN, PtrOff);
+ }
+ if (!MemOps.empty())
+ Root = DAG.getNode(ISD::TokenFactor, MVT::Other,&MemOps[0],MemOps.size());
+ }
+
+ ArgValues.push_back(Root);
+
+ // Return the new list of results.
+ std::vector<MVT::ValueType> RetVT(Op.Val->value_begin(),
+ Op.Val->value_end());
+ return DAG.getNode(ISD::MERGE_VALUES, RetVT, &ArgValues[0], ArgValues.size());
+}
+
+/// isLSAAddress - Return the immediate to use if the specified
+/// value is representable as a LSA address.
+static SDNode *isLSAAddress(SDOperand Op, SelectionDAG &DAG) {
+ ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op);
+ if (!C) return 0;
+
+ int Addr = C->getValue();
+ if ((Addr & 3) != 0 || // Low 2 bits are implicitly zero.
+ (Addr << 14 >> 14) != Addr)
+ return 0; // Top 14 bits have to be sext of immediate.
+
+ return DAG.getConstant((int)C->getValue() >> 2, MVT::i32).Val;
+}
+
+static
+SDOperand
+LowerCALL(SDOperand Op, SelectionDAG &DAG) {
+ SDOperand Chain = Op.getOperand(0);
+#if 0
+ bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
+ bool isTailCall = cast<ConstantSDNode>(Op.getOperand(3))->getValue() != 0;
+#endif
+ SDOperand Callee = Op.getOperand(4);
+ unsigned NumOps = (Op.getNumOperands() - 5) / 2;
+ unsigned StackSlotSize = SPUFrameInfo::stackSlotSize();
+ const unsigned *ArgRegs = SPURegisterInfo::getArgRegs();
+ const unsigned NumArgRegs = SPURegisterInfo::getNumArgRegs();
+
+ // Handy pointer type
+ MVT::ValueType PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
+
+ // Accumulate how many bytes are to be pushed on the stack, including the
+ // linkage area, and parameter passing area. According to the SPU ABI,
+ // we minimally need space for [LR] and [SP]
+ unsigned NumStackBytes = SPUFrameInfo::minStackSize();
+
+ // Set up a copy of the stack pointer for use loading and storing any
+ // arguments that may not fit in the registers available for argument
+ // passing.
+ SDOperand StackPtr = DAG.getRegister(SPU::R1, MVT::i32);
+
+ // Figure out which arguments are going to go in registers, and which in
+ // memory.
+ unsigned ArgOffset = SPUFrameInfo::minStackSize(); // Just below [LR]
+ unsigned ArgRegIdx = 0;
+
+ // Keep track of registers passing arguments
+ std::vector<std::pair<unsigned, SDOperand> > RegsToPass;
+ // And the arguments passed on the stack
+ SmallVector<SDOperand, 8> MemOpChains;
+
+ for (unsigned i = 0; i != NumOps; ++i) {
+ SDOperand Arg = Op.getOperand(5+2*i);
+
+ // PtrOff will be used to store the current argument to the stack if a
+ // register cannot be found for it.
+ SDOperand PtrOff = DAG.getConstant(ArgOffset, StackPtr.getValueType());
+ PtrOff = DAG.getNode(ISD::ADD, PtrVT, StackPtr, PtrOff);
+
+ switch (Arg.getValueType()) {
+ default: assert(0 && "Unexpected ValueType for argument!");
+ case MVT::i32:
+ case MVT::i64:
+ case MVT::i128:
+ if (ArgRegIdx != NumArgRegs) {
+ RegsToPass.push_back(std::make_pair(ArgRegs[ArgRegIdx++], Arg));
+ } else {
+ MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
+ ArgOffset += StackSlotSize;
+ }
+ break;
+ case MVT::f32:
+ case MVT::f64:
+ if (ArgRegIdx != NumArgRegs) {
+ RegsToPass.push_back(std::make_pair(ArgRegs[ArgRegIdx++], Arg));
+ } else {
+ MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
+ ArgOffset += StackSlotSize;
+ }
+ break;
+ case MVT::v4f32:
+ case MVT::v4i32:
+ case MVT::v8i16:
+ case MVT::v16i8:
+ if (ArgRegIdx != NumArgRegs) {
+ RegsToPass.push_back(std::make_pair(ArgRegs[ArgRegIdx++], Arg));
+ } else {
+ MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
+ ArgOffset += StackSlotSize;
+ }
+ break;
+ }
+ }
+
+ // Update number of stack bytes actually used, insert a call sequence start
+ NumStackBytes = (ArgOffset - SPUFrameInfo::minStackSize());
+ Chain = DAG.getCALLSEQ_START(Chain, DAG.getConstant(NumStackBytes, PtrVT));
+
+ if (!MemOpChains.empty()) {
+ // Adjust the stack pointer for the stack arguments.
+ Chain = DAG.getNode(ISD::TokenFactor, 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 the appropriate regs.
+ SDOperand InFlag;
+ for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
+ Chain = DAG.getCopyToReg(Chain, RegsToPass[i].first, RegsToPass[i].second,
+ InFlag);
+ InFlag = Chain.getValue(1);
+ }
+
+ std::vector<MVT::ValueType> NodeTys;
+ NodeTys.push_back(MVT::Other); // Returns a chain
+ NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
+
+ SmallVector<SDOperand, 8> Ops;
+ unsigned CallOpc = SPUISD::CALL;
+
+ // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
+ // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
+ // node so that legalize doesn't hack it.
+ if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ GlobalValue *GV = G->getGlobal();
+ unsigned CalleeVT = Callee.getValueType();
+
+ // Turn calls to targets that are defined (i.e., have bodies) into BRSL
+ // style calls, otherwise, external symbols are BRASL calls.
+ // NOTE:
+ // This may be an unsafe assumption for JIT and really large compilation
+ // units.
+ if (GV->isDeclaration()) {
+ Callee = DAG.getGlobalAddress(GV, CalleeVT);
+ } else {
+ Callee = DAG.getNode(SPUISD::PCRelAddr, CalleeVT,
+ DAG.getTargetGlobalAddress(GV, CalleeVT),
+ DAG.getConstant(0, PtrVT));
+ }
+ } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
+ Callee = DAG.getExternalSymbol(S->getSymbol(), Callee.getValueType());
+ else if (SDNode *Dest = isLSAAddress(Callee, DAG))
+ // If this is an absolute destination address that appears to be a legal
+ // local store address, use the munged value.
+ Callee = SDOperand(Dest, 0);
+
+ Ops.push_back(Chain);
+ Ops.push_back(Callee);
+
+ // Add argument registers to the end of the list so that they are known live
+ // into the call.
+ for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
+ Ops.push_back(DAG.getRegister(RegsToPass[i].first,
+ RegsToPass[i].second.getValueType()));
+
+ if (InFlag.Val)
+ Ops.push_back(InFlag);
+ Chain = DAG.getNode(CallOpc, NodeTys, &Ops[0], Ops.size());
+ InFlag = Chain.getValue(1);
+
+ SDOperand ResultVals[3];
+ unsigned NumResults = 0;
+ NodeTys.clear();
+
+ // If the call has results, copy the values out of the ret val registers.
+ switch (Op.Val->getValueType(0)) {
+ default: assert(0 && "Unexpected ret value!");
+ case MVT::Other: break;
+ case MVT::i32:
+ if (Op.Val->getValueType(1) == MVT::i32) {
+ Chain = DAG.getCopyFromReg(Chain, SPU::R4, MVT::i32, InFlag).getValue(1);
+ ResultVals[0] = Chain.getValue(0);
+ Chain = DAG.getCopyFromReg(Chain, SPU::R3, MVT::i32,
+ Chain.getValue(2)).getValue(1);
+ ResultVals[1] = Chain.getValue(0);
+ NumResults = 2;
+ NodeTys.push_back(MVT::i32);
+ } else {
+ Chain = DAG.getCopyFromReg(Chain, SPU::R3, MVT::i32, InFlag).getValue(1);
+ ResultVals[0] = Chain.getValue(0);
+ NumResults = 1;
+ }
+ NodeTys.push_back(MVT::i32);
+ break;
+ case MVT::i64:
+ Chain = DAG.getCopyFromReg(Chain, SPU::R3, MVT::i64, InFlag).getValue(1);
+ ResultVals[0] = Chain.getValue(0);
+ NumResults = 1;
+ NodeTys.push_back(MVT::i64);
+ break;
+ case MVT::f32:
+ case MVT::f64:
+ Chain = DAG.getCopyFromReg(Chain, SPU::R3, Op.Val->getValueType(0),
+ InFlag).getValue(1);
+ ResultVals[0] = Chain.getValue(0);
+ NumResults = 1;
+ NodeTys.push_back(Op.Val->getValueType(0));
+ break;
+ case MVT::v2f64:
+ case MVT::v4f32:
+ case MVT::v4i32:
+ case MVT::v8i16:
+ case MVT::v16i8:
+ Chain = DAG.getCopyFromReg(Chain, SPU::R3, Op.Val->getValueType(0),
+ InFlag).getValue(1);
+ ResultVals[0] = Chain.getValue(0);
+ NumResults = 1;
+ NodeTys.push_back(Op.Val->getValueType(0));
+ break;
+ }
+
+ Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
+ DAG.getConstant(NumStackBytes, PtrVT));
+ NodeTys.push_back(MVT::Other);
+
+ // If the function returns void, just return the chain.
+ if (NumResults == 0)
+ return Chain;
+
+ // Otherwise, merge everything together with a MERGE_VALUES node.
+ ResultVals[NumResults++] = Chain;
+ SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, NodeTys,
+ ResultVals, NumResults);
+ return Res.getValue(Op.ResNo);
+}
+
+static SDOperand
+LowerRET(SDOperand Op, SelectionDAG &DAG, TargetMachine &TM) {
+ SmallVector<CCValAssign, 16> RVLocs;
+ unsigned CC = DAG.getMachineFunction().getFunction()->getCallingConv();
+ bool isVarArg = DAG.getMachineFunction().getFunction()->isVarArg();
+ CCState CCInfo(CC, isVarArg, TM, RVLocs);
+ CCInfo.AnalyzeReturn(Op.Val, RetCC_SPU);
+
+ // If this is the first return lowered for this function, add the regs to the
+ // liveout set for the function.
+ if (DAG.getMachineFunction().liveout_empty()) {
+ for (unsigned i = 0; i != RVLocs.size(); ++i)
+ DAG.getMachineFunction().addLiveOut(RVLocs[i].getLocReg());
+ }
+
+ SDOperand Chain = Op.getOperand(0);
+ SDOperand Flag;
+
+ // Copy the result values into the output registers.
+ for (unsigned i = 0; i != RVLocs.size(); ++i) {
+ CCValAssign &VA = RVLocs[i];
+ assert(VA.isRegLoc() && "Can only return in registers!");
+ Chain = DAG.getCopyToReg(Chain, VA.getLocReg(), Op.getOperand(i*2+1), Flag);
+ Flag = Chain.getValue(1);
+ }
+
+ if (Flag.Val)
+ return DAG.getNode(SPUISD::RET_FLAG, MVT::Other, Chain, Flag);
+ else
+ return DAG.getNode(SPUISD::RET_FLAG, MVT::Other, Chain);
+}
+
+
+//===----------------------------------------------------------------------===//
+// Vector related lowering:
+//===----------------------------------------------------------------------===//
+
+static ConstantSDNode *
+getVecImm(SDNode *N) {
+ SDOperand OpVal(0, 0);
+
+ // Check to see if this buildvec has a single non-undef value in its elements.
+ for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) {
+ if (N->getOperand(i).getOpcode() == ISD::UNDEF) continue;
+ if (OpVal.Val == 0)
+ OpVal = N->getOperand(i);
+ else if (OpVal != N->getOperand(i))
+ return 0;
+ }
+
+ if (OpVal.Val != 0) {
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(OpVal)) {
+ return CN;
+ }
+ }
+
+ return 0; // All UNDEF: use implicit def.; not Constant node
+}
+
+/// get_vec_i18imm - Test if this vector is a vector filled with the same value
+/// and the value fits into an unsigned 18-bit constant, and if so, return the
+/// constant
+SDOperand SPU::get_vec_u18imm(SDNode *N, SelectionDAG &DAG,
+ MVT::ValueType ValueType) {
+ if (ConstantSDNode *CN = getVecImm(N)) {
+ uint64_t Value = CN->getValue();
+ if (Value <= 0x3ffff)
+ return DAG.getConstant(Value, ValueType);
+ }
+
+ return SDOperand();
+}
+
+/// get_vec_i16imm - Test if this vector is a vector filled with the same value
+/// and the value fits into a signed 16-bit constant, and if so, return the
+/// constant
+SDOperand SPU::get_vec_i16imm(SDNode *N, SelectionDAG &DAG,
+ MVT::ValueType ValueType) {
+ if (ConstantSDNode *CN = getVecImm(N)) {
+ if (ValueType == MVT::i32) {
+ int Value = (int) CN->getValue();
+ int SExtValue = ((Value & 0xffff) << 16) >> 16;
+
+ if (Value == SExtValue)
+ return DAG.getConstant(Value, ValueType);
+ } else if (ValueType == MVT::i16) {
+ short Value = (short) CN->getValue();
+ int SExtValue = ((int) Value << 16) >> 16;
+
+ if (Value == (short) SExtValue)
+ return DAG.getConstant(Value, ValueType);
+ } else if (ValueType == MVT::i64) {
+ int64_t Value = CN->getValue();
+ int64_t SExtValue = ((Value & 0xffff) << (64 - 16)) >> (64 - 16);
+
+ if (Value == SExtValue)
+ return DAG.getConstant(Value, ValueType);
+ }
+ }
+
+ return SDOperand();
+}
+
+/// get_vec_i10imm - Test if this vector is a vector filled with the same value
+/// and the value fits into a signed 10-bit constant, and if so, return the
+/// constant
+SDOperand SPU::get_vec_i10imm(SDNode *N, SelectionDAG &DAG,
+ MVT::ValueType ValueType) {
+ if (ConstantSDNode *CN = getVecImm(N)) {
+ int Value = (int) CN->getValue();
+ if ((ValueType == MVT::i32 && isS10Constant(Value))
+ || (ValueType == MVT::i16 && isS10Constant((short) Value)))
+ return DAG.getConstant(Value, ValueType);
+ }
+
+ return SDOperand();
+}
+
+/// get_vec_i8imm - Test if this vector is a vector filled with the same value
+/// and the value fits into a signed 8-bit constant, and if so, return the
+/// constant.
+///
+/// @note: The incoming vector is v16i8 because that's the only way we can load
+/// constant vectors. Thus, we test to see if the upper and lower bytes are the
+/// same value.
+SDOperand SPU::get_vec_i8imm(SDNode *N, SelectionDAG &DAG,
+ MVT::ValueType ValueType) {
+ if (ConstantSDNode *CN = getVecImm(N)) {
+ int Value = (int) CN->getValue();
+ if (ValueType == MVT::i16
+ && Value <= 0xffff /* truncated from uint64_t */
+ && ((short) Value >> 8) == ((short) Value & 0xff))
+ return DAG.getConstant(Value & 0xff, ValueType);
+ else if (ValueType == MVT::i8
+ && (Value & 0xff) == Value)
+ return DAG.getConstant(Value, ValueType);
+ }
+
+ return SDOperand();
+}
+
+/// get_ILHUvec_imm - Test if this vector is a vector filled with the same value
+/// and the value fits into a signed 16-bit constant, and if so, return the
+/// constant
+SDOperand SPU::get_ILHUvec_imm(SDNode *N, SelectionDAG &DAG,
+ MVT::ValueType ValueType) {
+ if (ConstantSDNode *CN = getVecImm(N)) {
+ uint64_t Value = CN->getValue();
+ if ((ValueType == MVT::i32
+ && ((unsigned) Value & 0xffff0000) == (unsigned) Value)
+ || (ValueType == MVT::i64 && (Value & 0xffff0000) == Value))
+ return DAG.getConstant(Value >> 16, ValueType);
+ }
+
+ return SDOperand();
+}
+
+/// get_v4i32_imm - Catch-all for general 32-bit constant vectors
+SDOperand SPU::get_v4i32_imm(SDNode *N, SelectionDAG &DAG) {
+ if (ConstantSDNode *CN = getVecImm(N)) {
+ return DAG.getConstant((unsigned) CN->getValue(), MVT::i32);
+ }
+
+ return SDOperand();
+}
+
+/// get_v4i32_imm - Catch-all for general 64-bit constant vectors
+SDOperand SPU::get_v2i64_imm(SDNode *N, SelectionDAG &DAG) {
+ if (ConstantSDNode *CN = getVecImm(N)) {
+ return DAG.getConstant((unsigned) CN->getValue(), MVT::i64);
+ }
+
+ return SDOperand();
+}
+
+// If this is a vector of constants or undefs, get the bits. A bit in
+// UndefBits is set if the corresponding element of the vector is an
+// ISD::UNDEF value. For undefs, the corresponding VectorBits values are
+// zero. Return true if this is not an array of constants, false if it is.
+//
+static bool GetConstantBuildVectorBits(SDNode *BV, uint64_t VectorBits[2],
+ uint64_t UndefBits[2]) {
+ // Start with zero'd results.
+ VectorBits[0] = VectorBits[1] = UndefBits[0] = UndefBits[1] = 0;
+
+ unsigned EltBitSize = MVT::getSizeInBits(BV->getOperand(0).getValueType());
+ for (unsigned i = 0, e = BV->getNumOperands(); i != e; ++i) {
+ SDOperand OpVal = BV->getOperand(i);
+
+ unsigned PartNo = i >= e/2; // In the upper 128 bits?
+ unsigned SlotNo = e/2 - (i & (e/2-1))-1; // Which subpiece of the uint64_t.
+
+ uint64_t EltBits = 0;
+ if (OpVal.getOpcode() == ISD::UNDEF) {
+ uint64_t EltUndefBits = ~0ULL >> (64-EltBitSize);
+ UndefBits[PartNo] |= EltUndefBits << (SlotNo*EltBitSize);
+ continue;
+ } else if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(OpVal)) {
+ EltBits = CN->getValue() & (~0ULL >> (64-EltBitSize));
+ } else if (ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(OpVal)) {
+ const APFloat &apf = CN->getValueAPF();
+ EltBits = (CN->getValueType(0) == MVT::f32
+ ? FloatToBits(apf.convertToFloat())
+ : DoubleToBits(apf.convertToDouble()));
+ } else {
+ // Nonconstant element.
+ return true;
+ }
+
+ VectorBits[PartNo] |= EltBits << (SlotNo*EltBitSize);
+ }
+
+ //printf("%llx %llx %llx %llx\n",
+ // VectorBits[0], VectorBits[1], UndefBits[0], UndefBits[1]);
+ return false;
+}
+
+/// If this is a splat (repetition) of a value across the whole vector, return
+/// the smallest size that splats it. For example, "0x01010101010101..." is a
+/// splat of 0x01, 0x0101, and 0x01010101. We return SplatBits = 0x01 and
+/// SplatSize = 1 byte.
+static bool isConstantSplat(const uint64_t Bits128[2],
+ const uint64_t Undef128[2],
+ int MinSplatBits,
+ uint64_t &SplatBits, uint64_t &SplatUndef,
+ int &SplatSize) {
+ // Don't let undefs prevent splats from matching. See if the top 64-bits are
+ // the same as the lower 64-bits, ignoring undefs.
+ uint64_t Bits64 = Bits128[0] | Bits128[1];
+ uint64_t Undef64 = Undef128[0] & Undef128[1];
+ uint32_t Bits32 = uint32_t(Bits64) | uint32_t(Bits64 >> 32);
+ uint32_t Undef32 = uint32_t(Undef64) & uint32_t(Undef64 >> 32);
+ uint16_t Bits16 = uint16_t(Bits32) | uint16_t(Bits32 >> 16);
+ uint16_t Undef16 = uint16_t(Undef32) & uint16_t(Undef32 >> 16);
+
+ if ((Bits128[0] & ~Undef128[1]) == (Bits128[1] & ~Undef128[0])) {
+ if (MinSplatBits < 64) {
+
+ // Check that the top 32-bits are the same as the lower 32-bits, ignoring
+ // undefs.
+ if ((Bits64 & (~Undef64 >> 32)) == ((Bits64 >> 32) & ~Undef64)) {
+ if (MinSplatBits < 32) {
+
+ // If the top 16-bits are different than the lower 16-bits, ignoring
+ // undefs, we have an i32 splat.
+ if ((Bits32 & (~Undef32 >> 16)) == ((Bits32 >> 16) & ~Undef32)) {
+ if (MinSplatBits < 16) {
+ // If the top 8-bits are different than the lower 8-bits, ignoring
+ // undefs, we have an i16 splat.
+ if ((Bits16 & (uint16_t(~Undef16) >> 8)) == ((Bits16 >> 8) & ~Undef16)) {
+ // Otherwise, we have an 8-bit splat.
+ SplatBits = uint8_t(Bits16) | uint8_t(Bits16 >> 8);
+ SplatUndef = uint8_t(Undef16) & uint8_t(Undef16 >> 8);
+ SplatSize = 1;
+ return true;
+ }
+ } else {
+ SplatBits = Bits16;
+ SplatUndef = Undef16;
+ SplatSize = 2;
+ return true;
+ }
+ }
+ } else {
+ SplatBits = Bits32;
+ SplatUndef = Undef32;
+ SplatSize = 4;
+ return true;
+ }
+ }
+ } else {
+ SplatBits = Bits128[0];
+ SplatUndef = Undef128[0];
+ SplatSize = 8;
+ return true;
+ }
+ }
+
+ return false; // Can't be a splat if two pieces don't match.
+}
+
+// If this is a case we can't handle, return null and let the default
+// expansion code take care of it. If we CAN select this case, and if it
+// selects to a single instruction, return Op. Otherwise, if we can codegen
+// this case more efficiently than a constant pool load, lower it to the
+// sequence of ops that should be used.
+static SDOperand LowerBUILD_VECTOR(SDOperand Op, SelectionDAG &DAG) {
+ MVT::ValueType VT = Op.getValueType();
+ // If this is a vector of constants or undefs, get the bits. A bit in
+ // UndefBits is set if the corresponding element of the vector is an
+ // ISD::UNDEF value. For undefs, the corresponding VectorBits values are
+ // zero.
+ uint64_t VectorBits[2];
+ uint64_t UndefBits[2];
+ uint64_t SplatBits, SplatUndef;
+ int SplatSize;
+ if (GetConstantBuildVectorBits(Op.Val, VectorBits, UndefBits)
+ || !isConstantSplat(VectorBits, UndefBits,
+ MVT::getSizeInBits(MVT::getVectorElementType(VT)),
+ SplatBits, SplatUndef, SplatSize))
+ return SDOperand(); // Not a constant vector, not a splat.
+
+ switch (VT) {
+ default:
+ case MVT::v4f32: {
+ uint32_t Value32 = SplatBits;
+ assert(SplatSize == 4
+ && "LowerBUILD_VECTOR: Unexpected floating point vector element.");
+ // NOTE: pretend the constant is an integer. LLVM won't load FP constants
+ SDOperand T = DAG.getConstant(Value32, MVT::i32);
+ return DAG.getNode(ISD::BIT_CONVERT, MVT::v4f32,
+ DAG.getNode(ISD::BUILD_VECTOR, MVT::v4i32, T, T, T, T));
+ break;
+ }
+ case MVT::v2f64: {
+ uint64_t f64val = SplatBits;
+ assert(SplatSize == 8
+ && "LowerBUILD_VECTOR: 64-bit float vector element: unexpected size.");
+ // NOTE: pretend the constant is an integer. LLVM won't load FP constants
+ SDOperand T = DAG.getConstant(f64val, MVT::i64);
+ return DAG.getNode(ISD::BIT_CONVERT, MVT::v2f64,
+ DAG.getNode(ISD::BUILD_VECTOR, MVT::v2i64, T, T));
+ break;
+ }
+ case MVT::v16i8: {
+ // 8-bit constants have to be expanded to 16-bits
+ unsigned short Value16 = SplatBits | (SplatBits << 8);
+ SDOperand Ops[8];
+ for (int i = 0; i < 8; ++i)
+ Ops[i] = DAG.getConstant(Value16, MVT::i16);
+ return DAG.getNode(ISD::BIT_CONVERT, VT,
+ DAG.getNode(ISD::BUILD_VECTOR, MVT::v8i16, Ops, 8));
+ }
+ case MVT::v8i16: {
+ unsigned short Value16;
+ if (SplatSize == 2)
+ Value16 = (unsigned short) (SplatBits & 0xffff);
+ else
+ Value16 = (unsigned short) (SplatBits | (SplatBits << 8));
+ SDOperand T = DAG.getConstant(Value16, MVT::getVectorElementType(VT));
+ SDOperand Ops[8];
+ for (int i = 0; i < 8; ++i) Ops[i] = T;
+ return DAG.getNode(ISD::BUILD_VECTOR, VT, Ops, 8);
+ }
+ case MVT::v4i32: {
+ unsigned int Value = SplatBits;
+ SDOperand T = DAG.getConstant(Value, MVT::getVectorElementType(VT));
+ return DAG.getNode(ISD::BUILD_VECTOR, VT, T, T, T, T);
+ }
+ case MVT::v2i64: {
+ uint64_t val = SplatBits;
+ uint32_t upper = uint32_t(val >> 32);
+ uint32_t lower = uint32_t(val);
+
+ if (val != 0) {
+ SDOperand LO32;
+ SDOperand HI32;
+ SmallVector<SDOperand, 16> ShufBytes;
+ SDOperand Result;
+ bool upper_special, lower_special;
+
+ // NOTE: This code creates common-case shuffle masks that can be easily
+ // detected as common expressions. It is not attempting to create highly
+ // specialized masks to replace any and all 0's, 0xff's and 0x80's.
+
+ // Detect if the upper or lower half is a special shuffle mask pattern:
+ upper_special = (upper == 0 || upper == 0xffffffff || upper == 0x80000000);
+ lower_special = (lower == 0 || lower == 0xffffffff || lower == 0x80000000);
+
+ // Create lower vector if not a special pattern
+ if (!lower_special) {
+ SDOperand LO32C = DAG.getConstant(lower, MVT::i32);
+ LO32 = DAG.getNode(ISD::BIT_CONVERT, VT,
+ DAG.getNode(ISD::BUILD_VECTOR, MVT::v4i32,
+ LO32C, LO32C, LO32C, LO32C));
+ }
+
+ // Create upper vector if not a special pattern
+ if (!upper_special) {
+ SDOperand HI32C = DAG.getConstant(upper, MVT::i32);
+ HI32 = DAG.getNode(ISD::BIT_CONVERT, VT,
+ DAG.getNode(ISD::BUILD_VECTOR, MVT::v4i32,
+ HI32C, HI32C, HI32C, HI32C));
+ }
+
+ // If either upper or lower are special, then the two input operands are
+ // the same (basically, one of them is a "don't care")
+ if (lower_special)
+ LO32 = HI32;
+ if (upper_special)
+ HI32 = LO32;
+ if (lower_special && upper_special) {
+ // Unhappy situation... both upper and lower are special, so punt with
+ // a target constant:
+ SDOperand Zero = DAG.getConstant(0, MVT::i32);
+ HI32 = LO32 = DAG.getNode(ISD::BUILD_VECTOR, MVT::v4i32, Zero, Zero,
+ Zero, Zero);
+ }
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ SDOperand V;
+ bool process_upper, process_lower;
+ uint64_t val;
+
+ process_upper = (upper_special && (i & 1) == 0);
+ process_lower = (lower_special && (i & 1) == 1);
+
+ if (process_upper || process_lower) {
+ if ((process_upper && upper == 0)
+ || (process_lower && lower == 0))
+ val = 0x80;
+ else if ((process_upper && upper == 0xffffffff)
+ || (process_lower && lower == 0xffffffff))
+ val = 0xc0;
+ else if ((process_upper && upper == 0x80000000)
+ || (process_lower && lower == 0x80000000))
+ val = (j == 0 ? 0xe0 : 0x80);
+ } else
+ val = i * 4 + j + ((i & 1) * 16);
+
+ ShufBytes.push_back(DAG.getConstant(val, MVT::i8));
+ }
+ }
+
+ return DAG.getNode(SPUISD::SHUFB, VT, HI32, LO32,
+ DAG.getNode(ISD::BUILD_VECTOR, MVT::v16i8,
+ &ShufBytes[0], ShufBytes.size()));
+ } else {
+ // For zero, this can be lowered efficiently via v4i32 BUILD_VECTOR
+ SDOperand Zero = DAG.getConstant(0, MVT::i32);
+ return DAG.getNode(ISD::BIT_CONVERT, VT,
+ DAG.getNode(ISD::BUILD_VECTOR, MVT::v4i32,
+ Zero, Zero, Zero, Zero));
+ }
+ }
+ }
+
+ return SDOperand();
+}
+
+/// LowerVECTOR_SHUFFLE - Lower a vector shuffle (V1, V2, V3) to something on
+/// which the Cell can operate. The code inspects V3 to ascertain whether the
+/// permutation vector, V3, is monotonically increasing with one "exception"
+/// element, e.g., (0, 1, _, 3). If this is the case, then generate a
+/// INSERT_MASK synthetic instruction. Otherwise, spill V3 to the constant pool.
+/// In either case, the net result is going to eventually invoke SHUFB to
+/// permute/shuffle the bytes from V1 and V2.
+/// \note
+/// INSERT_MASK is eventually selected as one of the C*D instructions, generate
+/// control word for byte/halfword/word insertion. This takes care of a single
+/// element move from V2 into V1.
+/// \note
+/// SPUISD::SHUFB is eventually selected as Cell's <i>shufb</i> instructions.
+static SDOperand LowerVECTOR_SHUFFLE(SDOperand Op, SelectionDAG &DAG) {
+ SDOperand V1 = Op.getOperand(0);
+ SDOperand V2 = Op.getOperand(1);
+ SDOperand PermMask = Op.getOperand(2);
+
+ if (V2.getOpcode() == ISD::UNDEF) V2 = V1;
+
+ // If we have a single element being moved from V1 to V2, this can be handled
+ // using the C*[DX] compute mask instructions, but the vector elements have
+ // to be monotonically increasing with one exception element.
+ MVT::ValueType EltVT = MVT::getVectorElementType(V1.getValueType());
+ unsigned EltsFromV2 = 0;
+ unsigned V2Elt = 0;
+ unsigned V2EltIdx0 = 0;
+ unsigned CurrElt = 0;
+ bool monotonic = true;
+ if (EltVT == MVT::i8)
+ V2EltIdx0 = 16;
+ else if (EltVT == MVT::i16)
+ V2EltIdx0 = 8;
+ else if (EltVT == MVT::i32)
+ V2EltIdx0 = 4;
+ else
+ assert(0 && "Unhandled vector type in LowerVECTOR_SHUFFLE");
+
+ for (unsigned i = 0, e = PermMask.getNumOperands();
+ EltsFromV2 <= 1 && monotonic && i != e;
+ ++i) {
+ unsigned SrcElt;
+ if (PermMask.getOperand(i).getOpcode() == ISD::UNDEF)
+ SrcElt = 0;
+ else
+ SrcElt = cast<ConstantSDNode>(PermMask.getOperand(i))->getValue();
+
+ if (SrcElt >= V2EltIdx0) {
+ ++EltsFromV2;
+ V2Elt = (V2EltIdx0 - SrcElt) << 2;
+ } else if (CurrElt != SrcElt) {
+ monotonic = false;
+ }
+
+ ++CurrElt;
+ }
+
+ if (EltsFromV2 == 1 && monotonic) {
+ // Compute mask and shuffle
+ MachineFunction &MF = DAG.getMachineFunction();
+ SSARegMap *RegMap = MF.getSSARegMap();
+ unsigned VReg = RegMap->createVirtualRegister(&SPU::R32CRegClass);
+ MVT::ValueType PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
+ // Initialize temporary register to 0
+ SDOperand InitTempReg =
+ DAG.getCopyToReg(DAG.getEntryNode(), VReg, DAG.getConstant(0, PtrVT));
+ // Copy register's contents as index in INSERT_MASK:
+ SDOperand ShufMaskOp =
+ DAG.getNode(SPUISD::INSERT_MASK, V1.getValueType(),
+ DAG.getTargetConstant(V2Elt, MVT::i32),
+ DAG.getCopyFromReg(InitTempReg, VReg, PtrVT));
+ // Use shuffle mask in SHUFB synthetic instruction:
+ return DAG.getNode(SPUISD::SHUFB, V1.getValueType(), V2, V1, ShufMaskOp);
+ } else {
+ // Convert the SHUFFLE_VECTOR mask's input element units to the actual bytes.
+ unsigned BytesPerElement = MVT::getSizeInBits(EltVT)/8;
+
+ SmallVector<SDOperand, 16> ResultMask;
+ for (unsigned i = 0, e = PermMask.getNumOperands(); i != e; ++i) {
+ unsigned SrcElt;
+ if (PermMask.getOperand(i).getOpcode() == ISD::UNDEF)
+ SrcElt = 0;
+ else
+ SrcElt = cast<ConstantSDNode>(PermMask.getOperand(i))->getValue();
+
+ for (unsigned j = 0; j != BytesPerElement; ++j) {
+ ResultMask.push_back(DAG.getConstant(SrcElt*BytesPerElement+j,
+ MVT::i8));
+ }
+ }
+
+ SDOperand VPermMask = DAG.getNode(ISD::BUILD_VECTOR, MVT::v16i8,
+ &ResultMask[0], ResultMask.size());
+ return DAG.getNode(SPUISD::SHUFB, V1.getValueType(), V1, V2, VPermMask);
+ }
+}
+
+static SDOperand LowerSCALAR_TO_VECTOR(SDOperand Op, SelectionDAG &DAG) {
+ SDOperand Op0 = Op.getOperand(0); // Op0 = the scalar
+
+ if (Op0.Val->getOpcode() == ISD::Constant) {
+ // For a constant, build the appropriate constant vector, which will
+ // eventually simplify to a vector register load.
+
+ ConstantSDNode *CN = cast<ConstantSDNode>(Op0.Val);
+ SmallVector<SDOperand, 16> ConstVecValues;
+ MVT::ValueType VT;
+ size_t n_copies;
+
+ // Create a constant vector:
+ switch (Op.getValueType()) {
+ default: assert(0 && "Unexpected constant value type in "
+ "LowerSCALAR_TO_VECTOR");
+ case MVT::v16i8: n_copies = 16; VT = MVT::i8; break;
+ case MVT::v8i16: n_copies = 8; VT = MVT::i16; break;
+ case MVT::v4i32: n_copies = 4; VT = MVT::i32; break;
+ case MVT::v4f32: n_copies = 4; VT = MVT::f32; break;
+ case MVT::v2i64: n_copies = 2; VT = MVT::i64; break;
+ case MVT::v2f64: n_copies = 2; VT = MVT::f64; break;
+ }
+
+ SDOperand CValue = DAG.getConstant(CN->getValue(), VT);
+ for (size_t j = 0; j < n_copies; ++j)
+ ConstVecValues.push_back(CValue);
+
+ return DAG.getNode(ISD::BUILD_VECTOR, Op.getValueType(),
+ &ConstVecValues[0], ConstVecValues.size());
+ } else {
+ // Otherwise, copy the value from one register to another:
+ switch (Op0.getValueType()) {
+ default: assert(0 && "Unexpected value type in LowerSCALAR_TO_VECTOR");
+ case MVT::i8:
+ case MVT::i16:
+ case MVT::i32:
+ case MVT::i64:
+ case MVT::f32:
+ case MVT::f64:
+ return DAG.getNode(SPUISD::PROMOTE_SCALAR, Op.getValueType(), Op0, Op0);
+ }
+ }
+
+ return SDOperand();
+}
+
+static SDOperand LowerVectorMUL(SDOperand Op, SelectionDAG &DAG) {
+ switch (Op.getValueType()) {
+ case MVT::v4i32: {
+ SDOperand rA = Op.getOperand(0);
+ SDOperand rB = Op.getOperand(1);
+ SDOperand HiProd1 = DAG.getNode(SPUISD::MPYH, MVT::v4i32, rA, rB);
+ SDOperand HiProd2 = DAG.getNode(SPUISD::MPYH, MVT::v4i32, rB, rA);
+ SDOperand LoProd = DAG.getNode(SPUISD::MPYU, MVT::v4i32, rA, rB);
+ SDOperand Residual1 = DAG.getNode(ISD::ADD, MVT::v4i32, LoProd, HiProd1);
+
+ return DAG.getNode(ISD::ADD, MVT::v4i32, Residual1, HiProd2);
+ break;
+ }
+
+ // Multiply two v8i16 vectors (pipeline friendly version):
+ // a) multiply lower halves, mask off upper 16-bit of 32-bit product
+ // b) multiply upper halves, rotate left by 16 bits (inserts 16 lower zeroes)
+ // c) Use SELB to select upper and lower halves from the intermediate results
+ //
+ // NOTE: We really want to move the FSMBI to earlier to actually get the
+ // dual-issue. This code does manage to do this, even if it's a little on
+ // the wacky side
+ case MVT::v8i16: {
+ MachineFunction &MF = DAG.getMachineFunction();
+ SSARegMap *RegMap = MF.getSSARegMap();
+ SDOperand Chain = Op.getOperand(0);
+ SDOperand rA = Op.getOperand(0);
+ SDOperand rB = Op.getOperand(1);
+ unsigned FSMBIreg = RegMap->createVirtualRegister(&SPU::VECREGRegClass);
+ unsigned HiProdReg = RegMap->createVirtualRegister(&SPU::VECREGRegClass);
+
+ SDOperand FSMBOp =
+ DAG.getCopyToReg(Chain, FSMBIreg,
+ DAG.getNode(SPUISD::FSMBI, MVT::v8i16,
+ DAG.getConstant(0xcccc, MVT::i32)));
+
+ SDOperand HHProd =
+ DAG.getCopyToReg(FSMBOp, HiProdReg,
+ DAG.getNode(SPUISD::MPYHH, MVT::v8i16, rA, rB));
+
+ SDOperand HHProd_v4i32 =
+ DAG.getNode(ISD::BIT_CONVERT, MVT::v4i32,
+ DAG.getCopyFromReg(HHProd, HiProdReg, MVT::v4i32));
+
+ return DAG.getNode(SPUISD::SELB, MVT::v8i16,
+ DAG.getNode(SPUISD::MPY, MVT::v8i16, rA, rB),
+ DAG.getNode(ISD::BIT_CONVERT, Op.getValueType(),
+ DAG.getNode(SPUISD::VEC_SHL, MVT::v4i32,
+ HHProd_v4i32,
+ DAG.getConstant(16, MVT::i16))),
+ DAG.getCopyFromReg(FSMBOp, FSMBIreg, MVT::v4i32));
+ }
+
+ // This M00sE is N@stI! (apologies to Monty Python)
+ //
+ // SPU doesn't know how to do any 8-bit multiplication, so the solution
+ // is to break it all apart, sign extend, and reassemble the various
+ // intermediate products.
+ case MVT::v16i8: {
+ MachineFunction &MF = DAG.getMachineFunction();
+ SSARegMap *RegMap = MF.getSSARegMap();
+ SDOperand Chain = Op.getOperand(0);
+ SDOperand rA = Op.getOperand(0);
+ SDOperand rB = Op.getOperand(1);
+ SDOperand c8 = DAG.getConstant(8, MVT::i8);
+ SDOperand c16 = DAG.getConstant(16, MVT::i8);
+
+ unsigned FSMBreg_2222 = RegMap->createVirtualRegister(&SPU::VECREGRegClass);
+ unsigned LoProd_reg = RegMap->createVirtualRegister(&SPU::VECREGRegClass);
+ unsigned HiProd_reg = RegMap->createVirtualRegister(&SPU::VECREGRegClass);
+
+ SDOperand LLProd =
+ DAG.getNode(SPUISD::MPY, MVT::v8i16,
+ DAG.getNode(ISD::BIT_CONVERT, MVT::v8i16, rA),
+ DAG.getNode(ISD::BIT_CONVERT, MVT::v8i16, rB));
+
+ SDOperand rALH = DAG.getNode(SPUISD::VEC_SRA, MVT::v8i16, rA, c8);
+
+ SDOperand rBLH = DAG.getNode(SPUISD::VEC_SRA, MVT::v8i16, rB, c8);
+
+ SDOperand LHProd =
+ DAG.getNode(SPUISD::VEC_SHL, MVT::v8i16,
+ DAG.getNode(SPUISD::MPY, MVT::v8i16, rALH, rBLH), c8);
+
+ SDOperand FSMBdef_2222 =
+ DAG.getCopyToReg(Chain, FSMBreg_2222,
+ DAG.getNode(SPUISD::FSMBI, MVT::v8i16,
+ DAG.getConstant(0x2222, MVT::i32)));
+
+ SDOperand FSMBuse_2222 =
+ DAG.getCopyFromReg(FSMBdef_2222, FSMBreg_2222, MVT::v4i32);
+
+ SDOperand LoProd_1 =
+ DAG.getCopyToReg(Chain, LoProd_reg,
+ DAG.getNode(SPUISD::SELB, MVT::v8i16, LLProd, LHProd,
+ FSMBuse_2222));
+
+ SDOperand LoProdMask = DAG.getConstant(0xffff, MVT::i32);
+
+ SDOperand LoProd =
+ DAG.getNode(ISD::AND, MVT::v4i32,
+ DAG.getCopyFromReg(LoProd_1, LoProd_reg, MVT::v4i32),
+ DAG.getNode(ISD::BUILD_VECTOR, MVT::v4i32,
+ LoProdMask, LoProdMask,
+ LoProdMask, LoProdMask));
+
+ SDOperand rAH =
+ DAG.getNode(SPUISD::VEC_SRA, MVT::v4i32,
+ DAG.getNode(ISD::BIT_CONVERT, MVT::v4i32, rA), c16);
+
+ SDOperand rBH =
+ DAG.getNode(SPUISD::VEC_SRA, MVT::v4i32,
+ DAG.getNode(ISD::BIT_CONVERT, MVT::v4i32, rB), c16);
+
+ SDOperand HLProd =
+ DAG.getNode(SPUISD::MPY, MVT::v8i16,
+ DAG.getNode(ISD::BIT_CONVERT, MVT::v8i16, rAH),
+ DAG.getNode(ISD::BIT_CONVERT, MVT::v8i16, rBH));
+
+ SDOperand HHProd_1 =
+ DAG.getNode(SPUISD::MPY, MVT::v8i16,
+ DAG.getNode(ISD::BIT_CONVERT, MVT::v8i16,
+ DAG.getNode(SPUISD::VEC_SRA, MVT::v4i32, rAH, c8)),
+ DAG.getNode(ISD::BIT_CONVERT, MVT::v8i16,
+ DAG.getNode(SPUISD::VEC_SRA, MVT::v4i32, rBH, c8)));
+
+ SDOperand HHProd =
+ DAG.getCopyToReg(Chain, HiProd_reg,
+ DAG.getNode(SPUISD::SELB, MVT::v8i16,
+ HLProd,
+ DAG.getNode(SPUISD::VEC_SHL, MVT::v8i16, HHProd_1, c8),
+ FSMBuse_2222));
+
+ SDOperand HiProd =
+ DAG.getNode(SPUISD::VEC_SHL, MVT::v4i32,
+ DAG.getCopyFromReg(HHProd, HiProd_reg, MVT::v4i32), c16);
+
+ return DAG.getNode(ISD::BIT_CONVERT, MVT::v16i8,
+ DAG.getNode(ISD::OR, MVT::v4i32,
+ LoProd, HiProd));
+ }
+
+ default:
+ cerr << "CellSPU: Unknown vector multiplication, got "
+ << MVT::getValueTypeString(Op.getValueType())
+ << "\n";
+ abort();
+ /*NOTREACHED*/
+ }
+
+ return SDOperand();
+}
+
+static SDOperand LowerFDIVf32(SDOperand Op, SelectionDAG &DAG) {
+ MachineFunction &MF = DAG.getMachineFunction();
+ SSARegMap *RegMap = MF.getSSARegMap();
+
+ SDOperand A = Op.getOperand(0);
+ SDOperand B = Op.getOperand(1);
+ unsigned VT = Op.getValueType();
+
+ unsigned VRegBR, VRegC;
+
+ if (VT == MVT::f32) {
+ VRegBR = RegMap->createVirtualRegister(&SPU::R32FPRegClass);
+ VRegC = RegMap->createVirtualRegister(&SPU::R32FPRegClass);
+ } else {
+ VRegBR = RegMap->createVirtualRegister(&SPU::VECREGRegClass);
+ VRegC = RegMap->createVirtualRegister(&SPU::VECREGRegClass);
+ }
+ // TODO: make sure we're feeding FPInterp the right arguments
+ // Right now: fi B, frest(B)
+
+ // Computes BRcpl =
+ // (Floating Interpolate (FP Reciprocal Estimate B))
+ SDOperand BRcpl =
+ DAG.getCopyToReg(DAG.getEntryNode(), VRegBR,
+ DAG.getNode(SPUISD::FPInterp, VT, B,
+ DAG.getNode(SPUISD::FPRecipEst, VT, B)));
+
+ // Computes A * BRcpl and stores in a temporary register
+ SDOperand AxBRcpl =
+ DAG.getCopyToReg(BRcpl, VRegC,
+ DAG.getNode(ISD::FMUL, VT, A,
+ DAG.getCopyFromReg(BRcpl, VRegBR, VT)));
+ // What's the Chain variable do? It's magic!
+ // TODO: set Chain = Op(0).getEntryNode()
+
+ return DAG.getNode(ISD::FADD, VT,
+ DAG.getCopyFromReg(AxBRcpl, VRegC, VT),
+ DAG.getNode(ISD::FMUL, VT,
+ DAG.getCopyFromReg(AxBRcpl, VRegBR, VT),
+ DAG.getNode(ISD::FSUB, VT, A,
+ DAG.getNode(ISD::FMUL, VT, B,
+ DAG.getCopyFromReg(AxBRcpl, VRegC, VT)))));
+}
+
+// Expands double-precision FDIV
+// Expects two doubles as inputs X and Y, does a floating point
+// reciprocal estimate, and three iterations of Newton-Raphson
+// to increase accuracy.
+//static SDOperand LowerFDIVf64(SDOperand Op, SelectionDAG &DAG) {
+// MachineFunction &MF = DAG.getMachineFunction();
+// SSARegMap *RegMap = MF.getSSARegMap();
+//
+// SDOperand X = Op.getOperand(0);
+// SDOperand Y = Op.getOperand(1);
+//}
+
+static SDOperand LowerEXTRACT_VECTOR_ELT(SDOperand Op, SelectionDAG &DAG) {
+ unsigned VT = Op.getValueType();
+ SDOperand N = Op.getOperand(0);
+ SDOperand Elt = Op.getOperand(1);
+ SDOperand ShufMask[16];
+ ConstantSDNode *C = dyn_cast<ConstantSDNode>(Elt);
+
+ assert(C != 0 && "LowerEXTRACT_VECTOR_ELT expecting constant SDNode");
+
+ int EltNo = (int) C->getValue();
+
+ // sanity checks:
+ if (VT == MVT::i8 && EltNo >= 16)
+ assert(0 && "SPU LowerEXTRACT_VECTOR_ELT: i8 extraction slot > 15");
+ else if (VT == MVT::i16 && EltNo >= 8)
+ assert(0 && "SPU LowerEXTRACT_VECTOR_ELT: i16 extraction slot > 7");
+ else if (VT == MVT::i32 && EltNo >= 4)
+ assert(0 && "SPU LowerEXTRACT_VECTOR_ELT: i32 extraction slot > 4");
+ else if (VT == MVT::i64 && EltNo >= 2)
+ assert(0 && "SPU LowerEXTRACT_VECTOR_ELT: i64 extraction slot > 2");
+
+ if (EltNo == 0 && (VT == MVT::i32 || VT == MVT::i64)) {
+ // i32 and i64: Element 0 is the preferred slot
+ return DAG.getNode(SPUISD::EXTRACT_ELT0, VT, N);
+ }
+
+ // Need to generate shuffle mask and extract:
+ int prefslot_begin, prefslot_end;
+ int elt_byte = EltNo * MVT::getSizeInBits(VT) / 8;
+
+ switch (VT) {
+ case MVT::i8: {
+ prefslot_begin = prefslot_end = 3;
+ break;
+ }
+ case MVT::i16: {
+ prefslot_begin = 2; prefslot_end = 3;
+ break;
+ }
+ case MVT::i32: {
+ prefslot_begin = 0; prefslot_end = 3;
+ break;
+ }
+ case MVT::i64: {
+ prefslot_begin = 0; prefslot_end = 7;
+ break;
+ }
+ }
+
+ for (int i = 0; i < 16; ++i) {
+ // zero fill uppper part of preferred slot, don't care about the
+ // other slots:
+ unsigned int mask_val;
+
+ if (i <= prefslot_end) {
+ mask_val =
+ ((i < prefslot_begin)
+ ? 0x80
+ : elt_byte + (i - prefslot_begin));
+
+ ShufMask[i] = DAG.getConstant(mask_val, MVT::i16);
+ } else
+ ShufMask[i] = ShufMask[i % (prefslot_end + 1)];
+ }
+
+ SDOperand ShufMaskVec =
+ DAG.getNode(ISD::BUILD_VECTOR, MVT::v16i8,
+ &ShufMask[0],
+ sizeof(ShufMask) / sizeof(ShufMask[0]));
+
+ return DAG.getNode(SPUISD::EXTRACT_ELT0, VT,
+ DAG.getNode(SPUISD::SHUFB, N.getValueType(),
+ N, N, ShufMaskVec));
+
+}
+
+static SDOperand LowerINSERT_VECTOR_ELT(SDOperand Op, SelectionDAG &DAG) {
+ SDOperand VecOp = Op.getOperand(0);
+ SDOperand ValOp = Op.getOperand(1);
+ SDOperand IdxOp = Op.getOperand(2);
+ MVT::ValueType VT = Op.getValueType();
+
+ ConstantSDNode *CN = cast<ConstantSDNode>(IdxOp);
+ assert(CN != 0 && "LowerINSERT_VECTOR_ELT: Index is not constant!");
+
+ MVT::ValueType PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
+ // Use $2 because it's always 16-byte aligned and it's available:
+ SDOperand PtrBase = DAG.getRegister(SPU::R2, PtrVT);
+
+ SDOperand result =
+ DAG.getNode(SPUISD::SHUFB, VT,
+ DAG.getNode(ISD::SCALAR_TO_VECTOR, VT, ValOp),
+ VecOp,
+ DAG.getNode(SPUISD::INSERT_MASK, VT,
+ DAG.getNode(ISD::ADD, PtrVT,
+ PtrBase,
+ DAG.getConstant(CN->getValue(),
+ PtrVT))));
+
+ return result;
+}
+
+static SDOperand LowerI8Math(SDOperand Op, SelectionDAG &DAG, unsigned Opc) {
+ SDOperand N0 = Op.getOperand(0); // Everything has at least one operand
+
+ assert(Op.getValueType() == MVT::i8);
+ switch (Opc) {
+ default:
+ assert(0 && "Unhandled i8 math operator");
+ /*NOTREACHED*/
+ break;
+ case ISD::SUB: {
+ // 8-bit subtraction: Promote the arguments up to 16-bits and truncate
+ // the result:
+ SDOperand N1 = Op.getOperand(1);
+ N0 = (N0.getOpcode() != ISD::Constant
+ ? DAG.getNode(ISD::SIGN_EXTEND, MVT::i16, N0)
+ : DAG.getConstant(cast<ConstantSDNode>(N0)->getValue(), MVT::i16));
+ N1 = (N1.getOpcode() != ISD::Constant
+ ? DAG.getNode(ISD::SIGN_EXTEND, MVT::i16, N1)
+ : DAG.getConstant(cast<ConstantSDNode>(N1)->getValue(), MVT::i16));
+ return DAG.getNode(ISD::TRUNCATE, MVT::i8,
+ DAG.getNode(Opc, MVT::i16, N0, N1));
+ }
+ case ISD::ROTR:
+ case ISD::ROTL: {
+ SDOperand N1 = Op.getOperand(1);
+ unsigned N1Opc;
+ N0 = (N0.getOpcode() != ISD::Constant
+ ? DAG.getNode(ISD::ZERO_EXTEND, MVT::i16, N0)
+ : DAG.getConstant(cast<ConstantSDNode>(N0)->getValue(), MVT::i16));
+ N1Opc = (N1.getValueType() < MVT::i16 ? ISD::ZERO_EXTEND : ISD::TRUNCATE);
+ N1 = (N1.getOpcode() != ISD::Constant
+ ? DAG.getNode(N1Opc, MVT::i16, N1)
+ : DAG.getConstant(cast<ConstantSDNode>(N1)->getValue(), MVT::i16));
+ SDOperand ExpandArg =
+ DAG.getNode(ISD::OR, MVT::i16, N0,
+ DAG.getNode(ISD::SHL, MVT::i16,
+ N0, DAG.getConstant(8, MVT::i16)));
+ return DAG.getNode(ISD::TRUNCATE, MVT::i8,
+ DAG.getNode(Opc, MVT::i16, ExpandArg, N1));
+ }
+ case ISD::SRL:
+ case ISD::SHL: {
+ SDOperand N1 = Op.getOperand(1);
+ unsigned N1Opc;
+ N0 = (N0.getOpcode() != ISD::Constant
+ ? DAG.getNode(ISD::ZERO_EXTEND, MVT::i16, N0)
+ : DAG.getConstant(cast<ConstantSDNode>(N0)->getValue(), MVT::i16));
+ N1Opc = (N1.getValueType() < MVT::i16 ? ISD::ZERO_EXTEND : ISD::TRUNCATE);
+ N1 = (N1.getOpcode() != ISD::Constant
+ ? DAG.getNode(N1Opc, MVT::i16, N1)
+ : DAG.getConstant(cast<ConstantSDNode>(N1)->getValue(), MVT::i16));
+ return DAG.getNode(ISD::TRUNCATE, MVT::i8,
+ DAG.getNode(Opc, MVT::i16, N0, N1));
+ }
+ case ISD::SRA: {
+ SDOperand N1 = Op.getOperand(1);
+ unsigned N1Opc;
+ N0 = (N0.getOpcode() != ISD::Constant
+ ? DAG.getNode(ISD::SIGN_EXTEND, MVT::i16, N0)
+ : DAG.getConstant(cast<ConstantSDNode>(N0)->getValue(), MVT::i16));
+ N1Opc = (N1.getValueType() < MVT::i16 ? ISD::SIGN_EXTEND : ISD::TRUNCATE);
+ N1 = (N1.getOpcode() != ISD::Constant
+ ? DAG.getNode(N1Opc, MVT::i16, N1)
+ : DAG.getConstant(cast<ConstantSDNode>(N1)->getValue(), MVT::i16));
+ return DAG.getNode(ISD::TRUNCATE, MVT::i8,
+ DAG.getNode(Opc, MVT::i16, N0, N1));
+ }
+ case ISD::MUL: {
+ SDOperand N1 = Op.getOperand(1);
+ unsigned N1Opc;
+ N0 = (N0.getOpcode() != ISD::Constant
+ ? DAG.getNode(ISD::SIGN_EXTEND, MVT::i16, N0)
+ : DAG.getConstant(cast<ConstantSDNode>(N0)->getValue(), MVT::i16));
+ N1Opc = (N1.getValueType() < MVT::i16 ? ISD::SIGN_EXTEND : ISD::TRUNCATE);
+ N1 = (N1.getOpcode() != ISD::Constant
+ ? DAG.getNode(N1Opc, MVT::i16, N1)
+ : DAG.getConstant(cast<ConstantSDNode>(N1)->getValue(), MVT::i16));
+ return DAG.getNode(ISD::TRUNCATE, MVT::i8,
+ DAG.getNode(Opc, MVT::i16, N0, N1));
+ break;
+ }
+ }
+
+ return SDOperand();
+}
+
+//! Lower byte immediate operations for v16i8 vectors:
+static SDOperand
+LowerByteImmed(SDOperand Op, SelectionDAG &DAG) {
+ SDOperand ConstVec;
+ SDOperand Arg;
+ MVT::ValueType VT = Op.getValueType();
+
+ ConstVec = Op.getOperand(0);
+ Arg = Op.getOperand(1);
+ if (ConstVec.Val->getOpcode() != ISD::BUILD_VECTOR) {
+ if (ConstVec.Val->getOpcode() == ISD::BIT_CONVERT) {
+ ConstVec = ConstVec.getOperand(0);
+ } else {
+ ConstVec = Op.getOperand(1);
+ Arg = Op.getOperand(0);
+ if (ConstVec.Val->getOpcode() == ISD::BIT_CONVERT) {
+ ConstVec = ConstVec.getOperand(0);
+ }
+ }
+ }
+
+ if (ConstVec.Val->getOpcode() == ISD::BUILD_VECTOR) {
+ uint64_t VectorBits[2];
+ uint64_t UndefBits[2];
+ uint64_t SplatBits, SplatUndef;
+ int SplatSize;
+
+ if (!GetConstantBuildVectorBits(ConstVec.Val, VectorBits, UndefBits)
+ && isConstantSplat(VectorBits, UndefBits,
+ MVT::getSizeInBits(MVT::getVectorElementType(VT)),
+ SplatBits, SplatUndef, SplatSize)) {
+ SDOperand tcVec[16];
+ SDOperand tc = DAG.getTargetConstant(SplatBits & 0xff, MVT::i8);
+ const size_t tcVecSize = sizeof(tcVec) / sizeof(tcVec[0]);
+
+ // Turn the BUILD_VECTOR into a set of target constants:
+ for (size_t i = 0; i < tcVecSize; ++i)
+ tcVec[i] = tc;
+
+ return DAG.getNode(Op.Val->getOpcode(), VT, Arg,
+ DAG.getNode(ISD::BUILD_VECTOR, VT, tcVec, tcVecSize));
+ }
+ }
+
+ return SDOperand();
+}
+
+//! Lower i32 multiplication
+static SDOperand LowerMUL(SDOperand Op, SelectionDAG &DAG, unsigned VT,
+ unsigned Opc) {
+ switch (VT) {
+ default:
+ cerr << "CellSPU: Unknown LowerMUL value type, got "
+ << MVT::getValueTypeString(Op.getValueType())
+ << "\n";
+ abort();
+ /*NOTREACHED*/
+
+ case MVT::i32: {
+ SDOperand rA = Op.getOperand(0);
+ SDOperand rB = Op.getOperand(1);
+
+ return DAG.getNode(ISD::ADD, MVT::i32,
+ DAG.getNode(ISD::ADD, MVT::i32,
+ DAG.getNode(SPUISD::MPYH, MVT::i32, rA, rB),
+ DAG.getNode(SPUISD::MPYH, MVT::i32, rB, rA)),
+ DAG.getNode(SPUISD::MPYU, MVT::i32, rA, rB));
+ }
+ }
+
+ return SDOperand();
+}
+
+//! Custom lowering for CTPOP (count population)
+/*!
+ Custom lowering code that counts the number ones in the input
+ operand. SPU has such an instruction, but it counts the number of
+ ones per byte, which then have to be accumulated.
+*/
+static SDOperand LowerCTPOP(SDOperand Op, SelectionDAG &DAG) {
+ unsigned VT = Op.getValueType();
+ unsigned vecVT = MVT::getVectorType(VT, (128 / MVT::getSizeInBits(VT)));
+
+ switch (VT) {
+ case MVT::i8: {
+ SDOperand N = Op.getOperand(0);
+ SDOperand Elt0 = DAG.getConstant(0, MVT::i32);
+
+ SDOperand Promote = DAG.getNode(SPUISD::PROMOTE_SCALAR, vecVT, N, N);
+ SDOperand CNTB = DAG.getNode(SPUISD::CNTB, vecVT, Promote);
+
+ return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, MVT::i8, CNTB, Elt0);
+ }
+
+ case MVT::i16: {
+ MachineFunction &MF = DAG.getMachineFunction();
+ SSARegMap *RegMap = MF.getSSARegMap();
+
+ unsigned CNTB_reg = RegMap->createVirtualRegister(&SPU::R16CRegClass);
+
+ SDOperand N = Op.getOperand(0);
+ SDOperand Elt0 = DAG.getConstant(0, MVT::i16);
+ SDOperand Mask0 = DAG.getConstant(0x0f, MVT::i16);
+ SDOperand Shift1 = DAG.getConstant(8, MVT::i16);
+
+ SDOperand Promote = DAG.getNode(SPUISD::PROMOTE_SCALAR, vecVT, N, N);
+ SDOperand CNTB = DAG.getNode(SPUISD::CNTB, vecVT, Promote);
+
+ // CNTB_result becomes the chain to which all of the virtual registers
+ // CNTB_reg, SUM1_reg become associated:
+ SDOperand CNTB_result =
+ DAG.getNode(ISD::EXTRACT_VECTOR_ELT, MVT::i16, CNTB, Elt0);
+
+ SDOperand CNTB_rescopy =
+ DAG.getCopyToReg(CNTB_result, CNTB_reg, CNTB_result);
+
+ SDOperand Tmp1 = DAG.getCopyFromReg(CNTB_rescopy, CNTB_reg, MVT::i16);
+
+ return DAG.getNode(ISD::AND, MVT::i16,
+ DAG.getNode(ISD::ADD, MVT::i16,
+ DAG.getNode(ISD::SRL, MVT::i16,
+ Tmp1, Shift1),
+ Tmp1),
+ Mask0);
+ }
+
+ case MVT::i32: {
+ MachineFunction &MF = DAG.getMachineFunction();
+ SSARegMap *RegMap = MF.getSSARegMap();
+
+ unsigned CNTB_reg = RegMap->createVirtualRegister(&SPU::R32CRegClass);
+ unsigned SUM1_reg = RegMap->createVirtualRegister(&SPU::R32CRegClass);
+
+ SDOperand N = Op.getOperand(0);
+ SDOperand Elt0 = DAG.getConstant(0, MVT::i32);
+ SDOperand Mask0 = DAG.getConstant(0xff, MVT::i32);
+ SDOperand Shift1 = DAG.getConstant(16, MVT::i32);
+ SDOperand Shift2 = DAG.getConstant(8, MVT::i32);
+
+ SDOperand Promote = DAG.getNode(SPUISD::PROMOTE_SCALAR, vecVT, N, N);
+ SDOperand CNTB = DAG.getNode(SPUISD::CNTB, vecVT, Promote);
+
+ // CNTB_result becomes the chain to which all of the virtual registers
+ // CNTB_reg, SUM1_reg become associated:
+ SDOperand CNTB_result =
+ DAG.getNode(ISD::EXTRACT_VECTOR_ELT, MVT::i32, CNTB, Elt0);
+
+ SDOperand CNTB_rescopy =
+ DAG.getCopyToReg(CNTB_result, CNTB_reg, CNTB_result);
+
+ SDOperand Comp1 =
+ DAG.getNode(ISD::SRL, MVT::i32,
+ DAG.getCopyFromReg(CNTB_rescopy, CNTB_reg, MVT::i32), Shift1);
+
+ SDOperand Sum1 =
+ DAG.getNode(ISD::ADD, MVT::i32,
+ Comp1, DAG.getCopyFromReg(CNTB_rescopy, CNTB_reg, MVT::i32));
+
+ SDOperand Sum1_rescopy =
+ DAG.getCopyToReg(CNTB_result, SUM1_reg, Sum1);
+
+ SDOperand Comp2 =
+ DAG.getNode(ISD::SRL, MVT::i32,
+ DAG.getCopyFromReg(Sum1_rescopy, SUM1_reg, MVT::i32),
+ Shift2);
+ SDOperand Sum2 =
+ DAG.getNode(ISD::ADD, MVT::i32, Comp2,
+ DAG.getCopyFromReg(Sum1_rescopy, SUM1_reg, MVT::i32));
+
+ return DAG.getNode(ISD::AND, MVT::i32, Sum2, Mask0);
+ }
+
+ case MVT::i64:
+ break;
+ }
+
+ return SDOperand();
+}
+
+/// LowerOperation - Provide custom lowering hooks for some operations.
+///
+SDOperand
+SPUTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG)
+{
+ switch (Op.getOpcode()) {
+ default: {
+ cerr << "SPUTargetLowering::LowerOperation(): need to lower this!\n";
+ cerr << "Op.getOpcode() = " << Op.getOpcode() << "\n";
+ cerr << "*Op.Val:\n";
+ Op.Val->dump();
+ abort();
+ }
+ case ISD::LOAD:
+ case ISD::SEXTLOAD:
+ case ISD::ZEXTLOAD:
+ return LowerLOAD(Op, DAG, SPUTM.getSubtargetImpl());
+ case ISD::STORE:
+ return LowerSTORE(Op, DAG, SPUTM.getSubtargetImpl());
+ case ISD::ConstantPool:
+ return LowerConstantPool(Op, DAG, SPUTM.getSubtargetImpl());
+ case ISD::GlobalAddress:
+ return LowerGlobalAddress(Op, DAG, SPUTM.getSubtargetImpl());
+ case ISD::JumpTable:
+ return LowerJumpTable(Op, DAG, SPUTM.getSubtargetImpl());
+ case ISD::Constant:
+ return LowerConstant(Op, DAG);
+ case ISD::ConstantFP:
+ return LowerConstantFP(Op, DAG);
+ case ISD::FORMAL_ARGUMENTS:
+ return LowerFORMAL_ARGUMENTS(Op, DAG, VarArgsFrameIndex);
+ case ISD::CALL:
+ return LowerCALL(Op, DAG);
+ case ISD::RET:
+ return LowerRET(Op, DAG, getTargetMachine());
+
+ // i8 math ops:
+ case ISD::SUB:
+ case ISD::ROTR:
+ case ISD::ROTL:
+ case ISD::SRL:
+ case ISD::SHL:
+ case ISD::SRA:
+ return LowerI8Math(Op, DAG, Op.getOpcode());
+
+ // Vector-related lowering.
+ case ISD::BUILD_VECTOR:
+ return LowerBUILD_VECTOR(Op, DAG);
+ case ISD::SCALAR_TO_VECTOR:
+ return LowerSCALAR_TO_VECTOR(Op, DAG);
+ case ISD::VECTOR_SHUFFLE:
+ return LowerVECTOR_SHUFFLE(Op, DAG);
+ case ISD::EXTRACT_VECTOR_ELT:
+ return LowerEXTRACT_VECTOR_ELT(Op, DAG);
+ case ISD::INSERT_VECTOR_ELT:
+ return LowerINSERT_VECTOR_ELT(Op, DAG);
+
+ // Look for ANDBI, ORBI and XORBI opportunities and lower appropriately:
+ case ISD::AND:
+ case ISD::OR:
+ case ISD::XOR:
+ return LowerByteImmed(Op, DAG);
+
+ // Vector and i8 multiply:
+ case ISD::MUL:
+ if (MVT::isVector(Op.getValueType()))
+ return LowerVectorMUL(Op, DAG);
+ else if (Op.getValueType() == MVT::i8)
+ return LowerI8Math(Op, DAG, Op.getOpcode());
+ else
+ return LowerMUL(Op, DAG, Op.getValueType(), Op.getOpcode());
+
+ case ISD::FDIV:
+ if (Op.getValueType() == MVT::f32 || Op.getValueType() == MVT::v4f32)
+ return LowerFDIVf32(Op, DAG);
+// else if (Op.getValueType() == MVT::f64)
+// return LowerFDIVf64(Op, DAG);
+ else
+ assert(0 && "Calling FDIV on unsupported MVT");
+
+ case ISD::CTPOP:
+ return LowerCTPOP(Op, DAG);
+ }
+
+ return SDOperand();
+}
+
+//===----------------------------------------------------------------------===//
+// Other Lowering Code
+//===----------------------------------------------------------------------===//
+
+MachineBasicBlock *
+SPUTargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI,
+ MachineBasicBlock *BB)
+{
+ return BB;
+}
+
+//===----------------------------------------------------------------------===//
+// Target Optimization Hooks
+//===----------------------------------------------------------------------===//
+
+SDOperand
+SPUTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const
+{
+#if 0
+ TargetMachine &TM = getTargetMachine();
+ SelectionDAG &DAG = DCI.DAG;
+#endif
+ SDOperand N0 = N->getOperand(0); // everything has at least one operand
+
+ switch (N->getOpcode()) {
+ default: break;
+
+ // Look for obvious optimizations for shift left:
+ // a) Replace 0 << V with 0
+ // b) Replace V << 0 with V
+ //
+ // N.B: llvm will generate an undef node if the shift amount is greater than
+ // 15 (e.g.: V << 16), which will naturally trigger an assert.
+ case SPU::SHLIr32:
+ case SPU::SHLHIr16:
+ case SPU::SHLQBIIvec:
+ case SPU::ROTHIr16:
+ case SPU::ROTHIr16_i32:
+ case SPU::ROTIr32:
+ case SPU::ROTIr32_i16:
+ case SPU::ROTQBYIvec:
+ case SPU::ROTQBYBIvec:
+ case SPU::ROTQBIIvec:
+ case SPU::ROTHMIr16:
+ case SPU::ROTMIr32:
+ case SPU::ROTQMBYIvec: {
+ if (N0.getOpcode() == ISD::Constant) {
+ if (ConstantSDNode *C = cast<ConstantSDNode>(N0)) {
+ if (C->getValue() == 0) // 0 << V -> 0.
+ return N0;
+ }
+ }
+ SDOperand N1 = N->getOperand(1);
+ if (N1.getOpcode() == ISD::Constant) {
+ if (ConstantSDNode *C = cast<ConstantSDNode>(N1)) {
+ if (C->getValue() == 0) // V << 0 -> V
+ return N1;
+ }
+ }
+ break;
+ }
+ }
+
+ return SDOperand();
+}
+
+//===----------------------------------------------------------------------===//
+// Inline Assembly Support
+//===----------------------------------------------------------------------===//
+
+/// getConstraintType - Given a constraint letter, return the type of
+/// constraint it is for this target.
+SPUTargetLowering::ConstraintType
+SPUTargetLowering::getConstraintType(const std::string &ConstraintLetter) const {
+ if (ConstraintLetter.size() == 1) {
+ switch (ConstraintLetter[0]) {
+ default: break;
+ case 'b':
+ case 'r':
+ case 'f':
+ case 'v':
+ case 'y':
+ return C_RegisterClass;
+ }
+ }
+ return TargetLowering::getConstraintType(ConstraintLetter);
+}
+
+std::pair<unsigned, const TargetRegisterClass*>
+SPUTargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint,
+ MVT::ValueType VT) const
+{
+ if (Constraint.size() == 1) {
+ // GCC RS6000 Constraint Letters
+ switch (Constraint[0]) {
+ case 'b': // R1-R31
+ case 'r': // R0-R31
+ if (VT == MVT::i64)
+ return std::make_pair(0U, SPU::R64CRegisterClass);
+ return std::make_pair(0U, SPU::R32CRegisterClass);
+ case 'f':
+ if (VT == MVT::f32)
+ return std::make_pair(0U, SPU::R32FPRegisterClass);
+ else if (VT == MVT::f64)
+ return std::make_pair(0U, SPU::R64FPRegisterClass);
+ break;
+ case 'v':
+ return std::make_pair(0U, SPU::GPRCRegisterClass);
+ }
+ }
+
+ return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
+}
+
+void
+SPUTargetLowering::computeMaskedBitsForTargetNode(const SDOperand Op,
+ uint64_t Mask,
+ uint64_t &KnownZero,
+ uint64_t &KnownOne,
+ const SelectionDAG &DAG,
+ unsigned Depth ) const {
+ KnownZero = 0;
+ KnownOne = 0;
+}
+
+// LowerAsmOperandForConstraint
+void
+SPUTargetLowering::LowerAsmOperandForConstraint(SDOperand Op,
+ char ConstraintLetter,
+ std::vector<SDOperand> &Ops,
+ SelectionDAG &DAG) {
+ // Default, for the time being, to the base class handler
+ TargetLowering::LowerAsmOperandForConstraint(Op, ConstraintLetter, Ops, DAG);
+}
+
+/// isLegalAddressImmediate - Return true if the integer value can be used
+/// as the offset of the target addressing mode.
+bool SPUTargetLowering::isLegalAddressImmediate(int64_t V, const Type *Ty) const {
+ // SPU's addresses are 256K:
+ return (V > -(1 << 18) && V < (1 << 18) - 1);
+}
+
+bool SPUTargetLowering::isLegalAddressImmediate(llvm::GlobalValue* GV) const {
+ return false;
+}
diff --git a/lib/Target/CellSPU/SPUISelLowering.h b/lib/Target/CellSPU/SPUISelLowering.h
new file mode 100644
index 0000000..4e3ec3a
--- /dev/null
+++ b/lib/Target/CellSPU/SPUISelLowering.h
@@ -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
diff --git a/lib/Target/CellSPU/SPUInstrBuilder.h b/lib/Target/CellSPU/SPUInstrBuilder.h
new file mode 100644
index 0000000..58e455f
--- /dev/null
+++ b/lib/Target/CellSPU/SPUInstrBuilder.h
@@ -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
diff --git a/lib/Target/CellSPU/SPUInstrFormats.td b/lib/Target/CellSPU/SPUInstrFormats.td
new file mode 100644
index 0000000..8d3a500
--- /dev/null
+++ b/lib/Target/CellSPU/SPUInstrFormats.td
@@ -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;
+}