diff options
Diffstat (limited to 'lib/Target/IA64')
27 files changed, 4321 insertions, 0 deletions
diff --git a/lib/Target/IA64/AsmPrinter/CMakeLists.txt b/lib/Target/IA64/AsmPrinter/CMakeLists.txt new file mode 100644 index 0000000000000..1d552bd5551c7 --- /dev/null +++ b/lib/Target/IA64/AsmPrinter/CMakeLists.txt @@ -0,0 +1,12 @@ +include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}/..
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+ )
+
+add_partially_linked_object(LLVMIA64AsmPrinter
+ IA64AsmPrinter.cpp
+ )
+
+target_name_of_partially_linked_object(LLVMIA64CodeGen n)
+
+add_dependencies(LLVMIA64AsmPrinter ${n})
diff --git a/lib/Target/IA64/AsmPrinter/IA64AsmPrinter.cpp b/lib/Target/IA64/AsmPrinter/IA64AsmPrinter.cpp new file mode 100644 index 0000000000000..fc54e23a44d7e --- /dev/null +++ b/lib/Target/IA64/AsmPrinter/IA64AsmPrinter.cpp @@ -0,0 +1,376 @@ +//===-- IA64AsmPrinter.cpp - Print out IA64 LLVM as assembly --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to assembly accepted by the GNU binutils 'gas' +// assembler. The Intel 'ias' and HP-UX 'as' assemblers *may* choke on this +// output, but if so that's a bug I'd like to hear about: please file a bug +// report in bugzilla. FYI, the not too bad 'ias' assembler is bundled with +// the Intel C/C++ compiler for Itanium Linux. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "IA64.h" +#include "IA64TargetMachine.h" +#include "llvm/Module.h" +#include "llvm/Type.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DwarfWriter.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Support/Mangler.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/Statistic.h" +using namespace llvm; + +STATISTIC(EmittedInsts, "Number of machine instrs printed"); + +namespace { + class IA64AsmPrinter : public AsmPrinter { + std::set<std::string> ExternalFunctionNames, ExternalObjectNames; + public: + explicit IA64AsmPrinter(raw_ostream &O, TargetMachine &TM, + const TargetAsmInfo *T, CodeGenOpt::Level OL, + bool V) + : AsmPrinter(O, TM, T, OL, V) {} + + virtual const char *getPassName() const { + return "IA64 Assembly Printer"; + } + + /// 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); + + // This method is used by the tablegen'erated instruction printer. + void printOperand(const MachineInstr *MI, unsigned OpNo){ + const MachineOperand &MO = MI->getOperand(OpNo); + if (MO.getType() == MachineOperand::MO_Register) { + assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) && + "Not physref??"); + //XXX Bug Workaround: See note in Printer::doInitialization about %. + O << TM.getRegisterInfo()->get(MO.getReg()).AsmName; + } else { + printOp(MO); + } + } + + void printS8ImmOperand(const MachineInstr *MI, unsigned OpNo) { + int val=(unsigned int)MI->getOperand(OpNo).getImm(); + if(val>=128) val=val-256; // if negative, flip sign + O << val; + } + void printS14ImmOperand(const MachineInstr *MI, unsigned OpNo) { + int val=(unsigned int)MI->getOperand(OpNo).getImm(); + if(val>=8192) val=val-16384; // if negative, flip sign + O << val; + } + void printS22ImmOperand(const MachineInstr *MI, unsigned OpNo) { + int val=(unsigned int)MI->getOperand(OpNo).getImm(); + if(val>=2097152) val=val-4194304; // if negative, flip sign + O << val; + } + void printU64ImmOperand(const MachineInstr *MI, unsigned OpNo) { + O << (uint64_t)MI->getOperand(OpNo).getImm(); + } + void printS64ImmOperand(const MachineInstr *MI, unsigned OpNo) { +// XXX : nasty hack to avoid GPREL22 "relocation truncated to fit" linker +// errors - instead of add rX = @gprel(CPI<whatever>), r1;; we now +// emit movl rX = @gprel(CPI<whatever);; +// add rX = rX, r1; +// this gives us 64 bits instead of 22 (for the add long imm) to play +// with, which shuts up the linker. The problem is that the constant +// pool entries aren't immediates at this stage, so we check here. +// If it's an immediate, print it the old fashioned way. If it's +// not, we print it as a constant pool index. + if (MI->getOperand(OpNo).isImm()) { + O << (int64_t)MI->getOperand(OpNo).getImm(); + } else { // this is a constant pool reference: FIXME: assert this + printOp(MI->getOperand(OpNo)); + } + } + + void printGlobalOperand(const MachineInstr *MI, unsigned OpNo) { + printOp(MI->getOperand(OpNo), false); // this is NOT a br.call instruction + } + + void printCallOperand(const MachineInstr *MI, unsigned OpNo) { + printOp(MI->getOperand(OpNo), true); // this is a br.call instruction + } + + void printMachineInstruction(const MachineInstr *MI); + void printOp(const MachineOperand &MO, bool isBRCALLinsn= false); + void printModuleLevelGV(const GlobalVariable* GVar); + bool runOnMachineFunction(MachineFunction &F); + bool doInitialization(Module &M); + bool doFinalization(Module &M); + }; +} // end of anonymous namespace + + +// Include the auto-generated portion of the assembly writer. +#include "IA64GenAsmWriter.inc" + +/// runOnMachineFunction - This uses the printMachineInstruction() +/// method to print assembly for each instruction. +/// +bool IA64AsmPrinter::runOnMachineFunction(MachineFunction &MF) { + this->MF = &MF; + + SetupMachineFunction(MF); + O << "\n\n"; + + // Print out constants referenced by the function + EmitConstantPool(MF.getConstantPool()); + + const Function *F = MF.getFunction(); + SwitchToSection(TAI->SectionForGlobal(F)); + + // Print out labels for the function. + EmitAlignment(5); + O << "\t.global\t" << CurrentFnName << '\n'; + + printVisibility(CurrentFnName, F->getVisibility()); + + O << "\t.type\t" << CurrentFnName << ", @function\n"; + O << CurrentFnName << ":\n"; + + // 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 there are any predecessors. + if (!I->pred_empty()) { + printBasicBlockLabel(I, true, true); + O << '\n'; + } + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + // Print the assembly for the instruction. + printMachineInstruction(II); + } + } + + // We didn't modify anything. + return false; +} + +void IA64AsmPrinter::printOp(const MachineOperand &MO, + bool isBRCALLinsn /* = false */) { + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + switch (MO.getType()) { + case MachineOperand::MO_Register: + O << RI.get(MO.getReg()).AsmName; + return; + + case MachineOperand::MO_Immediate: + O << MO.getImm(); + return; + case MachineOperand::MO_MachineBasicBlock: + printBasicBlockLabel(MO.getMBB()); + return; + case MachineOperand::MO_ConstantPoolIndex: { + O << "@gprel(" << TAI->getPrivateGlobalPrefix() + << "CPI" << getFunctionNumber() << "_" << MO.getIndex() << ")"; + return; + } + + case MachineOperand::MO_GlobalAddress: { + + // functions need @ltoff(@fptr(fn_name)) form + GlobalValue *GV = MO.getGlobal(); + Function *F = dyn_cast<Function>(GV); + + bool Needfptr=false; // if we're computing an address @ltoff(X), do + // we need to decorate it so it becomes + // @ltoff(@fptr(X)) ? + if (F && !isBRCALLinsn /*&& F->isDeclaration()*/) + Needfptr=true; + + // if this is the target of a call instruction, we should define + // the function somewhere (GNU gas has no problem without this, but + // Intel ias rightly complains of an 'undefined symbol') + + if (F /*&& isBRCALLinsn*/ && F->isDeclaration()) + ExternalFunctionNames.insert(Mang->getValueName(MO.getGlobal())); + else + if (GV->isDeclaration()) // e.g. stuff like 'stdin' + ExternalObjectNames.insert(Mang->getValueName(MO.getGlobal())); + + if (!isBRCALLinsn) + O << "@ltoff("; + if (Needfptr) + O << "@fptr("; + O << Mang->getValueName(MO.getGlobal()); + + if (Needfptr && !isBRCALLinsn) + O << "#))"; // close both fptr( and ltoff( + else { + if (Needfptr) + O << "#)"; // close only fptr( + if (!isBRCALLinsn) + O << "#)"; // close only ltoff( + } + + int Offset = MO.getOffset(); + if (Offset > 0) + O << " + " << Offset; + else if (Offset < 0) + O << " - " << -Offset; + return; + } + case MachineOperand::MO_ExternalSymbol: + O << MO.getSymbolName(); + ExternalFunctionNames.insert(MO.getSymbolName()); + return; + default: + O << "<AsmPrinter: unknown operand type: " << MO.getType() << " >"; return; + } +} + +/// printMachineInstruction -- Print out a single IA64 LLVM instruction +/// MI to the current output stream. +/// +void IA64AsmPrinter::printMachineInstruction(const MachineInstr *MI) { + ++EmittedInsts; + + // Call the autogenerated instruction printer routines. + printInstruction(MI); +} + +bool IA64AsmPrinter::doInitialization(Module &M) { + bool Result = AsmPrinter::doInitialization(M); + + O << "\n.ident \"LLVM-ia64\"\n\n" + << "\t.psr lsb\n" // should be "msb" on HP-UX, for starters + << "\t.radix C\n" + << "\t.psr abi64\n"; // we only support 64 bits for now + return Result; +} + +void IA64AsmPrinter::printModuleLevelGV(const GlobalVariable* GVar) { + const TargetData *TD = TM.getTargetData(); + + if (!GVar->hasInitializer()) + return; // External global require no code + + // Check to see if this is a special global used by LLVM, if so, emit it. + if (EmitSpecialLLVMGlobal(GVar)) + return; + + O << "\n\n"; + std::string name = Mang->getValueName(GVar); + Constant *C = GVar->getInitializer(); + unsigned Size = TD->getTypeAllocSize(C->getType()); + unsigned Align = TD->getPreferredAlignmentLog(GVar); + + printVisibility(name, GVar->getVisibility()); + + SwitchToSection(TAI->SectionForGlobal(GVar)); + + if (C->isNullValue() && !GVar->hasSection()) { + if (!GVar->isThreadLocal() && + (GVar->hasLocalLinkage() || GVar->isWeakForLinker())) { + if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it. + + if (GVar->hasLocalLinkage()) { + O << "\t.lcomm " << name << "#," << Size + << ',' << (1 << Align); + O << '\n'; + } else { + O << "\t.common " << name << "#," << Size + << ',' << (1 << Align); + O << '\n'; + } + + return; + } + } + + switch (GVar->getLinkage()) { + case GlobalValue::LinkOnceAnyLinkage: + case GlobalValue::LinkOnceODRLinkage: + case GlobalValue::CommonLinkage: + case GlobalValue::WeakAnyLinkage: + case GlobalValue::WeakODRLinkage: + // Nonnull linkonce -> weak + O << "\t.weak " << name << '\n'; + 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 << TAI->getGlobalDirective() << name << '\n'; + // FALL THROUGH + case GlobalValue::InternalLinkage: + case GlobalValue::PrivateLinkage: + break; + case GlobalValue::GhostLinkage: + cerr << "GhostLinkage cannot appear in IA64AsmPrinter!\n"; + abort(); + case GlobalValue::DLLImportLinkage: + cerr << "DLLImport linkage is not supported by this target!\n"; + abort(); + case GlobalValue::DLLExportLinkage: + cerr << "DLLExport linkage is not supported by this target!\n"; + abort(); + default: + assert(0 && "Unknown linkage type!"); + } + + EmitAlignment(Align, GVar); + + if (TAI->hasDotTypeDotSizeDirective()) { + O << "\t.type " << name << ",@object\n"; + O << "\t.size " << name << ',' << Size << '\n'; + } + + O << name << ":\n"; + EmitGlobalConstant(C); +} + + +bool IA64AsmPrinter::doFinalization(Module &M) { + // Print out module-level global variables here. + for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); + I != E; ++I) + printModuleLevelGV(I); + + // we print out ".global X \n .type X, @function" for each external function + O << "\n\n// br.call targets referenced (and not defined) above: \n"; + for (std::set<std::string>::iterator i = ExternalFunctionNames.begin(), + e = ExternalFunctionNames.end(); i!=e; ++i) { + O << "\t.global " << *i << "\n\t.type " << *i << ", @function\n"; + } + O << "\n\n"; + + // we print out ".global X \n .type X, @object" for each external object + O << "\n\n// (external) symbols referenced (and not defined) above: \n"; + for (std::set<std::string>::iterator i = ExternalObjectNames.begin(), + e = ExternalObjectNames.end(); i!=e; ++i) { + O << "\t.global " << *i << "\n\t.type " << *i << ", @object\n"; + } + O << "\n\n"; + + return AsmPrinter::doFinalization(M); +} + +/// createIA64CodePrinterPass - Returns a pass that prints the IA64 +/// assembly code for a MachineFunction to the given output stream, using +/// the given target machine description. +/// +FunctionPass *llvm::createIA64CodePrinterPass(raw_ostream &o, + IA64TargetMachine &tm, + CodeGenOpt::Level OptLevel, + bool verbose) { + return new IA64AsmPrinter(o, tm, tm.getTargetAsmInfo(), OptLevel, verbose); +} diff --git a/lib/Target/IA64/AsmPrinter/Makefile b/lib/Target/IA64/AsmPrinter/Makefile new file mode 100644 index 0000000000000..12880f36f76dc --- /dev/null +++ b/lib/Target/IA64/AsmPrinter/Makefile @@ -0,0 +1,17 @@ +##===- lib/Target/IA64/AsmPrinter/Makefile -----------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME = LLVMIA64AsmPrinter + +# Hack: we need to include 'main' IA64 target directory to grab +# private headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/lib/Target/IA64/CMakeLists.txt b/lib/Target/IA64/CMakeLists.txt new file mode 100644 index 0000000000000..26f86ca197fc2 --- /dev/null +++ b/lib/Target/IA64/CMakeLists.txt @@ -0,0 +1,20 @@ +set(LLVM_TARGET_DEFINITIONS IA64.td) + +tablegen(IA64GenRegisterInfo.h.inc -gen-register-desc-header) +tablegen(IA64GenRegisterNames.inc -gen-register-enums) +tablegen(IA64GenRegisterInfo.inc -gen-register-desc) +tablegen(IA64GenInstrNames.inc -gen-instr-enums) +tablegen(IA64GenInstrInfo.inc -gen-instr-desc) +tablegen(IA64GenAsmWriter.inc -gen-asm-writer) +tablegen(IA64GenDAGISel.inc -gen-dag-isel) + +add_llvm_target(IA64CodeGen + IA64Bundling.cpp + IA64InstrInfo.cpp + IA64ISelDAGToDAG.cpp + IA64ISelLowering.cpp + IA64RegisterInfo.cpp + IA64Subtarget.cpp + IA64TargetAsmInfo.cpp + IA64TargetMachine.cpp + ) diff --git a/lib/Target/IA64/IA64.h b/lib/Target/IA64/IA64.h new file mode 100644 index 0000000000000..ec8e3d6d74da3 --- /dev/null +++ b/lib/Target/IA64/IA64.h @@ -0,0 +1,58 @@ +//===-- IA64.h - Top-level interface for IA64 representation ------*- C++ -*-===// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the entry points for global functions defined in the IA64 +// target library, as used by the LLVM JIT. +// +//===----------------------------------------------------------------------===// + +#ifndef TARGET_IA64_H +#define TARGET_IA64_H + +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +class IA64TargetMachine; +class FunctionPass; +class raw_ostream; + +/// createIA64DAGToDAGInstructionSelector - This pass converts an LLVM +/// function into IA64 machine code in a sane, DAG->DAG transform. +/// +FunctionPass *createIA64DAGToDAGInstructionSelector(IA64TargetMachine &TM); + +/// createIA64BundlingPass - This pass adds stop bits and bundles +/// instructions. +/// +FunctionPass *createIA64BundlingPass(IA64TargetMachine &TM); + +/// createIA64CodePrinterPass - Returns a pass that prints the IA64 +/// assembly code for a MachineFunction to the given output stream, +/// using the given target machine description. This should work +/// regardless of whether the function is in SSA form. +/// +FunctionPass *createIA64CodePrinterPass(raw_ostream &o, + IA64TargetMachine &tm, + CodeGenOpt::Level OptLevel, + bool verbose); + +} // End llvm namespace + +// Defines symbolic names for IA64 registers. This defines a mapping from +// register name to register number. +// +#include "IA64GenRegisterNames.inc" + +// Defines symbolic names for the IA64 instructions. +// +#include "IA64GenInstrNames.inc" + +#endif + + diff --git a/lib/Target/IA64/IA64.td b/lib/Target/IA64/IA64.td new file mode 100644 index 0000000000000..c469281ab16e8 --- /dev/null +++ b/lib/Target/IA64/IA64.td @@ -0,0 +1,39 @@ +//===-- IA64.td - Target definition file for Intel IA64 -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a target description file for the Intel IA64 architecture, +// also known variously as ia64, IA-64, IPF, "the Itanium architecture" etc. +// +//===----------------------------------------------------------------------===// + +// Get the target-independent interfaces which we are implementing... +// +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// Register File Description +//===----------------------------------------------------------------------===// + +include "IA64RegisterInfo.td" + +//===----------------------------------------------------------------------===// +// Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "IA64InstrInfo.td" + +def IA64InstrInfo : InstrInfo { } + +def IA64 : Target { + // Our instruction set + let InstructionSet = IA64InstrInfo; + +} + + diff --git a/lib/Target/IA64/IA64Bundling.cpp b/lib/Target/IA64/IA64Bundling.cpp new file mode 100644 index 0000000000000..3a9ba6ca3f617 --- /dev/null +++ b/lib/Target/IA64/IA64Bundling.cpp @@ -0,0 +1,118 @@ +//===-- IA64Bundling.cpp - IA-64 instruction bundling pass. ------------ --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Add stops where required to prevent read-after-write and write-after-write +// dependencies, for both registers and memory addresses. There are exceptions: +// +// - Compare instructions (cmp*, tbit, tnat, fcmp, frcpa) are OK with +// WAW dependencies so long as they all target p0, or are of parallel +// type (.and*/.or*) +// +// FIXME: bundling, for now, is left to the assembler. +// FIXME: this might be an appropriate place to translate between different +// instructions that do the same thing, if this helps bundling. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "ia64-codegen" +#include "IA64.h" +#include "IA64InstrInfo.h" +#include "IA64TargetMachine.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/ADT/SetOperations.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/Debug.h" +#include <set> +using namespace llvm; + +STATISTIC(StopBitsAdded, "Number of stop bits added"); + +namespace { + struct IA64BundlingPass : public MachineFunctionPass { + static char ID; + /// Target machine description which we query for reg. names, data + /// layout, etc. + /// + IA64TargetMachine &TM; + + IA64BundlingPass(IA64TargetMachine &tm) + : MachineFunctionPass(&ID), TM(tm) { } + + virtual const char *getPassName() const { + return "IA64 (Itanium) Bundling Pass"; + } + + bool runOnMachineBasicBlock(MachineBasicBlock &MBB); + bool runOnMachineFunction(MachineFunction &F) { + bool Changed = false; + for (MachineFunction::iterator FI = F.begin(), FE = F.end(); + FI != FE; ++FI) + Changed |= runOnMachineBasicBlock(*FI); + return Changed; + } + + // XXX: ugly global, but pending writes can cross basic blocks. Note that + // taken branches end instruction groups. So we only need to worry about + // 'fallthrough' code + std::set<unsigned> PendingRegWrites; + }; + char IA64BundlingPass::ID = 0; +} // end of anonymous namespace + +/// createIA64BundlingPass - Returns a pass that adds STOP (;;) instructions +/// and arranges the result into bundles. +/// +FunctionPass *llvm::createIA64BundlingPass(IA64TargetMachine &tm) { + return new IA64BundlingPass(tm); +} + +/// runOnMachineBasicBlock - add stops and bundle this MBB. +/// +bool IA64BundlingPass::runOnMachineBasicBlock(MachineBasicBlock &MBB) { + bool Changed = false; + + for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) { + MachineInstr *CurrentInsn = I++; + std::set<unsigned> CurrentReads, CurrentWrites, OrigWrites; + + for(unsigned i=0; i < CurrentInsn->getNumOperands(); i++) { + MachineOperand &MO=CurrentInsn->getOperand(i); + if (MO.isReg()) { + if(MO.isUse()) { // TODO: exclude p0 + CurrentReads.insert(MO.getReg()); + } + if(MO.isDef()) { // TODO: exclude p0 + CurrentWrites.insert(MO.getReg()); + OrigWrites.insert(MO.getReg()); // FIXME: use a nondestructive + // set_intersect instead? + } + } + } + + // CurrentReads/CurrentWrites contain info for the current instruction. + // Does it read or write any registers that are pending a write? + // (i.e. not separated by a stop) + set_intersect(CurrentReads, PendingRegWrites); + set_intersect(CurrentWrites, PendingRegWrites); + + if(! (CurrentReads.empty() && CurrentWrites.empty()) ) { + // there is a conflict, insert a stop and reset PendingRegWrites + CurrentInsn = BuildMI(MBB, CurrentInsn, CurrentInsn->getDebugLoc(), + TM.getInstrInfo()->get(IA64::STOP), 0); + PendingRegWrites=OrigWrites; // carry over current writes to next insn + Changed=true; StopBitsAdded++; // update stats + } else { // otherwise, track additional pending writes + set_union(PendingRegWrites, OrigWrites); + } + } // onto the next insn in the MBB + + return Changed; +} + diff --git a/lib/Target/IA64/IA64ISelDAGToDAG.cpp b/lib/Target/IA64/IA64ISelDAGToDAG.cpp new file mode 100644 index 0000000000000..9800c506ca9ea --- /dev/null +++ b/lib/Target/IA64/IA64ISelDAGToDAG.cpp @@ -0,0 +1,575 @@ +//===---- IA64ISelDAGToDAG.cpp - IA64 pattern matching inst selector ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a pattern matching instruction selector for IA64, +// converting a legalized dag to an IA64 dag. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "ia64-codegen" +#include "IA64.h" +#include "IA64TargetMachine.h" +#include "IA64ISelLowering.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Constants.h" +#include "llvm/GlobalValue.h" +#include "llvm/Intrinsics.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" +using namespace llvm; + +namespace { + //===--------------------------------------------------------------------===// + /// IA64DAGToDAGISel - IA64 specific code to select IA64 machine + /// instructions for SelectionDAG operations. + /// + class IA64DAGToDAGISel : public SelectionDAGISel { + unsigned GlobalBaseReg; + public: + explicit IA64DAGToDAGISel(IA64TargetMachine &TM) + : SelectionDAGISel(TM) {} + + virtual bool runOnFunction(Function &Fn) { + // Make sure we re-emit a set of the global base reg if necessary + GlobalBaseReg = 0; + return SelectionDAGISel::runOnFunction(Fn); + } + + /// getI64Imm - Return a target constant with the specified value, of type + /// i64. + inline SDValue getI64Imm(uint64_t Imm) { + return CurDAG->getTargetConstant(Imm, MVT::i64); + } + + /// getGlobalBaseReg - insert code into the entry mbb to materialize the PIC + /// base register. Return the virtual register that holds this value. + // SDValue getGlobalBaseReg(); TODO: hmm + + // Select - Convert the specified operand from a target-independent to a + // target-specific node if it hasn't already been changed. + SDNode *Select(SDValue N); + + SDNode *SelectIntImmediateExpr(SDValue LHS, SDValue RHS, + unsigned OCHi, unsigned OCLo, + bool IsArithmetic = false, + bool Negate = false); + SDNode *SelectBitfieldInsert(SDNode *N); + + /// SelectCC - Select a comparison of the specified values with the + /// specified condition code, returning the CR# of the expression. + SDValue SelectCC(SDValue LHS, SDValue RHS, ISD::CondCode CC); + + /// SelectAddr - Given the specified address, return the two operands for a + /// load/store instruction, and return true if it should be an indexed [r+r] + /// operation. + bool SelectAddr(SDValue Addr, SDValue &Op1, SDValue &Op2); + + /// InstructionSelect - This callback is invoked by + /// SelectionDAGISel when it has created a SelectionDAG for us to codegen. + virtual void InstructionSelect(); + + virtual const char *getPassName() const { + return "IA64 (Itanium) DAG->DAG Instruction Selector"; + } + +// Include the pieces autogenerated from the target description. +#include "IA64GenDAGISel.inc" + +private: + SDNode *SelectDIV(SDValue Op); + }; +} + +/// InstructionSelect - This callback is invoked by +/// SelectionDAGISel when it has created a SelectionDAG for us to codegen. +void IA64DAGToDAGISel::InstructionSelect() { + DEBUG(BB->dump()); + + // Select target instructions for the DAG. + SelectRoot(*CurDAG); + CurDAG->RemoveDeadNodes(); +} + +SDNode *IA64DAGToDAGISel::SelectDIV(SDValue Op) { + SDNode *N = Op.getNode(); + SDValue Chain = N->getOperand(0); + SDValue Tmp1 = N->getOperand(0); + SDValue Tmp2 = N->getOperand(1); + DebugLoc dl = N->getDebugLoc(); + + bool isFP=false; + + if(Tmp1.getValueType().isFloatingPoint()) + isFP=true; + + bool isModulus=false; // is it a division or a modulus? + bool isSigned=false; + + switch(N->getOpcode()) { + case ISD::FDIV: + case ISD::SDIV: isModulus=false; isSigned=true; break; + case ISD::UDIV: isModulus=false; isSigned=false; break; + case ISD::FREM: + case ISD::SREM: isModulus=true; isSigned=true; break; + case ISD::UREM: isModulus=true; isSigned=false; break; + } + + // TODO: check for integer divides by powers of 2 (or other simple patterns?) + + SDValue TmpPR, TmpPR2; + SDValue TmpF1, TmpF2, TmpF3, TmpF4, TmpF5, TmpF6, TmpF7, TmpF8; + SDValue TmpF9, TmpF10,TmpF11,TmpF12,TmpF13,TmpF14,TmpF15; + SDNode *Result; + + // we'll need copies of F0 and F1 + SDValue F0 = CurDAG->getRegister(IA64::F0, MVT::f64); + SDValue F1 = CurDAG->getRegister(IA64::F1, MVT::f64); + + // OK, emit some code: + + if(!isFP) { + // first, load the inputs into FP regs. + TmpF1 = + SDValue(CurDAG->getTargetNode(IA64::SETFSIG, dl, MVT::f64, Tmp1), 0); + Chain = TmpF1.getValue(1); + TmpF2 = + SDValue(CurDAG->getTargetNode(IA64::SETFSIG, dl, MVT::f64, Tmp2), 0); + Chain = TmpF2.getValue(1); + + // next, convert the inputs to FP + if(isSigned) { + TmpF3 = + SDValue(CurDAG->getTargetNode(IA64::FCVTXF, dl, MVT::f64, TmpF1), 0); + Chain = TmpF3.getValue(1); + TmpF4 = + SDValue(CurDAG->getTargetNode(IA64::FCVTXF, dl, MVT::f64, TmpF2), 0); + Chain = TmpF4.getValue(1); + } else { // is unsigned + TmpF3 = + SDValue(CurDAG->getTargetNode(IA64::FCVTXUFS1, dl, MVT::f64, TmpF1), + 0); + Chain = TmpF3.getValue(1); + TmpF4 = + SDValue(CurDAG->getTargetNode(IA64::FCVTXUFS1, dl, MVT::f64, TmpF2), + 0); + Chain = TmpF4.getValue(1); + } + + } else { // this is an FP divide/remainder, so we 'leak' some temp + // regs and assign TmpF3=Tmp1, TmpF4=Tmp2 + TmpF3=Tmp1; + TmpF4=Tmp2; + } + + // we start by computing an approximate reciprocal (good to 9 bits?) + // note, this instruction writes _both_ TmpF5 (answer) and TmpPR (predicate) + if(isFP) + TmpF5 = SDValue(CurDAG->getTargetNode(IA64::FRCPAS0, dl, MVT::f64, + MVT::i1, TmpF3, TmpF4), 0); + else + TmpF5 = SDValue(CurDAG->getTargetNode(IA64::FRCPAS1, dl, MVT::f64, + MVT::i1, TmpF3, TmpF4), 0); + + TmpPR = TmpF5.getValue(1); + Chain = TmpF5.getValue(2); + + SDValue minusB; + if(isModulus) { // for remainders, it'll be handy to have + // copies of -input_b + minusB = SDValue(CurDAG->getTargetNode(IA64::SUB, dl, MVT::i64, + CurDAG->getRegister(IA64::r0, MVT::i64), Tmp2), 0); + Chain = minusB.getValue(1); + } + + SDValue TmpE0, TmpY1, TmpE1, TmpY2; + + SDValue OpsE0[] = { TmpF4, TmpF5, F1, TmpPR }; + TmpE0 = SDValue(CurDAG->getTargetNode(IA64::CFNMAS1, dl, MVT::f64, + OpsE0, 4), 0); + Chain = TmpE0.getValue(1); + SDValue OpsY1[] = { TmpF5, TmpE0, TmpF5, TmpPR }; + TmpY1 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64, + OpsY1, 4), 0); + Chain = TmpY1.getValue(1); + SDValue OpsE1[] = { TmpE0, TmpE0, F0, TmpPR }; + TmpE1 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64, + OpsE1, 4), 0); + Chain = TmpE1.getValue(1); + SDValue OpsY2[] = { TmpY1, TmpE1, TmpY1, TmpPR }; + TmpY2 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64, + OpsY2, 4), 0); + Chain = TmpY2.getValue(1); + + if(isFP) { // if this is an FP divide, we finish up here and exit early + if(isModulus) + assert(0 && "Sorry, try another FORTRAN compiler."); + + SDValue TmpE2, TmpY3, TmpQ0, TmpR0; + + SDValue OpsE2[] = { TmpE1, TmpE1, F0, TmpPR }; + TmpE2 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64, + OpsE2, 4), 0); + Chain = TmpE2.getValue(1); + SDValue OpsY3[] = { TmpY2, TmpE2, TmpY2, TmpPR }; + TmpY3 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64, + OpsY3, 4), 0); + Chain = TmpY3.getValue(1); + SDValue OpsQ0[] = { Tmp1, TmpY3, F0, TmpPR }; + TmpQ0 = + SDValue(CurDAG->getTargetNode(IA64::CFMADS1, dl, // double prec! + MVT::f64, OpsQ0, 4), 0); + Chain = TmpQ0.getValue(1); + SDValue OpsR0[] = { Tmp2, TmpQ0, Tmp1, TmpPR }; + TmpR0 = + SDValue(CurDAG->getTargetNode(IA64::CFNMADS1, dl, // double prec! + MVT::f64, OpsR0, 4), 0); + Chain = TmpR0.getValue(1); + +// we want Result to have the same target register as the frcpa, so +// we two-address hack it. See the comment "for this to work..." on +// page 48 of Intel application note #245415 + SDValue Ops[] = { TmpF5, TmpY3, TmpR0, TmpQ0, TmpPR }; + Result = CurDAG->getTargetNode(IA64::TCFMADS0, dl, // d.p. s0 rndg! + MVT::f64, Ops, 5); + Chain = SDValue(Result, 1); + return Result; // XXX: early exit! + } else { // this is *not* an FP divide, so there's a bit left to do: + + SDValue TmpQ2, TmpR2, TmpQ3, TmpQ; + + SDValue OpsQ2[] = { TmpF3, TmpY2, F0, TmpPR }; + TmpQ2 = SDValue(CurDAG->getTargetNode(IA64::CFMAS1, dl, MVT::f64, + OpsQ2, 4), 0); + Chain = TmpQ2.getValue(1); + SDValue OpsR2[] = { TmpF4, TmpQ2, TmpF3, TmpPR }; + TmpR2 = SDValue(CurDAG->getTargetNode(IA64::CFNMAS1, dl, MVT::f64, + OpsR2, 4), 0); + Chain = TmpR2.getValue(1); + +// we want TmpQ3 to have the same target register as the frcpa? maybe we +// should two-address hack it. See the comment "for this to work..." on page +// 48 of Intel application note #245415 + SDValue OpsQ3[] = { TmpF5, TmpR2, TmpY2, TmpQ2, TmpPR }; + TmpQ3 = SDValue(CurDAG->getTargetNode(IA64::TCFMAS1, dl, MVT::f64, + OpsQ3, 5), 0); + Chain = TmpQ3.getValue(1); + + // STORY: without these two-address instructions (TCFMAS1 and TCFMADS0) + // the FPSWA won't be able to help out in the case of large/tiny + // arguments. Other fun bugs may also appear, e.g. 0/x = x, not 0. + + if(isSigned) + TmpQ = SDValue(CurDAG->getTargetNode(IA64::FCVTFXTRUNCS1, dl, + MVT::f64, TmpQ3), 0); + else + TmpQ = SDValue(CurDAG->getTargetNode(IA64::FCVTFXUTRUNCS1, dl, + MVT::f64, TmpQ3), 0); + + Chain = TmpQ.getValue(1); + + if(isModulus) { + SDValue FPminusB = + SDValue(CurDAG->getTargetNode(IA64::SETFSIG, dl, MVT::f64, minusB), + 0); + Chain = FPminusB.getValue(1); + SDValue Remainder = + SDValue(CurDAG->getTargetNode(IA64::XMAL, dl, MVT::f64, + TmpQ, FPminusB, TmpF1), 0); + Chain = Remainder.getValue(1); + Result = CurDAG->getTargetNode(IA64::GETFSIG, dl, MVT::i64, Remainder); + Chain = SDValue(Result, 1); + } else { // just an integer divide + Result = CurDAG->getTargetNode(IA64::GETFSIG, dl, MVT::i64, TmpQ); + Chain = SDValue(Result, 1); + } + + return Result; + } // wasn't an FP divide +} + +// Select - Convert the specified operand from a target-independent to a +// target-specific node if it hasn't already been changed. +SDNode *IA64DAGToDAGISel::Select(SDValue Op) { + SDNode *N = Op.getNode(); + if (N->isMachineOpcode()) + return NULL; // Already selected. + DebugLoc dl = Op.getDebugLoc(); + + switch (N->getOpcode()) { + default: break; + + case IA64ISD::BRCALL: { // XXX: this is also a hack! + SDValue Chain = N->getOperand(0); + SDValue InFlag; // Null incoming flag value. + + if(N->getNumOperands()==3) { // we have an incoming chain, callee and flag + InFlag = N->getOperand(2); + } + + unsigned CallOpcode; + SDValue CallOperand; + + // if we can call directly, do so + if (GlobalAddressSDNode *GASD = + dyn_cast<GlobalAddressSDNode>(N->getOperand(1))) { + CallOpcode = IA64::BRCALL_IPREL_GA; + CallOperand = CurDAG->getTargetGlobalAddress(GASD->getGlobal(), MVT::i64); + } else if (isa<ExternalSymbolSDNode>(N->getOperand(1))) { + // FIXME: we currently NEED this case for correctness, to avoid + // "non-pic code with imm reloc.n against dynamic symbol" errors + CallOpcode = IA64::BRCALL_IPREL_ES; + CallOperand = N->getOperand(1); + } else { + // otherwise we need to load the function descriptor, + // load the branch target (function)'s entry point and GP, + // branch (call) then restore the GP + SDValue FnDescriptor = N->getOperand(1); + + // load the branch target's entry point [mem] and + // GP value [mem+8] + SDValue targetEntryPoint= + SDValue(CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, MVT::Other, + FnDescriptor, CurDAG->getEntryNode()), 0); + Chain = targetEntryPoint.getValue(1); + SDValue targetGPAddr= + SDValue(CurDAG->getTargetNode(IA64::ADDS, dl, MVT::i64, + FnDescriptor, + CurDAG->getConstant(8, MVT::i64)), 0); + Chain = targetGPAddr.getValue(1); + SDValue targetGP = + SDValue(CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64,MVT::Other, + targetGPAddr, CurDAG->getEntryNode()), 0); + Chain = targetGP.getValue(1); + + Chain = CurDAG->getCopyToReg(Chain, dl, IA64::r1, targetGP, InFlag); + InFlag = Chain.getValue(1); + Chain = CurDAG->getCopyToReg(Chain, dl, IA64::B6, + targetEntryPoint, InFlag); // FLAG these? + InFlag = Chain.getValue(1); + + CallOperand = CurDAG->getRegister(IA64::B6, MVT::i64); + CallOpcode = IA64::BRCALL_INDIRECT; + } + + // Finally, once everything is setup, emit the call itself + if (InFlag.getNode()) + Chain = SDValue(CurDAG->getTargetNode(CallOpcode, dl, MVT::Other, + MVT::Flag, CallOperand, InFlag), 0); + else // there might be no arguments + Chain = SDValue(CurDAG->getTargetNode(CallOpcode, dl, MVT::Other, + MVT::Flag, CallOperand, Chain), 0); + InFlag = Chain.getValue(1); + + std::vector<SDValue> CallResults; + + CallResults.push_back(Chain); + CallResults.push_back(InFlag); + + for (unsigned i = 0, e = CallResults.size(); i != e; ++i) + ReplaceUses(Op.getValue(i), CallResults[i]); + return NULL; + } + + case IA64ISD::GETFD: { + SDValue Input = N->getOperand(0); + return CurDAG->getTargetNode(IA64::GETFD, dl, MVT::i64, Input); + } + + case ISD::FDIV: + case ISD::SDIV: + case ISD::UDIV: + case ISD::SREM: + case ISD::UREM: + return SelectDIV(Op); + + case ISD::TargetConstantFP: { + SDValue Chain = CurDAG->getEntryNode(); // this is a constant, so.. + + SDValue V; + ConstantFPSDNode* N2 = cast<ConstantFPSDNode>(N); + if (N2->getValueAPF().isPosZero()) { + V = CurDAG->getCopyFromReg(Chain, dl, IA64::F0, MVT::f64); + } else if (N2->isExactlyValue(N2->getValueType(0) == MVT::f32 ? + APFloat(+1.0f) : APFloat(+1.0))) { + V = CurDAG->getCopyFromReg(Chain, dl, IA64::F1, MVT::f64); + } else + assert(0 && "Unexpected FP constant!"); + + ReplaceUses(SDValue(N, 0), V); + return 0; + } + + case ISD::FrameIndex: { // TODO: reduce creepyness + int FI = cast<FrameIndexSDNode>(N)->getIndex(); + if (N->hasOneUse()) + return CurDAG->SelectNodeTo(N, IA64::MOV, MVT::i64, + CurDAG->getTargetFrameIndex(FI, MVT::i64)); + else + return CurDAG->getTargetNode(IA64::MOV, dl, MVT::i64, + CurDAG->getTargetFrameIndex(FI, MVT::i64)); + } + + case ISD::ConstantPool: { // TODO: nuke the constant pool + // (ia64 doesn't need one) + ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(N); + Constant *C = CP->getConstVal(); + SDValue CPI = CurDAG->getTargetConstantPool(C, MVT::i64, + CP->getAlignment()); + return CurDAG->getTargetNode(IA64::ADDL_GA, dl, MVT::i64, // ? + CurDAG->getRegister(IA64::r1, MVT::i64), CPI); + } + + case ISD::GlobalAddress: { + GlobalValue *GV = cast<GlobalAddressSDNode>(N)->getGlobal(); + SDValue GA = CurDAG->getTargetGlobalAddress(GV, MVT::i64); + SDValue Tmp = + SDValue(CurDAG->getTargetNode(IA64::ADDL_GA, dl, MVT::i64, + CurDAG->getRegister(IA64::r1, + MVT::i64), GA), 0); + return CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, MVT::Other, Tmp, + CurDAG->getEntryNode()); + } + +/* XXX + case ISD::ExternalSymbol: { + SDValue EA = CurDAG->getTargetExternalSymbol( + cast<ExternalSymbolSDNode>(N)->getSymbol(), + MVT::i64); + SDValue Tmp = CurDAG->getTargetNode(IA64::ADDL_EA, dl, MVT::i64, + CurDAG->getRegister(IA64::r1, + MVT::i64), + EA); + return CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, Tmp); + } +*/ + + case ISD::LOAD: { // FIXME: load -1, not 1, for bools? + LoadSDNode *LD = cast<LoadSDNode>(N); + SDValue Chain = LD->getChain(); + SDValue Address = LD->getBasePtr(); + + MVT TypeBeingLoaded = LD->getMemoryVT(); + unsigned Opc; + switch (TypeBeingLoaded.getSimpleVT()) { + default: +#ifndef NDEBUG + N->dump(CurDAG); +#endif + assert(0 && "Cannot load this type!"); + case MVT::i1: { // this is a bool + Opc = IA64::LD1; // first we load a byte, then compare for != 0 + if(N->getValueType(0) == MVT::i1) { // XXX: early exit! + return CurDAG->SelectNodeTo(N, IA64::CMPNE, MVT::i1, MVT::Other, + SDValue(CurDAG->getTargetNode(Opc, dl, + MVT::i64, + Address), 0), + CurDAG->getRegister(IA64::r0, MVT::i64), + Chain); + } + /* otherwise, we want to load a bool into something bigger: LD1 + will do that for us, so we just fall through */ + } + case MVT::i8: Opc = IA64::LD1; break; + case MVT::i16: Opc = IA64::LD2; break; + case MVT::i32: Opc = IA64::LD4; break; + case MVT::i64: Opc = IA64::LD8; break; + + case MVT::f32: Opc = IA64::LDF4; break; + case MVT::f64: Opc = IA64::LDF8; break; + } + + // TODO: comment this + return CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other, + Address, Chain); + } + + case ISD::STORE: { + StoreSDNode *ST = cast<StoreSDNode>(N); + SDValue Address = ST->getBasePtr(); + SDValue Chain = ST->getChain(); + + unsigned Opc; + if (ISD::isNON_TRUNCStore(N)) { + switch (N->getOperand(1).getValueType().getSimpleVT()) { + default: assert(0 && "unknown type in store"); + case MVT::i1: { // this is a bool + Opc = IA64::ST1; // we store either 0 or 1 as a byte + // first load zero! + SDValue Initial = CurDAG->getCopyFromReg(Chain, dl, IA64::r0, MVT::i64); + Chain = Initial.getValue(1); + // then load 1 into the same reg iff the predicate to store is 1 + SDValue Tmp = ST->getValue(); + Tmp = + SDValue(CurDAG->getTargetNode(IA64::TPCADDS, dl, MVT::i64, Initial, + CurDAG->getTargetConstant(1, + MVT::i64), + Tmp), 0); + return CurDAG->SelectNodeTo(N, Opc, MVT::Other, Address, Tmp, Chain); + } + case MVT::i64: Opc = IA64::ST8; break; + case MVT::f64: Opc = IA64::STF8; break; + } + } else { // Truncating store + switch(ST->getMemoryVT().getSimpleVT()) { + default: assert(0 && "unknown type in truncstore"); + case MVT::i8: Opc = IA64::ST1; break; + case MVT::i16: Opc = IA64::ST2; break; + case MVT::i32: Opc = IA64::ST4; break; + case MVT::f32: Opc = IA64::STF4; break; + } + } + + SDValue N1 = N->getOperand(1); + SDValue N2 = N->getOperand(2); + return CurDAG->SelectNodeTo(N, Opc, MVT::Other, N2, N1, Chain); + } + + case ISD::BRCOND: { + SDValue Chain = N->getOperand(0); + SDValue CC = N->getOperand(1); + MachineBasicBlock *Dest = + cast<BasicBlockSDNode>(N->getOperand(2))->getBasicBlock(); + //FIXME - we do NOT need long branches all the time + return CurDAG->SelectNodeTo(N, IA64::BRLCOND_NOTCALL, MVT::Other, CC, + CurDAG->getBasicBlock(Dest), Chain); + } + + case ISD::CALLSEQ_START: + case ISD::CALLSEQ_END: { + int64_t Amt = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue(); + unsigned Opc = N->getOpcode() == ISD::CALLSEQ_START ? + IA64::ADJUSTCALLSTACKDOWN : IA64::ADJUSTCALLSTACKUP; + SDValue N0 = N->getOperand(0); + return CurDAG->SelectNodeTo(N, Opc, MVT::Other, getI64Imm(Amt), N0); + } + + case ISD::BR: + // FIXME: we don't need long branches all the time! + SDValue N0 = N->getOperand(0); + return CurDAG->SelectNodeTo(N, IA64::BRL_NOTCALL, MVT::Other, + N->getOperand(1), N0); + } + + return SelectCode(Op); +} + + +/// createIA64DAGToDAGInstructionSelector - This pass converts a legalized DAG +/// into an IA64-specific DAG, ready for instruction scheduling. +/// +FunctionPass +*llvm::createIA64DAGToDAGInstructionSelector(IA64TargetMachine &TM) { + return new IA64DAGToDAGISel(TM); +} + diff --git a/lib/Target/IA64/IA64ISelLowering.cpp b/lib/Target/IA64/IA64ISelLowering.cpp new file mode 100644 index 0000000000000..34a0686564c07 --- /dev/null +++ b/lib/Target/IA64/IA64ISelLowering.cpp @@ -0,0 +1,622 @@ +//===-- IA64ISelLowering.cpp - IA64 DAG Lowering Implementation -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the IA64ISelLowering class. +// +//===----------------------------------------------------------------------===// + +#include "IA64ISelLowering.h" +#include "IA64MachineFunctionInfo.h" +#include "IA64TargetMachine.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Constants.h" +#include "llvm/Function.h" +using namespace llvm; + +IA64TargetLowering::IA64TargetLowering(TargetMachine &TM) + : TargetLowering(TM) { + + // register class for general registers + addRegisterClass(MVT::i64, IA64::GRRegisterClass); + + // register class for FP registers + addRegisterClass(MVT::f64, IA64::FPRegisterClass); + + // register class for predicate registers + addRegisterClass(MVT::i1, IA64::PRRegisterClass); + + setLoadExtAction(ISD::EXTLOAD , MVT::i1 , Promote); + + setLoadExtAction(ISD::ZEXTLOAD , MVT::i1 , Promote); + + setLoadExtAction(ISD::SEXTLOAD , MVT::i1 , Promote); + setLoadExtAction(ISD::SEXTLOAD , MVT::i8 , Expand); + setLoadExtAction(ISD::SEXTLOAD , MVT::i16 , Expand); + setLoadExtAction(ISD::SEXTLOAD , MVT::i32 , Expand); + + setOperationAction(ISD::BRIND , MVT::Other, Expand); + setOperationAction(ISD::BR_JT , MVT::Other, Expand); + setOperationAction(ISD::BR_CC , MVT::Other, Expand); + setOperationAction(ISD::FP_ROUND_INREG , MVT::f32 , Expand); + + // ia64 uses SELECT not SELECT_CC + setOperationAction(ISD::SELECT_CC , MVT::Other, Expand); + + // We need to handle ISD::RET for void functions ourselves, + // so we get a chance to restore ar.pfs before adding a + // br.ret insn + setOperationAction(ISD::RET, MVT::Other, Custom); + + setShiftAmountType(MVT::i64); + + setOperationAction(ISD::FREM , MVT::f32 , Expand); + setOperationAction(ISD::FREM , MVT::f64 , Expand); + + setOperationAction(ISD::UREM , MVT::f32 , Expand); + setOperationAction(ISD::UREM , MVT::f64 , Expand); + + setOperationAction(ISD::MEMBARRIER , MVT::Other, Expand); + + setOperationAction(ISD::SINT_TO_FP , MVT::i1 , Promote); + setOperationAction(ISD::UINT_TO_FP , MVT::i1 , Promote); + + // We don't support sin/cos/sqrt/pow + setOperationAction(ISD::FSIN , MVT::f64, Expand); + setOperationAction(ISD::FCOS , MVT::f64, Expand); + setOperationAction(ISD::FSQRT, MVT::f64, Expand); + setOperationAction(ISD::FPOW , MVT::f64, Expand); + setOperationAction(ISD::FSIN , MVT::f32, Expand); + setOperationAction(ISD::FCOS , MVT::f32, Expand); + setOperationAction(ISD::FSQRT, MVT::f32, Expand); + setOperationAction(ISD::FPOW , MVT::f32, Expand); + + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand); + + // FIXME: IA64 supports fcopysign natively! + setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand); + setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand); + + // We don't have line number support yet. + setOperationAction(ISD::DBG_STOPPOINT, MVT::Other, Expand); + setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand); + setOperationAction(ISD::DBG_LABEL, MVT::Other, Expand); + setOperationAction(ISD::EH_LABEL, MVT::Other, Expand); + + // IA64 has ctlz in the form of the 'fnorm' instruction. The Legalizer + // expansion for ctlz/cttz in terms of ctpop is much larger, but lower + // latency. + // FIXME: Custom lower CTLZ when compiling for size? + setOperationAction(ISD::CTLZ , MVT::i64 , Expand); + setOperationAction(ISD::CTTZ , MVT::i64 , Expand); + setOperationAction(ISD::ROTL , MVT::i64 , Expand); + setOperationAction(ISD::ROTR , MVT::i64 , Expand); + + // FIXME: IA64 has this, but is not implemented. should be mux @rev + setOperationAction(ISD::BSWAP, MVT::i64 , Expand); + + // VASTART needs to be custom lowered to use the VarArgsFrameIndex + setOperationAction(ISD::VAARG , MVT::Other, Custom); + setOperationAction(ISD::VASTART , MVT::Other, Custom); + + // Use the default implementation. + setOperationAction(ISD::VACOPY , MVT::Other, Expand); + setOperationAction(ISD::VAEND , MVT::Other, Expand); + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand); + + // Thread Local Storage + setOperationAction(ISD::GlobalTLSAddress, MVT::i64, Custom); + + setStackPointerRegisterToSaveRestore(IA64::r12); + + setJumpBufSize(704); // on ia64-linux, jmp_bufs are 704 bytes.. + setJumpBufAlignment(16); // ...and must be 16-byte aligned + + computeRegisterProperties(); + + addLegalFPImmediate(APFloat(+0.0)); + addLegalFPImmediate(APFloat(-0.0)); + addLegalFPImmediate(APFloat(+1.0)); + addLegalFPImmediate(APFloat(-1.0)); +} + +const char *IA64TargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + default: return 0; + case IA64ISD::GETFD: return "IA64ISD::GETFD"; + case IA64ISD::BRCALL: return "IA64ISD::BRCALL"; + case IA64ISD::RET_FLAG: return "IA64ISD::RET_FLAG"; + } +} + +MVT IA64TargetLowering::getSetCCResultType(MVT VT) const { + return MVT::i1; +} + +void IA64TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &ArgValues, + DebugLoc dl) { + // + // add beautiful description of IA64 stack frame format + // here (from intel 24535803.pdf most likely) + // + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + + GP = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i64)); + SP = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i64)); + RP = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i64)); + + MachineBasicBlock& BB = MF.front(); + + unsigned args_int[] = {IA64::r32, IA64::r33, IA64::r34, IA64::r35, + IA64::r36, IA64::r37, IA64::r38, IA64::r39}; + + unsigned args_FP[] = {IA64::F8, IA64::F9, IA64::F10, IA64::F11, + IA64::F12,IA64::F13,IA64::F14, IA64::F15}; + + unsigned argVreg[8]; + unsigned argPreg[8]; + unsigned argOpc[8]; + + unsigned used_FPArgs = 0; // how many FP args have been used so far? + + unsigned ArgOffset = 0; + int count = 0; + + for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I) + { + SDValue newroot, argt; + if(count < 8) { // need to fix this logic? maybe. + + switch (getValueType(I->getType()).getSimpleVT()) { + default: + assert(0 && "ERROR in LowerArgs: can't lower this type of arg.\n"); + case MVT::f32: + // fixme? (well, will need to for weird FP structy stuff, + // see intel ABI docs) + case MVT::f64: +//XXX BuildMI(&BB, IA64::IDEF, 0, args_FP[used_FPArgs]); + MF.getRegInfo().addLiveIn(args_FP[used_FPArgs]); + // mark this reg as liveIn + // floating point args go into f8..f15 as-needed, the increment + argVreg[count] = // is below..: + MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::f64)); + // FP args go into f8..f15 as needed: (hence the ++) + argPreg[count] = args_FP[used_FPArgs++]; + argOpc[count] = IA64::FMOV; + argt = newroot = DAG.getCopyFromReg(DAG.getRoot(), dl, + argVreg[count], MVT::f64); + if (I->getType() == Type::FloatTy) + argt = DAG.getNode(ISD::FP_ROUND, dl, MVT::f32, argt, + DAG.getIntPtrConstant(0)); + break; + case MVT::i1: // NOTE: as far as C abi stuff goes, + // bools are just boring old ints + case MVT::i8: + case MVT::i16: + case MVT::i32: + case MVT::i64: +//XXX BuildMI(&BB, IA64::IDEF, 0, args_int[count]); + MF.getRegInfo().addLiveIn(args_int[count]); + // mark this register as liveIn + argVreg[count] = + MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i64)); + argPreg[count] = args_int[count]; + argOpc[count] = IA64::MOV; + argt = newroot = + DAG.getCopyFromReg(DAG.getRoot(), dl, argVreg[count], MVT::i64); + if ( getValueType(I->getType()) != MVT::i64) + argt = DAG.getNode(ISD::TRUNCATE, dl, getValueType(I->getType()), + newroot); + break; + } + } else { // more than 8 args go into the frame + // Create the frame index object for this incoming parameter... + ArgOffset = 16 + 8 * (count - 8); + int FI = MFI->CreateFixedObject(8, ArgOffset); + + // Create the SelectionDAG nodes corresponding to a load + //from this parameter + SDValue FIN = DAG.getFrameIndex(FI, MVT::i64); + argt = newroot = DAG.getLoad(getValueType(I->getType()), dl, + DAG.getEntryNode(), FIN, NULL, 0); + } + ++count; + DAG.setRoot(newroot.getValue(1)); + ArgValues.push_back(argt); + } + + + // Create a vreg to hold the output of (what will become) + // the "alloc" instruction + VirtGPR = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i64)); + BuildMI(&BB, dl, TII->get(IA64::PSEUDO_ALLOC), VirtGPR); + // we create a PSEUDO_ALLOC (pseudo)instruction for now +/* + BuildMI(&BB, IA64::IDEF, 0, IA64::r1); + + // hmm: + BuildMI(&BB, IA64::IDEF, 0, IA64::r12); + BuildMI(&BB, IA64::IDEF, 0, IA64::rp); + // ..hmm. + + BuildMI(&BB, IA64::MOV, 1, GP).addReg(IA64::r1); + + // hmm: + BuildMI(&BB, IA64::MOV, 1, SP).addReg(IA64::r12); + BuildMI(&BB, IA64::MOV, 1, RP).addReg(IA64::rp); + // ..hmm. +*/ + + unsigned tempOffset=0; + + // if this is a varargs function, we simply lower llvm.va_start by + // pointing to the first entry + if(F.isVarArg()) { + tempOffset=0; + VarArgsFrameIndex = MFI->CreateFixedObject(8, tempOffset); + } + + // here we actually do the moving of args, and store them to the stack + // too if this is a varargs function: + for (int i = 0; i < count && i < 8; ++i) { + BuildMI(&BB, dl, TII->get(argOpc[i]), argVreg[i]).addReg(argPreg[i]); + if(F.isVarArg()) { + // if this is a varargs function, we copy the input registers to the stack + int FI = MFI->CreateFixedObject(8, tempOffset); + tempOffset+=8; //XXX: is it safe to use r22 like this? + BuildMI(&BB, dl, TII->get(IA64::MOV), IA64::r22).addFrameIndex(FI); + // FIXME: we should use st8.spill here, one day + BuildMI(&BB, dl, TII->get(IA64::ST8), IA64::r22).addReg(argPreg[i]); + } + } + + // Finally, inform the code generator which regs we return values in. + // (see the ISD::RET: case in the instruction selector) + switch (getValueType(F.getReturnType()).getSimpleVT()) { + default: assert(0 && "i have no idea where to return this type!"); + case MVT::isVoid: break; + case MVT::i1: + case MVT::i8: + case MVT::i16: + case MVT::i32: + case MVT::i64: + MF.getRegInfo().addLiveOut(IA64::r8); + break; + case MVT::f32: + case MVT::f64: + MF.getRegInfo().addLiveOut(IA64::F8); + break; + } +} + +std::pair<SDValue, SDValue> +IA64TargetLowering::LowerCallTo(SDValue Chain, const Type *RetTy, + bool RetSExt, bool RetZExt, bool isVarArg, + bool isInreg, unsigned CallingConv, + bool isTailCall, SDValue Callee, + ArgListTy &Args, SelectionDAG &DAG, + DebugLoc dl) { + + MachineFunction &MF = DAG.getMachineFunction(); + + unsigned NumBytes = 16; + unsigned outRegsUsed = 0; + + if (Args.size() > 8) { + NumBytes += (Args.size() - 8) * 8; + outRegsUsed = 8; + } else { + outRegsUsed = Args.size(); + } + + // FIXME? this WILL fail if we ever try to pass around an arg that + // consumes more than a single output slot (a 'real' double, int128 + // some sort of aggregate etc.), as we'll underestimate how many 'outX' + // registers we use. Hopefully, the assembler will notice. + MF.getInfo<IA64FunctionInfo>()->outRegsUsed= + std::max(outRegsUsed, MF.getInfo<IA64FunctionInfo>()->outRegsUsed); + + // keep stack frame 16-byte aligned + // assert(NumBytes==((NumBytes+15) & ~15) && + // "stack frame not 16-byte aligned!"); + NumBytes = (NumBytes+15) & ~15; + + Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(NumBytes, true)); + + SDValue StackPtr; + std::vector<SDValue> Stores; + std::vector<SDValue> Converts; + std::vector<SDValue> RegValuesToPass; + unsigned ArgOffset = 16; + + for (unsigned i = 0, e = Args.size(); i != e; ++i) + { + SDValue Val = Args[i].Node; + MVT ObjectVT = Val.getValueType(); + SDValue ValToStore(0, 0), ValToConvert(0, 0); + unsigned ObjSize=8; + switch (ObjectVT.getSimpleVT()) { + default: assert(0 && "unexpected argument type!"); + case MVT::i1: + case MVT::i8: + case MVT::i16: + case MVT::i32: { + //promote to 64-bits, sign/zero extending based on type + //of the argument + ISD::NodeType ExtendKind = ISD::ANY_EXTEND; + if (Args[i].isSExt) + ExtendKind = ISD::SIGN_EXTEND; + else if (Args[i].isZExt) + ExtendKind = ISD::ZERO_EXTEND; + Val = DAG.getNode(ExtendKind, dl, MVT::i64, Val); + // XXX: fall through + } + case MVT::i64: + //ObjSize = 8; + if(RegValuesToPass.size() >= 8) { + ValToStore = Val; + } else { + RegValuesToPass.push_back(Val); + } + break; + case MVT::f32: + //promote to 64-bits + Val = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f64, Val); + // XXX: fall through + case MVT::f64: + if(RegValuesToPass.size() >= 8) { + ValToStore = Val; + } else { + RegValuesToPass.push_back(Val); + if(1 /* TODO: if(calling external or varadic function)*/ ) { + ValToConvert = Val; // additionally pass this FP value as an int + } + } + break; + } + + if(ValToStore.getNode()) { + if(!StackPtr.getNode()) { + StackPtr = DAG.getRegister(IA64::r12, MVT::i64); + } + SDValue PtrOff = DAG.getConstant(ArgOffset, getPointerTy()); + PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i64, StackPtr, PtrOff); + Stores.push_back(DAG.getStore(Chain, dl, ValToStore, PtrOff, NULL, 0)); + ArgOffset += ObjSize; + } + + if(ValToConvert.getNode()) { + Converts.push_back(DAG.getNode(IA64ISD::GETFD, dl, + MVT::i64, ValToConvert)); + } + } + + // Emit all stores, make sure they occur before any copies into physregs. + if (!Stores.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, + MVT::Other, &Stores[0],Stores.size()); + + static const unsigned IntArgRegs[] = { + IA64::out0, IA64::out1, IA64::out2, IA64::out3, + IA64::out4, IA64::out5, IA64::out6, IA64::out7 + }; + + static const unsigned FPArgRegs[] = { + IA64::F8, IA64::F9, IA64::F10, IA64::F11, + IA64::F12, IA64::F13, IA64::F14, IA64::F15 + }; + + SDValue InFlag; + + // save the current GP, SP and RP : FIXME: do we need to do all 3 always? + SDValue GPBeforeCall = DAG.getCopyFromReg(Chain, dl, IA64::r1, + MVT::i64, InFlag); + Chain = GPBeforeCall.getValue(1); + InFlag = Chain.getValue(2); + SDValue SPBeforeCall = DAG.getCopyFromReg(Chain, dl, IA64::r12, + MVT::i64, InFlag); + Chain = SPBeforeCall.getValue(1); + InFlag = Chain.getValue(2); + SDValue RPBeforeCall = DAG.getCopyFromReg(Chain, dl, IA64::rp, + MVT::i64, InFlag); + Chain = RPBeforeCall.getValue(1); + InFlag = Chain.getValue(2); + + // Build a sequence of copy-to-reg nodes chained together with token chain + // and flag operands which copy the outgoing integer args into regs out[0-7] + // mapped 1:1 and the FP args into regs F8-F15 "lazily" + // TODO: for performance, we should only copy FP args into int regs when we + // know this is required (i.e. for varardic or external (unknown) functions) + + // first to the FP->(integer representation) conversions, these are + // flagged for now, but shouldn't have to be (TODO) + unsigned seenConverts = 0; + for (unsigned i = 0, e = RegValuesToPass.size(); i != e; ++i) { + if(RegValuesToPass[i].getValueType().isFloatingPoint()) { + Chain = DAG.getCopyToReg(Chain, dl, IntArgRegs[i], + Converts[seenConverts++], InFlag); + InFlag = Chain.getValue(1); + } + } + + // next copy args into the usual places, these are flagged + unsigned usedFPArgs = 0; + for (unsigned i = 0, e = RegValuesToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, dl, + RegValuesToPass[i].getValueType().isInteger() ? + IntArgRegs[i] : FPArgRegs[usedFPArgs++], RegValuesToPass[i], InFlag); + InFlag = Chain.getValue(1); + } + + // If the callee is a GlobalAddress node (quite common, every direct call is) + // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. +/* + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) { + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i64); + } +*/ + + std::vector<MVT> NodeTys; + std::vector<SDValue> CallOperands; + NodeTys.push_back(MVT::Other); // Returns a chain + NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use. + CallOperands.push_back(Chain); + CallOperands.push_back(Callee); + + // emit the call itself + if (InFlag.getNode()) + CallOperands.push_back(InFlag); + else + assert(0 && "this should never happen!\n"); + + // to make way for a hack: + Chain = DAG.getNode(IA64ISD::BRCALL, dl, NodeTys, + &CallOperands[0], CallOperands.size()); + InFlag = Chain.getValue(1); + + // restore the GP, SP and RP after the call + Chain = DAG.getCopyToReg(Chain, dl, IA64::r1, GPBeforeCall, InFlag); + InFlag = Chain.getValue(1); + Chain = DAG.getCopyToReg(Chain, dl, IA64::r12, SPBeforeCall, InFlag); + InFlag = Chain.getValue(1); + Chain = DAG.getCopyToReg(Chain, dl, IA64::rp, RPBeforeCall, InFlag); + InFlag = Chain.getValue(1); + + std::vector<MVT> RetVals; + RetVals.push_back(MVT::Other); + RetVals.push_back(MVT::Flag); + + MVT RetTyVT = getValueType(RetTy); + SDValue RetVal; + if (RetTyVT != MVT::isVoid) { + switch (RetTyVT.getSimpleVT()) { + default: assert(0 && "Unknown value type to return!"); + case MVT::i1: { // bools are just like other integers (returned in r8) + // we *could* fall through to the truncate below, but this saves a + // few redundant predicate ops + SDValue boolInR8 = DAG.getCopyFromReg(Chain, dl, IA64::r8, + MVT::i64,InFlag); + InFlag = boolInR8.getValue(2); + Chain = boolInR8.getValue(1); + SDValue zeroReg = DAG.getCopyFromReg(Chain, dl, IA64::r0, + MVT::i64, InFlag); + InFlag = zeroReg.getValue(2); + Chain = zeroReg.getValue(1); + + RetVal = DAG.getSetCC(dl, MVT::i1, boolInR8, zeroReg, ISD::SETNE); + break; + } + case MVT::i8: + case MVT::i16: + case MVT::i32: + RetVal = DAG.getCopyFromReg(Chain, dl, IA64::r8, MVT::i64, InFlag); + Chain = RetVal.getValue(1); + + // keep track of whether it is sign or zero extended (todo: bools?) +/* XXX + RetVal = DAG.getNode(RetTy->isSigned() ? ISD::AssertSext :ISD::AssertZext, + dl, MVT::i64, RetVal, DAG.getValueType(RetTyVT)); +*/ + RetVal = DAG.getNode(ISD::TRUNCATE, dl, RetTyVT, RetVal); + break; + case MVT::i64: + RetVal = DAG.getCopyFromReg(Chain, dl, IA64::r8, MVT::i64, InFlag); + Chain = RetVal.getValue(1); + InFlag = RetVal.getValue(2); // XXX dead + break; + case MVT::f32: + RetVal = DAG.getCopyFromReg(Chain, dl, IA64::F8, MVT::f64, InFlag); + Chain = RetVal.getValue(1); + RetVal = DAG.getNode(ISD::FP_ROUND, dl, MVT::f32, RetVal, + DAG.getIntPtrConstant(0)); + break; + case MVT::f64: + RetVal = DAG.getCopyFromReg(Chain, dl, IA64::F8, MVT::f64, InFlag); + Chain = RetVal.getValue(1); + InFlag = RetVal.getValue(2); // XXX dead + break; + } + } + + Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, true), + DAG.getIntPtrConstant(0, true), SDValue()); + return std::make_pair(RetVal, Chain); +} + +SDValue IA64TargetLowering:: +LowerOperation(SDValue Op, SelectionDAG &DAG) { + DebugLoc dl = Op.getDebugLoc(); + switch (Op.getOpcode()) { + default: assert(0 && "Should not custom lower this!"); + case ISD::GlobalTLSAddress: + assert(0 && "TLS not implemented for IA64."); + case ISD::RET: { + SDValue AR_PFSVal, Copy; + + switch(Op.getNumOperands()) { + default: + assert(0 && "Do not know how to return this many arguments!"); + abort(); + case 1: + AR_PFSVal = DAG.getCopyFromReg(Op.getOperand(0), dl, VirtGPR, MVT::i64); + AR_PFSVal = DAG.getCopyToReg(AR_PFSVal.getValue(1), dl, IA64::AR_PFS, + AR_PFSVal); + return DAG.getNode(IA64ISD::RET_FLAG, dl, MVT::Other, AR_PFSVal); + case 3: { + // Copy the result into the output register & restore ar.pfs + MVT ArgVT = Op.getOperand(1).getValueType(); + unsigned ArgReg = ArgVT.isInteger() ? IA64::r8 : IA64::F8; + + AR_PFSVal = DAG.getCopyFromReg(Op.getOperand(0), dl, VirtGPR, MVT::i64); + Copy = DAG.getCopyToReg(AR_PFSVal.getValue(1), dl, ArgReg, + Op.getOperand(1), SDValue()); + AR_PFSVal = DAG.getCopyToReg(Copy.getValue(0), dl, + IA64::AR_PFS, AR_PFSVal, Copy.getValue(1)); + return DAG.getNode(IA64ISD::RET_FLAG, dl, MVT::Other, + AR_PFSVal, AR_PFSVal.getValue(1)); + } + } + return SDValue(); + } + case ISD::VAARG: { + MVT VT = getPointerTy(); + const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); + SDValue VAList = DAG.getLoad(VT, dl, Op.getOperand(0), Op.getOperand(1), + SV, 0); + // Increment the pointer, VAList, to the next vaarg + SDValue VAIncr = DAG.getNode(ISD::ADD, dl, VT, VAList, + DAG.getConstant(VT.getSizeInBits()/8, + VT)); + // Store the incremented VAList to the legalized pointer + VAIncr = DAG.getStore(VAList.getValue(1), dl, VAIncr, + Op.getOperand(1), SV, 0); + // Load the actual argument out of the pointer VAList + return DAG.getLoad(Op.getValueType(), dl, VAIncr, VAList, NULL, 0); + } + case ISD::VASTART: { + // vastart just stores the address of the VarArgsFrameIndex slot into the + // memory location argument. + SDValue FR = DAG.getFrameIndex(VarArgsFrameIndex, MVT::i64); + const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); + return DAG.getStore(Op.getOperand(0), dl, FR, Op.getOperand(1), SV, 0); + } + // Frame & Return address. Currently unimplemented + case ISD::RETURNADDR: break; + case ISD::FRAMEADDR: break; + } + return SDValue(); +} diff --git a/lib/Target/IA64/IA64ISelLowering.h b/lib/Target/IA64/IA64ISelLowering.h new file mode 100644 index 0000000000000..edf7eb895ad28 --- /dev/null +++ b/lib/Target/IA64/IA64ISelLowering.h @@ -0,0 +1,76 @@ +//===-- IA64ISelLowering.h - IA64 DAG Lowering Interface --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that IA64 uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_IA64_IA64ISELLOWERING_H +#define LLVM_TARGET_IA64_IA64ISELLOWERING_H + +#include "llvm/Target/TargetLowering.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "IA64.h" + +namespace llvm { + namespace IA64ISD { + enum NodeType { + // Start the numbering where the builting ops and target ops leave off. + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + /// GETFD - the getf.d instruction takes a floating point operand and + /// returns its 64-bit memory representation as an i64 + GETFD, + + // TODO: explain this hack + BRCALL, + + // RET_FLAG - Return with a flag operand + RET_FLAG + }; + } + + class IA64TargetLowering : public TargetLowering { + int VarArgsFrameIndex; // FrameIndex for start of varargs area. + //int ReturnAddrIndex; // FrameIndex for return slot. + unsigned GP, SP, RP; // FIXME - clean this mess up + public: + explicit IA64TargetLowering(TargetMachine &TM); + + unsigned VirtGPR; // this is public so it can be accessed in the selector + // for ISD::RET. add an accessor instead? FIXME + const char *getTargetNodeName(unsigned Opcode) const; + + /// getSetCCResultType: return ISD::SETCC's result type. + virtual MVT getSetCCResultType(MVT VT) const; + + /// LowerArguments - This hook must be implemented to indicate how we should + /// lower the arguments for the specified function, into the specified DAG. + virtual void LowerArguments(Function &F, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &ArgValues, + DebugLoc dl); + + /// LowerCallTo - This hook lowers an abstract call to a function into an + /// actual call. + virtual std::pair<SDValue, SDValue> + LowerCallTo(SDValue Chain, const Type *RetTy, + bool RetSExt, bool RetZExt, bool isVarArg, bool isInreg, + unsigned CC, bool isTailCall, + SDValue Callee, ArgListTy &Args, SelectionDAG &DAG, + DebugLoc dl); + + /// LowerOperation - for custom lowering specific ops + /// (currently, only "ret void") + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG); + + }; +} + +#endif // LLVM_TARGET_IA64_IA64ISELLOWERING_H diff --git a/lib/Target/IA64/IA64InstrBuilder.h b/lib/Target/IA64/IA64InstrBuilder.h new file mode 100644 index 0000000000000..a5d4dca530fb8 --- /dev/null +++ b/lib/Target/IA64/IA64InstrBuilder.h @@ -0,0 +1,40 @@ +//===-- IA64PCInstrBuilder.h - Aids for building IA64 insts -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file exposes functions that may be used with BuildMI from the +// MachineInstrBuilder.h file to simplify generating frame and constant pool +// references. +// +//===----------------------------------------------------------------------===// + +#ifndef IA64_INSTRBUILDER_H +#define IA64_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); +} + +} // End llvm namespace + +#endif + diff --git a/lib/Target/IA64/IA64InstrFormats.td b/lib/Target/IA64/IA64InstrFormats.td new file mode 100644 index 0000000000000..c465880d3e1a6 --- /dev/null +++ b/lib/Target/IA64/IA64InstrFormats.td @@ -0,0 +1,80 @@ +//===- IA64InstrFormats.td - IA64 Instruction Formats --*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// - Warning: the stuff in here isn't really being used, so is mostly +// junk. It'll get fixed as the JIT gets built. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Instruction format superclass +//===----------------------------------------------------------------------===// + +class InstIA64<bits<4> op, dag OOL, dag IOL, string asmstr> : Instruction { + // IA64 instruction baseline + field bits<41> Inst; + let Namespace = "IA64"; + let OutOperandList = OOL; + let InOperandList = IOL; + let AsmString = asmstr; + + let Inst{40-37} = op; +} + +//"Each Itanium instruction is categorized into one of six types." +//We should have: +// A, I, M, F, B, L+X + +class AForm<bits<4> opcode, bits<6> qpReg, dag OOL, dag IOL, string asmstr> : + InstIA64<opcode, OOL, IOL, asmstr> { + + let Inst{5-0} = qpReg; +} + +class AForm_DAG<bits<4> opcode, bits<6> qpReg, dag OOL, dag IOL, string asmstr, + list<dag> pattern> : + InstIA64<opcode, OOL, IOL, asmstr> { + + let Pattern = pattern; + let Inst{5-0} = qpReg; +} + +let isBranch = 1, isTerminator = 1 in +class BForm<bits<4> opcode, bits<6> x6, bits<3> btype, dag OOL, dag IOL, string asmstr> : + InstIA64<opcode, OOL, IOL, asmstr> { + + let Inst{32-27} = x6; + let Inst{8-6} = btype; +} + +class MForm<bits<4> opcode, bits<6> x6, dag OOL, dag IOL, string asmstr> : + InstIA64<opcode, OOL, IOL, asmstr> { + bits<7> Ra; + bits<7> Rb; + bits<16> disp; + + let Inst{35-30} = x6; +// let Inst{20-16} = Rb; + let Inst{15-0} = disp; +} + +class RawForm<bits<4> opcode, bits<26> rest, dag OOL, dag IOL, string asmstr> : + InstIA64<opcode, OOL, IOL, asmstr> { + let Inst{25-0} = rest; +} + +// Pseudo instructions. +class PseudoInstIA64<dag OOL, dag IOL, string nm> : InstIA64<0, OOL, IOL, nm> { +} + +class PseudoInstIA64_DAG<dag OOL, dag IOL, string nm, list<dag> pattern> + : InstIA64<0, OOL, IOL, nm> { + let Pattern = pattern; +} + diff --git a/lib/Target/IA64/IA64InstrInfo.cpp b/lib/Target/IA64/IA64InstrInfo.cpp new file mode 100644 index 0000000000000..5f89d4f139940 --- /dev/null +++ b/lib/Target/IA64/IA64InstrInfo.cpp @@ -0,0 +1,193 @@ +//===- IA64InstrInfo.cpp - IA64 Instruction Information -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the IA64 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "IA64InstrInfo.h" +#include "IA64.h" +#include "IA64InstrBuilder.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/ADT/SmallVector.h" +#include "IA64GenInstrInfo.inc" +using namespace llvm; + +IA64InstrInfo::IA64InstrInfo() + : TargetInstrInfoImpl(IA64Insts, sizeof(IA64Insts)/sizeof(IA64Insts[0])), + RI(*this) { +} + + +bool IA64InstrInfo::isMoveInstr(const MachineInstr& MI, + unsigned& sourceReg, + unsigned& destReg, + unsigned& SrcSR, unsigned& DstSR) const { + SrcSR = DstSR = 0; // No sub-registers. + + unsigned oc = MI.getOpcode(); + if (oc == IA64::MOV || oc == IA64::FMOV) { + // TODO: this doesn't detect predicate moves + assert(MI.getNumOperands() >= 2 && + /* MI.getOperand(0).isReg() && + MI.getOperand(1).isReg() && */ + "invalid register-register move instruction"); + if (MI.getOperand(0).isReg() && + MI.getOperand(1).isReg()) { + // if both operands of the MOV/FMOV are registers, then + // yes, this is a move instruction + sourceReg = MI.getOperand(1).getReg(); + destReg = MI.getOperand(0).getReg(); + return true; + } + } + return false; // we don't consider e.g. %regN = MOV <FrameIndex #x> a + // move instruction +} + +unsigned +IA64InstrInfo::InsertBranch(MachineBasicBlock &MBB,MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond)const { + // FIXME this should probably have a DebugLoc argument + DebugLoc dl = DebugLoc::getUnknownLoc(); + // Can only insert uncond branches so far. + assert(Cond.empty() && !FBB && TBB && "Can only handle uncond branches!"); + BuildMI(&MBB, dl, get(IA64::BRL_NOTCALL)).addMBB(TBB); + return 1; +} + +bool IA64InstrInfo::copyRegToReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *DestRC, + const TargetRegisterClass *SrcRC) const { + if (DestRC != SrcRC) { + // Not yet supported! + return false; + } + + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + if(DestRC == IA64::PRRegisterClass ) // if a bool, we use pseudocode + // (SrcReg) DestReg = cmp.eq.unc(r0, r0) + BuildMI(MBB, MI, DL, get(IA64::PCMPEQUNC), DestReg) + .addReg(IA64::r0).addReg(IA64::r0).addReg(SrcReg); + else // otherwise, MOV works (for both gen. regs and FP regs) + BuildMI(MBB, MI, DL, get(IA64::MOV), DestReg).addReg(SrcReg); + + return true; +} + +void IA64InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, + int FrameIdx, + const TargetRegisterClass *RC) const{ + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + if (RC == IA64::FPRegisterClass) { + BuildMI(MBB, MI, DL, get(IA64::STF_SPILL)).addFrameIndex(FrameIdx) + .addReg(SrcReg, getKillRegState(isKill)); + } else if (RC == IA64::GRRegisterClass) { + BuildMI(MBB, MI, DL, get(IA64::ST8)).addFrameIndex(FrameIdx) + .addReg(SrcReg, getKillRegState(isKill)); + } else if (RC == IA64::PRRegisterClass) { + /* we use IA64::r2 as a temporary register for doing this hackery. */ + // first we load 0: + BuildMI(MBB, MI, DL, get(IA64::MOV), IA64::r2).addReg(IA64::r0); + // then conditionally add 1: + BuildMI(MBB, MI, DL, get(IA64::CADDIMM22), IA64::r2).addReg(IA64::r2) + .addImm(1).addReg(SrcReg, getKillRegState(isKill)); + // and then store it to the stack + BuildMI(MBB, MI, DL, get(IA64::ST8)) + .addFrameIndex(FrameIdx) + .addReg(IA64::r2); + } else assert(0 && + "sorry, I don't know how to store this sort of reg in the stack\n"); +} + +void IA64InstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg, + bool isKill, + SmallVectorImpl<MachineOperand> &Addr, + const TargetRegisterClass *RC, + SmallVectorImpl<MachineInstr*> &NewMIs) const { + unsigned Opc = 0; + if (RC == IA64::FPRegisterClass) { + Opc = IA64::STF8; + } else if (RC == IA64::GRRegisterClass) { + Opc = IA64::ST8; + } else if (RC == IA64::PRRegisterClass) { + Opc = IA64::ST1; + } else { + assert(0 && + "sorry, I don't know how to store this sort of reg\n"); + } + + DebugLoc DL = DebugLoc::getUnknownLoc(); + MachineInstrBuilder MIB = BuildMI(MF, DL, get(Opc)); + for (unsigned i = 0, e = Addr.size(); i != e; ++i) + MIB.addOperand(Addr[i]); + MIB.addReg(SrcReg, getKillRegState(isKill)); + NewMIs.push_back(MIB); + return; + +} + +void IA64InstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC)const{ + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + if (RC == IA64::FPRegisterClass) { + BuildMI(MBB, MI, DL, get(IA64::LDF_FILL), DestReg).addFrameIndex(FrameIdx); + } else if (RC == IA64::GRRegisterClass) { + BuildMI(MBB, MI, DL, get(IA64::LD8), DestReg).addFrameIndex(FrameIdx); + } else if (RC == IA64::PRRegisterClass) { + // first we load a byte from the stack into r2, our 'predicate hackery' + // scratch reg + BuildMI(MBB, MI, DL, get(IA64::LD8), IA64::r2).addFrameIndex(FrameIdx); + // then we compare it to zero. If it _is_ zero, compare-not-equal to + // r0 gives us 0, which is what we want, so that's nice. + BuildMI(MBB, MI, DL, get(IA64::CMPNE), DestReg) + .addReg(IA64::r2) + .addReg(IA64::r0); + } else { + assert(0 && + "sorry, I don't know how to load this sort of reg from the stack\n"); + } +} + +void IA64InstrInfo::loadRegFromAddr(MachineFunction &MF, unsigned DestReg, + SmallVectorImpl<MachineOperand> &Addr, + const TargetRegisterClass *RC, + SmallVectorImpl<MachineInstr*> &NewMIs) const { + unsigned Opc = 0; + if (RC == IA64::FPRegisterClass) { + Opc = IA64::LDF8; + } else if (RC == IA64::GRRegisterClass) { + Opc = IA64::LD8; + } else if (RC == IA64::PRRegisterClass) { + Opc = IA64::LD1; + } else { + assert(0 && + "sorry, I don't know how to load this sort of reg\n"); + } + + DebugLoc DL = DebugLoc::getUnknownLoc(); + MachineInstrBuilder MIB = BuildMI(MF, DL, get(Opc), DestReg); + for (unsigned i = 0, e = Addr.size(); i != e; ++i) + MIB.addOperand(Addr[i]); + NewMIs.push_back(MIB); + return; +} diff --git a/lib/Target/IA64/IA64InstrInfo.h b/lib/Target/IA64/IA64InstrInfo.h new file mode 100644 index 0000000000000..79236c2c7c865 --- /dev/null +++ b/lib/Target/IA64/IA64InstrInfo.h @@ -0,0 +1,70 @@ +//===- IA64InstrInfo.h - IA64 Instruction Information ----------*- C++ -*- ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the IA64 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef IA64INSTRUCTIONINFO_H +#define IA64INSTRUCTIONINFO_H + +#include "llvm/Target/TargetInstrInfo.h" +#include "IA64RegisterInfo.h" + +namespace llvm { + +class IA64InstrInfo : public TargetInstrInfoImpl { + const IA64RegisterInfo RI; +public: + IA64InstrInfo(); + + /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As + /// such, whenever a client has an instance of instruction info, it should + /// always be able to get register info as well (through this method). + /// + virtual const IA64RegisterInfo &getRegisterInfo() const { return RI; } + + /// Return true if the instruction is a register to register move and return + /// the source and dest operands and their sub-register indices by reference. + virtual bool isMoveInstr(const MachineInstr &MI, + unsigned &SrcReg, unsigned &DstReg, + unsigned &SrcSubIdx, unsigned &DstSubIdx) const; + virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond) const; + virtual bool copyRegToReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *DestRC, + const TargetRegisterClass *SrcRC) const; + virtual void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC) const; + + virtual void storeRegToAddr(MachineFunction &MF, unsigned SrcReg, bool isKill, + SmallVectorImpl<MachineOperand> &Addr, + const TargetRegisterClass *RC, + SmallVectorImpl<MachineInstr*> &NewMIs) const; + + virtual void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC) const; + + virtual void loadRegFromAddr(MachineFunction &MF, unsigned DestReg, + SmallVectorImpl<MachineOperand> &Addr, + const TargetRegisterClass *RC, + SmallVectorImpl<MachineInstr*> &NewMIs) const; +}; + +} // End llvm namespace + +#endif + diff --git a/lib/Target/IA64/IA64InstrInfo.td b/lib/Target/IA64/IA64InstrInfo.td new file mode 100644 index 0000000000000..2ab9897bddeb5 --- /dev/null +++ b/lib/Target/IA64/IA64InstrInfo.td @@ -0,0 +1,751 @@ +//===- IA64InstrInfo.td - Describe the IA64 Instruction Set -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the IA64 instruction set, defining the instructions, and +// properties of the instructions which are needed for code generation, machine +// code emission, and analysis. +// +//===----------------------------------------------------------------------===// + +include "IA64InstrFormats.td" + +//===----------------------------------------------------------------------===// +// IA-64 specific DAG Nodes. +// + +def IA64getfd : SDNode<"IA64ISD::GETFD", SDTFPToIntOp, []>; + +def retflag : SDNode<"IA64ISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInFlag]>; + +//===--------- +// Instruction types + +class isA { bit A=1; } // I or M unit +class isM { bit M=1; } // M unit +class isI { bit I=1; } // I unit +class isB { bit B=1; } // B unit +class isF { bit F=1; } // F unit +class isLX { bit LX=1; } // I/B + +//===--------- + +def u2imm : Operand<i8>; +def u6imm : Operand<i8>; +def s8imm : Operand<i8> { + let PrintMethod = "printS8ImmOperand"; +} +def s14imm : Operand<i64> { + let PrintMethod = "printS14ImmOperand"; +} +def s22imm : Operand<i64> { + let PrintMethod = "printS22ImmOperand"; +} +def u64imm : Operand<i64> { + let PrintMethod = "printU64ImmOperand"; +} +def s64imm : Operand<i64> { + let PrintMethod = "printS64ImmOperand"; +} + +let PrintMethod = "printGlobalOperand" in + def globaladdress : Operand<i64>; + +// the asmprinter needs to know about calls +let PrintMethod = "printCallOperand" in + def calltarget : Operand<i64>; + +/* new daggy action!!! */ + +def is32ones : PatLeaf<(i64 imm), [{ + // is32ones predicate - True if the immediate is 0x00000000FFFFFFFF + // Used to create ZXT4s appropriately + uint64_t v = (uint64_t)N->getZExtValue(); + return (v == 0x00000000FFFFFFFFLL); +}]>; + +// isMIXable predicates - True if the immediate is +// 0xFF00FF00FF00FF00, 0x00FF00FF00FF00FF +// etc, through 0x00000000FFFFFFFF +// Used to test for the suitability of mix* +def isMIX1Lable: PatLeaf<(i64 imm), [{ + return((uint64_t)N->getZExtValue()==0xFF00FF00FF00FF00LL); +}]>; +def isMIX1Rable: PatLeaf<(i64 imm), [{ + return((uint64_t)N->getZExtValue()==0x00FF00FF00FF00FFLL); +}]>; +def isMIX2Lable: PatLeaf<(i64 imm), [{ + return((uint64_t)N->getZExtValue()==0xFFFF0000FFFF0000LL); +}]>; +def isMIX2Rable: PatLeaf<(i64 imm), [{ + return((uint64_t)N->getZExtValue()==0x0000FFFF0000FFFFLL); +}]>; +def isMIX4Lable: PatLeaf<(i64 imm), [{ + return((uint64_t)N->getZExtValue()==0xFFFFFFFF00000000LL); +}]>; +def isMIX4Rable: PatLeaf<(i64 imm), [{ + return((uint64_t)N->getZExtValue()==0x00000000FFFFFFFFLL); +}]>; + +def isSHLADDimm: PatLeaf<(i64 imm), [{ + // isSHLADDimm predicate - True if the immediate is exactly 1, 2, 3 or 4 + // - 0 is *not* okay. + // Used to create shladd instructions appropriately + int64_t v = (int64_t)N->getZExtValue(); + return (v >= 1 && v <= 4); +}]>; + +def immSExt14 : PatLeaf<(i64 imm), [{ + // immSExt14 predicate - True if the immediate fits in a 14-bit sign extended + // field. Used by instructions like 'adds'. + int64_t v = (int64_t)N->getZExtValue(); + return (v <= 8191 && v >= -8192); +}]>; + +// imm64 predicate - True if the immediate fits in a 64-bit +// field - i.e., true. used to keep movl happy +def imm64 : PatLeaf<(i64 imm)>; + +def ADD : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "add $dst = $src1, $src2", + [(set GR:$dst, (add GR:$src1, GR:$src2))]>, isA; + +def ADD1 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "add $dst = $src1, $src2, 1", + [(set GR:$dst, (add (add GR:$src1, GR:$src2), 1))]>, isA; + +def ADDS : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s14imm:$imm), + "adds $dst = $imm, $src1", + [(set GR:$dst, (add GR:$src1, immSExt14:$imm))]>, isA; + +def MOVL : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins s64imm:$imm), + "movl $dst = $imm", + [(set GR:$dst, imm64:$imm)]>, isLX; + +def ADDL_GA : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, globaladdress:$imm), + "addl $dst = $imm, $src1", + []>, isA; + +// hmm +def ADDL_EA : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, calltarget:$imm), + "addl $dst = $imm, $src1", + []>, isA; + +def SUB : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "sub $dst = $src1, $src2", + [(set GR:$dst, (sub GR:$src1, GR:$src2))]>, isA; + +def SUB1 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "sub $dst = $src1, $src2, 1", + [(set GR:$dst, (add (sub GR: $src1, GR:$src2), -1))]>, isA; + +let isTwoAddress = 1 in { +def TPCADDIMM22 : AForm<0x03, 0x0b, + (outs GR:$dst), (ins GR:$src1, s22imm:$imm, PR:$qp), + "($qp) add $dst = $imm, $dst">, isA; +def TPCADDS : AForm_DAG<0x03, 0x0b, + (outs GR:$dst), (ins GR:$src1, s14imm:$imm, PR:$qp), + "($qp) adds $dst = $imm, $dst", + []>, isA; +def TPCMPIMM8NE : AForm<0x03, 0x0b, + (outs PR:$dst), (ins PR:$src1, s22imm:$imm, GR:$src2, PR:$qp), + "($qp) cmp.ne $dst , p0 = $imm, $src2">, isA; +} + +// zero extend a bool (predicate reg) into an integer reg +def ZXTb : Pat<(zext PR:$src), + (TPCADDIMM22 (ADDS r0, 0), 1, PR:$src)>; +def AXTb : Pat<(anyext PR:$src), + (TPCADDIMM22 (ADDS r0, 0), 1, PR:$src)>; + +// normal sign/zero-extends +def SXT1 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "sxt1 $dst = $src", + [(set GR:$dst, (sext_inreg GR:$src, i8))]>, isI; +def ZXT1 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "zxt1 $dst = $src", + [(set GR:$dst, (and GR:$src, 255))]>, isI; +def SXT2 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "sxt2 $dst = $src", + [(set GR:$dst, (sext_inreg GR:$src, i16))]>, isI; +def ZXT2 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "zxt2 $dst = $src", + [(set GR:$dst, (and GR:$src, 65535))]>, isI; +def SXT4 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "sxt4 $dst = $src", + [(set GR:$dst, (sext_inreg GR:$src, i32))]>, isI; +def ZXT4 : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "zxt4 $dst = $src", + [(set GR:$dst, (and GR:$src, is32ones))]>, isI; + +// fixme: shrs vs shru? +def MIX1L : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "mix1.l $dst = $src1, $src2", + [(set GR:$dst, (or (and GR:$src1, isMIX1Lable), + (and (srl GR:$src2, (i64 8)), isMIX1Lable)))]>, isI; + +def MIX2L : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "mix2.l $dst = $src1, $src2", + [(set GR:$dst, (or (and GR:$src1, isMIX2Lable), + (and (srl GR:$src2, (i64 16)), isMIX2Lable)))]>, isI; + +def MIX4L : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "mix4.l $dst = $src1, $src2", + [(set GR:$dst, (or (and GR:$src1, isMIX4Lable), + (and (srl GR:$src2, (i64 32)), isMIX4Lable)))]>, isI; + +def MIX1R : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "mix1.r $dst = $src1, $src2", + [(set GR:$dst, (or (and (shl GR:$src1, (i64 8)), isMIX1Rable), + (and GR:$src2, isMIX1Rable)))]>, isI; + +def MIX2R : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "mix2.r $dst = $src1, $src2", + [(set GR:$dst, (or (and (shl GR:$src1, (i64 16)), isMIX2Rable), + (and GR:$src2, isMIX2Rable)))]>, isI; + +def MIX4R : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "mix4.r $dst = $src1, $src2", + [(set GR:$dst, (or (and (shl GR:$src1, (i64 32)), isMIX4Rable), + (and GR:$src2, isMIX4Rable)))]>, isI; + +def GETFSIGD : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins FP:$src), + "getf.sig $dst = $src", + []>, isM; + +def SETFSIGD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins GR:$src), + "setf.sig $dst = $src", + []>, isM; + +def XMALD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3), + "xma.l $dst = $src1, $src2, $src3", + []>, isF; +def XMAHD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3), + "xma.h $dst = $src1, $src2, $src3", + []>, isF; +def XMAHUD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3), + "xma.hu $dst = $src1, $src2, $src3", + []>, isF; + +// pseudocode for integer multiplication +def : Pat<(mul GR:$src1, GR:$src2), + (GETFSIGD (XMALD (SETFSIGD GR:$src1), (SETFSIGD GR:$src2), F0))>; +def : Pat<(mulhs GR:$src1, GR:$src2), + (GETFSIGD (XMAHD (SETFSIGD GR:$src1), (SETFSIGD GR:$src2), F0))>; +def : Pat<(mulhu GR:$src1, GR:$src2), + (GETFSIGD (XMAHUD (SETFSIGD GR:$src1), (SETFSIGD GR:$src2), F0))>; + +// TODO: addp4 (addp4 dst = src, r0 is a 32-bit add) +// has imm form, too + +// def ADDS : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s14imm:$imm), +// "adds $dst = $imm, $src1">; + +def AND : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "and $dst = $src1, $src2", + [(set GR:$dst, (and GR:$src1, GR:$src2))]>, isA; +def ANDCM : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "andcm $dst = $src1, $src2", + [(set GR:$dst, (and GR:$src1, (not GR:$src2)))]>, isA; +// TODO: and/andcm/or/xor/add/sub/shift immediate forms +def OR : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "or $dst = $src1, $src2", + [(set GR:$dst, (or GR:$src1, GR:$src2))]>, isA; + +def pOR : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2, PR:$qp), + "($qp) or $dst = $src1, $src2">, isA; + +// the following are all a bit unfortunate: we throw away the complement +// of the compare! +def CMPEQ : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2), + "cmp.eq $dst, p0 = $src1, $src2", + [(set PR:$dst, (seteq GR:$src1, GR:$src2))]>, isA; +def CMPGT : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2), + "cmp.gt $dst, p0 = $src1, $src2", + [(set PR:$dst, (setgt GR:$src1, GR:$src2))]>, isA; +def CMPGE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2), + "cmp.ge $dst, p0 = $src1, $src2", + [(set PR:$dst, (setge GR:$src1, GR:$src2))]>, isA; +def CMPLT : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2), + "cmp.lt $dst, p0 = $src1, $src2", + [(set PR:$dst, (setlt GR:$src1, GR:$src2))]>, isA; +def CMPLE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2), + "cmp.le $dst, p0 = $src1, $src2", + [(set PR:$dst, (setle GR:$src1, GR:$src2))]>, isA; +def CMPNE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2), + "cmp.ne $dst, p0 = $src1, $src2", + [(set PR:$dst, (setne GR:$src1, GR:$src2))]>, isA; +def CMPLTU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2), + "cmp.ltu $dst, p0 = $src1, $src2", + [(set PR:$dst, (setult GR:$src1, GR:$src2))]>, isA; +def CMPGTU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2), + "cmp.gtu $dst, p0 = $src1, $src2", + [(set PR:$dst, (setugt GR:$src1, GR:$src2))]>, isA; +def CMPLEU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2), + "cmp.leu $dst, p0 = $src1, $src2", + [(set PR:$dst, (setule GR:$src1, GR:$src2))]>, isA; +def CMPGEU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2), + "cmp.geu $dst, p0 = $src1, $src2", + [(set PR:$dst, (setuge GR:$src1, GR:$src2))]>, isA; + +// and we do the whole thing again for FP compares! +def FCMPEQ : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2), + "fcmp.eq $dst, p0 = $src1, $src2", + [(set PR:$dst, (seteq FP:$src1, FP:$src2))]>, isF; +def FCMPGT : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2), + "fcmp.gt $dst, p0 = $src1, $src2", + [(set PR:$dst, (setgt FP:$src1, FP:$src2))]>, isF; +def FCMPGE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2), + "fcmp.ge $dst, p0 = $src1, $src2", + [(set PR:$dst, (setge FP:$src1, FP:$src2))]>, isF; +def FCMPLT : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2), + "fcmp.lt $dst, p0 = $src1, $src2", + [(set PR:$dst, (setlt FP:$src1, FP:$src2))]>, isF; +def FCMPLE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2), + "fcmp.le $dst, p0 = $src1, $src2", + [(set PR:$dst, (setle FP:$src1, FP:$src2))]>, isF; +def FCMPNE : AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2), + "fcmp.neq $dst, p0 = $src1, $src2", + [(set PR:$dst, (setne FP:$src1, FP:$src2))]>, isF; +def FCMPLTU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2), + "fcmp.lt $dst, p0 = $src1, $src2", + [(set PR:$dst, (setult FP:$src1, FP:$src2))]>, isF; +def FCMPGTU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2), + "fcmp.gt $dst, p0 = $src1, $src2", + [(set PR:$dst, (setugt FP:$src1, FP:$src2))]>, isF; +def FCMPLEU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2), + "fcmp.le $dst, p0 = $src1, $src2", + [(set PR:$dst, (setule FP:$src1, FP:$src2))]>, isF; +def FCMPGEU: AForm_DAG<0x03, 0x0b, (outs PR:$dst), (ins FP:$src1, FP:$src2), + "fcmp.ge $dst, p0 = $src1, $src2", + [(set PR:$dst, (setuge FP:$src1, FP:$src2))]>, isF; + +def PCMPEQUNCR0R0 : AForm<0x03, 0x0b, (outs PR:$dst), (ins PR:$qp), + "($qp) cmp.eq.unc $dst, p0 = r0, r0">, isA; + +def : Pat<(trunc GR:$src), // truncate i64 to i1 + (CMPNE GR:$src, r0)>; // $src!=0? If so, PR:$dst=true + +let isTwoAddress=1 in { + def TPCMPEQR0R0 : AForm<0x03, 0x0b, (outs PR:$dst), (ins PR:$bogus, PR:$qp), + "($qp) cmp.eq $dst, p0 = r0, r0">, isA; + def TPCMPNER0R0 : AForm<0x03, 0x0b, (outs PR:$dst), (ins PR:$bogus, PR:$qp), + "($qp) cmp.ne $dst, p0 = r0, r0">, isA; +} + +/* our pseudocode for OR on predicates is: +pC = pA OR pB +------------- +(pA) cmp.eq.unc pC,p0 = r0,r0 // pC = pA + ;; +(pB) cmp.eq pC,p0 = r0,r0 // if (pB) pC = 1 */ + +def bOR : Pat<(or PR:$src1, PR:$src2), + (TPCMPEQR0R0 (PCMPEQUNCR0R0 PR:$src1), PR:$src2)>; + +/* our pseudocode for AND on predicates is: + * +(pA) cmp.eq.unc pC,p0 = r0,r0 // pC = pA + cmp.eq pTemp,p0 = r0,r0 // pTemp = NOT pB + ;; +(pB) cmp.ne pTemp,p0 = r0,r0 + ;; +(pTemp)cmp.ne pC,p0 = r0,r0 // if (NOT pB) pC = 0 */ + +def bAND : Pat<(and PR:$src1, PR:$src2), + ( TPCMPNER0R0 (PCMPEQUNCR0R0 PR:$src1), + (TPCMPNER0R0 (CMPEQ r0, r0), PR:$src2) )>; + +/* one possible routine for XOR on predicates is: + + // Compute px = py ^ pz + // using sum of products: px = (py & !pz) | (pz & !py) + // Uses 5 instructions in 3 cycles. + // cycle 1 +(pz) cmp.eq.unc px = r0, r0 // px = pz +(py) cmp.eq.unc pt = r0, r0 // pt = py + ;; + // cycle 2 +(pt) cmp.ne.and px = r0, r0 // px = px & !pt (px = pz & !pt) +(pz) cmp.ne.and pt = r0, r0 // pt = pt & !pz + ;; + } { .mmi + // cycle 3 +(pt) cmp.eq.or px = r0, r0 // px = px | pt + +*** Another, which we use here, requires one scratch GR. it is: + + mov rt = 0 // initialize rt off critical path + ;; + + // cycle 1 +(pz) cmp.eq.unc px = r0, r0 // px = pz +(pz) mov rt = 1 // rt = pz + ;; + // cycle 2 +(py) cmp.ne px = 1, rt // if (py) px = !pz + +.. these routines kindly provided by Jim Hull +*/ + +def bXOR : Pat<(xor PR:$src1, PR:$src2), + (TPCMPIMM8NE (PCMPEQUNCR0R0 PR:$src2), 1, + (TPCADDS (ADDS r0, 0), 1, PR:$src2), + PR:$src1)>; + +def XOR : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "xor $dst = $src1, $src2", + [(set GR:$dst, (xor GR:$src1, GR:$src2))]>, isA; + +def SHLADD: AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1,s64imm:$imm,GR:$src2), + "shladd $dst = $src1, $imm, $src2", + [(set GR:$dst, (add GR:$src2, (shl GR:$src1, isSHLADDimm:$imm)))]>, isA; + +def SHL : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "shl $dst = $src1, $src2", + [(set GR:$dst, (shl GR:$src1, GR:$src2))]>, isI; + +def SHRU : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "shr.u $dst = $src1, $src2", + [(set GR:$dst, (srl GR:$src1, GR:$src2))]>, isI; + +def SHRS : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, GR:$src2), + "shr $dst = $src1, $src2", + [(set GR:$dst, (sra GR:$src1, GR:$src2))]>, isI; + +def MOV : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), "mov $dst = $src">, isA; +def FMOV : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "mov $dst = $src">, isF; // XXX: there _is_ no fmov +def PMOV : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src, PR:$qp), + "($qp) mov $dst = $src">, isA; + +def SPILL_ALL_PREDICATES_TO_GR : AForm<0x03, 0x0b, (outs GR:$dst), (ins), + "mov $dst = pr">, isI; +def FILL_ALL_PREDICATES_FROM_GR : AForm<0x03, 0x0b, (outs), (ins GR:$src), + "mov pr = $src">, isI; + +let isTwoAddress = 1 in { + def CMOV : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src2, GR:$src, PR:$qp), + "($qp) mov $dst = $src">, isA; +} + +def PFMOV : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src, PR:$qp), + "($qp) mov $dst = $src">, isF; + +let isTwoAddress = 1 in { + def CFMOV : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src2, FP:$src, PR:$qp), + "($qp) mov $dst = $src">, isF; +} + +def SELECTINT : Pat<(select PR:$which, GR:$src1, GR:$src2), + (CMOV (MOV GR:$src2), GR:$src1, PR:$which)>; // note order! +def SELECTFP : Pat<(select PR:$which, FP:$src1, FP:$src2), + (CFMOV (FMOV FP:$src2), FP:$src1, PR:$which)>; // note order! +// TODO: can do this faster, w/o using any integer regs (see pattern isel) +def SELECTBOOL : Pat<(select PR:$which, PR:$src1, PR:$src2), // note order! + (CMPNE (CMOV + (MOV (TPCADDIMM22 (ADDS r0, 0), 1, PR:$src2)), + (TPCADDIMM22 (ADDS r0, 0), 1, PR:$src1), PR:$which), r0)>; + +// load constants of various sizes // FIXME: prettyprint -ve constants +def : Pat<(i64 immSExt14:$imm), (ADDS r0, immSExt14:$imm)>; +def : Pat<(i1 -1), (CMPEQ r0, r0)>; // TODO: this should just be a ref to p0 +def : Pat<(i1 0), (CMPNE r0, r0)>; // TODO: any instruction actually *using* + // this predicate should be killed! + +// TODO: support postincrement (reg, imm9) loads+stores - this needs more +// tablegen support + +def IUSE : PseudoInstIA64<(outs), (ins variable_ops), "// IUSE">; +def ADJUSTCALLSTACKUP : PseudoInstIA64<(outs), (ins variable_ops), + "// ADJUSTCALLSTACKUP">; +def ADJUSTCALLSTACKDOWN : PseudoInstIA64<(outs), (ins variable_ops), + "// ADJUSTCALLSTACKDOWN">; +def PSEUDO_ALLOC : PseudoInstIA64<(outs), (ins GR:$foo), "// PSEUDO_ALLOC">; + +def ALLOC : AForm<0x03, 0x0b, + (outs GR:$dst), (ins i8imm:$inputs, i8imm:$locals, i8imm:$outputs, i8imm:$rotating), + "alloc $dst = ar.pfs,$inputs,$locals,$outputs,$rotating">, isM; + +let isTwoAddress = 1 in { + def TCMPNE : AForm<0x03, 0x0b, + (outs PR:$dst), (ins PR:$src2, GR:$src3, GR:$src4), + "cmp.ne $dst, p0 = $src3, $src4">, isA; + + def TPCMPEQOR : AForm<0x03, 0x0b, + (outs PR:$dst), (ins PR:$src2, GR:$src3, GR:$src4, PR:$qp), + "($qp) cmp.eq.or $dst, p0 = $src3, $src4">, isA; + + def TPCMPNE : AForm<0x03, 0x0b, + (outs PR:$dst), (ins PR:$src2, GR:$src3, GR:$src4, PR:$qp), + "($qp) cmp.ne $dst, p0 = $src3, $src4">, isA; + + def TPCMPEQ : AForm<0x03, 0x0b, + (outs PR:$dst), (ins PR:$src2, GR:$src3, GR:$src4, PR:$qp), + "($qp) cmp.eq $dst, p0 = $src3, $src4">, isA; +} + +def MOVSIMM14 : AForm<0x03, 0x0b, (outs GR:$dst), (ins s14imm:$imm), + "mov $dst = $imm">, isA; +def MOVSIMM22 : AForm<0x03, 0x0b, (outs GR:$dst), (ins s22imm:$imm), + "mov $dst = $imm">, isA; +def MOVLIMM64 : AForm<0x03, 0x0b, (outs GR:$dst), (ins s64imm:$imm), + "movl $dst = $imm">, isLX; + +def SHLI : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, u6imm:$imm), + "shl $dst = $src1, $imm">, isI; +def SHRUI : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, u6imm:$imm), + "shr.u $dst = $src1, $imm">, isI; +def SHRSI : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, u6imm:$imm), + "shr $dst = $src1, $imm">, isI; + +def EXTRU : AForm<0x03, 0x0b, + (outs GR:$dst), (ins GR:$src1, u6imm:$imm1, u6imm:$imm2), + "extr.u $dst = $src1, $imm1, $imm2">, isI; + +def DEPZ : AForm<0x03, 0x0b, + (outs GR:$dst), (ins GR:$src1, u6imm:$imm1, u6imm:$imm2), + "dep.z $dst = $src1, $imm1, $imm2">, isI; + +def PCMPEQOR : AForm<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2, PR:$qp), + "($qp) cmp.eq.or $dst, p0 = $src1, $src2">, isA; +def PCMPEQUNC : AForm<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2, PR:$qp), + "($qp) cmp.eq.unc $dst, p0 = $src1, $src2">, isA; +def PCMPNE : AForm<0x03, 0x0b, (outs PR:$dst), (ins GR:$src1, GR:$src2, PR:$qp), + "($qp) cmp.ne $dst, p0 = $src1, $src2">, isA; + +// two destinations! +def BCMPEQ : AForm<0x03, 0x0b, (outs PR:$dst1, PR:$dst2), (ins GR:$src1, GR:$src2), + "cmp.eq $dst1, dst2 = $src1, $src2">, isA; + +def ADDIMM14 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s14imm:$imm), + "adds $dst = $imm, $src1">, isA; + +def ADDIMM22 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s22imm:$imm), + "add $dst = $imm, $src1">, isA; +def CADDIMM22 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$src1, s22imm:$imm, PR:$qp), + "($qp) add $dst = $imm, $src1">, isA; + +def SUBIMM8 : AForm<0x03, 0x0b, (outs GR:$dst), (ins s8imm:$imm, GR:$src2), + "sub $dst = $imm, $src2">, isA; + +let mayStore = 1 in { + def ST1 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, GR:$value), + "st1 [$dstPtr] = $value">, isM; + def ST2 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, GR:$value), + "st2 [$dstPtr] = $value">, isM; + def ST4 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, GR:$value), + "st4 [$dstPtr] = $value">, isM; + def ST8 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, GR:$value), + "st8 [$dstPtr] = $value">, isM; + def STF4 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, FP:$value), + "stfs [$dstPtr] = $value">, isM; + def STF8 : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, FP:$value), + "stfd [$dstPtr] = $value">, isM; + def STF_SPILL : AForm<0x03, 0x0b, (outs), (ins GR:$dstPtr, FP:$value), + "stf.spill [$dstPtr] = $value">, isM; +} + +let canFoldAsLoad = 1 in { + def LD1 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$srcPtr), + "ld1 $dst = [$srcPtr]">, isM; + def LD2 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$srcPtr), + "ld2 $dst = [$srcPtr]">, isM; + def LD4 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$srcPtr), + "ld4 $dst = [$srcPtr]">, isM; + def LD8 : AForm<0x03, 0x0b, (outs GR:$dst), (ins GR:$srcPtr), + "ld8 $dst = [$srcPtr]">, isM; + def LDF4 : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$srcPtr), + "ldfs $dst = [$srcPtr]">, isM; + def LDF8 : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$srcPtr), + "ldfd $dst = [$srcPtr]">, isM; + def LDF_FILL : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$srcPtr), + "ldf.fill $dst = [$srcPtr]">, isM; +} + +def POPCNT : AForm_DAG<0x03, 0x0b, (outs GR:$dst), (ins GR:$src), + "popcnt $dst = $src", + [(set GR:$dst, (ctpop GR:$src))]>, isI; + +// some FP stuff: // TODO: single-precision stuff? +def FADD : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2), + "fadd $dst = $src1, $src2", + [(set FP:$dst, (fadd FP:$src1, FP:$src2))]>, isF; +def FADDS: AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2), + "fadd.s $dst = $src1, $src2">, isF; +def FSUB : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2), + "fsub $dst = $src1, $src2", + [(set FP:$dst, (fsub FP:$src1, FP:$src2))]>, isF; +def FMPY : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2), + "fmpy $dst = $src1, $src2", + [(set FP:$dst, (fmul FP:$src1, FP:$src2))]>, isF; +def FMA : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3), + "fma $dst = $src1, $src2, $src3", + [(set FP:$dst, (fadd (fmul FP:$src1, FP:$src2), FP:$src3))]>, isF; +def FMS : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3), + "fms $dst = $src1, $src2, $src3", + [(set FP:$dst, (fsub (fmul FP:$src1, FP:$src2), FP:$src3))]>, isF; +def FNMA : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3), + "fnma $dst = $src1, $src2, $src3", + [(set FP:$dst, (fneg (fadd (fmul FP:$src1, FP:$src2), FP:$src3)))]>, isF; +def FABS : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fabs $dst = $src", + [(set FP:$dst, (fabs FP:$src))]>, isF; +def FNEG : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fneg $dst = $src", + [(set FP:$dst, (fneg FP:$src))]>, isF; +def FNEGABS : AForm_DAG<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fnegabs $dst = $src", + [(set FP:$dst, (fneg (fabs FP:$src)))]>, isF; + +let isTwoAddress=1 in { +def TCFMAS1 : AForm<0x03, 0x0b, + (outs FP:$dst), (ins FP:$bogussrc, FP:$src1, FP:$src2, FP:$src3, PR:$qp), + "($qp) fma.s1 $dst = $src1, $src2, $src3">, isF; +def TCFMADS0 : AForm<0x03, 0x0b, + (outs FP:$dst), (ins FP:$bogussrc, FP:$src1, FP:$src2, FP:$src3, PR:$qp), + "($qp) fma.d.s0 $dst = $src1, $src2, $src3">, isF; +} + +def CFMAS1 : AForm<0x03, 0x0b, + (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp), + "($qp) fma.s1 $dst = $src1, $src2, $src3">, isF; +def CFNMAS1 : AForm<0x03, 0x0b, + (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp), + "($qp) fnma.s1 $dst = $src1, $src2, $src3">, isF; + +def CFMADS1 : AForm<0x03, 0x0b, + (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp), + "($qp) fma.d.s1 $dst = $src1, $src2, $src3">, isF; +def CFMADS0 : AForm<0x03, 0x0b, + (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp), + "($qp) fma.d.s0 $dst = $src1, $src2, $src3">, isF; +def CFNMADS1 : AForm<0x03, 0x0b, + (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3, PR:$qp), + "($qp) fnma.d.s1 $dst = $src1, $src2, $src3">, isF; + +def FRCPAS0 : AForm<0x03, 0x0b, (outs FP:$dstFR, PR:$dstPR), (ins FP:$src1, FP:$src2), + "frcpa.s0 $dstFR, $dstPR = $src1, $src2">, isF; +def FRCPAS1 : AForm<0x03, 0x0b, (outs FP:$dstFR, PR:$dstPR), (ins FP:$src1, FP:$src2), + "frcpa.s1 $dstFR, $dstPR = $src1, $src2">, isF; + +def XMAL : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src1, FP:$src2, FP:$src3), + "xma.l $dst = $src1, $src2, $src3">, isF; + +def FCVTXF : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fcvt.xf $dst = $src">, isF; +def FCVTXUF : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fcvt.xuf $dst = $src">, isF; +def FCVTXUFS1 : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fcvt.xuf.s1 $dst = $src">, isF; +def FCVTFX : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fcvt.fx $dst = $src">, isF; +def FCVTFXU : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fcvt.fxu $dst = $src">, isF; + +def FCVTFXTRUNC : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fcvt.fx.trunc $dst = $src">, isF; +def FCVTFXUTRUNC : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fcvt.fxu.trunc $dst = $src">, isF; + +def FCVTFXTRUNCS1 : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fcvt.fx.trunc.s1 $dst = $src">, isF; +def FCVTFXUTRUNCS1 : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fcvt.fxu.trunc.s1 $dst = $src">, isF; + +def FNORMD : AForm<0x03, 0x0b, (outs FP:$dst), (ins FP:$src), + "fnorm.d $dst = $src">, isF; + +def GETFD : AForm<0x03, 0x0b, (outs GR:$dst), (ins FP:$src), + "getf.d $dst = $src">, isM; +def SETFD : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$src), + "setf.d $dst = $src">, isM; + +def GETFSIG : AForm<0x03, 0x0b, (outs GR:$dst), (ins FP:$src), + "getf.sig $dst = $src">, isM; +def SETFSIG : AForm<0x03, 0x0b, (outs FP:$dst), (ins GR:$src), + "setf.sig $dst = $src">, isM; + +// these four FP<->int conversion patterns need checking/cleaning +def SINT_TO_FP : Pat<(sint_to_fp GR:$src), + (FNORMD (FCVTXF (SETFSIG GR:$src)))>; +def UINT_TO_FP : Pat<(uint_to_fp GR:$src), + (FNORMD (FCVTXUF (SETFSIG GR:$src)))>; +def FP_TO_SINT : Pat<(i64 (fp_to_sint FP:$src)), + (GETFSIG (FCVTFXTRUNC FP:$src))>; +def FP_TO_UINT : Pat<(i64 (fp_to_uint FP:$src)), + (GETFSIG (FCVTFXUTRUNC FP:$src))>; + +def fpimm0 : PatLeaf<(fpimm), [{ + return N->isExactlyValue(+0.0); +}]>; +def fpimm1 : PatLeaf<(fpimm), [{ + return N->isExactlyValue(+1.0); +}]>; +def fpimmn0 : PatLeaf<(fpimm), [{ + return N->isExactlyValue(-0.0); +}]>; +def fpimmn1 : PatLeaf<(fpimm), [{ + return N->isExactlyValue(-1.0); +}]>; + +def : Pat<(f64 fpimm0), (FMOV F0)>; +def : Pat<(f64 fpimm1), (FMOV F1)>; +def : Pat<(f64 fpimmn0), (FNEG F0)>; +def : Pat<(f64 fpimmn1), (FNEG F1)>; + +let isTerminator = 1, isBranch = 1 in { + def BRL_NOTCALL : RawForm<0x03, 0xb0, (outs), (ins i64imm:$dst), + "(p0) brl.cond.sptk $dst">, isB; + def BRLCOND_NOTCALL : RawForm<0x03, 0xb0, (outs), (ins PR:$qp, i64imm:$dst), + "($qp) brl.cond.sptk $dst">, isB; + def BRCOND_NOTCALL : RawForm<0x03, 0xb0, (outs), (ins PR:$qp, GR:$dst), + "($qp) br.cond.sptk $dst">, isB; +} + +let isCall = 1, /* isTerminator = 1, isBranch = 1, */ + Uses = [out0,out1,out2,out3,out4,out5,out6,out7], +// all calls clobber non-callee-saved registers, and for now, they are these: + Defs = [r2,r3,r8,r9,r10,r11,r14,r15,r16,r17,r18,r19,r20,r21,r22,r23,r24, + r25,r26,r27,r28,r29,r30,r31, + p6,p7,p8,p9,p10,p11,p12,p13,p14,p15, + F6,F7,F8,F9,F10,F11,F12,F13,F14,F15, + F32,F33,F34,F35,F36,F37,F38,F39,F40,F41,F42,F43,F44,F45,F46,F47,F48,F49, + F50,F51,F52,F53,F54,F55,F56, + F57,F58,F59,F60,F61,F62,F63,F64,F65,F66,F67,F68,F69,F70,F71,F72,F73,F74, + F75,F76,F77,F78,F79,F80,F81, + F82,F83,F84,F85,F86,F87,F88,F89,F90,F91,F92,F93,F94,F95,F96,F97,F98,F99, + F100,F101,F102,F103,F104,F105, + F106,F107,F108,F109,F110,F111,F112,F113,F114,F115,F116,F117,F118,F119, + F120,F121,F122,F123,F124,F125,F126,F127, + out0,out1,out2,out3,out4,out5,out6,out7] in { +// old pattern call + def BRCALL: RawForm<0x03, 0xb0, (outs), (ins calltarget:$dst), + "br.call.sptk rp = $dst">, isB; // FIXME: teach llvm about branch regs? +// new daggy stuff! + +// calls a globaladdress + def BRCALL_IPREL_GA : RawForm<0x03, 0xb0, (outs), (ins calltarget:$dst), + "br.call.sptk rp = $dst">, isB; // FIXME: teach llvm about branch regs? +// calls an externalsymbol + def BRCALL_IPREL_ES : RawForm<0x03, 0xb0, (outs), (ins calltarget:$dst), + "br.call.sptk rp = $dst">, isB; // FIXME: teach llvm about branch regs? +// calls through a function descriptor + def BRCALL_INDIRECT : RawForm<0x03, 0xb0, (outs), (ins GR:$branchreg), + "br.call.sptk rp = $branchreg">, isB; // FIXME: teach llvm about branch regs? + def BRLCOND_CALL : RawForm<0x03, 0xb0, (outs), (ins PR:$qp, i64imm:$dst), + "($qp) brl.cond.call.sptk $dst">, isB; + def BRCOND_CALL : RawForm<0x03, 0xb0, (outs), (ins PR:$qp, GR:$dst), + "($qp) br.cond.call.sptk $dst">, isB; +} + +// Return branch: +let isTerminator = 1, isReturn = 1 in + def RET : AForm_DAG<0x03, 0x0b, (outs), (ins), + "br.ret.sptk.many rp", + [(retflag)]>, isB; // return +def : Pat<(ret), (RET)>; + +// the evil stop bit of despair +def STOP : PseudoInstIA64<(outs), (ins variable_ops), ";;">; + diff --git a/lib/Target/IA64/IA64MachineFunctionInfo.h b/lib/Target/IA64/IA64MachineFunctionInfo.h new file mode 100644 index 0000000000000..fb930564a9d15 --- /dev/null +++ b/lib/Target/IA64/IA64MachineFunctionInfo.h @@ -0,0 +1,34 @@ +//===-- IA64MachineFunctionInfo.h - IA64-specific information ---*- C++ -*-===// +//===-- for MachineFunction ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +//===----------------------------------------------------------------------===// +// +// This file declares IA64-specific per-machine-function information. +// +//===----------------------------------------------------------------------===// + +#ifndef IA64MACHINEFUNCTIONINFO_H +#define IA64MACHINEFUNCTIONINFO_H + +#include "llvm/CodeGen/MachineFunction.h" +//#include "IA64JITInfo.h" + +namespace llvm { + +class IA64FunctionInfo : public MachineFunctionInfo { + +public: + unsigned outRegsUsed; // how many 'out' registers are used + // by this machinefunction? (used to compute the appropriate + // entry in the 'alloc' instruction at the top of the + // machinefunction) + IA64FunctionInfo(MachineFunction& MF) { outRegsUsed=0; }; + +}; + +} // End llvm namespace + +#endif + diff --git a/lib/Target/IA64/IA64RegisterInfo.cpp b/lib/Target/IA64/IA64RegisterInfo.cpp new file mode 100644 index 0000000000000..7ad6f51a9b8bd --- /dev/null +++ b/lib/Target/IA64/IA64RegisterInfo.cpp @@ -0,0 +1,319 @@ +//===- IA64RegisterInfo.cpp - IA64 Register Information ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the IA64 implementation of the TargetRegisterInfo class. +// This file is responsible for the frame pointer elimination optimization +// on IA64. +// +//===----------------------------------------------------------------------===// + +#include "IA64.h" +#include "IA64RegisterInfo.h" +#include "IA64InstrBuilder.h" +#include "IA64MachineFunctionInfo.h" +#include "llvm/Constants.h" +#include "llvm/Type.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineLocation.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +using namespace llvm; + +IA64RegisterInfo::IA64RegisterInfo(const TargetInstrInfo &tii) + : IA64GenRegisterInfo(IA64::ADJUSTCALLSTACKDOWN, IA64::ADJUSTCALLSTACKUP), + TII(tii) {} + +const unsigned* IA64RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) + const { + static const unsigned CalleeSavedRegs[] = { + IA64::r5, 0 + }; + return CalleeSavedRegs; +} + +const TargetRegisterClass* const* +IA64RegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const { + static const TargetRegisterClass * const CalleeSavedRegClasses[] = { + &IA64::GRRegClass, 0 + }; + return CalleeSavedRegClasses; +} + +BitVector IA64RegisterInfo::getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + Reserved.set(IA64::r0); + Reserved.set(IA64::r1); + Reserved.set(IA64::r2); + Reserved.set(IA64::r5); + Reserved.set(IA64::r12); + Reserved.set(IA64::r13); + Reserved.set(IA64::r22); + Reserved.set(IA64::rp); + return Reserved; +} + +//===----------------------------------------------------------------------===// +// Stack Frame Processing methods +//===----------------------------------------------------------------------===// + +// hasFP - Return true if the specified function should have a dedicated frame +// pointer register. This is true if the function has variable sized allocas or +// if frame pointer elimination is disabled. +// +bool IA64RegisterInfo::hasFP(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + return NoFramePointerElim || MFI->hasVarSizedObjects(); +} + +void IA64RegisterInfo:: +eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + if (hasFP(MF)) { + // If we have a frame pointer, turn the adjcallstackup instruction into a + // 'sub SP, <amt>' and the adjcallstackdown instruction into 'add SP, + // <amt>' + MachineInstr *Old = I; + unsigned Amount = Old->getOperand(0).getImm(); + DebugLoc dl = Old->getDebugLoc(); + if (Amount != 0) { + // We need to keep the stack aligned properly. To do this, we round the + // amount of space needed for the outgoing arguments up to the next + // alignment boundary. + unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment(); + Amount = (Amount+Align-1)/Align*Align; + + // Replace the pseudo instruction with a new instruction... + if (Old->getOpcode() == IA64::ADJUSTCALLSTACKDOWN) { + BuildMI(MBB, I, dl, TII.get(IA64::ADDIMM22), IA64::r12) + .addReg(IA64::r12).addImm(-Amount); + } else { + assert(Old->getOpcode() == IA64::ADJUSTCALLSTACKUP); + BuildMI(MBB, I, dl, TII.get(IA64::ADDIMM22), IA64::r12) + .addReg(IA64::r12).addImm(Amount); + } + } + } + + MBB.erase(I); +} + +void IA64RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS)const{ + assert(SPAdj == 0 && "Unexpected"); + + unsigned i = 0; + MachineInstr &MI = *II; + MachineBasicBlock &MBB = *MI.getParent(); + MachineFunction &MF = *MBB.getParent(); + DebugLoc dl = MI.getDebugLoc(); + + bool FP = hasFP(MF); + + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); + } + + int FrameIndex = MI.getOperand(i).getIndex(); + + // choose a base register: ( hasFP? framepointer : stack pointer ) + unsigned BaseRegister = FP ? IA64::r5 : IA64::r12; + // Add the base register + MI.getOperand(i).ChangeToRegister(BaseRegister, false); + + // Now add the frame object offset to the offset from r1. + int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex); + + // If we're not using a Frame Pointer that has been set to the value of the + // SP before having the stack size subtracted from it, then add the stack size + // to Offset to get the correct offset. + Offset += MF.getFrameInfo()->getStackSize(); + + // XXX: we use 'r22' as another hack+slash temporary register here :( + if (Offset <= 8191 && Offset >= -8192) { // smallish offset + // Fix up the old: + MI.getOperand(i).ChangeToRegister(IA64::r22, false); + //insert the new + BuildMI(MBB, II, dl, TII.get(IA64::ADDIMM22), IA64::r22) + .addReg(BaseRegister).addImm(Offset); + } else { // it's big + //fix up the old: + MI.getOperand(i).ChangeToRegister(IA64::r22, false); + BuildMI(MBB, II, dl, TII.get(IA64::MOVLIMM64), IA64::r22).addImm(Offset); + BuildMI(MBB, II, dl, TII.get(IA64::ADD), IA64::r22).addReg(BaseRegister) + .addReg(IA64::r22); + } + +} + +void IA64RegisterInfo::emitPrologue(MachineFunction &MF) const { + MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB + MachineBasicBlock::iterator MBBI = MBB.begin(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + bool FP = hasFP(MF); + DebugLoc dl = (MBBI != MBB.end() ? + MBBI->getDebugLoc() : DebugLoc::getUnknownLoc()); + + // first, we handle the 'alloc' instruction, that should be right up the + // top of any function + static const unsigned RegsInOrder[96] = { // there are 96 GPRs the + // RSE worries about + IA64::r32, IA64::r33, IA64::r34, IA64::r35, + IA64::r36, IA64::r37, IA64::r38, IA64::r39, IA64::r40, IA64::r41, + IA64::r42, IA64::r43, IA64::r44, IA64::r45, IA64::r46, IA64::r47, + IA64::r48, IA64::r49, IA64::r50, IA64::r51, IA64::r52, IA64::r53, + IA64::r54, IA64::r55, IA64::r56, IA64::r57, IA64::r58, IA64::r59, + IA64::r60, IA64::r61, IA64::r62, IA64::r63, IA64::r64, IA64::r65, + IA64::r66, IA64::r67, IA64::r68, IA64::r69, IA64::r70, IA64::r71, + IA64::r72, IA64::r73, IA64::r74, IA64::r75, IA64::r76, IA64::r77, + IA64::r78, IA64::r79, IA64::r80, IA64::r81, IA64::r82, IA64::r83, + IA64::r84, IA64::r85, IA64::r86, IA64::r87, IA64::r88, IA64::r89, + IA64::r90, IA64::r91, IA64::r92, IA64::r93, IA64::r94, IA64::r95, + IA64::r96, IA64::r97, IA64::r98, IA64::r99, IA64::r100, IA64::r101, + IA64::r102, IA64::r103, IA64::r104, IA64::r105, IA64::r106, IA64::r107, + IA64::r108, IA64::r109, IA64::r110, IA64::r111, IA64::r112, IA64::r113, + IA64::r114, IA64::r115, IA64::r116, IA64::r117, IA64::r118, IA64::r119, + IA64::r120, IA64::r121, IA64::r122, IA64::r123, IA64::r124, IA64::r125, + IA64::r126, IA64::r127 }; + + unsigned numStackedGPRsUsed=0; + for (int i=0; i != 96; i++) { + if (MF.getRegInfo().isPhysRegUsed(RegsInOrder[i])) + numStackedGPRsUsed=i+1; // (i+1 and not ++ - consider fn(fp, fp, int) + } + + unsigned numOutRegsUsed=MF.getInfo<IA64FunctionInfo>()->outRegsUsed; + + // XXX FIXME : this code should be a bit more reliable (in case there _isn't_ + // a pseudo_alloc in the MBB) + unsigned dstRegOfPseudoAlloc; + for(MBBI = MBB.begin(); /*MBBI->getOpcode() != IA64::PSEUDO_ALLOC*/; ++MBBI) { + assert(MBBI != MBB.end()); + if(MBBI->getOpcode() == IA64::PSEUDO_ALLOC) { + dstRegOfPseudoAlloc=MBBI->getOperand(0).getReg(); + break; + } + } + + if (MBBI != MBB.end()) dl = MBBI->getDebugLoc(); + + BuildMI(MBB, MBBI, dl, TII.get(IA64::ALLOC)). + addReg(dstRegOfPseudoAlloc).addImm(0). + addImm(numStackedGPRsUsed).addImm(numOutRegsUsed).addImm(0); + + // Get the number of bytes to allocate from the FrameInfo + unsigned NumBytes = MFI->getStackSize(); + + if(FP) + NumBytes += 8; // reserve space for the old FP + + // Do we need to allocate space on the stack? + if (NumBytes == 0) + return; + + // Add 16 bytes at the bottom of the stack (scratch area) + // and round the size to a multiple of the alignment. + unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment(); + unsigned Size = 16 + (FP ? 8 : 0); + NumBytes = (NumBytes+Size+Align-1)/Align*Align; + + // Update frame info to pretend that this is part of the stack... + MFI->setStackSize(NumBytes); + + // adjust stack pointer: r12 -= numbytes + if (NumBytes <= 8191) { + BuildMI(MBB, MBBI, dl, TII.get(IA64::ADDIMM22),IA64::r12).addReg(IA64::r12). + addImm(-NumBytes); + } else { // we use r22 as a scratch register here + // first load the decrement into r22 + BuildMI(MBB, MBBI, dl, TII.get(IA64::MOVLIMM64), IA64::r22). + addImm(-NumBytes); + // FIXME: MOVLSI32 expects a _u_32imm + // then add (subtract) it to r12 (stack ptr) + BuildMI(MBB, MBBI, dl, TII.get(IA64::ADD), IA64::r12) + .addReg(IA64::r12).addReg(IA64::r22); + + } + + // now if we need to, save the old FP and set the new + if (FP) { + BuildMI(MBB, MBBI,dl,TII.get(IA64::ST8)).addReg(IA64::r12).addReg(IA64::r5); + // this must be the last instr in the prolog ? (XXX: why??) + BuildMI(MBB, MBBI, dl, TII.get(IA64::MOV), IA64::r5).addReg(IA64::r12); + } + +} + +void IA64RegisterInfo::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + MachineBasicBlock::iterator MBBI = prior(MBB.end()); + assert(MBBI->getOpcode() == IA64::RET && + "Can only insert epilog into returning blocks"); + DebugLoc dl = MBBI->getDebugLoc(); + bool FP = hasFP(MF); + + // Get the number of bytes allocated from the FrameInfo... + unsigned NumBytes = MFI->getStackSize(); + + //now if we need to, restore the old FP + if (FP) { + //copy the FP into the SP (discards allocas) + BuildMI(MBB, MBBI, dl, TII.get(IA64::MOV), IA64::r12).addReg(IA64::r5); + //restore the FP + BuildMI(MBB, MBBI, dl, TII.get(IA64::LD8), IA64::r5).addReg(IA64::r5); + } + + if (NumBytes != 0) { + if (NumBytes <= 8191) { + BuildMI(MBB, MBBI, dl, TII.get(IA64::ADDIMM22),IA64::r12). + addReg(IA64::r12).addImm(NumBytes); + } else { + BuildMI(MBB, MBBI, dl, TII.get(IA64::MOVLIMM64), IA64::r22). + addImm(NumBytes); + BuildMI(MBB, MBBI, dl, TII.get(IA64::ADD), IA64::r12).addReg(IA64::r12). + addReg(IA64::r22); + } + } +} + +unsigned IA64RegisterInfo::getRARegister() const { + assert(0 && "What is the return address register"); + return 0; +} + +unsigned IA64RegisterInfo::getFrameRegister(MachineFunction &MF) const { + return hasFP(MF) ? IA64::r5 : IA64::r12; +} + +unsigned IA64RegisterInfo::getEHExceptionRegister() const { + assert(0 && "What is the exception register"); + return 0; +} + +unsigned IA64RegisterInfo::getEHHandlerRegister() const { + assert(0 && "What is the exception handler register"); + return 0; +} + +int IA64RegisterInfo::getDwarfRegNum(unsigned RegNum, bool isEH) const { + assert(0 && "What is the dwarf register number"); + return -1; +} + +#include "IA64GenRegisterInfo.inc" + diff --git a/lib/Target/IA64/IA64RegisterInfo.h b/lib/Target/IA64/IA64RegisterInfo.h new file mode 100644 index 0000000000000..0c5083e75c25c --- /dev/null +++ b/lib/Target/IA64/IA64RegisterInfo.h @@ -0,0 +1,63 @@ +//===- IA64RegisterInfo.h - IA64 Register Information Impl ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the IA64 implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef IA64REGISTERINFO_H +#define IA64REGISTERINFO_H + +#include "llvm/Target/TargetRegisterInfo.h" +#include "IA64GenRegisterInfo.h.inc" + +namespace llvm { + +class TargetInstrInfo; + +struct IA64RegisterInfo : public IA64GenRegisterInfo { + const TargetInstrInfo &TII; + + IA64RegisterInfo(const TargetInstrInfo &tii); + + /// Code Generation virtual methods... + const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const; + + const TargetRegisterClass* const* getCalleeSavedRegClasses( + const MachineFunction *MF = 0) const; + + BitVector getReservedRegs(const MachineFunction &MF) const; + + bool hasFP(const MachineFunction &MF) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const; + + void eliminateFrameIndex(MachineBasicBlock::iterator MI, + int SPAdj, RegScavenger *RS = NULL) const; + + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + + // Debug information queries. + unsigned getRARegister() const; + unsigned getFrameRegister(MachineFunction &MF) const; + + // Exception handling queries. + unsigned getEHExceptionRegister() const; + unsigned getEHHandlerRegister() const; + + int getDwarfRegNum(unsigned RegNum, bool isEH) const; +}; + +} // End llvm namespace + +#endif + diff --git a/lib/Target/IA64/IA64RegisterInfo.td b/lib/Target/IA64/IA64RegisterInfo.td new file mode 100644 index 0000000000000..dd72dc3008a36 --- /dev/null +++ b/lib/Target/IA64/IA64RegisterInfo.td @@ -0,0 +1,509 @@ +//===- IA64RegisterInfo.td - Describe the IA64 Register File ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the IA64 register file, defining the registers +// themselves, aliases between the registers, and the register classes built +// out of the registers. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Register definitions... +// + +class IA64Register<string n> : Register<n> { + let Namespace = "IA64"; +} + +// GR - One of 128 32-bit general registers +class GR<bits<7> num, string n> : IA64Register<n> { + field bits<7> Num = num; +} + +// FP - One of 128 82-bit floating-point registers +class FP<bits<7> num, string n> : IA64Register<n> { + field bits<7> Num = num; +} + +// PR - One of 64 1-bit predicate registers +class PR<bits<6> num, string n> : IA64Register<n> { + field bits<6> Num = num; +} + +/* general registers */ +def r0 : GR< 0, "r0">, DwarfRegNum<[0]>; +def r1 : GR< 1, "r1">, DwarfRegNum<[1]>; +def r2 : GR< 2, "r2">, DwarfRegNum<[2]>; +def r3 : GR< 3, "r3">, DwarfRegNum<[3]>; +def r4 : GR< 4, "r4">, DwarfRegNum<[4]>; +def r5 : GR< 5, "r5">, DwarfRegNum<[5]>; +def r6 : GR< 6, "r6">, DwarfRegNum<[6]>; +def r7 : GR< 7, "r7">, DwarfRegNum<[7]>; +def r8 : GR< 8, "r8">, DwarfRegNum<[8]>; +def r9 : GR< 9, "r9">, DwarfRegNum<[9]>; +def r10 : GR< 10, "r10">, DwarfRegNum<[10]>; +def r11 : GR< 11, "r11">, DwarfRegNum<[11]>; +def r12 : GR< 12, "r12">, DwarfRegNum<[12]>; +def r13 : GR< 13, "r13">, DwarfRegNum<[13]>; +def r14 : GR< 14, "r14">, DwarfRegNum<[14]>; +def r15 : GR< 15, "r15">, DwarfRegNum<[15]>; +def r16 : GR< 16, "r16">, DwarfRegNum<[16]>; +def r17 : GR< 17, "r17">, DwarfRegNum<[17]>; +def r18 : GR< 18, "r18">, DwarfRegNum<[18]>; +def r19 : GR< 19, "r19">, DwarfRegNum<[19]>; +def r20 : GR< 20, "r20">, DwarfRegNum<[20]>; +def r21 : GR< 21, "r21">, DwarfRegNum<[21]>; +def r22 : GR< 22, "r22">, DwarfRegNum<[22]>; +def r23 : GR< 23, "r23">, DwarfRegNum<[23]>; +def r24 : GR< 24, "r24">, DwarfRegNum<[24]>; +def r25 : GR< 25, "r25">, DwarfRegNum<[25]>; +def r26 : GR< 26, "r26">, DwarfRegNum<[26]>; +def r27 : GR< 27, "r27">, DwarfRegNum<[27]>; +def r28 : GR< 28, "r28">, DwarfRegNum<[28]>; +def r29 : GR< 29, "r29">, DwarfRegNum<[29]>; +def r30 : GR< 30, "r30">, DwarfRegNum<[30]>; +def r31 : GR< 31, "r31">, DwarfRegNum<[31]>; +def r32 : GR< 32, "r32">, DwarfRegNum<[32]>; +def r33 : GR< 33, "r33">, DwarfRegNum<[33]>; +def r34 : GR< 34, "r34">, DwarfRegNum<[34]>; +def r35 : GR< 35, "r35">, DwarfRegNum<[35]>; +def r36 : GR< 36, "r36">, DwarfRegNum<[36]>; +def r37 : GR< 37, "r37">, DwarfRegNum<[37]>; +def r38 : GR< 38, "r38">, DwarfRegNum<[38]>; +def r39 : GR< 39, "r39">, DwarfRegNum<[39]>; +def r40 : GR< 40, "r40">, DwarfRegNum<[40]>; +def r41 : GR< 41, "r41">, DwarfRegNum<[41]>; +def r42 : GR< 42, "r42">, DwarfRegNum<[42]>; +def r43 : GR< 43, "r43">, DwarfRegNum<[43]>; +def r44 : GR< 44, "r44">, DwarfRegNum<[44]>; +def r45 : GR< 45, "r45">, DwarfRegNum<[45]>; +def r46 : GR< 46, "r46">, DwarfRegNum<[46]>; +def r47 : GR< 47, "r47">, DwarfRegNum<[47]>; +def r48 : GR< 48, "r48">, DwarfRegNum<[48]>; +def r49 : GR< 49, "r49">, DwarfRegNum<[49]>; +def r50 : GR< 50, "r50">, DwarfRegNum<[50]>; +def r51 : GR< 51, "r51">, DwarfRegNum<[51]>; +def r52 : GR< 52, "r52">, DwarfRegNum<[52]>; +def r53 : GR< 53, "r53">, DwarfRegNum<[53]>; +def r54 : GR< 54, "r54">, DwarfRegNum<[54]>; +def r55 : GR< 55, "r55">, DwarfRegNum<[55]>; +def r56 : GR< 56, "r56">, DwarfRegNum<[56]>; +def r57 : GR< 57, "r57">, DwarfRegNum<[57]>; +def r58 : GR< 58, "r58">, DwarfRegNum<[58]>; +def r59 : GR< 59, "r59">, DwarfRegNum<[59]>; +def r60 : GR< 60, "r60">, DwarfRegNum<[60]>; +def r61 : GR< 61, "r61">, DwarfRegNum<[61]>; +def r62 : GR< 62, "r62">, DwarfRegNum<[62]>; +def r63 : GR< 63, "r63">, DwarfRegNum<[63]>; +def r64 : GR< 64, "r64">, DwarfRegNum<[64]>; +def r65 : GR< 65, "r65">, DwarfRegNum<[65]>; +def r66 : GR< 66, "r66">, DwarfRegNum<[66]>; +def r67 : GR< 67, "r67">, DwarfRegNum<[67]>; +def r68 : GR< 68, "r68">, DwarfRegNum<[68]>; +def r69 : GR< 69, "r69">, DwarfRegNum<[69]>; +def r70 : GR< 70, "r70">, DwarfRegNum<[70]>; +def r71 : GR< 71, "r71">, DwarfRegNum<[71]>; +def r72 : GR< 72, "r72">, DwarfRegNum<[72]>; +def r73 : GR< 73, "r73">, DwarfRegNum<[73]>; +def r74 : GR< 74, "r74">, DwarfRegNum<[74]>; +def r75 : GR< 75, "r75">, DwarfRegNum<[75]>; +def r76 : GR< 76, "r76">, DwarfRegNum<[76]>; +def r77 : GR< 77, "r77">, DwarfRegNum<[77]>; +def r78 : GR< 78, "r78">, DwarfRegNum<[78]>; +def r79 : GR< 79, "r79">, DwarfRegNum<[79]>; +def r80 : GR< 80, "r80">, DwarfRegNum<[80]>; +def r81 : GR< 81, "r81">, DwarfRegNum<[81]>; +def r82 : GR< 82, "r82">, DwarfRegNum<[82]>; +def r83 : GR< 83, "r83">, DwarfRegNum<[83]>; +def r84 : GR< 84, "r84">, DwarfRegNum<[84]>; +def r85 : GR< 85, "r85">, DwarfRegNum<[85]>; +def r86 : GR< 86, "r86">, DwarfRegNum<[86]>; +def r87 : GR< 87, "r87">, DwarfRegNum<[87]>; +def r88 : GR< 88, "r88">, DwarfRegNum<[88]>; +def r89 : GR< 89, "r89">, DwarfRegNum<[89]>; +def r90 : GR< 90, "r90">, DwarfRegNum<[90]>; +def r91 : GR< 91, "r91">, DwarfRegNum<[91]>; +def r92 : GR< 92, "r92">, DwarfRegNum<[92]>; +def r93 : GR< 93, "r93">, DwarfRegNum<[93]>; +def r94 : GR< 94, "r94">, DwarfRegNum<[94]>; +def r95 : GR< 95, "r95">, DwarfRegNum<[95]>; +def r96 : GR< 96, "r96">, DwarfRegNum<[96]>; +def r97 : GR< 97, "r97">, DwarfRegNum<[97]>; +def r98 : GR< 98, "r98">, DwarfRegNum<[98]>; +def r99 : GR< 99, "r99">, DwarfRegNum<[99]>; +def r100 : GR< 100, "r100">, DwarfRegNum<[100]>; +def r101 : GR< 101, "r101">, DwarfRegNum<[101]>; +def r102 : GR< 102, "r102">, DwarfRegNum<[102]>; +def r103 : GR< 103, "r103">, DwarfRegNum<[103]>; +def r104 : GR< 104, "r104">, DwarfRegNum<[104]>; +def r105 : GR< 105, "r105">, DwarfRegNum<[105]>; +def r106 : GR< 106, "r106">, DwarfRegNum<[106]>; +def r107 : GR< 107, "r107">, DwarfRegNum<[107]>; +def r108 : GR< 108, "r108">, DwarfRegNum<[108]>; +def r109 : GR< 109, "r109">, DwarfRegNum<[109]>; +def r110 : GR< 110, "r110">, DwarfRegNum<[110]>; +def r111 : GR< 111, "r111">, DwarfRegNum<[111]>; +def r112 : GR< 112, "r112">, DwarfRegNum<[112]>; +def r113 : GR< 113, "r113">, DwarfRegNum<[113]>; +def r114 : GR< 114, "r114">, DwarfRegNum<[114]>; +def r115 : GR< 115, "r115">, DwarfRegNum<[115]>; +def r116 : GR< 116, "r116">, DwarfRegNum<[116]>; +def r117 : GR< 117, "r117">, DwarfRegNum<[117]>; +def r118 : GR< 118, "r118">, DwarfRegNum<[118]>; +def r119 : GR< 119, "r119">, DwarfRegNum<[119]>; +def r120 : GR< 120, "r120">, DwarfRegNum<[120]>; +def r121 : GR< 121, "r121">, DwarfRegNum<[121]>; +def r122 : GR< 122, "r122">, DwarfRegNum<[122]>; +def r123 : GR< 123, "r123">, DwarfRegNum<[123]>; +def r124 : GR< 124, "r124">, DwarfRegNum<[124]>; +def r125 : GR< 125, "r125">, DwarfRegNum<[125]>; +def r126 : GR< 126, "r126">, DwarfRegNum<[126]>; +def r127 : GR< 127, "r127">, DwarfRegNum<[127]>; + +/* floating-point registers */ +def F0 : FP< 0, "f0">, DwarfRegNum<[128]>; +def F1 : FP< 1, "f1">, DwarfRegNum<[129]>; +def F2 : FP< 2, "f2">, DwarfRegNum<[130]>; +def F3 : FP< 3, "f3">, DwarfRegNum<[131]>; +def F4 : FP< 4, "f4">, DwarfRegNum<[132]>; +def F5 : FP< 5, "f5">, DwarfRegNum<[133]>; +def F6 : FP< 6, "f6">, DwarfRegNum<[134]>; +def F7 : FP< 7, "f7">, DwarfRegNum<[135]>; +def F8 : FP< 8, "f8">, DwarfRegNum<[136]>; +def F9 : FP< 9, "f9">, DwarfRegNum<[137]>; +def F10 : FP< 10, "f10">, DwarfRegNum<[138]>; +def F11 : FP< 11, "f11">, DwarfRegNum<[139]>; +def F12 : FP< 12, "f12">, DwarfRegNum<[140]>; +def F13 : FP< 13, "f13">, DwarfRegNum<[141]>; +def F14 : FP< 14, "f14">, DwarfRegNum<[142]>; +def F15 : FP< 15, "f15">, DwarfRegNum<[143]>; +def F16 : FP< 16, "f16">, DwarfRegNum<[144]>; +def F17 : FP< 17, "f17">, DwarfRegNum<[145]>; +def F18 : FP< 18, "f18">, DwarfRegNum<[146]>; +def F19 : FP< 19, "f19">, DwarfRegNum<[147]>; +def F20 : FP< 20, "f20">, DwarfRegNum<[148]>; +def F21 : FP< 21, "f21">, DwarfRegNum<[149]>; +def F22 : FP< 22, "f22">, DwarfRegNum<[150]>; +def F23 : FP< 23, "f23">, DwarfRegNum<[151]>; +def F24 : FP< 24, "f24">, DwarfRegNum<[152]>; +def F25 : FP< 25, "f25">, DwarfRegNum<[153]>; +def F26 : FP< 26, "f26">, DwarfRegNum<[154]>; +def F27 : FP< 27, "f27">, DwarfRegNum<[155]>; +def F28 : FP< 28, "f28">, DwarfRegNum<[156]>; +def F29 : FP< 29, "f29">, DwarfRegNum<[157]>; +def F30 : FP< 30, "f30">, DwarfRegNum<[158]>; +def F31 : FP< 31, "f31">, DwarfRegNum<[159]>; +def F32 : FP< 32, "f32">, DwarfRegNum<[160]>; +def F33 : FP< 33, "f33">, DwarfRegNum<[161]>; +def F34 : FP< 34, "f34">, DwarfRegNum<[162]>; +def F35 : FP< 35, "f35">, DwarfRegNum<[163]>; +def F36 : FP< 36, "f36">, DwarfRegNum<[164]>; +def F37 : FP< 37, "f37">, DwarfRegNum<[165]>; +def F38 : FP< 38, "f38">, DwarfRegNum<[166]>; +def F39 : FP< 39, "f39">, DwarfRegNum<[167]>; +def F40 : FP< 40, "f40">, DwarfRegNum<[168]>; +def F41 : FP< 41, "f41">, DwarfRegNum<[169]>; +def F42 : FP< 42, "f42">, DwarfRegNum<[170]>; +def F43 : FP< 43, "f43">, DwarfRegNum<[171]>; +def F44 : FP< 44, "f44">, DwarfRegNum<[172]>; +def F45 : FP< 45, "f45">, DwarfRegNum<[173]>; +def F46 : FP< 46, "f46">, DwarfRegNum<[174]>; +def F47 : FP< 47, "f47">, DwarfRegNum<[175]>; +def F48 : FP< 48, "f48">, DwarfRegNum<[176]>; +def F49 : FP< 49, "f49">, DwarfRegNum<[177]>; +def F50 : FP< 50, "f50">, DwarfRegNum<[178]>; +def F51 : FP< 51, "f51">, DwarfRegNum<[179]>; +def F52 : FP< 52, "f52">, DwarfRegNum<[180]>; +def F53 : FP< 53, "f53">, DwarfRegNum<[181]>; +def F54 : FP< 54, "f54">, DwarfRegNum<[182]>; +def F55 : FP< 55, "f55">, DwarfRegNum<[183]>; +def F56 : FP< 56, "f56">, DwarfRegNum<[184]>; +def F57 : FP< 57, "f57">, DwarfRegNum<[185]>; +def F58 : FP< 58, "f58">, DwarfRegNum<[186]>; +def F59 : FP< 59, "f59">, DwarfRegNum<[187]>; +def F60 : FP< 60, "f60">, DwarfRegNum<[188]>; +def F61 : FP< 61, "f61">, DwarfRegNum<[189]>; +def F62 : FP< 62, "f62">, DwarfRegNum<[190]>; +def F63 : FP< 63, "f63">, DwarfRegNum<[191]>; +def F64 : FP< 64, "f64">, DwarfRegNum<[192]>; +def F65 : FP< 65, "f65">, DwarfRegNum<[193]>; +def F66 : FP< 66, "f66">, DwarfRegNum<[194]>; +def F67 : FP< 67, "f67">, DwarfRegNum<[195]>; +def F68 : FP< 68, "f68">, DwarfRegNum<[196]>; +def F69 : FP< 69, "f69">, DwarfRegNum<[197]>; +def F70 : FP< 70, "f70">, DwarfRegNum<[198]>; +def F71 : FP< 71, "f71">, DwarfRegNum<[199]>; +def F72 : FP< 72, "f72">, DwarfRegNum<[200]>; +def F73 : FP< 73, "f73">, DwarfRegNum<[201]>; +def F74 : FP< 74, "f74">, DwarfRegNum<[202]>; +def F75 : FP< 75, "f75">, DwarfRegNum<[203]>; +def F76 : FP< 76, "f76">, DwarfRegNum<[204]>; +def F77 : FP< 77, "f77">, DwarfRegNum<[205]>; +def F78 : FP< 78, "f78">, DwarfRegNum<[206]>; +def F79 : FP< 79, "f79">, DwarfRegNum<[207]>; +def F80 : FP< 80, "f80">, DwarfRegNum<[208]>; +def F81 : FP< 81, "f81">, DwarfRegNum<[209]>; +def F82 : FP< 82, "f82">, DwarfRegNum<[210]>; +def F83 : FP< 83, "f83">, DwarfRegNum<[211]>; +def F84 : FP< 84, "f84">, DwarfRegNum<[212]>; +def F85 : FP< 85, "f85">, DwarfRegNum<[213]>; +def F86 : FP< 86, "f86">, DwarfRegNum<[214]>; +def F87 : FP< 87, "f87">, DwarfRegNum<[215]>; +def F88 : FP< 88, "f88">, DwarfRegNum<[216]>; +def F89 : FP< 89, "f89">, DwarfRegNum<[217]>; +def F90 : FP< 90, "f90">, DwarfRegNum<[218]>; +def F91 : FP< 91, "f91">, DwarfRegNum<[219]>; +def F92 : FP< 92, "f92">, DwarfRegNum<[220]>; +def F93 : FP< 93, "f93">, DwarfRegNum<[221]>; +def F94 : FP< 94, "f94">, DwarfRegNum<[222]>; +def F95 : FP< 95, "f95">, DwarfRegNum<[223]>; +def F96 : FP< 96, "f96">, DwarfRegNum<[224]>; +def F97 : FP< 97, "f97">, DwarfRegNum<[225]>; +def F98 : FP< 98, "f98">, DwarfRegNum<[226]>; +def F99 : FP< 99, "f99">, DwarfRegNum<[227]>; +def F100 : FP< 100, "f100">, DwarfRegNum<[228]>; +def F101 : FP< 101, "f101">, DwarfRegNum<[229]>; +def F102 : FP< 102, "f102">, DwarfRegNum<[230]>; +def F103 : FP< 103, "f103">, DwarfRegNum<[231]>; +def F104 : FP< 104, "f104">, DwarfRegNum<[232]>; +def F105 : FP< 105, "f105">, DwarfRegNum<[233]>; +def F106 : FP< 106, "f106">, DwarfRegNum<[234]>; +def F107 : FP< 107, "f107">, DwarfRegNum<[235]>; +def F108 : FP< 108, "f108">, DwarfRegNum<[236]>; +def F109 : FP< 109, "f109">, DwarfRegNum<[237]>; +def F110 : FP< 110, "f110">, DwarfRegNum<[238]>; +def F111 : FP< 111, "f111">, DwarfRegNum<[239]>; +def F112 : FP< 112, "f112">, DwarfRegNum<[240]>; +def F113 : FP< 113, "f113">, DwarfRegNum<[241]>; +def F114 : FP< 114, "f114">, DwarfRegNum<[242]>; +def F115 : FP< 115, "f115">, DwarfRegNum<[243]>; +def F116 : FP< 116, "f116">, DwarfRegNum<[244]>; +def F117 : FP< 117, "f117">, DwarfRegNum<[245]>; +def F118 : FP< 118, "f118">, DwarfRegNum<[246]>; +def F119 : FP< 119, "f119">, DwarfRegNum<[247]>; +def F120 : FP< 120, "f120">, DwarfRegNum<[248]>; +def F121 : FP< 121, "f121">, DwarfRegNum<[249]>; +def F122 : FP< 122, "f122">, DwarfRegNum<[250]>; +def F123 : FP< 123, "f123">, DwarfRegNum<[251]>; +def F124 : FP< 124, "f124">, DwarfRegNum<[252]>; +def F125 : FP< 125, "f125">, DwarfRegNum<[253]>; +def F126 : FP< 126, "f126">, DwarfRegNum<[254]>; +def F127 : FP< 127, "f127">, DwarfRegNum<[255]>; + +/* predicate registers */ +def p0 : PR< 0, "p0">, DwarfRegNum<[256]>; +def p1 : PR< 1, "p1">, DwarfRegNum<[257]>; +def p2 : PR< 2, "p2">, DwarfRegNum<[258]>; +def p3 : PR< 3, "p3">, DwarfRegNum<[259]>; +def p4 : PR< 4, "p4">, DwarfRegNum<[260]>; +def p5 : PR< 5, "p5">, DwarfRegNum<[261]>; +def p6 : PR< 6, "p6">, DwarfRegNum<[262]>; +def p7 : PR< 7, "p7">, DwarfRegNum<[263]>; +def p8 : PR< 8, "p8">, DwarfRegNum<[264]>; +def p9 : PR< 9, "p9">, DwarfRegNum<[265]>; +def p10 : PR< 10, "p10">, DwarfRegNum<[266]>; +def p11 : PR< 11, "p11">, DwarfRegNum<[267]>; +def p12 : PR< 12, "p12">, DwarfRegNum<[268]>; +def p13 : PR< 13, "p13">, DwarfRegNum<[269]>; +def p14 : PR< 14, "p14">, DwarfRegNum<[270]>; +def p15 : PR< 15, "p15">, DwarfRegNum<[271]>; +def p16 : PR< 16, "p16">, DwarfRegNum<[272]>; +def p17 : PR< 17, "p17">, DwarfRegNum<[273]>; +def p18 : PR< 18, "p18">, DwarfRegNum<[274]>; +def p19 : PR< 19, "p19">, DwarfRegNum<[275]>; +def p20 : PR< 20, "p20">, DwarfRegNum<[276]>; +def p21 : PR< 21, "p21">, DwarfRegNum<[277]>; +def p22 : PR< 22, "p22">, DwarfRegNum<[278]>; +def p23 : PR< 23, "p23">, DwarfRegNum<[279]>; +def p24 : PR< 24, "p24">, DwarfRegNum<[280]>; +def p25 : PR< 25, "p25">, DwarfRegNum<[281]>; +def p26 : PR< 26, "p26">, DwarfRegNum<[282]>; +def p27 : PR< 27, "p27">, DwarfRegNum<[283]>; +def p28 : PR< 28, "p28">, DwarfRegNum<[284]>; +def p29 : PR< 29, "p29">, DwarfRegNum<[285]>; +def p30 : PR< 30, "p30">, DwarfRegNum<[286]>; +def p31 : PR< 31, "p31">, DwarfRegNum<[287]>; +def p32 : PR< 32, "p32">, DwarfRegNum<[288]>; +def p33 : PR< 33, "p33">, DwarfRegNum<[289]>; +def p34 : PR< 34, "p34">, DwarfRegNum<[290]>; +def p35 : PR< 35, "p35">, DwarfRegNum<[291]>; +def p36 : PR< 36, "p36">, DwarfRegNum<[292]>; +def p37 : PR< 37, "p37">, DwarfRegNum<[293]>; +def p38 : PR< 38, "p38">, DwarfRegNum<[294]>; +def p39 : PR< 39, "p39">, DwarfRegNum<[295]>; +def p40 : PR< 40, "p40">, DwarfRegNum<[296]>; +def p41 : PR< 41, "p41">, DwarfRegNum<[297]>; +def p42 : PR< 42, "p42">, DwarfRegNum<[298]>; +def p43 : PR< 43, "p43">, DwarfRegNum<[299]>; +def p44 : PR< 44, "p44">, DwarfRegNum<[300]>; +def p45 : PR< 45, "p45">, DwarfRegNum<[301]>; +def p46 : PR< 46, "p46">, DwarfRegNum<[302]>; +def p47 : PR< 47, "p47">, DwarfRegNum<[303]>; +def p48 : PR< 48, "p48">, DwarfRegNum<[304]>; +def p49 : PR< 49, "p49">, DwarfRegNum<[305]>; +def p50 : PR< 50, "p50">, DwarfRegNum<[306]>; +def p51 : PR< 51, "p51">, DwarfRegNum<[307]>; +def p52 : PR< 52, "p52">, DwarfRegNum<[308]>; +def p53 : PR< 53, "p53">, DwarfRegNum<[309]>; +def p54 : PR< 54, "p54">, DwarfRegNum<[310]>; +def p55 : PR< 55, "p55">, DwarfRegNum<[311]>; +def p56 : PR< 56, "p56">, DwarfRegNum<[312]>; +def p57 : PR< 57, "p57">, DwarfRegNum<[313]>; +def p58 : PR< 58, "p58">, DwarfRegNum<[314]>; +def p59 : PR< 59, "p59">, DwarfRegNum<[315]>; +def p60 : PR< 60, "p60">, DwarfRegNum<[316]>; +def p61 : PR< 61, "p61">, DwarfRegNum<[317]>; +def p62 : PR< 62, "p62">, DwarfRegNum<[318]>; +def p63 : PR< 63, "p63">, DwarfRegNum<[319]>; + +// XXX : this is temporary, we'll eventually have the output registers +// in the general purpose register class too? +def out0 : GR<0, "out0">, DwarfRegNum<[120]>; +def out1 : GR<1, "out1">, DwarfRegNum<[121]>; +def out2 : GR<2, "out2">, DwarfRegNum<[122]>; +def out3 : GR<3, "out3">, DwarfRegNum<[123]>; +def out4 : GR<4, "out4">, DwarfRegNum<[124]>; +def out5 : GR<5, "out5">, DwarfRegNum<[125]>; +def out6 : GR<6, "out6">, DwarfRegNum<[126]>; +def out7 : GR<7, "out7">, DwarfRegNum<[127]>; + +// application (special) registers: + +// "previous function state" application register +def AR_PFS : GR<0, "ar.pfs">, DwarfRegNum<[331]>; + +// "return pointer" (this is really branch register b0) +def rp : GR<0, "rp">, DwarfRegNum<[-1]>; + +// branch reg 6 +def B6 : GR<0, "b6">, DwarfRegNum<[326]>; + +//===----------------------------------------------------------------------===// +// Register Class Definitions... now that we have all of the pieces, define the +// top-level register classes. The order specified in the register list is +// implicitly defined to be the register allocation order. +// + +// these are the scratch (+stacked) general registers +// FIXME/XXX we also reserve a frame pointer (r5) +// FIXME/XXX we also reserve r2 for spilling/filling predicates +// in IA64RegisterInfo.cpp +// FIXME/XXX we also reserve r22 for calculating addresses +// in IA64RegisterInfo.cpp + +def GR : RegisterClass<"IA64", [i64], 64, + [ + +//FIXME!: for both readability and performance, we don't want the out +// registers to be the first ones allocated + + out7, out6, out5, out4, out3, out2, out1, out0, + r3, r8, r9, r10, r11, r14, r15, + r16, r17, r18, r19, r20, r21, r23, + r24, r25, r26, r27, r28, r29, r30, r31, + r32, r33, r34, r35, r36, r37, r38, r39, + r40, r41, r42, r43, r44, r45, r46, r47, + r48, r49, r50, r51, r52, r53, r54, r55, + r56, r57, r58, r59, r60, r61, r62, r63, + r64, r65, r66, r67, r68, r69, r70, r71, + r72, r73, r74, r75, r76, r77, r78, r79, + r80, r81, r82, r83, r84, r85, r86, r87, + r88, r89, r90, r91, r92, r93, r94, r95, + r96, r97, r98, r99, r100, r101, r102, r103, + r104, r105, r106, r107, r108, r109, r110, r111, + r112, r113, r114, r115, r116, r117, r118, r119, + // last 17 are special (look down) + r120, r121, r122, r123, r124, r125, r126, r127, + r0, r1, r2, r5, r12, r13, r22, rp, AR_PFS]> + { + let MethodProtos = [{ + iterator allocation_order_begin(const MachineFunction &MF) const; + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + GRClass::iterator + GRClass::allocation_order_begin(const MachineFunction &MF) const { + // hide the 8 out? registers appropriately: + return begin()+(8-(MF.getInfo<IA64FunctionInfo>()->outRegsUsed)); + } + + GRClass::iterator + GRClass::allocation_order_end(const MachineFunction &MF) const { + // the 9 special registers r0,r1,r2,r5,r12,r13 etc + int numReservedRegs=9; + + // we also can't allocate registers for use as locals if they're already + // required as 'out' registers + numReservedRegs+=MF.getInfo<IA64FunctionInfo>()->outRegsUsed; + return end()-numReservedRegs; // hide registers appropriately + } + }]; +} + + +// these are the scratch (+stacked) FP registers + +def FP : RegisterClass<"IA64", [f64], 64, + [F6, F7, + F8, F9, F10, F11, F12, F13, F14, F15, + F32, F33, F34, F35, F36, F37, F38, F39, + F40, F41, F42, F43, F44, F45, F46, F47, + F48, F49, F50, F51, F52, F53, F54, F55, + F56, F57, F58, F59, F60, F61, F62, F63, + F64, F65, F66, F67, F68, F69, F70, F71, + F72, F73, F74, F75, F76, F77, F78, F79, + F80, F81, F82, F83, F84, F85, F86, F87, + F88, F89, F90, F91, F92, F93, F94, F95, + F96, F97, F98, F99, F100, F101, F102, F103, + F104, F105, F106, F107, F108, F109, F110, F111, + F112, F113, F114, F115, F116, F117, F118, F119, + F120, F121, F122, F123, F124, F125, F126, F127, + F0, F1]> // these last two are hidden + { +// the 128s here are to make stf.spill/ldf.fill happy, +// when storing full (82-bit) FP regs to stack slots +// we need to 16-byte align + let Size=128; + let Alignment=128; + + let MethodProtos = [{ + iterator allocation_order_begin(const MachineFunction &MF) const; + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + FPClass::iterator + FPClass::allocation_order_begin(const MachineFunction &MF) const { + return begin(); // we don't hide any FP regs from the start + } + + FPClass::iterator + FPClass::allocation_order_end(const MachineFunction &MF) const { + return end()-2; // we hide regs F0, F1 from the end + } + }]; +} + +// these are the predicate registers, p0 (1/TRUE) is not here +def PR : RegisterClass<"IA64", [i1], 64, + +// for now, let's be wimps and only have the scratch predicate regs + [p6, p7, p8, p9, p10, p11, p12, p13, p14, p15]> { + let Size = 64; + } + +/* + [p1, p2, p3, p4, p5, p6, p7, + p8, p9, p10, p11, p12, p13, p14, p15, + p16, p17, p18, p19, p20, p21, p22, p23, + p24, p25, p26, p27, p28, p29, p30, p31, + p32, p33, p34, p35, p36, p37, p38, p39, + p40, p41, p42, p43, p44, p45, p46, p47, + p48, p49, p50, p51, p52, p53, p54, p55, + p56, p57, p58, p59, p60, p61, p62, p63]>; + */ diff --git a/lib/Target/IA64/IA64Subtarget.cpp b/lib/Target/IA64/IA64Subtarget.cpp new file mode 100644 index 0000000000000..4eca50bdd22b4 --- /dev/null +++ b/lib/Target/IA64/IA64Subtarget.cpp @@ -0,0 +1,18 @@ +//===-- IA64Subtarget.cpp - IA64 Subtarget Information ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the IA64 specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "subtarget" +#include "IA64Subtarget.h" +using namespace llvm; + +IA64Subtarget::IA64Subtarget() {} diff --git a/lib/Target/IA64/IA64Subtarget.h b/lib/Target/IA64/IA64Subtarget.h new file mode 100644 index 0000000000000..0387af55119a7 --- /dev/null +++ b/lib/Target/IA64/IA64Subtarget.h @@ -0,0 +1,28 @@ +//====---- IA64Subtarget.h - Define Subtarget for the IA64 -----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the IA64 specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#ifndef IA64SUBTARGET_H +#define IA64SUBTARGET_H + +#include "llvm/Target/TargetSubtarget.h" + +namespace llvm { + +class IA64Subtarget : public TargetSubtarget { +public: + IA64Subtarget(); +}; + +} // End llvm namespace + +#endif diff --git a/lib/Target/IA64/IA64TargetAsmInfo.cpp b/lib/Target/IA64/IA64TargetAsmInfo.cpp new file mode 100644 index 0000000000000..2ae8beb9148ed --- /dev/null +++ b/lib/Target/IA64/IA64TargetAsmInfo.cpp @@ -0,0 +1,44 @@ +//===-- IA64TargetAsmInfo.cpp - IA64 asm properties -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the IA64TargetAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "IA64TargetAsmInfo.h" +#include "llvm/Constants.h" +#include "llvm/Target/TargetMachine.h" + +using namespace llvm; + +IA64TargetAsmInfo::IA64TargetAsmInfo(const TargetMachine &TM): + ELFTargetAsmInfo(TM) { + CommentString = "//"; + Data8bitsDirective = "\tdata1\t"; // FIXME: check that we are + Data16bitsDirective = "\tdata2.ua\t"; // disabling auto-alignment + Data32bitsDirective = "\tdata4.ua\t"; // properly + Data64bitsDirective = "\tdata8.ua\t"; + ZeroDirective = "\t.skip\t"; + AsciiDirective = "\tstring\t"; + + GlobalVarAddrPrefix=""; + GlobalVarAddrSuffix=""; + FunctionAddrPrefix="@fptr("; + FunctionAddrSuffix=")"; + + // FIXME: would be nice to have rodata (no 'w') when appropriate? + ConstantPoolSection = "\n\t.section .data, \"aw\", \"progbits\"\n"; +} + +unsigned IA64TargetAsmInfo::RelocBehaviour() const { + return (TM.getRelocationModel() != Reloc::Static ? + Reloc::LocalOrGlobal : Reloc::Global); +} + +// FIXME: Support small data/bss/rodata sections someday. diff --git a/lib/Target/IA64/IA64TargetAsmInfo.h b/lib/Target/IA64/IA64TargetAsmInfo.h new file mode 100644 index 0000000000000..130822e887f4d --- /dev/null +++ b/lib/Target/IA64/IA64TargetAsmInfo.h @@ -0,0 +1,33 @@ +//=====-- IA64TargetAsmInfo.h - IA64 asm properties -----------*- C++ -*--====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the IA64TargetAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef IA64TARGETASMINFO_H +#define IA64TARGETASMINFO_H + +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/ELFTargetAsmInfo.h" + +namespace llvm { + + // Forward declaration. + class TargetMachine; + + struct IA64TargetAsmInfo : public ELFTargetAsmInfo { + explicit IA64TargetAsmInfo(const TargetMachine &TM); + virtual unsigned RelocBehaviour() const; + }; + + +} // namespace llvm + +#endif diff --git a/lib/Target/IA64/IA64TargetMachine.cpp b/lib/Target/IA64/IA64TargetMachine.cpp new file mode 100644 index 0000000000000..878a00a445185 --- /dev/null +++ b/lib/Target/IA64/IA64TargetMachine.cpp @@ -0,0 +1,94 @@ +//===-- IA64TargetMachine.cpp - Define TargetMachine for IA64 -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the IA64 specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#include "IA64TargetAsmInfo.h" +#include "IA64TargetMachine.h" +#include "IA64.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/Target/TargetMachineRegistry.h" +using namespace llvm; + +/// IA64TargetMachineModule - Note that this is used on hosts that cannot link +/// in a library unless there are references into the library. In particular, +/// it seems that it is not possible to get things to work on Win32 without +/// this. Though it is unused, do not remove it. +extern "C" int IA64TargetMachineModule; +int IA64TargetMachineModule = 0; + +static RegisterTarget<IA64TargetMachine> X("ia64", + "IA-64 (Itanium) [experimental]"); + +const TargetAsmInfo *IA64TargetMachine::createTargetAsmInfo() const { + return new IA64TargetAsmInfo(*this); +} + +unsigned IA64TargetMachine::getModuleMatchQuality(const Module &M) { + // we match [iI][aA]*64 + bool seenIA64=false; + std::string TT = M.getTargetTriple(); + + if (TT.size() >= 4) { + if( (TT[0]=='i' || TT[0]=='I') && + (TT[1]=='a' || TT[1]=='A') ) { + for(unsigned int i=2; i<(TT.size()-1); i++) + if(TT[i]=='6' && TT[i+1]=='4') + seenIA64=true; + } + + if (seenIA64) + return 20; // strong match + } + // If the target triple is something non-ia64, we don't match. + if (!TT.empty()) return 0; + +#if defined(__ia64__) || defined(__IA64__) + return 5; +#else + return 0; +#endif +} + +/// IA64TargetMachine ctor - Create an LP64 architecture model +/// +IA64TargetMachine::IA64TargetMachine(const Module &M, const std::string &FS) + : DataLayout("e-f80:128:128"), + FrameInfo(TargetFrameInfo::StackGrowsDown, 16, 0), + TLInfo(*this) { // FIXME? check this stuff +} + + +//===----------------------------------------------------------------------===// +// Pass Pipeline Configuration +//===----------------------------------------------------------------------===// + +bool IA64TargetMachine::addInstSelector(PassManagerBase &PM, + CodeGenOpt::Level OptLevel){ + PM.add(createIA64DAGToDAGInstructionSelector(*this)); + return false; +} + +bool IA64TargetMachine::addPreEmitPass(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + // Make sure everything is bundled happily + PM.add(createIA64BundlingPass(*this)); + return true; +} +bool IA64TargetMachine::addAssemblyEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool Verbose, + raw_ostream &Out) { + PM.add(createIA64CodePrinterPass(Out, *this, OptLevel, Verbose)); + return false; +} + diff --git a/lib/Target/IA64/IA64TargetMachine.h b/lib/Target/IA64/IA64TargetMachine.h new file mode 100644 index 0000000000000..29d625ce673a3 --- /dev/null +++ b/lib/Target/IA64/IA64TargetMachine.h @@ -0,0 +1,64 @@ +//===-- IA64TargetMachine.h - Define TargetMachine for IA64 ---*- C++ -*---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the IA64 specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_IA64TARGETMACHINE_H +#define LLVM_TARGET_IA64TARGETMACHINE_H + +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameInfo.h" +#include "IA64InstrInfo.h" +#include "IA64ISelLowering.h" +#include "IA64Subtarget.h" + +namespace llvm { + +class IA64TargetMachine : public LLVMTargetMachine { + IA64Subtarget Subtarget; + const TargetData DataLayout; // Calculates type size & alignment + IA64InstrInfo InstrInfo; + TargetFrameInfo FrameInfo; + //IA64JITInfo JITInfo; + IA64TargetLowering TLInfo; + +protected: + virtual const TargetAsmInfo *createTargetAsmInfo() const; + +public: + IA64TargetMachine(const Module &M, const std::string &FS); + + virtual const IA64InstrInfo *getInstrInfo() const { return &InstrInfo; } + virtual const TargetFrameInfo *getFrameInfo() const { return &FrameInfo; } + virtual const IA64Subtarget *getSubtargetImpl() const { return &Subtarget; } + virtual IA64TargetLowering *getTargetLowering() const { + return const_cast<IA64TargetLowering*>(&TLInfo); + } + virtual const IA64RegisterInfo *getRegisterInfo() const { + return &InstrInfo.getRegisterInfo(); + } + virtual const TargetData *getTargetData() const { return &DataLayout; } + + static unsigned getModuleMatchQuality(const Module &M); + + // Pass Pipeline Configuration + virtual bool addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel); + virtual bool addPreEmitPass(PassManagerBase &PM, CodeGenOpt::Level OptLevel); + virtual bool addAssemblyEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool Verbose, raw_ostream &Out); +}; +} // End llvm namespace + +#endif + + diff --git a/lib/Target/IA64/Makefile b/lib/Target/IA64/Makefile new file mode 100644 index 0000000000000..d38325422c60a --- /dev/null +++ b/lib/Target/IA64/Makefile @@ -0,0 +1,20 @@ +##===- lib/Target/IA64/Makefile -----------------------------*- Makefile -*-===## +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +LEVEL = ../../.. +LIBRARYNAME = LLVMIA64CodeGen +TARGET = IA64 +# Make sure that tblgen is run, first thing. +BUILT_SOURCES = IA64GenRegisterInfo.h.inc IA64GenRegisterNames.inc \ + IA64GenRegisterInfo.inc IA64GenInstrNames.inc \ + IA64GenInstrInfo.inc IA64GenAsmWriter.inc \ + IA64GenDAGISel.inc + +DIRS = AsmPrinter + +include $(LEVEL)/Makefile.common + diff --git a/lib/Target/IA64/README b/lib/Target/IA64/README new file mode 100644 index 0000000000000..60761ac11d97a --- /dev/null +++ b/lib/Target/IA64/README @@ -0,0 +1,48 @@ +TODO: + - Un-bitrot ISel + - Hook up If-Conversion a la ARM target + - Hook up all branch analysis functions + - Instruction scheduling + - Bundling + - Dynamic Optimization + - Testing and bugfixing + - stop passing FP args in both FP *and* integer regs when not required + - allocate low (nonstacked) registers more aggressively + - clean up and thoroughly test the isel patterns. + - fix stacked register allocation order: (for readability) we don't want + the out? registers being the first ones used + - fix up floating point + (nb http://gcc.gnu.org/wiki?pagename=ia64%20floating%20point ) + - bundling! + (we will avoid the mess that is: + http://gcc.gnu.org/ml/gcc/2003-12/msg00832.html ) + - instruction scheduling (hmmmm! ;) + - counted loop support + - make integer + FP mul/div more clever (we have fixed pseudocode atm) + - track and use comparison complements + +INFO: + - we are strictly LP64 here, no support for ILP32 on HP-UX. Linux users + don't need to worry about this. + - i have instruction scheduling/bundling pseudocode, that really works + (has been tested, albeit at the perl-script level). + so, before you go write your own, send me an email! + +KNOWN DEFECTS AT THE CURRENT TIME: + - C++ vtables contain naked function pointers, not function descriptors, + which is bad. see http://llvm.cs.uiuc.edu/bugs/show_bug.cgi?id=406 + - varargs are broken + - alloca doesn't work (indeed, stack frame layout is bogus) + - no support for big-endian environments + - (not really the backend, but...) the CFE has some issues on IA64. + these will probably be fixed soon. + +ACKNOWLEDGEMENTS: + - Chris Lattner (x100) + - Other LLVM developers ("hey, that looks familiar") + +CONTACT: + - You can email me at duraid@octopus.com.au. If you find a small bug, + just email me. If you find a big bug, please file a bug report + in bugzilla! http://llvm.cs.uiuc.edu is your one stop shop for all + things LLVM. |