aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Target/IA64/IA64.h5
-rw-r--r--lib/Target/IA64/IA64AsmPrinter.cpp22
-rw-r--r--lib/Target/IA64/IA64ISelDAGToDAG.cpp497
-rw-r--r--lib/Target/IA64/IA64ISelLowering.cpp369
-rw-r--r--lib/Target/IA64/IA64ISelLowering.h88
-rw-r--r--lib/Target/IA64/IA64ISelPattern.cpp11
-rw-r--r--lib/Target/IA64/IA64InstrFormats.td8
-rw-r--r--lib/Target/IA64/IA64InstrInfo.td245
-rw-r--r--lib/Target/IA64/IA64RegisterInfo.td8
-rw-r--r--lib/Target/IA64/IA64TargetMachine.cpp11
-rw-r--r--lib/Target/IA64/Makefile3
11 files changed, 1226 insertions, 41 deletions
diff --git a/lib/Target/IA64/IA64.h b/lib/Target/IA64/IA64.h
index 4eda1903c5..8fe7d9c1d6 100644
--- a/lib/Target/IA64/IA64.h
+++ b/lib/Target/IA64/IA64.h
@@ -22,6 +22,11 @@ class TargetMachine;
class FunctionPass;
class IntrinsicLowering;
+/// createIA64DAGToDAGInstructionSelector - This pass converts an LLVM
+/// function into IA64 machine code in a sane, DAG->DAG transform.
+///
+FunctionPass *createIA64DAGToDAGInstructionSelector(TargetMachine &TM);
+
/// createIA64PatternInstructionSelector - This pass converts an LLVM function
/// into a machine code representation in a more aggressive way.
///
diff --git a/lib/Target/IA64/IA64AsmPrinter.cpp b/lib/Target/IA64/IA64AsmPrinter.cpp
index 395fc89b8c..d96a10a08f 100644
--- a/lib/Target/IA64/IA64AsmPrinter.cpp
+++ b/lib/Target/IA64/IA64AsmPrinter.cpp
@@ -11,7 +11,7 @@
// 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 excellent 'ias' assembler is bundled with
+// report in bugzilla. FYI, the not too bad 'ias' assembler is bundled with
// the Intel C/C++ compiler for Itanium Linux.
//
//===----------------------------------------------------------------------===//
@@ -249,7 +249,25 @@ namespace {
}
void printS64ImmOperand(const MachineInstr *MI, unsigned OpNo,
MVT::ValueType VT) {
- O << (int64_t)MI->getOperand(OpNo).getImmedValue();
+// 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).isImmediate()) {
+ O << (int64_t)MI->getOperand(OpNo).getImmedValue();
+ } else { // this is a constant pool reference: FIXME: assert this
+ printOp(MI->getOperand(OpNo));
+ }
+ }
+
+ void printGlobalOperand(const MachineInstr *MI, unsigned OpNo,
+ MVT::ValueType VT) {
+ printOp(MI->getOperand(OpNo), false); // this is NOT a br.call instruction
}
void printCallOperand(const MachineInstr *MI, unsigned OpNo,
diff --git a/lib/Target/IA64/IA64ISelDAGToDAG.cpp b/lib/Target/IA64/IA64ISelDAGToDAG.cpp
new file mode 100644
index 0000000000..791004cc5f
--- /dev/null
+++ b/lib/Target/IA64/IA64ISelDAGToDAG.cpp
@@ -0,0 +1,497 @@
+//===---- IA64ISelDAGToDAG.cpp - IA64 pattern matching inst selector ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Duraid Madina and 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IA64.h"
+#include "IA64TargetMachine.h"
+#include "IA64ISelLowering.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/SSARegMap.h"
+#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/SelectionDAGISel.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Constants.h"
+#include "llvm/GlobalValue.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MathExtras.h"
+using namespace llvm;
+
+namespace {
+ Statistic<> FusedFP ("ia64-codegen", "Number of fused fp operations");
+ Statistic<> FrameOff("ia64-codegen", "Number of frame idx offsets collapsed");
+
+ //===--------------------------------------------------------------------===//
+ /// IA64DAGToDAGISel - IA64 specific code to select IA64 machine
+ /// instructions for SelectionDAG operations.
+ ///
+ class IA64DAGToDAGISel : public SelectionDAGISel {
+ IA64TargetLowering IA64Lowering;
+ unsigned GlobalBaseReg;
+ public:
+ IA64DAGToDAGISel(TargetMachine &TM)
+ : SelectionDAGISel(IA64Lowering), IA64Lowering(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 SDOperand 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.
+ // SDOperand getGlobalBaseReg(); TODO: hmm
+
+ // Select - Convert the specified operand from a target-independent to a
+ // target-specific node if it hasn't already been changed.
+ SDOperand Select(SDOperand Op);
+
+ SDNode *SelectIntImmediateExpr(SDOperand LHS, SDOperand 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.
+ SDOperand SelectCC(SDOperand LHS, SDOperand 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(SDOperand Addr, SDOperand &Op1, SDOperand &Op2);
+
+ SDOperand BuildSDIVSequence(SDNode *N);
+ SDOperand BuildUDIVSequence(SDNode *N);
+
+ /// InstructionSelectBasicBlock - This callback is invoked by
+ /// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
+ virtual void InstructionSelectBasicBlock(SelectionDAG &DAG);
+
+ virtual const char *getPassName() const {
+ return "IA64 (Itanium) DAG->DAG Instruction Selector";
+ }
+
+// Include the pieces autogenerated from the target description.
+#include "IA64GenDAGISel.inc"
+
+private:
+ SDOperand SelectCALL(SDOperand Op);
+ };
+}
+
+/// InstructionSelectBasicBlock - This callback is invoked by
+/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
+void IA64DAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) {
+ DEBUG(BB->dump());
+
+ // The selection process is inherently a bottom-up recursive process (users
+ // select their uses before themselves). Given infinite stack space, we
+ // could just start selecting on the root and traverse the whole graph. In
+ // practice however, this causes us to run out of stack space on large basic
+ // blocks. To avoid this problem, select the entry node, then all its uses,
+ // iteratively instead of recursively.
+ std::vector<SDOperand> Worklist;
+ Worklist.push_back(DAG.getEntryNode());
+
+ // Note that we can do this in the IA64 target (scanning forward across token
+ // chain edges) because no nodes ever get folded across these edges. On a
+ // target like X86 which supports load/modify/store operations, this would
+ // have to be more careful.
+ while (!Worklist.empty()) {
+ SDOperand Node = Worklist.back();
+ Worklist.pop_back();
+
+ // Chose from the least deep of the top two nodes.
+ if (!Worklist.empty() &&
+ Worklist.back().Val->getNodeDepth() < Node.Val->getNodeDepth())
+ std::swap(Worklist.back(), Node);
+
+ if ((Node.Val->getOpcode() >= ISD::BUILTIN_OP_END &&
+ Node.Val->getOpcode() < IA64ISD::FIRST_NUMBER) ||
+ CodeGenMap.count(Node)) continue;
+
+ for (SDNode::use_iterator UI = Node.Val->use_begin(),
+ E = Node.Val->use_end(); UI != E; ++UI) {
+ // Scan the values. If this use has a value that is a token chain, add it
+ // to the worklist.
+ SDNode *User = *UI;
+ for (unsigned i = 0, e = User->getNumValues(); i != e; ++i)
+ if (User->getValueType(i) == MVT::Other) {
+ Worklist.push_back(SDOperand(User, i));
+ break;
+ }
+ }
+
+ // Finally, legalize this node.
+ Select(Node);
+ }
+
+ // Select target instructions for the DAG.
+ DAG.setRoot(Select(DAG.getRoot()));
+ CodeGenMap.clear();
+ DAG.RemoveDeadNodes();
+
+ // Emit machine code to BB.
+ ScheduleAndEmitDAG(DAG);
+}
+
+
+SDOperand IA64DAGToDAGISel::SelectCALL(SDOperand Op) {
+ SDNode *N = Op.Val;
+ SDOperand Chain = Select(N->getOperand(0));
+
+ unsigned CallOpcode;
+ std::vector<SDOperand> CallOperands;
+
+ // save the current GP, SP and RP : FIXME: do we need to do all 3 always?
+ SDOperand GPBeforeCall = CurDAG->getCopyFromReg(Chain, IA64::r1, MVT::i64);
+ Chain = GPBeforeCall.getValue(1);
+ SDOperand SPBeforeCall = CurDAG->getCopyFromReg(Chain, IA64::r12, MVT::i64);
+ Chain = SPBeforeCall.getValue(1);
+ SDOperand RPBeforeCall = CurDAG->getCopyFromReg(Chain, IA64::rp, MVT::i64);
+ Chain = RPBeforeCall.getValue(1);
+
+ // if we can call directly, do so
+ if (GlobalAddressSDNode *GASD =
+ dyn_cast<GlobalAddressSDNode>(N->getOperand(1))) {
+ CallOpcode = IA64::BRCALL_IPREL;
+ CallOperands.push_back(CurDAG->getTargetGlobalAddress(GASD->getGlobal(),
+ MVT::i64));
+ } else if (ExternalSymbolSDNode *ESSDN = // FIXME: we currently NEED this
+ // case for correctness, to avoid
+ // "non-pic code with imm reloc.n
+ // against dynamic symbol" errors
+ dyn_cast<ExternalSymbolSDNode>(N->getOperand(1))) {
+ CallOpcode = IA64::BRCALL_IPREL;
+ CallOperands.push_back(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
+
+ SDOperand FnDescriptor = Select(N->getOperand(1));
+
+ // load the branch target's entry point [mem] and
+ // GP value [mem+8]
+ SDOperand targetEntryPoint=CurDAG->getLoad(MVT::i64, Chain, FnDescriptor,
+ CurDAG->getSrcValue(0));
+ SDOperand targetGPAddr=CurDAG->getNode(ISD::ADD, MVT::i64, FnDescriptor,
+ CurDAG->getConstant(8, MVT::i64));
+ SDOperand targetGP=CurDAG->getLoad(MVT::i64, Chain, targetGPAddr,
+ CurDAG->getSrcValue(0));
+
+ // Copy the callee address into the b6 branch register
+ SDOperand B6 = CurDAG->getRegister(IA64::B6, MVT::i64);
+ Chain = CurDAG->getNode(ISD::CopyToReg, MVT::Other, Chain, B6,
+ targetEntryPoint);
+
+ CallOperands.push_back(B6);
+ CallOpcode = IA64::BRCALL_INDIRECT;
+ }
+
+ // TODO: support in-memory arguments
+ unsigned used_FPArgs=0; // how many FP args have been used so far?
+
+ unsigned intArgs[] = {IA64::out0, IA64::out1, IA64::out2, IA64::out3,
+ IA64::out4, IA64::out5, IA64::out6, IA64::out7 };
+ unsigned FPArgs[] = {IA64::F8, IA64::F9, IA64::F10, IA64::F11,
+ IA64::F12, IA64::F13, IA64::F14, IA64::F15 };
+
+ SDOperand InFlag; // Null incoming flag value.
+
+ for (unsigned i = 2, e = N->getNumOperands(); i != e; ++i) {
+ unsigned DestReg = 0;
+ MVT::ValueType RegTy = N->getOperand(i).getValueType();
+ if (RegTy == MVT::i64) {
+ assert((i-2) < 8 && "Too many int args");
+ DestReg = intArgs[i-2];
+ } else {
+ assert(MVT::isFloatingPoint(N->getOperand(i).getValueType()) &&
+ "Unpromoted integer arg?");
+ assert(used_FPArgs < 8 && "Too many fp args");
+ DestReg = FPArgs[used_FPArgs++];
+ }
+
+ if (N->getOperand(i).getOpcode() != ISD::UNDEF) {
+ SDOperand Val = Select(N->getOperand(i));
+ Chain = CurDAG->getCopyToReg(Chain, DestReg, Val, InFlag);
+ InFlag = Chain.getValue(1);
+ CallOperands.push_back(CurDAG->getRegister(DestReg, RegTy));
+ }
+ }
+
+ // Finally, once everything is in registers to pass to the call, emit the
+ // call itself.
+ if (InFlag.Val)
+ CallOperands.push_back(InFlag); // Strong dep on register copies.
+ else
+ CallOperands.push_back(Chain); // Weak dep on whatever occurs before
+ Chain = CurDAG->getTargetNode(CallOpcode, MVT::Other, MVT::Flag,
+ CallOperands);
+
+// return Chain; // HACK: err, this means that functions never return anything. need to intergrate this with the code immediately below FIXME XXX
+
+ std::vector<SDOperand> CallResults;
+
+ // If the call has results, copy the values out of the ret val registers.
+ switch (N->getValueType(0)) {
+ default: assert(0 && "Unexpected ret value!");
+ case MVT::Other: break;
+ case MVT::i64:
+ Chain = CurDAG->getCopyFromReg(Chain, IA64::r8, MVT::i64,
+ Chain.getValue(1)).getValue(1);
+ CallResults.push_back(Chain.getValue(0));
+ break;
+ case MVT::f64:
+ Chain = CurDAG->getCopyFromReg(Chain, IA64::F8, N->getValueType(0),
+ Chain.getValue(1)).getValue(1);
+ CallResults.push_back(Chain.getValue(0));
+ break;
+ }
+ // restore GP, SP and RP
+ Chain = CurDAG->getCopyToReg(Chain, IA64::r1, GPBeforeCall);
+ Chain = CurDAG->getCopyToReg(Chain, IA64::r12, SPBeforeCall);
+ Chain = CurDAG->getCopyToReg(Chain, IA64::rp, RPBeforeCall);
+
+ CallResults.push_back(Chain);
+
+ for (unsigned i = 0, e = CallResults.size(); i != e; ++i)
+ CodeGenMap[Op.getValue(i)] = CallResults[i];
+
+ return CallResults[Op.ResNo];
+}
+
+// Select - Convert the specified operand from a target-independent to a
+// target-specific node if it hasn't already been changed.
+SDOperand IA64DAGToDAGISel::Select(SDOperand Op) {
+ SDNode *N = Op.Val;
+ if (N->getOpcode() >= ISD::BUILTIN_OP_END &&
+ N->getOpcode() < IA64ISD::FIRST_NUMBER)
+ return Op; // Already selected.
+
+ // If this has already been converted, use it.
+ std::map<SDOperand, SDOperand>::iterator CGMI = CodeGenMap.find(Op);
+ if (CGMI != CodeGenMap.end()) return CGMI->second;
+
+ switch (N->getOpcode()) {
+ default: break;
+
+ case ISD::CALL:
+ case ISD::TAILCALL: return SelectCALL(Op);
+
+/* todo:
+ * case ISD::DYNAMIC_STACKALLOC:
+*/
+
+ case ISD::FrameIndex: { // TODO: reduce creepyness
+ int FI = cast<FrameIndexSDNode>(N)->getIndex();
+ if (N->hasOneUse()) {
+ CurDAG->SelectNodeTo(N, IA64::MOV, MVT::i64,
+ CurDAG->getTargetFrameIndex(FI, MVT::i64));
+ return SDOperand(N, 0);
+ }
+ return CurDAG->getTargetNode(IA64::MOV, MVT::i64,
+ CurDAG->getTargetFrameIndex(FI, MVT::i64));
+ }
+
+ case ISD::TokenFactor: {
+ SDOperand New;
+ if (N->getNumOperands() == 2) {
+ SDOperand Op0 = Select(N->getOperand(0));
+ SDOperand Op1 = Select(N->getOperand(1));
+ New = CurDAG->getNode(ISD::TokenFactor, MVT::Other, Op0, Op1);
+ } else {
+ std::vector<SDOperand> Ops;
+ for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i)
+ Ops.push_back(Select(N->getOperand(i)));
+ New = CurDAG->getNode(ISD::TokenFactor, MVT::Other, Ops);
+ }
+
+ CodeGenMap[Op] = New;
+ return New;
+ }
+ case ISD::CopyFromReg: {
+ SDOperand Chain = Select(N->getOperand(0));
+ if (Chain == N->getOperand(0)) return Op; // No change
+ SDOperand New = CurDAG->getCopyFromReg(Chain,
+ cast<RegisterSDNode>(N->getOperand(1))->getReg(), N->getValueType(0));
+ return New.getValue(Op.ResNo);
+ }
+ case ISD::CopyToReg: {
+ SDOperand Chain = Select(N->getOperand(0));
+ SDOperand Reg = N->getOperand(1);
+ SDOperand Val = Select(N->getOperand(2));
+ SDOperand New = CurDAG->getNode(ISD::CopyToReg, MVT::Other,
+ Chain, Reg, Val);
+ CodeGenMap[Op] = New;
+ return New;
+ }
+
+ case ISD::GlobalAddress: {
+ GlobalValue *GV = cast<GlobalAddressSDNode>(N)->getGlobal();
+ SDOperand GA = CurDAG->getTargetGlobalAddress(GV, MVT::i64);
+ SDOperand Tmp = CurDAG->getTargetNode(IA64::ADDL_GA, MVT::i64,
+ CurDAG->getRegister(IA64::r1, MVT::i64), GA);
+ return CurDAG->getTargetNode(IA64::LD8, MVT::i64, Tmp);
+ }
+
+ case ISD::LOAD:
+ case ISD::EXTLOAD:
+ case ISD::ZEXTLOAD: {
+ SDOperand Chain = Select(N->getOperand(0));
+ SDOperand Address = Select(N->getOperand(1));
+
+ MVT::ValueType TypeBeingLoaded = (N->getOpcode() == ISD::LOAD) ?
+ N->getValueType(0) : cast<VTSDNode>(N->getOperand(3))->getVT();
+ unsigned Opc;
+ switch (TypeBeingLoaded) {
+ default: N->dump(); assert(0 && "Cannot load this type!");
+ // FIXME: bools? case MVT::i1:
+ 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;
+ }
+
+ CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other,
+ Address, Chain); // TODO: comment this
+
+ return SDOperand(N, Op.ResNo);
+ }
+
+ case ISD::TRUNCSTORE:
+ case ISD::STORE: {
+ SDOperand Address = Select(N->getOperand(2));
+
+ unsigned Opc;
+ if (N->getOpcode() == ISD::STORE) {
+ switch (N->getOperand(1).getValueType()) {
+ default: assert(0 && "unknown Type in store");
+ case MVT::i64: Opc = IA64::ST8; break;
+ case MVT::f64: Opc = IA64::STF8; break;
+ }
+ } else { //ISD::TRUNCSTORE
+ switch(cast<VTSDNode>(N->getOperand(4))->getVT()) {
+ default: assert(0 && "unknown Type in store");
+ 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;
+ }
+ }
+
+ CurDAG->SelectNodeTo(N, Opc, MVT::Other, Select(N->getOperand(2)),
+ Select(N->getOperand(1)), Select(N->getOperand(0)));
+ return SDOperand(N, 0);
+ }
+
+ case ISD::BRCOND: {
+ SDOperand Chain = Select(N->getOperand(0));
+ SDOperand CC = Select(N->getOperand(1));
+ MachineBasicBlock *Dest =
+ cast<BasicBlockSDNode>(N->getOperand(2))->getBasicBlock();
+ //FIXME - we do NOT need long branches all the time
+ CurDAG->SelectNodeTo(N, IA64::BRLCOND_NOTCALL, MVT::Other, CC, CurDAG->getBasicBlock(Dest), Chain);
+ return SDOperand(N, 0);
+ }
+
+ case ISD::CALLSEQ_START:
+ case ISD::CALLSEQ_END: {
+ int64_t Amt = cast<ConstantSDNode>(N->getOperand(1))->getValue();
+ unsigned Opc = N->getOpcode() == ISD::CALLSEQ_START ?
+ IA64::ADJUSTCALLSTACKDOWN : IA64::ADJUSTCALLSTACKUP;
+ CurDAG->SelectNodeTo(N, Opc, MVT::Other,
+ getI64Imm(Amt), Select(N->getOperand(0)));
+ return SDOperand(N, 0);
+ }
+
+ case ISD::RET: {
+ SDOperand Chain = Select(N->getOperand(0)); // Token chain.
+
+ switch (N->getNumOperands()) {
+ default:
+ assert(0 && "Unknown return instruction!");
+ case 2: {
+ SDOperand RetVal = Select(N->getOperand(1));
+ switch (RetVal.getValueType()) {
+ default: assert(0 && "I don't know how to return this type! (promote?)");
+ // FIXME: do I need to add support for bools here?
+ // (return '0' or '1' in r8, basically...)
+ //
+ // FIXME: need to round floats - 80 bits is bad, the tester
+ // told me so
+ case MVT::i64:
+ // we mark r8 as live on exit up above in LowerArguments()
+ // BuildMI(BB, IA64::MOV, 1, IA64::r8).addReg(Tmp1);
+ Chain = CurDAG->getCopyToReg(Chain, IA64::r8, RetVal);
+ break;
+ case MVT::f64:
+ // we mark F8 as live on exit up above in LowerArguments()
+ // BuildMI(BB, IA64::FMOV, 1, IA64::F8).addReg(Tmp1);
+ Chain = CurDAG->getCopyToReg(Chain, IA64::F8, RetVal);
+ break;
+ }
+ break;
+ }
+ case 1:
+ break;
+ }
+
+ // we need to copy VirtGPR (the vreg (to become a real reg)) that holds
+ // the output of this function's alloc instruction back into ar.pfs
+ // before we return. this copy must not float up above the last
+ // outgoing call in this function!!!
+ SDOperand AR_PFSVal = CurDAG->getCopyFromReg(Chain, IA64Lowering.VirtGPR,
+ MVT::i64);
+ Chain = AR_PFSVal.getValue(1);
+ Chain = CurDAG->getCopyToReg(Chain, IA64::AR_PFS, AR_PFSVal);
+
+ CurDAG->SelectNodeTo(N, IA64::RET, MVT::Other, Chain); // and then just emit a 'ret' instruction
+
+ // before returning, restore the ar.pfs register (set by the 'alloc' up top)
+ // BuildMI(BB, IA64::MOV, 1).addReg(IA64::AR_PFS).addReg(IA64Lowering.VirtGPR);
+ //
+ return SDOperand(N, 0);
+ }
+
+ case ISD::BR:
+ // FIXME: we don't need long branches all the time!
+ CurDAG->SelectNodeTo(N, IA64::BRL_NOTCALL, MVT::Other, N->getOperand(1),
+ Select(N->getOperand(0)));
+ return SDOperand(N, 0);
+
+ }
+
+ return SelectCode(Op);
+}
+
+
+/// createIA64DAGToDAGInstructionSelector - This pass converts a legalized DAG
+/// into an IA64-specific DAG, ready for instruction scheduling.
+///
+FunctionPass *llvm::createIA64DAGToDAGInstructionSelector(TargetMachine &TM) {
+ return new IA64DAGToDAGISel(TM);
+}
+
diff --git a/lib/Target/IA64/IA64ISelLowering.cpp b/lib/Target/IA64/IA64ISelLowering.cpp
new file mode 100644
index 0000000000..2ffa24e78c
--- /dev/null
+++ b/lib/Target/IA64/IA64ISelLowering.cpp
@@ -0,0 +1,369 @@
+//===-- IA64ISelLowering.cpp - IA64 DAG Lowering Implementation -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Duraid Madina and 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/SSARegMap.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);
+
+ setOperationAction(ISD::BRCONDTWOWAY , MVT::Other, Expand);
+ setOperationAction(ISD::BRTWOWAY_CC , MVT::Other, Expand);
+ setOperationAction(ISD::FP_ROUND_INREG , MVT::f32 , Expand);
+
+ setSetCCResultType(MVT::i1);
+ setShiftAmountType(MVT::i64);
+
+ setOperationAction(ISD::EXTLOAD , MVT::i1 , Promote);
+
+ setOperationAction(ISD::ZEXTLOAD , MVT::i1 , Expand);
+
+ setOperationAction(ISD::SEXTLOAD , MVT::i1 , Expand);
+ setOperationAction(ISD::SEXTLOAD , MVT::i8 , Expand);
+ setOperationAction(ISD::SEXTLOAD , MVT::i16 , Expand);
+ setOperationAction(ISD::SEXTLOAD , MVT::i32 , Expand);
+
+ 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::MEMMOVE , MVT::Other, Expand);
+ setOperationAction(ISD::MEMSET , MVT::Other, Expand);
+ setOperationAction(ISD::MEMCPY , 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
+ setOperationAction(ISD::FSIN , MVT::f64, Expand);
+ setOperationAction(ISD::FCOS , MVT::f64, Expand);
+ setOperationAction(ISD::FSQRT, MVT::f64, Expand);
+ setOperationAction(ISD::FSIN , MVT::f32, Expand);
+ setOperationAction(ISD::FCOS , MVT::f32, Expand);
+ setOperationAction(ISD::FSQRT, MVT::f32, Expand);
+
+ //IA64 has these, but they are not implemented
+ setOperationAction(ISD::CTTZ , MVT::i64 , Expand);
+ setOperationAction(ISD::CTLZ , MVT::i64 , Expand);
+
+ computeRegisterProperties();
+
+ addLegalFPImmediate(+0.0);
+ addLegalFPImmediate(+1.0);
+ addLegalFPImmediate(-0.0);
+ addLegalFPImmediate(-1.0);
+
+}
+
+/// isFloatingPointZero - Return true if this is 0.0 or -0.0.
+static bool isFloatingPointZero(SDOperand Op) {
+ if (ConstantFPSDNode *CFP = dyn_cast<ConstantFPSDNode>(Op))
+ return CFP->isExactlyValue(-0.0) || CFP->isExactlyValue(0.0);
+ else if (Op.getOpcode() == ISD::EXTLOAD || Op.getOpcode() == ISD::LOAD) {
+ // Maybe this has already been legalized into the constant pool?
+ if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Op.getOperand(1)))
+ if (ConstantFP *CFP = dyn_cast<ConstantFP>(CP->get()))
+ return CFP->isExactlyValue(-0.0) || CFP->isExactlyValue(0.0);
+ }
+ return false;
+}
+
+std::vector<SDOperand>
+IA64TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
+ std::vector<SDOperand> ArgValues;
+ //
+ // add beautiful description of IA64 stack frame format
+ // here (from intel 24535803.pdf most likely)
+ //
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+
+ GP = MF.getSSARegMap()->createVirtualRegister(getRegClassFor(MVT::i64));
+ SP = MF.getSSARegMap()->createVirtualRegister(getRegClassFor(MVT::i64));
+ RP = MF.getSSARegMap()->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)
+ {
+ SDOperand newroot, argt;
+ if(count < 8) { // need to fix this logic? maybe.
+
+ switch (getValueType(I->getType())) {
+ 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.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.getSSARegMap()->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(), argVreg[count],
+ MVT::f64);
+ if (I->getType() == Type::FloatTy)
+ argt = DAG.getNode(ISD::FP_ROUND, MVT::f32, argt);
+ 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.addLiveIn(args_int[count]); // mark this register as liveIn
+ argVreg[count] =
+ MF.getSSARegMap()->createVirtualRegister(getRegClassFor(MVT::i64));
+ argPreg[count] = args_int[count];
+ argOpc[count] = IA64::MOV;
+ argt = newroot =
+ DAG.getCopyFromReg(DAG.getRoot(), argVreg[count], MVT::i64);
+ if ( getValueType(I->getType()) != MVT::i64)
+ argt = DAG.getNode(ISD::TRUNCATE, 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
+ SDOperand FIN = DAG.getFrameIndex(FI, MVT::i64);
+ argt = newroot = DAG.getLoad(getValueType(I->getType()),
+ DAG.getEntryNode(), FIN, DAG.getSrcValue(NULL));
+ }
+ ++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.getSSARegMap()->createVirtualRegister(getRegClassFor(MVT::i64));
+ BuildMI(&BB, IA64::PSEUDO_ALLOC, 0, 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, argOpc[i], 1, 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, IA64::MOV, 1, IA64::r22).addFrameIndex(FI);
+ // FIXME: we should use st8.spill here, one day
+ BuildMI(&BB, IA64::ST8, 1, 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())) {
+ 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.addLiveOut(IA64::r8);
+ break;
+ case MVT::f32:
+ case MVT::f64:
+ MF.addLiveOut(IA64::F8);
+ break;
+ }
+
+ return ArgValues;
+}
+
+std::pair<SDOperand, SDOperand>
+IA64TargetLowering::LowerCallTo(SDOperand Chain,
+ const Type *RetTy, bool isVarArg,
+ unsigned CallingConv, bool isTailCall,
+ SDOperand Callee, ArgListTy &Args,
+ SelectionDAG &DAG) {
+
+ 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);
+
+ Chain = DAG.getNode(ISD::CALLSEQ_START, MVT::Other, Chain,
+ DAG.getConstant(NumBytes, getPointerTy()));
+
+ std::vector<SDOperand> args_to_use;
+ for (unsigned i = 0, e = Args.size(); i != e; ++i)
+ {
+ switch (getValueType(Args[i].second)) {
+ 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
+ if(Args[i].second->isSigned())
+ Args[i].first = DAG.getNode(ISD::SIGN_EXTEND, MVT::i64,
+ Args[i].first);
+ else
+ Args[i].first = DAG.getNode(ISD::ZERO_EXTEND, MVT::i64,
+ Args[i].first);
+ break;
+ case MVT::f32:
+ //promote to 64-bits
+ Args[i].first = DAG.getNode(ISD::FP_EXTEND, MVT::f64, Args[i].first);
+ case MVT::f64:
+ case MVT::i64:
+ break;
+ }
+ args_to_use.push_back(Args[i].first);
+ }
+
+ std::vector<MVT::ValueType> RetVals;
+ MVT::ValueType RetTyVT = getValueType(RetTy);
+ if (RetTyVT != MVT::isVoid)
+ RetVals.push_back(RetTyVT);
+ RetVals.push_back(MVT::Other);
+
+ SDOperand TheCall = SDOperand(DAG.getCall(RetVals, Chain,