2005-10-16 05:39:50 +00:00
|
|
|
//===-- PPCISelDAGToDAG.cpp - PPC --pattern matching inst selector --------===//
|
2005-08-17 19:33:03 +00:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file was developed by Chris Lattner and is distributed under
|
|
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2005-10-16 05:39:50 +00:00
|
|
|
// This file defines a pattern matching instruction selector for PowerPC,
|
2005-08-17 19:33:03 +00:00
|
|
|
// converting from a legalized dag to a PPC dag.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2005-10-14 23:51:18 +00:00
|
|
|
#include "PPC.h"
|
2005-10-14 23:59:06 +00:00
|
|
|
#include "PPCTargetMachine.h"
|
|
|
|
#include "PPCISelLowering.h"
|
2006-03-07 06:32:48 +00:00
|
|
|
#include "PPCHazardRecognizers.h"
|
2005-08-19 22:38:53 +00:00
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
|
|
#include "llvm/CodeGen/SSARegMap.h"
|
2005-08-17 19:33:03 +00:00
|
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
|
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
|
|
#include "llvm/Target/TargetOptions.h"
|
|
|
|
#include "llvm/ADT/Statistic.h"
|
2005-08-25 04:47:18 +00:00
|
|
|
#include "llvm/Constants.h"
|
2005-08-19 22:38:53 +00:00
|
|
|
#include "llvm/GlobalValue.h"
|
2006-03-25 06:47:10 +00:00
|
|
|
#include "llvm/Intrinsics.h"
|
2005-08-17 19:33:03 +00:00
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Support/MathExtras.h"
|
2006-01-22 23:41:00 +00:00
|
|
|
#include <iostream>
|
2006-02-05 06:46:41 +00:00
|
|
|
#include <set>
|
2005-08-17 19:33:03 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
Statistic<> FrameOff("ppc-codegen", "Number of frame idx offsets collapsed");
|
|
|
|
|
|
|
|
//===--------------------------------------------------------------------===//
|
2005-10-18 00:28:58 +00:00
|
|
|
/// PPCDAGToDAGISel - PPC specific code to select PPC machine
|
2005-08-17 19:33:03 +00:00
|
|
|
/// instructions for SelectionDAG operations.
|
|
|
|
///
|
2005-10-18 00:28:58 +00:00
|
|
|
class PPCDAGToDAGISel : public SelectionDAGISel {
|
2006-03-16 18:25:23 +00:00
|
|
|
PPCTargetMachine &TM;
|
2005-10-16 05:39:50 +00:00
|
|
|
PPCTargetLowering PPCLowering;
|
2005-08-19 22:38:53 +00:00
|
|
|
unsigned GlobalBaseReg;
|
2005-08-17 19:33:03 +00:00
|
|
|
public:
|
2006-03-16 18:25:23 +00:00
|
|
|
PPCDAGToDAGISel(PPCTargetMachine &tm)
|
|
|
|
: SelectionDAGISel(PPCLowering), TM(tm),
|
|
|
|
PPCLowering(*TM.getTargetLowering()) {}
|
2005-08-17 19:33:03 +00:00
|
|
|
|
2005-08-19 22:38:53 +00:00
|
|
|
virtual bool runOnFunction(Function &Fn) {
|
|
|
|
// Make sure we re-emit a set of the global base reg if necessary
|
|
|
|
GlobalBaseReg = 0;
|
2006-03-16 18:25:23 +00:00
|
|
|
SelectionDAGISel::runOnFunction(Fn);
|
|
|
|
|
|
|
|
InsertVRSaveCode(Fn);
|
|
|
|
return true;
|
2005-08-19 22:38:53 +00:00
|
|
|
}
|
|
|
|
|
2005-08-17 19:33:03 +00:00
|
|
|
/// getI32Imm - Return a target constant with the specified value, of type
|
|
|
|
/// i32.
|
|
|
|
inline SDOperand getI32Imm(unsigned Imm) {
|
|
|
|
return CurDAG->getTargetConstant(Imm, MVT::i32);
|
|
|
|
}
|
2005-08-19 22:38:53 +00:00
|
|
|
|
2006-06-27 00:04:13 +00:00
|
|
|
/// getI64Imm - Return a target constant with the specified value, of type
|
|
|
|
/// i64.
|
|
|
|
inline SDOperand getI64Imm(uint64_t Imm) {
|
|
|
|
return CurDAG->getTargetConstant(Imm, MVT::i64);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getSmallIPtrImm - Return a target constant of pointer type.
|
|
|
|
inline SDOperand getSmallIPtrImm(unsigned Imm) {
|
|
|
|
return CurDAG->getTargetConstant(Imm, PPCLowering.getPointerTy());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-19 22:38:53 +00:00
|
|
|
/// getGlobalBaseReg - insert code into the entry mbb to materialize the PIC
|
|
|
|
/// base register. Return the virtual register that holds this value.
|
2005-08-21 22:31:09 +00:00
|
|
|
SDOperand getGlobalBaseReg();
|
2005-08-17 19:33:03 +00:00
|
|
|
|
|
|
|
// Select - Convert the specified operand from a target-independent to a
|
|
|
|
// target-specific node if it hasn't already been changed.
|
2006-02-09 00:37:58 +00:00
|
|
|
void Select(SDOperand &Result, SDOperand Op);
|
2005-08-17 19:33:03 +00:00
|
|
|
|
2005-08-19 00:38:14 +00:00
|
|
|
SDNode *SelectBitfieldInsert(SDNode *N);
|
|
|
|
|
2005-08-21 18:50:37 +00:00
|
|
|
/// 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);
|
|
|
|
|
2005-12-19 23:25:09 +00:00
|
|
|
/// SelectAddrImm - Returns true if the address N can be represented by
|
|
|
|
/// a base register plus a signed 16-bit displacement [r+imm].
|
|
|
|
bool SelectAddrImm(SDOperand N, SDOperand &Disp, SDOperand &Base);
|
|
|
|
|
|
|
|
/// SelectAddrIdx - Given the specified addressed, check to see if it can be
|
|
|
|
/// represented as an indexed [r+r] operation. Returns false if it can
|
|
|
|
/// be represented by [r+imm], which are preferred.
|
|
|
|
bool SelectAddrIdx(SDOperand N, SDOperand &Base, SDOperand &Index);
|
2005-11-30 08:22:07 +00:00
|
|
|
|
2005-12-19 23:25:09 +00:00
|
|
|
/// SelectAddrIdxOnly - Given the specified addressed, force it to be
|
|
|
|
/// represented as an indexed [r+r] operation.
|
|
|
|
bool SelectAddrIdxOnly(SDOperand N, SDOperand &Base, SDOperand &Index);
|
2005-08-21 22:31:09 +00:00
|
|
|
|
2006-03-22 05:26:03 +00:00
|
|
|
/// SelectAddrImmShift - Returns true if the address N can be represented by
|
|
|
|
/// a base register plus a signed 14-bit displacement [r+imm*4]. Suitable
|
|
|
|
/// for use by STD and friends.
|
|
|
|
bool SelectAddrImmShift(SDOperand N, SDOperand &Disp, SDOperand &Base);
|
|
|
|
|
2006-02-24 02:13:12 +00:00
|
|
|
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
|
|
|
|
/// inline asm expressions.
|
|
|
|
virtual bool SelectInlineAsmMemoryOperand(const SDOperand &Op,
|
|
|
|
char ConstraintCode,
|
|
|
|
std::vector<SDOperand> &OutOps,
|
|
|
|
SelectionDAG &DAG) {
|
|
|
|
SDOperand Op0, Op1;
|
|
|
|
switch (ConstraintCode) {
|
|
|
|
default: return true;
|
|
|
|
case 'm': // memory
|
|
|
|
if (!SelectAddrIdx(Op, Op0, Op1))
|
|
|
|
SelectAddrImm(Op, Op0, Op1);
|
|
|
|
break;
|
|
|
|
case 'o': // offsetable
|
|
|
|
if (!SelectAddrImm(Op, Op0, Op1)) {
|
|
|
|
Select(Op0, Op); // r+0.
|
2006-06-27 00:04:13 +00:00
|
|
|
Op1 = getSmallIPtrImm(0);
|
2006-02-24 02:13:12 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'v': // not offsetable
|
|
|
|
SelectAddrIdxOnly(Op, Op0, Op1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
OutOps.push_back(Op0);
|
|
|
|
OutOps.push_back(Op1);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-08-25 22:04:30 +00:00
|
|
|
SDOperand BuildSDIVSequence(SDNode *N);
|
|
|
|
SDOperand BuildUDIVSequence(SDNode *N);
|
|
|
|
|
2005-08-17 19:33:03 +00:00
|
|
|
/// InstructionSelectBasicBlock - This callback is invoked by
|
|
|
|
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
2005-10-06 18:45:51 +00:00
|
|
|
virtual void InstructionSelectBasicBlock(SelectionDAG &DAG);
|
|
|
|
|
2006-03-16 18:25:23 +00:00
|
|
|
void InsertVRSaveCode(Function &Fn);
|
|
|
|
|
2005-08-17 19:33:03 +00:00
|
|
|
virtual const char *getPassName() const {
|
|
|
|
return "PowerPC DAG->DAG Pattern Instruction Selection";
|
|
|
|
}
|
2006-03-07 06:32:48 +00:00
|
|
|
|
2006-05-16 23:54:25 +00:00
|
|
|
/// CreateTargetHazardRecognizer - Return the hazard recognizer to use for
|
|
|
|
/// this target when scheduling the DAG.
|
2006-03-08 04:25:59 +00:00
|
|
|
virtual HazardRecognizer *CreateTargetHazardRecognizer() {
|
2006-03-07 06:32:48 +00:00
|
|
|
// Should use subtarget info to pick the right hazard recognizer. For
|
|
|
|
// now, always return a PPC970 recognizer.
|
2006-03-12 09:13:49 +00:00
|
|
|
const TargetInstrInfo *II = PPCLowering.getTargetMachine().getInstrInfo();
|
|
|
|
assert(II && "No InstrInfo?");
|
|
|
|
return new PPCHazardRecognizer970(*II);
|
2006-03-07 06:32:48 +00:00
|
|
|
}
|
2005-09-13 22:03:06 +00:00
|
|
|
|
|
|
|
// Include the pieces autogenerated from the target description.
|
2005-10-14 23:37:35 +00:00
|
|
|
#include "PPCGenDAGISel.inc"
|
2005-10-06 18:45:51 +00:00
|
|
|
|
|
|
|
private:
|
2005-10-06 19:03:35 +00:00
|
|
|
SDOperand SelectSETCC(SDOperand Op);
|
2006-06-10 01:15:02 +00:00
|
|
|
void MySelect_PPCbctrl(SDOperand &Result, SDOperand N);
|
|
|
|
void MySelect_PPCcall(SDOperand &Result, SDOperand N);
|
2005-08-17 19:33:03 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2005-10-06 18:45:51 +00:00
|
|
|
/// InstructionSelectBasicBlock - This callback is invoked by
|
|
|
|
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
2005-10-18 00:28:58 +00:00
|
|
|
void PPCDAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) {
|
2005-10-06 18:45:51 +00:00
|
|
|
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 PPC 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();
|
|
|
|
|
2005-10-07 22:10:27 +00:00
|
|
|
// 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);
|
|
|
|
|
2005-10-06 18:45:51 +00:00
|
|
|
if ((Node.Val->getOpcode() >= ISD::BUILTIN_OP_END &&
|
|
|
|
Node.Val->getOpcode() < PPCISD::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.
|
2006-02-09 00:37:58 +00:00
|
|
|
SDOperand Dummy;
|
|
|
|
Select(Dummy, Node);
|
2005-10-06 18:45:51 +00:00
|
|
|
}
|
2005-10-07 22:10:27 +00:00
|
|
|
|
2005-10-06 18:45:51 +00:00
|
|
|
// Select target instructions for the DAG.
|
2006-02-05 06:46:41 +00:00
|
|
|
DAG.setRoot(SelectRoot(DAG.getRoot()));
|
2006-05-25 00:24:28 +00:00
|
|
|
assert(InFlightSet.empty() && "ISel InFlightSet has not been emptied!");
|
2005-10-06 18:45:51 +00:00
|
|
|
CodeGenMap.clear();
|
2006-05-24 20:46:25 +00:00
|
|
|
HandleMap.clear();
|
|
|
|
ReplaceMap.clear();
|
2005-10-06 18:45:51 +00:00
|
|
|
DAG.RemoveDeadNodes();
|
|
|
|
|
For functions that use vector registers, save VRSAVE, mark used
registers, and update it on entry to each function, then restore it on exit.
This compiles:
void func(vfloat *a, vfloat *b, vfloat *c) {
*a = *b * *c + *c;
}
to this:
_func:
mfspr r2, 256
oris r6, r2, 49152
mtspr 256, r6
lvx v0, 0, r5
lvx v1, 0, r4
vmaddfp v0, v1, v0, v0
stvx v0, 0, r3
mtspr 256, r2
blr
GCC produces this (which has additional stack accesses):
_func:
mfspr r0,256
stw r0,-4(r1)
oris r0,r0,0xc000
mtspr 256,r0
lvx v0,0,r5
lvx v1,0,r4
lwz r12,-4(r1)
vmaddfp v0,v0,v1,v0
stvx v0,0,r3
mtspr 256,r12
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26733 91177308-0d34-0410-b5e6-96231b3b80d8
2006-03-13 21:52:10 +00:00
|
|
|
// Emit machine code to BB.
|
2005-10-06 18:45:51 +00:00
|
|
|
ScheduleAndEmitDAG(DAG);
|
2006-03-16 18:25:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// InsertVRSaveCode - Once the entire function has been instruction selected,
|
|
|
|
/// all virtual registers are created and all machine instructions are built,
|
|
|
|
/// check to see if we need to save/restore VRSAVE. If so, do it.
|
|
|
|
void PPCDAGToDAGISel::InsertVRSaveCode(Function &F) {
|
For functions that use vector registers, save VRSAVE, mark used
registers, and update it on entry to each function, then restore it on exit.
This compiles:
void func(vfloat *a, vfloat *b, vfloat *c) {
*a = *b * *c + *c;
}
to this:
_func:
mfspr r2, 256
oris r6, r2, 49152
mtspr 256, r6
lvx v0, 0, r5
lvx v1, 0, r4
vmaddfp v0, v1, v0, v0
stvx v0, 0, r3
mtspr 256, r2
blr
GCC produces this (which has additional stack accesses):
_func:
mfspr r0,256
stw r0,-4(r1)
oris r0,r0,0xc000
mtspr 256,r0
lvx v0,0,r5
lvx v1,0,r4
lwz r12,-4(r1)
vmaddfp v0,v0,v1,v0
stvx v0,0,r3
mtspr 256,r12
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26733 91177308-0d34-0410-b5e6-96231b3b80d8
2006-03-13 21:52:10 +00:00
|
|
|
// Check to see if this function uses vector registers, which means we have to
|
|
|
|
// save and restore the VRSAVE register and update it with the regs we use.
|
|
|
|
//
|
|
|
|
// In this case, there will be virtual registers of vector type type created
|
|
|
|
// by the scheduler. Detect them now.
|
2006-03-16 18:25:23 +00:00
|
|
|
MachineFunction &Fn = MachineFunction::get(&F);
|
|
|
|
SSARegMap *RegMap = Fn.getSSARegMap();
|
For functions that use vector registers, save VRSAVE, mark used
registers, and update it on entry to each function, then restore it on exit.
This compiles:
void func(vfloat *a, vfloat *b, vfloat *c) {
*a = *b * *c + *c;
}
to this:
_func:
mfspr r2, 256
oris r6, r2, 49152
mtspr 256, r6
lvx v0, 0, r5
lvx v1, 0, r4
vmaddfp v0, v1, v0, v0
stvx v0, 0, r3
mtspr 256, r2
blr
GCC produces this (which has additional stack accesses):
_func:
mfspr r0,256
stw r0,-4(r1)
oris r0,r0,0xc000
mtspr 256,r0
lvx v0,0,r5
lvx v1,0,r4
lwz r12,-4(r1)
vmaddfp v0,v0,v1,v0
stvx v0,0,r3
mtspr 256,r12
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26733 91177308-0d34-0410-b5e6-96231b3b80d8
2006-03-13 21:52:10 +00:00
|
|
|
bool HasVectorVReg = false;
|
|
|
|
for (unsigned i = MRegisterInfo::FirstVirtualRegister,
|
2006-03-14 17:56:49 +00:00
|
|
|
e = RegMap->getLastVirtReg()+1; i != e; ++i)
|
For functions that use vector registers, save VRSAVE, mark used
registers, and update it on entry to each function, then restore it on exit.
This compiles:
void func(vfloat *a, vfloat *b, vfloat *c) {
*a = *b * *c + *c;
}
to this:
_func:
mfspr r2, 256
oris r6, r2, 49152
mtspr 256, r6
lvx v0, 0, r5
lvx v1, 0, r4
vmaddfp v0, v1, v0, v0
stvx v0, 0, r3
mtspr 256, r2
blr
GCC produces this (which has additional stack accesses):
_func:
mfspr r0,256
stw r0,-4(r1)
oris r0,r0,0xc000
mtspr 256,r0
lvx v0,0,r5
lvx v1,0,r4
lwz r12,-4(r1)
vmaddfp v0,v0,v1,v0
stvx v0,0,r3
mtspr 256,r12
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26733 91177308-0d34-0410-b5e6-96231b3b80d8
2006-03-13 21:52:10 +00:00
|
|
|
if (RegMap->getRegClass(i) == &PPC::VRRCRegClass) {
|
|
|
|
HasVectorVReg = true;
|
|
|
|
break;
|
|
|
|
}
|
2006-03-16 18:25:23 +00:00
|
|
|
if (!HasVectorVReg) return; // nothing to do.
|
|
|
|
|
For functions that use vector registers, save VRSAVE, mark used
registers, and update it on entry to each function, then restore it on exit.
This compiles:
void func(vfloat *a, vfloat *b, vfloat *c) {
*a = *b * *c + *c;
}
to this:
_func:
mfspr r2, 256
oris r6, r2, 49152
mtspr 256, r6
lvx v0, 0, r5
lvx v1, 0, r4
vmaddfp v0, v1, v0, v0
stvx v0, 0, r3
mtspr 256, r2
blr
GCC produces this (which has additional stack accesses):
_func:
mfspr r0,256
stw r0,-4(r1)
oris r0,r0,0xc000
mtspr 256,r0
lvx v0,0,r5
lvx v1,0,r4
lwz r12,-4(r1)
vmaddfp v0,v0,v1,v0
stvx v0,0,r3
mtspr 256,r12
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26733 91177308-0d34-0410-b5e6-96231b3b80d8
2006-03-13 21:52:10 +00:00
|
|
|
// If we have a vector register, we want to emit code into the entry and exit
|
|
|
|
// blocks to save and restore the VRSAVE register. We do this here (instead
|
|
|
|
// of marking all vector instructions as clobbering VRSAVE) for two reasons:
|
|
|
|
//
|
|
|
|
// 1. This (trivially) reduces the load on the register allocator, by not
|
|
|
|
// having to represent the live range of the VRSAVE register.
|
|
|
|
// 2. This (more significantly) allows us to create a temporary virtual
|
|
|
|
// register to hold the saved VRSAVE value, allowing this temporary to be
|
|
|
|
// register allocated, instead of forcing it to be spilled to the stack.
|
2006-03-16 18:25:23 +00:00
|
|
|
|
|
|
|
// Create two vregs - one to hold the VRSAVE register that is live-in to the
|
|
|
|
// function and one for the value after having bits or'd into it.
|
|
|
|
unsigned InVRSAVE = RegMap->createVirtualRegister(&PPC::GPRCRegClass);
|
|
|
|
unsigned UpdatedVRSAVE = RegMap->createVirtualRegister(&PPC::GPRCRegClass);
|
|
|
|
|
|
|
|
MachineBasicBlock &EntryBB = *Fn.begin();
|
|
|
|
// Emit the following code into the entry block:
|
|
|
|
// InVRSAVE = MFVRSAVE
|
|
|
|
// UpdatedVRSAVE = UPDATE_VRSAVE InVRSAVE
|
|
|
|
// MTVRSAVE UpdatedVRSAVE
|
|
|
|
MachineBasicBlock::iterator IP = EntryBB.begin(); // Insert Point
|
|
|
|
BuildMI(EntryBB, IP, PPC::MFVRSAVE, 0, InVRSAVE);
|
|
|
|
BuildMI(EntryBB, IP, PPC::UPDATE_VRSAVE, 1, UpdatedVRSAVE).addReg(InVRSAVE);
|
|
|
|
BuildMI(EntryBB, IP, PPC::MTVRSAVE, 1).addReg(UpdatedVRSAVE);
|
|
|
|
|
|
|
|
// Find all return blocks, outputting a restore in each epilog.
|
|
|
|
const TargetInstrInfo &TII = *TM.getInstrInfo();
|
|
|
|
for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) {
|
|
|
|
if (!BB->empty() && TII.isReturn(BB->back().getOpcode())) {
|
|
|
|
IP = BB->end(); --IP;
|
|
|
|
|
|
|
|
// Skip over all terminator instructions, which are part of the return
|
|
|
|
// sequence.
|
|
|
|
MachineBasicBlock::iterator I2 = IP;
|
|
|
|
while (I2 != BB->begin() && TII.isTerminatorInstr((--I2)->getOpcode()))
|
|
|
|
IP = I2;
|
|
|
|
|
|
|
|
// Emit: MTVRSAVE InVRSave
|
|
|
|
BuildMI(*BB, IP, PPC::MTVRSAVE, 1).addReg(InVRSAVE);
|
|
|
|
}
|
For functions that use vector registers, save VRSAVE, mark used
registers, and update it on entry to each function, then restore it on exit.
This compiles:
void func(vfloat *a, vfloat *b, vfloat *c) {
*a = *b * *c + *c;
}
to this:
_func:
mfspr r2, 256
oris r6, r2, 49152
mtspr 256, r6
lvx v0, 0, r5
lvx v1, 0, r4
vmaddfp v0, v1, v0, v0
stvx v0, 0, r3
mtspr 256, r2
blr
GCC produces this (which has additional stack accesses):
_func:
mfspr r0,256
stw r0,-4(r1)
oris r0,r0,0xc000
mtspr 256,r0
lvx v0,0,r5
lvx v1,0,r4
lwz r12,-4(r1)
vmaddfp v0,v0,v1,v0
stvx v0,0,r3
mtspr 256,r12
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26733 91177308-0d34-0410-b5e6-96231b3b80d8
2006-03-13 21:52:10 +00:00
|
|
|
}
|
2005-10-06 18:45:51 +00:00
|
|
|
}
|
2005-09-03 01:17:22 +00:00
|
|
|
|
2006-03-16 18:25:23 +00:00
|
|
|
|
2005-08-19 22:38:53 +00:00
|
|
|
/// getGlobalBaseReg - Output the instructions required to put the
|
|
|
|
/// base address to use for accessing globals into a register.
|
|
|
|
///
|
2005-10-18 00:28:58 +00:00
|
|
|
SDOperand PPCDAGToDAGISel::getGlobalBaseReg() {
|
2005-08-19 22:38:53 +00:00
|
|
|
if (!GlobalBaseReg) {
|
|
|
|
// Insert the set of GlobalBaseReg into the first MBB of the function
|
|
|
|
MachineBasicBlock &FirstMBB = BB->getParent()->front();
|
|
|
|
MachineBasicBlock::iterator MBBI = FirstMBB.begin();
|
|
|
|
SSARegMap *RegMap = BB->getParent()->getSSARegMap();
|
2006-06-27 00:04:13 +00:00
|
|
|
|
|
|
|
if (PPCLowering.getPointerTy() == MVT::i32)
|
|
|
|
GlobalBaseReg = RegMap->createVirtualRegister(PPC::GPRCRegisterClass);
|
|
|
|
else
|
|
|
|
GlobalBaseReg = RegMap->createVirtualRegister(PPC::G8RCRegisterClass);
|
|
|
|
|
2005-08-19 22:38:53 +00:00
|
|
|
BuildMI(FirstMBB, MBBI, PPC::MovePCtoLR, 0, PPC::LR);
|
|
|
|
BuildMI(FirstMBB, MBBI, PPC::MFLR, 1, GlobalBaseReg);
|
|
|
|
}
|
2006-06-27 00:04:13 +00:00
|
|
|
return CurDAG->getRegister(GlobalBaseReg, PPCLowering.getPointerTy());
|
2005-08-19 22:38:53 +00:00
|
|
|
}
|
|
|
|
|
2006-06-27 00:04:13 +00:00
|
|
|
/// isIntS16Immediate - This method tests to see if the node is either a 32-bit
|
|
|
|
/// or 64-bit immediate, and if the value can be accurately represented as a
|
|
|
|
/// sign extension from a 16-bit value. If so, this returns true and the
|
|
|
|
/// immediate.
|
|
|
|
static bool isIntS16Immediate(SDNode *N, short &Imm) {
|
|
|
|
if (N->getOpcode() != ISD::Constant)
|
|
|
|
return false;
|
2005-08-19 22:38:53 +00:00
|
|
|
|
2006-06-27 00:04:13 +00:00
|
|
|
Imm = (short)cast<ConstantSDNode>(N)->getValue();
|
|
|
|
if (N->getValueType(0) == MVT::i32)
|
|
|
|
return Imm == (int32_t)cast<ConstantSDNode>(N)->getValue();
|
|
|
|
else
|
|
|
|
return Imm == (int64_t)cast<ConstantSDNode>(N)->getValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool isIntS16Immediate(SDOperand Op, short &Imm) {
|
|
|
|
return isIntS16Immediate(Op.Val, Imm);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// isInt32Immediate - This method tests to see if the node is a 32-bit constant
|
|
|
|
/// operand. If so Imm will receive the 32-bit value.
|
|
|
|
static bool isInt32Immediate(SDNode *N, unsigned &Imm) {
|
|
|
|
if (N->getOpcode() == ISD::Constant && N->getValueType(0) == MVT::i32) {
|
2005-08-18 05:00:13 +00:00
|
|
|
Imm = cast<ConstantSDNode>(N)->getValue();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-06-27 00:04:13 +00:00
|
|
|
/// isInt64Immediate - This method tests to see if the node is a 64-bit constant
|
|
|
|
/// operand. If so Imm will receive the 64-bit value.
|
|
|
|
static bool isInt64Immediate(SDNode *N, uint64_t &Imm) {
|
|
|
|
if (N->getOpcode() == ISD::Constant && N->getValueType(0) == MVT::i32) {
|
|
|
|
Imm = cast<ConstantSDNode>(N)->getValue();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// isInt32Immediate - This method tests to see if a constant operand.
|
|
|
|
// If so Imm will receive the 32 bit value.
|
|
|
|
static bool isInt32Immediate(SDOperand N, unsigned &Imm) {
|
|
|
|
return isInt32Immediate(N.Val, Imm);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// isOpcWithIntImmediate - This method tests to see if the node is a specific
|
|
|
|
// opcode and that it has a immediate integer right operand.
|
|
|
|
// If so Imm will receive the 32 bit value.
|
|
|
|
static bool isOpcWithIntImmediate(SDNode *N, unsigned Opc, unsigned& Imm) {
|
|
|
|
return N->getOpcode() == Opc && isInt32Immediate(N->getOperand(1).Val, Imm);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-18 07:30:46 +00:00
|
|
|
// isRunOfOnes - Returns true iff Val consists of one contiguous run of 1s with
|
|
|
|
// any number of 0s on either side. The 1s are allowed to wrap from LSB to
|
|
|
|
// MSB, so 0x000FFF0, 0x0000FFFF, and 0xFF0000FF are all runs. 0x0F0F0000 is
|
|
|
|
// not, since all 1s are not contiguous.
|
|
|
|
static bool isRunOfOnes(unsigned Val, unsigned &MB, unsigned &ME) {
|
|
|
|
if (isShiftedMask_32(Val)) {
|
|
|
|
// look for the first non-zero bit
|
|
|
|
MB = CountLeadingZeros_32(Val);
|
|
|
|
// look for the first zero bit after the run of ones
|
|
|
|
ME = CountLeadingZeros_32((Val - 1) ^ Val);
|
|
|
|
return true;
|
2005-08-25 04:47:18 +00:00
|
|
|
} else {
|
|
|
|
Val = ~Val; // invert mask
|
|
|
|
if (isShiftedMask_32(Val)) {
|
|
|
|
// effectively look for the first zero bit
|
|
|
|
ME = CountLeadingZeros_32(Val) - 1;
|
|
|
|
// effectively look for the first one bit after the run of zeros
|
|
|
|
MB = CountLeadingZeros_32((Val - 1) ^ Val) + 1;
|
|
|
|
return true;
|
|
|
|
}
|
2005-08-18 07:30:46 +00:00
|
|
|
}
|
|
|
|
// no run present
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-10-09 05:36:17 +00:00
|
|
|
// isRotateAndMask - Returns true if Mask and Shift can be folded into a rotate
|
2005-08-18 07:30:46 +00:00
|
|
|
// and mask opcode and mask operation.
|
|
|
|
static bool isRotateAndMask(SDNode *N, unsigned Mask, bool IsShiftMask,
|
|
|
|
unsigned &SH, unsigned &MB, unsigned &ME) {
|
2005-10-19 00:05:37 +00:00
|
|
|
// Don't even go down this path for i64, since different logic will be
|
|
|
|
// necessary for rldicl/rldicr/rldimi.
|
|
|
|
if (N->getValueType(0) != MVT::i32)
|
|
|
|
return false;
|
|
|
|
|
2005-08-18 07:30:46 +00:00
|
|
|
unsigned Shift = 32;
|
|
|
|
unsigned Indeterminant = ~0; // bit mask marking indeterminant results
|
|
|
|
unsigned Opcode = N->getOpcode();
|
2005-08-30 00:59:16 +00:00
|
|
|
if (N->getNumOperands() != 2 ||
|
2006-06-27 00:04:13 +00:00
|
|
|
!isInt32Immediate(N->getOperand(1).Val, Shift) || (Shift > 31))
|
2005-08-18 07:30:46 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (Opcode == ISD::SHL) {
|
|
|
|
// apply shift left to mask if it comes first
|
|
|
|
if (IsShiftMask) Mask = Mask << Shift;
|
|
|
|
// determine which bits are made indeterminant by shift
|
|
|
|
Indeterminant = ~(0xFFFFFFFFu << Shift);
|
2005-10-15 21:40:12 +00:00
|
|
|
} else if (Opcode == ISD::SRL) {
|
2005-08-18 07:30:46 +00:00
|
|
|
// apply shift right to mask if it comes first
|
|
|
|
if (IsShiftMask) Mask = Mask >> Shift;
|
|
|
|
// determine which bits are made indeterminant by shift
|
|
|
|
Indeterminant = ~(0xFFFFFFFFu >> Shift);
|
|
|
|
// adjust for the left rotate
|
|
|
|
Shift = 32 - Shift;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the mask doesn't intersect any Indeterminant bits
|
|
|
|
if (Mask && !(Mask & Indeterminant)) {
|
2006-05-12 16:29:37 +00:00
|
|
|
SH = Shift & 31;
|
2005-08-18 07:30:46 +00:00
|
|
|
// make sure the mask is still a mask (wrap arounds may not be)
|
|
|
|
return isRunOfOnes(Mask, MB, ME);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-08-19 00:38:14 +00:00
|
|
|
/// SelectBitfieldInsert - turn an or of two masked values into
|
|
|
|
/// the rotate left word immediate then mask insert (rlwimi) instruction.
|
2005-10-18 00:28:58 +00:00
|
|
|
SDNode *PPCDAGToDAGISel::SelectBitfieldInsert(SDNode *N) {
|
2005-08-19 00:38:14 +00:00
|
|
|
SDOperand Op0 = N->getOperand(0);
|
|
|
|
SDOperand Op1 = N->getOperand(1);
|
|
|
|
|
2006-05-07 00:23:38 +00:00
|
|
|
uint64_t LKZ, LKO, RKZ, RKO;
|
2006-05-08 17:38:32 +00:00
|
|
|
TLI.ComputeMaskedBits(Op0, 0xFFFFFFFFULL, LKZ, LKO);
|
|
|
|
TLI.ComputeMaskedBits(Op1, 0xFFFFFFFFULL, RKZ, RKO);
|
2005-08-19 00:38:14 +00:00
|
|
|
|
2006-05-08 17:38:32 +00:00
|
|
|
unsigned TargetMask = LKZ;
|
|
|
|
unsigned InsertMask = RKZ;
|
|
|
|
|
|
|
|
if ((TargetMask | InsertMask) == 0xFFFFFFFF) {
|
|
|
|
unsigned Op0Opc = Op0.getOpcode();
|
|
|
|
unsigned Op1Opc = Op1.getOpcode();
|
|
|
|
unsigned Value, SH = 0;
|
|
|
|
TargetMask = ~TargetMask;
|
|
|
|
InsertMask = ~InsertMask;
|
2006-05-07 00:23:38 +00:00
|
|
|
|
2006-05-08 17:38:32 +00:00
|
|
|
// If the LHS has a foldable shift and the RHS does not, then swap it to the
|
|
|
|
// RHS so that we can fold the shift into the insert.
|
2006-05-07 00:23:38 +00:00
|
|
|
if (Op0Opc == ISD::AND && Op1Opc == ISD::AND) {
|
|
|
|
if (Op0.getOperand(0).getOpcode() == ISD::SHL ||
|
|
|
|
Op0.getOperand(0).getOpcode() == ISD::SRL) {
|
|
|
|
if (Op1.getOperand(0).getOpcode() != ISD::SHL &&
|
|
|
|
Op1.getOperand(0).getOpcode() != ISD::SRL) {
|
|
|
|
std::swap(Op0, Op1);
|
|
|
|
std::swap(Op0Opc, Op1Opc);
|
2006-05-08 17:38:32 +00:00
|
|
|
std::swap(TargetMask, InsertMask);
|
2006-05-07 00:23:38 +00:00
|
|
|
}
|
|
|
|
}
|
2006-05-08 17:38:32 +00:00
|
|
|
} else if (Op0Opc == ISD::SHL || Op0Opc == ISD::SRL) {
|
|
|
|
if (Op1Opc == ISD::AND && Op1.getOperand(0).getOpcode() != ISD::SHL &&
|
|
|
|
Op1.getOperand(0).getOpcode() != ISD::SRL) {
|
|
|
|
std::swap(Op0, Op1);
|
|
|
|
std::swap(Op0Opc, Op1Opc);
|
|
|
|
std::swap(TargetMask, InsertMask);
|
|
|
|
}
|
2005-08-19 00:38:14 +00:00
|
|
|
}
|
2006-05-07 00:23:38 +00:00
|
|
|
|
|
|
|
unsigned MB, ME;
|
2006-05-12 16:29:37 +00:00
|
|
|
if (InsertMask && isRunOfOnes(InsertMask, MB, ME)) {
|
2006-05-07 00:23:38 +00:00
|
|
|
SDOperand Tmp1, Tmp2, Tmp3;
|
2006-05-08 17:38:32 +00:00
|
|
|
bool DisjointMask = (TargetMask ^ InsertMask) == 0xFFFFFFFF;
|
2006-05-07 00:23:38 +00:00
|
|
|
|
|
|
|
if ((Op1Opc == ISD::SHL || Op1Opc == ISD::SRL) &&
|
2006-06-27 00:04:13 +00:00
|
|
|
isInt32Immediate(Op1.getOperand(1), Value)) {
|
2006-05-07 00:23:38 +00:00
|
|
|
Op1 = Op1.getOperand(0);
|
|
|
|
SH = (Op1Opc == ISD::SHL) ? Value : 32 - Value;
|
2005-08-19 00:38:14 +00:00
|
|
|
}
|
2006-05-07 00:23:38 +00:00
|
|
|
if (Op1Opc == ISD::AND) {
|
|
|
|
unsigned SHOpc = Op1.getOperand(0).getOpcode();
|
|
|
|
if ((SHOpc == ISD::SHL || SHOpc == ISD::SRL) &&
|
2006-06-27 00:04:13 +00:00
|
|
|
isInt32Immediate(Op1.getOperand(0).getOperand(1), Value)) {
|
2006-05-07 00:23:38 +00:00
|
|
|
Op1 = Op1.getOperand(0).getOperand(0);
|
|
|
|
SH = (SHOpc == ISD::SHL) ? Value : 32 - Value;
|
|
|
|
} else {
|
|
|
|
Op1 = Op1.getOperand(0);
|
|
|
|
}
|
2005-08-19 00:38:14 +00:00
|
|
|
}
|
2006-05-07 00:23:38 +00:00
|
|
|
|
|
|
|
Tmp3 = (Op0Opc == ISD::AND && DisjointMask) ? Op0.getOperand(0) : Op0;
|
|
|
|
Select(Tmp1, Tmp3);
|
|
|
|
Select(Tmp2, Op1);
|
2006-05-12 16:29:37 +00:00
|
|
|
SH &= 31;
|
2006-05-07 00:23:38 +00:00
|
|
|
return CurDAG->getTargetNode(PPC::RLWIMI, MVT::i32, Tmp1, Tmp2,
|
|
|
|
getI32Imm(SH), getI32Imm(MB), getI32Imm(ME));
|
2005-08-19 00:38:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-12-19 23:25:09 +00:00
|
|
|
/// SelectAddrImm - Returns true if the address N can be represented by
|
|
|
|
/// a base register plus a signed 16-bit displacement [r+imm].
|
|
|
|
bool PPCDAGToDAGISel::SelectAddrImm(SDOperand N, SDOperand &Disp,
|
|
|
|
SDOperand &Base) {
|
2006-03-01 07:14:48 +00:00
|
|
|
// If this can be more profitably realized as r+r, fail.
|
|
|
|
if (SelectAddrIdx(N, Disp, Base))
|
|
|
|
return false;
|
|
|
|
|
2005-12-19 23:25:09 +00:00
|
|
|
if (N.getOpcode() == ISD::ADD) {
|
2006-06-27 00:04:13 +00:00
|
|
|
short imm = 0;
|
|
|
|
if (isIntS16Immediate(N.getOperand(1), imm)) {
|
|
|
|
Disp = getI32Imm((int)imm & 0xFFFF);
|
2005-12-19 23:25:09 +00:00
|
|
|
if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N.getOperand(0))) {
|
2006-06-27 00:04:13 +00:00
|
|
|
Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType());
|
2005-08-21 22:31:09 +00:00
|
|
|
} else {
|
2006-02-05 08:45:01 +00:00
|
|
|
Base = N.getOperand(0);
|
2005-08-21 22:31:09 +00:00
|
|
|
}
|
2005-12-19 23:25:09 +00:00
|
|
|
return true; // [r+i]
|
|
|
|
} else if (N.getOperand(1).getOpcode() == PPCISD::Lo) {
|
2005-11-17 18:02:16 +00:00
|
|
|
// Match LOAD (ADD (X, Lo(G))).
|
2005-12-19 23:25:09 +00:00
|
|
|
assert(!cast<ConstantSDNode>(N.getOperand(1).getOperand(1))->getValue()
|
2005-11-17 18:02:16 +00:00
|
|
|
&& "Cannot handle constant offsets yet!");
|
2005-12-19 23:25:09 +00:00
|
|
|
Disp = N.getOperand(1).getOperand(0); // The global address.
|
|
|
|
assert(Disp.getOpcode() == ISD::TargetGlobalAddress ||
|
2006-04-22 18:53:45 +00:00
|
|
|
Disp.getOpcode() == ISD::TargetConstantPool ||
|
|
|
|
Disp.getOpcode() == ISD::TargetJumpTable);
|
2006-02-05 08:45:01 +00:00
|
|
|
Base = N.getOperand(0);
|
2005-12-19 23:25:09 +00:00
|
|
|
return true; // [&g+r]
|
2005-08-21 22:31:09 +00:00
|
|
|
}
|
2006-03-01 07:14:48 +00:00
|
|
|
} else if (N.getOpcode() == ISD::OR) {
|
2006-06-27 00:04:13 +00:00
|
|
|
short imm = 0;
|
|
|
|
if (isIntS16Immediate(N.getOperand(1), imm)) {
|
2006-03-01 07:14:48 +00:00
|
|
|
// If this is an or of disjoint bitfields, we can codegen this as an add
|
|
|
|
// (for better address arithmetic) if the LHS and RHS of the OR are
|
|
|
|
// provably disjoint.
|
|
|
|
uint64_t LHSKnownZero, LHSKnownOne;
|
|
|
|
PPCLowering.ComputeMaskedBits(N.getOperand(0), ~0U,
|
|
|
|
LHSKnownZero, LHSKnownOne);
|
2006-06-27 00:04:13 +00:00
|
|
|
if ((LHSKnownZero|~(unsigned)imm) == ~0U) {
|
2006-03-01 07:14:48 +00:00
|
|
|
// If all of the bits are known zero on the LHS or RHS, the add won't
|
|
|
|
// carry.
|
|
|
|
Base = N.getOperand(0);
|
2006-06-27 00:04:13 +00:00
|
|
|
Disp = getI32Imm((int)imm & 0xFFFF);
|
2006-03-01 07:14:48 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2006-03-20 22:38:22 +00:00
|
|
|
} else if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) {
|
|
|
|
// Loading from a constant address.
|
2006-06-27 00:04:13 +00:00
|
|
|
|
2006-03-20 22:38:22 +00:00
|
|
|
// If this address fits entirely in a 16-bit sext immediate field, codegen
|
|
|
|
// this as "d, 0"
|
2006-06-27 00:04:13 +00:00
|
|
|
short Imm;
|
|
|
|
if (isIntS16Immediate(CN, Imm)) {
|
|
|
|
Disp = CurDAG->getTargetConstant(Imm, CN->getValueType(0));
|
|
|
|
Base = CurDAG->getRegister(PPC::R0, CN->getValueType(0));
|
2006-03-20 22:38:22 +00:00
|
|
|
return true;
|
|
|
|
}
|
2006-06-27 00:04:13 +00:00
|
|
|
|
|
|
|
// FIXME: Handle small sext constant offsets in PPC64 mode also!
|
|
|
|
if (CN->getValueType(0) == MVT::i32) {
|
|
|
|
int Addr = (int)CN->getValue();
|
2006-03-20 22:38:22 +00:00
|
|
|
|
2006-06-27 00:04:13 +00:00
|
|
|
// Otherwise, break this down into an LIS + disp.
|
|
|
|
Disp = getI32Imm((short)Addr);
|
|
|
|
Base = CurDAG->getConstant(Addr - (signed short)Addr, MVT::i32);
|
|
|
|
return true;
|
|
|
|
}
|
2005-08-21 22:31:09 +00:00
|
|
|
}
|
2006-03-20 22:38:22 +00:00
|
|
|
|
2006-06-27 00:04:13 +00:00
|
|
|
Disp = getSmallIPtrImm(0);
|
2005-12-19 23:25:09 +00:00
|
|
|
if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N))
|
2006-06-27 00:04:13 +00:00
|
|
|
Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType());
|
2005-12-10 02:36:00 +00:00
|
|
|
else
|
2006-02-05 08:45:01 +00:00
|
|
|
Base = N;
|
2005-12-19 23:25:09 +00:00
|
|
|
return true; // [r+0]
|
2005-08-21 22:31:09 +00:00
|
|
|
}
|
2005-08-17 19:33:03 +00:00
|
|
|
|
2005-12-19 23:25:09 +00:00
|
|
|
/// SelectAddrIdx - Given the specified addressed, check to see if it can be
|
|
|
|
/// represented as an indexed [r+r] operation. Returns false if it can
|
|
|
|
/// be represented by [r+imm], which are preferred.
|
|
|
|
bool PPCDAGToDAGISel::SelectAddrIdx(SDOperand N, SDOperand &Base,
|
|
|
|
SDOperand &Index) {
|
2006-06-27 00:04:13 +00:00
|
|
|
short imm = 0;
|
2005-12-19 23:25:09 +00:00
|
|
|
if (N.getOpcode() == ISD::ADD) {
|
2006-06-27 00:04:13 +00:00
|
|
|
if (isIntS16Immediate(N.getOperand(1), imm))
|
2006-03-01 07:14:48 +00:00
|
|
|
return false; // r+i
|
|
|
|
if (N.getOperand(1).getOpcode() == PPCISD::Lo)
|
|
|
|
return false; // r+i
|
|
|
|
|
2006-02-05 08:45:01 +00:00
|
|
|
Base = N.getOperand(0);
|
|
|
|
Index = N.getOperand(1);
|
2005-12-19 23:25:09 +00:00
|
|
|
return true;
|
2006-03-01 07:14:48 +00:00
|
|
|
} else if (N.getOpcode() == ISD::OR) {
|
2006-06-27 00:04:13 +00:00
|
|
|
if (isIntS16Immediate(N.getOperand(1), imm))
|
2006-03-01 07:14:48 +00:00
|
|
|
return false; // r+i can fold it if we can.
|
|
|
|
|
|
|
|
// If this is an or of disjoint bitfields, we can codegen this as an add
|
|
|
|
// (for better address arithmetic) if the LHS and RHS of the OR are provably
|
|
|
|
// disjoint.
|
|
|
|
uint64_t LHSKnownZero, LHSKnownOne;
|
|
|
|
uint64_t RHSKnownZero, RHSKnownOne;
|
|
|
|
PPCLowering.ComputeMaskedBits(N.getOperand(0), ~0U,
|
|
|
|
LHSKnownZero, LHSKnownOne);
|
|
|
|
|
|
|
|
if (LHSKnownZero) {
|
|
|
|
PPCLowering.ComputeMaskedBits(N.getOperand(1), ~0U,
|
|
|
|
RHSKnownZero, RHSKnownOne);
|
|
|
|
// If all of the bits are known zero on the LHS or RHS, the add won't
|
|
|
|
// carry.
|
|
|
|
if ((LHSKnownZero | RHSKnownZero) == ~0U) {
|
|
|
|
Base = N.getOperand(0);
|
|
|
|
Index = N.getOperand(1);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2005-12-19 23:25:09 +00:00
|
|
|
}
|
2006-03-01 07:14:48 +00:00
|
|
|
|
|
|
|
return false;
|
2005-12-19 23:25:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// SelectAddrIdxOnly - Given the specified addressed, force it to be
|
|
|
|
/// represented as an indexed [r+r] operation.
|
|
|
|
bool PPCDAGToDAGISel::SelectAddrIdxOnly(SDOperand N, SDOperand &Base,
|
|
|
|
SDOperand &Index) {
|
2006-03-01 07:14:48 +00:00
|
|
|
// Check to see if we can easily represent this as an [r+r] address. This
|
|
|
|
// will fail if it thinks that the address is more profitably represented as
|
|
|
|
// reg+imm, e.g. where imm = 0.
|
2006-03-24 17:58:06 +00:00
|
|
|
if (SelectAddrIdx(N, Base, Index))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// If the operand is an addition, always emit this as [r+r], since this is
|
|
|
|
// better (for code size, and execution, as the memop does the add for free)
|
|
|
|
// than emitting an explicit add.
|
|
|
|
if (N.getOpcode() == ISD::ADD) {
|
|
|
|
Base = N.getOperand(0);
|
|
|
|
Index = N.getOperand(1);
|
|
|
|
return true;
|
2005-11-30 08:22:07 +00:00
|
|
|
}
|
2006-03-24 17:58:06 +00:00
|
|
|
|
|
|
|
// Otherwise, do it the hard way, using R0 as the base register.
|
2006-06-27 00:04:13 +00:00
|
|
|
Base = CurDAG->getRegister(PPC::R0, N.getValueType());
|
2006-03-24 17:58:06 +00:00
|
|
|
Index = N;
|
2005-12-19 23:25:09 +00:00
|
|
|
return true;
|
2005-11-30 08:22:07 +00:00
|
|
|
}
|
|
|
|
|
2006-03-22 05:26:03 +00:00
|
|
|
/// SelectAddrImmShift - Returns true if the address N can be represented by
|
|
|
|
/// a base register plus a signed 14-bit displacement [r+imm*4]. Suitable
|
|
|
|
/// for use by STD and friends.
|
|
|
|
bool PPCDAGToDAGISel::SelectAddrImmShift(SDOperand N, SDOperand &Disp,
|
|
|
|
SDOperand &Base) {
|
|
|
|
// If this can be more profitably realized as r+r, fail.
|
|
|
|
if (SelectAddrIdx(N, Disp, Base))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (N.getOpcode() == ISD::ADD) {
|
2006-06-27 00:04:13 +00:00
|
|
|
short imm = 0;
|
|
|
|
if (isIntS16Immediate(N.getOperand(1), imm) && (imm & 3) == 0) {
|
|
|
|
Disp = getI32Imm(((int)imm & 0xFFFF) >> 2);
|
2006-03-22 05:26:03 +00:00
|
|
|
if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N.getOperand(0))) {
|
2006-06-27 00:04:13 +00:00
|
|
|
Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType());
|
2006-03-22 05:26:03 +00:00
|
|
|
} else {
|
|
|
|
Base = N.getOperand(0);
|
|
|
|
}
|
|
|
|
return true; // [r+i]
|
|
|
|
} else if (N.getOperand(1).getOpcode() == PPCISD::Lo) {
|
|
|
|
// Match LOAD (ADD (X, Lo(G))).
|
|
|
|
assert(!cast<ConstantSDNode>(N.getOperand(1).getOperand(1))->getValue()
|
|
|
|
&& "Cannot handle constant offsets yet!");
|
|
|
|
Disp = N.getOperand(1).getOperand(0); // The global address.
|
|
|
|
assert(Disp.getOpcode() == ISD::TargetGlobalAddress ||
|
2006-04-22 18:53:45 +00:00
|
|
|
Disp.getOpcode() == ISD::TargetConstantPool ||
|
|
|
|
Disp.getOpcode() == ISD::TargetJumpTable);
|
2006-03-22 05:26:03 +00:00
|
|
|
Base = N.getOperand(0);
|
|
|
|
return true; // [&g+r]
|
|
|
|
}
|
|
|
|
} else if (N.getOpcode() == ISD::OR) {
|
2006-06-27 00:04:13 +00:00
|
|
|
short imm = 0;
|
|
|
|
if (isIntS16Immediate(N.getOperand(1), imm) && (imm & 3) == 0) {
|
2006-03-22 05:26:03 +00:00
|
|
|
// If this is an or of disjoint bitfields, we can codegen this as an add
|
|
|
|
// (for better address arithmetic) if the LHS and RHS of the OR are
|
|
|
|
// provably disjoint.
|
|
|
|
uint64_t LHSKnownZero, LHSKnownOne;
|
|
|
|
PPCLowering.ComputeMaskedBits(N.getOperand(0), ~0U,
|
|
|
|
LHSKnownZero, LHSKnownOne);
|
2006-06-27 00:04:13 +00:00
|
|
|
if ((LHSKnownZero|~(unsigned)imm) == ~0U) {
|
2006-03-22 05:26:03 +00:00
|
|
|
// If all of the bits are known zero on the LHS or RHS, the add won't
|
|
|
|
// carry.
|
|
|
|
Base = N.getOperand(0);
|
2006-06-27 00:04:13 +00:00
|
|
|
Disp = getI32Imm(((int)imm & 0xFFFF) >> 2);
|
2006-03-22 05:26:03 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) {
|
|
|
|
// Loading from a constant address.
|
2006-06-27 00:04:13 +00:00
|
|
|
|
|
|
|
// If this address fits entirely in a 14-bit sext immediate field, codegen
|
|
|
|
// this as "d, 0"
|
|
|
|
short Imm;
|
|
|
|
if (isIntS16Immediate(CN, Imm)) {
|
|
|
|
Disp = getSmallIPtrImm((unsigned short)Imm >> 2);
|
|
|
|
Base = CurDAG->getRegister(PPC::R0, CN->getValueType(0));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Handle small sext constant offsets in PPC64 mode also!
|
|
|
|
if (CN->getValueType(0) == MVT::i32) {
|
|
|
|
int Addr = (int)CN->getValue();
|
2006-03-22 05:26:03 +00:00
|
|
|
|
|
|
|
// Otherwise, break this down into an LIS + disp.
|
|
|
|
Disp = getI32Imm((short)Addr >> 2);
|
|
|
|
Base = CurDAG->getConstant(Addr - (signed short)Addr, MVT::i32);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-27 00:04:13 +00:00
|
|
|
Disp = getSmallIPtrImm(0);
|
2006-03-22 05:26:03 +00:00
|
|
|
if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N))
|
2006-06-27 00:04:13 +00:00
|
|
|
Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType());
|
2006-03-22 05:26:03 +00:00
|
|
|
else
|
|
|
|
Base = N;
|
|
|
|
return true; // [r+0]
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-21 18:50:37 +00:00
|
|
|
/// SelectCC - Select a comparison of the specified values with the specified
|
|
|
|
/// condition code, returning the CR# of the expression.
|
2005-10-18 00:28:58 +00:00
|
|
|
SDOperand PPCDAGToDAGISel::SelectCC(SDOperand LHS, SDOperand RHS,
|
|
|
|
ISD::CondCode CC) {
|
2005-08-21 18:50:37 +00:00
|
|
|
// Always select the LHS.
|
2006-02-09 00:37:58 +00:00
|
|
|
Select(LHS, LHS);
|
2006-06-27 00:04:13 +00:00
|
|
|
unsigned Opc;
|
|
|
|
|
|
|
|
if (LHS.getValueType() == MVT::i32) {
|
2006-06-27 00:10:13 +00:00
|
|
|
unsigned Imm;
|
2006-06-27 00:04:13 +00:00
|
|
|
if (ISD::isUnsignedIntSetCC(CC)) {
|
|
|
|
if (isInt32Immediate(RHS, Imm) && isUInt16(Imm))
|
|
|
|
return SDOperand(CurDAG->getTargetNode(PPC::CMPLWI, MVT::i32, LHS,
|
|
|
|
getI32Imm(Imm & 0xFFFF)), 0);
|
|
|
|
Opc = PPC::CMPLW;
|
|
|
|
} else {
|
|
|
|
short SImm;
|
|
|
|
if (isIntS16Immediate(RHS, SImm))
|
|
|
|
return SDOperand(CurDAG->getTargetNode(PPC::CMPWI, MVT::i32, LHS,
|
|
|
|
getI32Imm((int)SImm & 0xFFFF)),
|
|
|
|
0);
|
|
|
|
Opc = PPC::CMPW;
|
|
|
|
}
|
|
|
|
} else if (LHS.getValueType() == MVT::i64) {
|
|
|
|
uint64_t Imm;
|
|
|
|
if (ISD::isUnsignedIntSetCC(CC)) {
|
|
|
|
if (isInt64Immediate(RHS.Val, Imm) && isUInt16(Imm))
|
|
|
|
return SDOperand(CurDAG->getTargetNode(PPC::CMPLDI, MVT::i64, LHS,
|
|
|
|
getI64Imm(Imm & 0xFFFF)), 0);
|
|
|
|
Opc = PPC::CMPLD;
|
|
|
|
} else {
|
|
|
|
short SImm;
|
|
|
|
if (isIntS16Immediate(RHS, SImm))
|
|
|
|
return SDOperand(CurDAG->getTargetNode(PPC::CMPDI, MVT::i64, LHS,
|
|
|
|
getI64Imm((int)SImm & 0xFFFF)),
|
|
|
|
0);
|
|
|
|
Opc = PPC::CMPD;
|
|
|
|
}
|
2005-10-01 01:35:02 +00:00
|
|
|
} else if (LHS.getValueType() == MVT::f32) {
|
2006-06-27 00:04:13 +00:00
|
|
|
Opc = PPC::FCMPUS;
|
2005-08-21 18:50:37 +00:00
|
|
|
} else {
|
2006-06-27 00:04:13 +00:00
|
|
|
assert(LHS.getValueType() == MVT::f64 && "Unknown vt!");
|
|
|
|
Opc = PPC::FCMPUD;
|
2005-08-21 18:50:37 +00:00
|
|
|
}
|
2006-06-27 00:04:13 +00:00
|
|
|
Select(RHS, RHS);
|
|
|
|
return SDOperand(CurDAG->getTargetNode(Opc, MVT::i32, LHS, RHS), 0);
|
2005-08-21 18:50:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// getBCCForSetCC - Returns the PowerPC condition branch mnemonic corresponding
|
|
|
|
/// to Condition.
|
|
|
|
static unsigned getBCCForSetCC(ISD::CondCode CC) {
|
|
|
|
switch (CC) {
|
|
|
|
default: assert(0 && "Unknown condition!"); abort();
|
2005-10-28 20:49:47 +00:00
|
|
|
case ISD::SETOEQ: // FIXME: This is incorrect see PR642.
|
2006-05-25 16:54:16 +00:00
|
|
|
case ISD::SETUEQ:
|
2005-08-21 18:50:37 +00:00
|
|
|
case ISD::SETEQ: return PPC::BEQ;
|
2005-10-28 20:49:47 +00:00
|
|
|
case ISD::SETONE: // FIXME: This is incorrect see PR642.
|
2006-05-25 16:54:16 +00:00
|
|
|
case ISD::SETUNE:
|
2005-08-21 18:50:37 +00:00
|
|
|
case ISD::SETNE: return PPC::BNE;
|
2005-10-28 20:49:47 +00:00
|
|
|
case ISD::SETOLT: // FIXME: This is incorrect see PR642.
|
2005-08-21 18:50:37 +00:00
|
|
|
case ISD::SETULT:
|
|
|
|
case ISD::SETLT: return PPC::BLT;
|
2005-10-28 20:49:47 +00:00
|
|
|
case ISD::SETOLE: // FIXME: This is incorrect see PR642.
|
2005-08-21 18:50:37 +00:00
|
|
|
case ISD::SETULE:
|
|
|
|
case ISD::SETLE: return PPC::BLE;
|
2005-10-28 20:49:47 +00:00
|
|
|
case ISD::SETOGT: // FIXME: This is incorrect see PR642.
|
2005-08-21 18:50:37 +00:00
|
|
|
case ISD::SETUGT:
|
|
|
|
case ISD::SETGT: return PPC::BGT;
|
2005-10-28 20:49:47 +00:00
|
|
|
case ISD::SETOGE: // FIXME: This is incorrect see PR642.
|
2005-08-21 18:50:37 +00:00
|
|
|
case ISD::SETUGE:
|
|
|
|
case ISD::SETGE: return PPC::BGE;
|
2005-10-28 20:32:44 +00:00
|
|
|
|
|
|
|
case ISD::SETO: return PPC::BUN;
|
|
|
|
case ISD::SETUO: return PPC::BNU;
|
2005-08-21 18:50:37 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-08-25 20:08:18 +00:00
|
|
|
/// getCRIdxForSetCC - Return the index of the condition register field
|
|
|
|
/// associated with the SetCC condition, and whether or not the field is
|
|
|
|
/// treated as inverted. That is, lt = 0; ge = 0 inverted.
|
|
|
|
static unsigned getCRIdxForSetCC(ISD::CondCode CC, bool& Inv) {
|
|
|
|
switch (CC) {
|
|
|
|
default: assert(0 && "Unknown condition!"); abort();
|
2005-10-28 20:49:47 +00:00
|
|
|
case ISD::SETOLT: // FIXME: This is incorrect see PR642.
|
2005-08-25 20:08:18 +00:00
|
|
|
case ISD::SETULT:
|
|
|
|
case ISD::SETLT: Inv = false; return 0;
|
2005-10-28 20:49:47 +00:00
|
|
|
case ISD::SETOGE: // FIXME: This is incorrect see PR642.
|
2005-08-25 20:08:18 +00:00
|
|
|
case ISD::SETUGE:
|
|
|
|
case ISD::SETGE: Inv = true; return 0;
|
2005-10-28 20:49:47 +00:00
|
|
|
case ISD::SETOGT: // FIXME: This is incorrect see PR642.
|
2005-08-25 20:08:18 +00:00
|
|
|
case ISD::SETUGT:
|
|
|
|
case ISD::SETGT: Inv = false; return 1;
|
2005-10-28 20:49:47 +00:00
|
|
|
case ISD::SETOLE: // FIXME: This is incorrect see PR642.
|
2005-08-25 20:08:18 +00:00
|
|
|
case ISD::SETULE:
|
|
|
|
case ISD::SETLE: Inv = true; return 1;
|
2005-10-28 20:49:47 +00:00
|
|
|
case ISD::SETOEQ: // FIXME: This is incorrect see PR642.
|
2006-05-25 18:06:16 +00:00
|
|
|
case ISD::SETUEQ:
|
2005-08-25 20:08:18 +00:00
|
|
|
case ISD::SETEQ: Inv = false; return 2;
|
2005-10-28 20:49:47 +00:00
|
|
|
case ISD::SETONE: // FIXME: This is incorrect see PR642.
|
2006-05-25 18:06:16 +00:00
|
|
|
case ISD::SETUNE:
|
2005-08-25 20:08:18 +00:00
|
|
|
case ISD::SETNE: Inv = true; return 2;
|
2005-10-28 20:32:44 +00:00
|
|
|
case ISD::SETO: Inv = true; return 3;
|
|
|
|
case ISD::SETUO: Inv = false; return 3;
|
2005-08-25 20:08:18 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2005-08-21 22:31:09 +00:00
|
|
|
|
2005-10-18 00:28:58 +00:00
|
|
|
SDOperand PPCDAGToDAGISel::SelectSETCC(SDOperand Op) {
|
2005-10-06 19:03:35 +00:00
|
|
|
SDNode *N = Op.Val;
|
|
|
|
unsigned Imm;
|
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
|
2006-06-27 00:04:13 +00:00
|
|
|
if (isInt32Immediate(N->getOperand(1), Imm)) {
|
2005-10-06 19:03:35 +00:00
|
|
|
// We can codegen setcc op, imm very efficiently compared to a brcond.
|
|
|
|
// Check for those cases here.
|
|
|
|
// setcc op, 0
|
|
|
|
if (Imm == 0) {
|
2006-02-09 00:37:58 +00:00
|
|
|
SDOperand Op;
|
|
|
|
Select(Op, N->getOperand(0));
|
2005-10-06 19:03:35 +00:00
|
|
|
switch (CC) {
|
2005-10-21 21:17:10 +00:00
|
|
|
default: break;
|
|
|
|
case ISD::SETEQ:
|
2006-02-09 07:17:49 +00:00
|
|
|
Op = SDOperand(CurDAG->getTargetNode(PPC::CNTLZW, MVT::i32, Op), 0);
|
2005-11-30 22:53:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Op, getI32Imm(27),
|
|
|
|
getI32Imm(5), getI32Imm(31));
|
2005-10-21 21:17:10 +00:00
|
|
|
case ISD::SETNE: {
|
2006-02-09 07:17:49 +00:00
|
|
|
SDOperand AD =
|
|
|
|
SDOperand(CurDAG->getTargetNode(PPC::ADDIC, MVT::i32, MVT::Flag,
|
|
|
|
Op, getI32Imm(~0U)), 0);
|
2005-11-30 22:53:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::SUBFE, MVT::i32, AD, Op,
|
|
|
|
AD.getValue(1));
|
2005-10-21 21:17:10 +00:00
|
|
|
}
|
|
|
|
case ISD::SETLT:
|
2005-11-30 22:53:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Op, getI32Imm(1),
|
|
|
|
getI32Imm(31), getI32Imm(31));
|
2005-10-21 21:17:10 +00:00
|
|
|
case ISD::SETGT: {
|
2006-02-09 07:17:49 +00:00
|
|
|
SDOperand T =
|
|
|
|
SDOperand(CurDAG->getTargetNode(PPC::NEG, MVT::i32, Op), 0);
|
|
|
|
T = SDOperand(CurDAG->getTargetNode(PPC::ANDC, MVT::i32, T, Op), 0);
|
2005-11-30 22:53:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, T, getI32Imm(1),
|
|
|
|
getI32Imm(31), getI32Imm(31));
|
2005-10-21 21:17:10 +00:00
|
|
|
}
|
2005-10-06 19:03:35 +00:00
|
|
|
}
|
|
|
|
} else if (Imm == ~0U) { // setcc op, -1
|
2006-02-09 00:37:58 +00:00
|
|
|
SDOperand Op;
|
|
|
|
Select(Op, N->getOperand(0));
|
2005-10-06 19:03:35 +00:00
|
|
|
switch (CC) {
|
2005-10-21 21:17:10 +00:00
|
|
|
default: break;
|
|
|
|
case ISD::SETEQ:
|
2006-02-09 07:17:49 +00:00
|
|
|
Op = SDOperand(CurDAG->getTargetNode(PPC::ADDIC, MVT::i32, MVT::Flag,
|
|
|
|
Op, getI32Imm(1)), 0);
|
2005-11-30 22:53:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::ADDZE, MVT::i32,
|
2006-02-09 07:17:49 +00:00
|
|
|
SDOperand(CurDAG->getTargetNode(PPC::LI, MVT::i32,
|
|
|
|
getI32Imm(0)), 0),
|
2005-11-30 22:53:06 +00:00
|
|
|
Op.getValue(1));
|
2005-10-21 21:17:10 +00:00
|
|
|
case ISD::SETNE: {
|
2006-02-09 07:17:49 +00:00
|
|
|
Op = SDOperand(CurDAG->getTargetNode(PPC::NOR, MVT::i32, Op, Op), 0);
|
|
|
|
SDNode *AD = CurDAG->getTargetNode(PPC::ADDIC, MVT::i32, MVT::Flag,
|
|
|
|
Op, getI32Imm(~0U));
|
2006-05-16 23:54:25 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::SUBFE, MVT::i32, SDOperand(AD, 0),
|
|
|
|
Op, SDOperand(AD, 1));
|
2005-10-21 21:17:10 +00:00
|
|
|
}
|
|
|
|
case ISD::SETLT: {
|
2006-02-09 07:17:49 +00:00
|
|
|
SDOperand AD = SDOperand(CurDAG->getTargetNode(PPC::ADDI, MVT::i32, Op,
|
|
|
|
getI32Imm(1)), 0);
|
|
|
|
SDOperand AN = SDOperand(CurDAG->getTargetNode(PPC::AND, MVT::i32, AD,
|
|
|
|
Op), 0);
|
2005-11-30 22:53:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, AN, getI32Imm(1),
|
|
|
|
getI32Imm(31), getI32Imm(31));
|
2005-10-21 21:17:10 +00:00
|
|
|
}
|
|
|
|
case ISD::SETGT:
|
2006-02-09 07:17:49 +00:00
|
|
|
Op = SDOperand(CurDAG->getTargetNode(PPC::RLWINM, MVT::i32, Op,
|
|
|
|
getI32Imm(1), getI32Imm(31),
|
|
|
|
getI32Imm(31)), 0);
|
2005-11-30 22:53:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::XORI, MVT::i32, Op, getI32Imm(1));
|
2005-10-06 19:03:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inv;
|
|
|
|
unsigned Idx = getCRIdxForSetCC(CC, Inv);
|
|
|
|
SDOperand CCReg = SelectCC(N->getOperand(0), N->getOperand(1), CC);
|
|
|
|
SDOperand IntCR;
|
|
|
|
|
|
|
|
// Force the ccreg into CR7.
|
|
|
|
SDOperand CR7Reg = CurDAG->getRegister(PPC::CR7, MVT::i32);
|
|
|
|
|
2005-12-06 20:56:18 +00:00
|
|
|
SDOperand InFlag(0, 0); // Null incoming flag value.
|
2005-12-01 03:50:19 +00:00
|
|
|
CCReg = CurDAG->getCopyToReg(CurDAG->getEntryNode(), CR7Reg, CCReg,
|
|
|
|
InFlag).getValue(1);
|
2005-10-06 19:03:35 +00:00
|
|
|
|
|
|
|
if (TLI.getTargetMachine().getSubtarget<PPCSubtarget>().isGigaProcessor())
|
2006-02-09 07:17:49 +00:00
|
|
|
IntCR = SDOperand(CurDAG->getTargetNode(PPC::MFOCRF, MVT::i32, CR7Reg,
|
|
|
|
CCReg), 0);
|
2005-10-06 19:03:35 +00:00
|
|
|
else
|
2006-02-09 07:17:49 +00:00
|
|
|
IntCR = SDOperand(CurDAG->getTargetNode(PPC::MFCR, MVT::i32, CCReg), 0);
|
2005-10-06 19:03:35 +00:00
|
|
|
|
|
|
|
if (!Inv) {
|
2005-11-30 22:53:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, IntCR,
|
|
|
|
getI32Imm((32-(3-Idx)) & 31),
|
|
|
|
getI32Imm(31), getI32Imm(31));
|
2005-10-06 19:03:35 +00:00
|
|
|
} else {
|
|
|
|
SDOperand Tmp =
|
2006-02-09 07:17:49 +00:00
|
|
|
SDOperand(CurDAG->getTargetNode(PPC::RLWINM, MVT::i32, IntCR,
|
|
|
|
getI32Imm((32-(3-Idx)) & 31),
|
|
|
|
getI32Imm(31),getI32Imm(31)), 0);
|
2005-11-30 22:53:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::XORI, MVT::i32, Tmp, getI32Imm(1));
|
2005-10-06 19:03:35 +00:00
|
|
|
}
|
|
|
|
}
|
2005-10-06 18:56:10 +00:00
|
|
|
|
2005-10-06 19:07:45 +00:00
|
|
|
|
2005-08-17 19:33:03 +00:00
|
|
|
// Select - Convert the specified operand from a target-independent to a
|
|
|
|
// target-specific node if it hasn't already been changed.
|
2006-02-09 00:37:58 +00:00
|
|
|
void PPCDAGToDAGISel::Select(SDOperand &Result, SDOperand Op) {
|
2005-08-17 19:33:03 +00:00
|
|
|
SDNode *N = Op.Val;
|
2005-08-26 20:25:03 +00:00
|
|
|
if (N->getOpcode() >= ISD::BUILTIN_OP_END &&
|
2006-02-09 00:37:58 +00:00
|
|
|
N->getOpcode() < PPCISD::FIRST_NUMBER) {
|
|
|
|
Result = Op;
|
|
|
|
return; // Already selected.
|
|
|
|
}
|
2005-09-29 00:59:32 +00:00
|
|
|
|
|
|
|
// If this has already been converted, use it.
|
|
|
|
std::map<SDOperand, SDOperand>::iterator CGMI = CodeGenMap.find(Op);
|
2006-02-09 00:37:58 +00:00
|
|
|
if (CGMI != CodeGenMap.end()) {
|
|
|
|
Result = CGMI->second;
|
|
|
|
return;
|
|
|
|
}
|
2005-08-17 19:33:03 +00:00
|
|
|
|
|
|
|
switch (N->getOpcode()) {
|
2005-09-07 23:45:15 +00:00
|
|
|
default: break;
|
2006-02-09 00:37:58 +00:00
|
|
|
case ISD::SETCC:
|
|
|
|
Result = SelectSETCC(Op);
|
|
|
|
return;
|
|
|
|
case PPCISD::GlobalBaseReg:
|
|
|
|
Result = getGlobalBaseReg();
|
|
|
|
return;
|
2005-11-17 07:30:41 +00:00
|
|
|
|
2005-08-25 00:45:43 +00:00
|
|
|
case ISD::FrameIndex: {
|
|
|
|
int FI = cast<FrameIndexSDNode>(N)->getIndex();
|
2006-06-27 00:04:13 +00:00
|
|
|
SDOperand TFI = CurDAG->getTargetFrameIndex(FI, Op.getValueType());
|
|
|
|
unsigned Opc = Op.getValueType() == MVT::i32 ? PPC::ADDI : PPC::ADDI8;
|
2006-02-09 00:37:58 +00:00
|
|
|
if (N->hasOneUse()) {
|
2006-06-27 00:04:13 +00:00
|
|
|
Result = CurDAG->SelectNodeTo(N, Opc, Op.getValueType(), TFI,
|
|
|
|
getSmallIPtrImm(0));
|
2006-02-09 00:37:58 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
Result = CodeGenMap[Op] =
|
2006-06-27 00:04:13 +00:00
|
|
|
SDOperand(CurDAG->getTargetNode(Opc, Op.getValueType(), TFI,
|
|
|
|
getSmallIPtrImm(0)), 0);
|
2006-02-09 00:37:58 +00:00
|
|
|
return;
|
2005-08-25 00:45:43 +00:00
|
|
|
}
|
2006-03-26 10:06:40 +00:00
|
|
|
|
|
|
|
case PPCISD::MFCR: {
|
|
|
|
SDOperand InFlag;
|
|
|
|
Select(InFlag, N->getOperand(1));
|
|
|
|
// Use MFOCRF if supported.
|
|
|
|
if (TLI.getTargetMachine().getSubtarget<PPCSubtarget>().isGigaProcessor())
|
|
|
|
Result = SDOperand(CurDAG->getTargetNode(PPC::MFOCRF, MVT::i32,
|
|
|
|
N->getOperand(0), InFlag), 0);
|
|
|
|
else
|
|
|
|
Result = SDOperand(CurDAG->getTargetNode(PPC::MFCR, MVT::i32, InFlag), 0);
|
|
|
|
CodeGenMap[Op] = Result;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-09-28 22:50:24 +00:00
|
|
|
case ISD::SDIV: {
|
2005-10-21 00:02:42 +00:00
|
|
|
// FIXME: since this depends on the setting of the carry flag from the srawi
|
|
|
|
// we should really be making notes about that for the scheduler.
|
|
|
|
// FIXME: It sure would be nice if we could cheaply recognize the
|
|
|
|
// srl/add/sra pattern the dag combiner will generate for this as
|
|
|
|
// sra/addze rather than having to handle sdiv ourselves. oh well.
|
2005-08-25 17:50:06 +00:00
|
|
|
unsigned Imm;
|
2006-06-27 00:04:13 +00:00
|
|
|
if (isInt32Immediate(N->getOperand(1), Imm)) {
|
2006-02-09 00:37:58 +00:00
|
|
|
SDOperand N0;
|
|
|
|
Select(N0, N->getOperand(0));
|
2005-08-25 17:50:06 +00:00
|
|
|
if ((signed)Imm > 0 && isPowerOf2_32(Imm)) {
|
2006-02-09 07:17:49 +00:00
|
|
|
SDNode *Op =
|
2005-08-25 17:50:06 +00:00
|
|
|
CurDAG->getTargetNode(PPC::SRAWI, MVT::i32, MVT::Flag,
|
2006-02-09 00:37:58 +00:00
|
|
|
N0, getI32Imm(Log2_32(Imm)));
|
|
|
|
Result = CurDAG->SelectNodeTo(N, PPC::ADDZE, MVT::i32,
|
2006-02-09 07:17:49 +00:00
|
|
|
SDOperand(Op, 0), SDOperand(Op, 1));
|
2005-08-25 17:50:06 +00:00
|
|
|
} else if ((signed)Imm < 0 && isPowerOf2_32(-Imm)) {
|
2006-02-09 07:17:49 +00:00
|
|
|
SDNode *Op =
|
2005-08-30 17:13:58 +00:00
|
|
|
CurDAG->getTargetNode(PPC::SRAWI, MVT::i32, MVT::Flag,
|
2006-02-09 00:37:58 +00:00
|
|
|
N0, getI32Imm(Log2_32(-Imm)));
|
2005-08-25 17:50:06 +00:00
|
|
|
SDOperand PT =
|
2006-02-09 07:17:49 +00:00
|
|
|
SDOperand(CurDAG->getTargetNode(PPC::ADDZE, MVT::i32,
|
|
|
|
SDOperand(Op, 0), SDOperand(Op, 1)),
|
|
|
|
0);
|
2006-02-09 00:37:58 +00:00
|
|
|
Result = CurDAG->SelectNodeTo(N, PPC::NEG, MVT::i32, PT);
|
2005-08-25 17:50:06 +00:00
|
|
|
}
|
2006-02-09 00:37:58 +00:00
|
|
|
return;
|
2005-08-25 17:50:06 +00:00
|
|
|
}
|
2005-08-25 22:04:30 +00:00
|
|
|
|
2005-09-29 23:33:31 +00:00
|
|
|
// Other cases are autogenerated.
|
|
|
|
break;
|
2005-08-25 22:04:30 +00:00
|
|
|
}
|
2005-08-18 07:30:46 +00:00
|
|
|
case ISD::AND: {
|
2005-12-24 01:00:15 +00:00
|
|
|
unsigned Imm, Imm2;
|
2005-08-18 07:30:46 +00:00
|
|
|
// If this is an and of a value rotated between 0 and 31 bits and then and'd
|
|
|
|
// with a mask, emit rlwinm
|
2006-06-27 00:04:13 +00:00
|
|
|
if (isInt32Immediate(N->getOperand(1), Imm) &&
|
|
|
|
(isShiftedMask_32(Imm) || isShiftedMask_32(~Imm))) {
|
2005-08-18 07:30:46 +00:00
|
|
|
SDOperand Val;
|
2005-08-18 18:01:39 +00:00
|
|
|
unsigned SH, MB, ME;
|
2005-08-18 07:30:46 +00:00
|
|
|
if (isRotateAndMask(N->getOperand(0).Val, Imm, false, SH, MB, ME)) {
|
2006-02-09 00:37:58 +00:00
|
|
|
Select(Val, N->getOperand(0).getOperand(0));
|
2005-10-25 19:32:37 +00:00
|
|
|
} else if (Imm == 0) {
|
|
|
|
// AND X, 0 -> 0, not "rlwinm 32".
|
2006-02-09 00:37:58 +00:00
|
|
|
Select(Result, N->getOperand(1));
|
|
|
|
return ;
|
2005-10-25 19:32:37 +00:00
|
|
|
} else {
|
2006-02-09 00:37:58 +00:00
|
|
|
Select(Val, N->getOperand(0));
|
2005-08-18 07:30:46 +00:00
|
|
|
isRunOfOnes(Imm, MB, ME);
|
|
|
|
SH = 0;
|
|
|
|
}
|
2006-02-09 00:37:58 +00:00
|
|
|
Result = CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Val,
|
|
|
|
getI32Imm(SH), getI32Imm(MB),
|
|
|
|
getI32Imm(ME));
|
|
|
|
return;
|
2005-08-18 07:30:46 +00:00
|
|
|
}
|
2005-12-24 01:00:15 +00:00
|
|
|
// ISD::OR doesn't get all the bitfield insertion fun.
|
|
|
|
// (and (or x, c1), c2) where isRunOfOnes(~(c1^c2)) is a bitfield insert
|
2006-06-27 00:04:13 +00:00
|
|
|
if (isInt32Immediate(N->getOperand(1), Imm) &&
|
2005-12-24 01:00:15 +00:00
|
|
|
N->getOperand(0).getOpcode() == ISD::OR &&
|
2006-06-27 00:04:13 +00:00
|
|
|
isInt32Immediate(N->getOperand(0).getOperand(1), Imm2)) {
|
2006-01-05 18:32:49 +00:00
|
|
|
unsigned MB, ME;
|
2005-12-24 01:00:15 +00:00
|
|
|
Imm = ~(Imm^Imm2);
|
|
|
|
if (isRunOfOnes(Imm, MB, ME)) {
|
2006-02-09 00:37:58 +00:00
|
|
|
SDOperand Tmp1, Tmp2;
|
|
|
|
Select(Tmp1, N->getOperand(0).getOperand(0));
|
|
|
|
Select(Tmp2, N->getOperand(0).getOperand(1));
|
2006-02-09 07:17:49 +00:00
|
|
|
Result = SDOperand(CurDAG->getTargetNode(PPC::RLWIMI, MVT::i32,
|
|
|
|
Tmp1, Tmp2,
|
|
|
|
getI32Imm(0), getI32Imm(MB),
|
|
|
|
getI32Imm(ME)), 0);
|
2006-02-09 00:37:58 +00:00
|
|
|
return;
|
2005-12-24 01:00:15 +00:00
|
|
|
}
|
|
|
|
}
|
2005-09-29 23:33:31 +00:00
|
|
|
|
|
|
|
// Other cases are autogenerated.
|
|
|
|
break;
|
2005-08-18 07:30:46 +00:00
|
|
|
}
|
2005-08-19 00:38:14 +00:00
|
|
|
case ISD::OR:
|
2006-02-09 00:37:58 +00:00
|
|
|
if (SDNode *I = SelectBitfieldInsert(N)) {
|
|
|
|
Result = CodeGenMap[Op] = SDOperand(I, 0);
|
|
|
|
return;
|
|
|
|
}
|
2005-09-29 00:59:32 +00:00
|
|
|
|
2005-09-29 23:33:31 +00:00
|
|
|
// Other cases are autogenerated.
|
|
|
|
break;
|
2005-08-18 23:38:00 +00:00
|
|
|
case ISD::SHL: {
|
|
|
|
unsigned Imm, SH, MB, ME;
|
|
|
|
if (isOpcWithIntImmediate(N->getOperand(0).Val, ISD::AND, Imm) &&
|
2005-10-19 18:42:01 +00:00
|
|
|
isRotateAndMask(N, Imm, true, SH, MB, ME)) {
|
2006-02-09 00:37:58 +00:00
|
|
|
SDOperand Val;
|
|
|
|
Select(Val, N->getOperand(0).getOperand(0));
|
|
|
|
Result = CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32,
|
|
|
|
Val, getI32Imm(SH), getI32Imm(MB),
|
|
|
|
getI32Imm(ME));
|
|
|
|
return;
|
Woo, it kinda works. We now generate this atrociously bad, but correct,
code for long long foo(long long a, long long b) { return a + b; }
_foo:
or r2, r3, r3
or r3, r4, r4
or r4, r5, r5
or r5, r6, r6
rldicr r2, r2, 32, 31
rldicl r3, r3, 0, 32
rldicr r4, r4, 32, 31
rldicl r5, r5, 0, 32
or r2, r3, r2
or r3, r5, r4
add r4, r3, r2
rldicl r2, r4, 32, 32
or r4, r4, r4
or r3, r2, r2
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@23809 91177308-0d34-0410-b5e6-96231b3b80d8
2005-10-19 01:12:32 +00:00
|
|
|
}
|
2005-10-19 18:42:01 +00:00
|
|
|
|
|
|
|
// Other cases are autogenerated.
|
|
|
|
break;
|
2005-08-18 23:38:00 +00:00
|
|
|
}
|
|
|
|
case ISD::SRL: {
|
|
|
|
unsigned Imm, SH, MB, ME;
|
|
|
|
if (isOpcWithIntImmediate(N->getOperand(0).Val, ISD::AND, Imm) &&
|
2005-10-19 18:42:01 +00:00
|
|
|
isRotateAndMask(N, Imm, true, SH, MB, ME)) {
|
2006-02-09 00:37:58 +00:00
|
|
|
SDOperand Val;
|
|
|
|
Select(Val, N->getOperand(0).getOperand(0));
|
|
|
|
Result = CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32,
|
2006-05-12 16:29:37 +00:00
|
|
|
Val, getI32Imm(SH), getI32Imm(MB),
|
2006-02-09 00:37:58 +00:00
|
|
|
getI32Imm(ME));
|
|
|
|
return;
|
Woo, it kinda works. We now generate this atrociously bad, but correct,
code for long long foo(long long a, long long b) { return a + b; }
_foo:
or r2, r3, r3
or r3, r4, r4
or r4, r5, r5
or r5, r6, r6
rldicr r2, r2, 32, 31
rldicl r3, r3, 0, 32
rldicr r4, r4, 32, 31
rldicl r5, r5, 0, 32
or r2, r3, r2
or r3, r5, r4
add r4, r3, r2
rldicl r2, r4, 32, 32
or r4, r4, r4
or r3, r2, r2
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@23809 91177308-0d34-0410-b5e6-96231b3b80d8
2005-10-19 01:12:32 +00:00
|
|
|
}
|
2005-10-19 18:42:01 +00:00
|
|
|
|
|
|
|
// Other cases are autogenerated.
|
|
|
|
break;
|
2005-08-18 23:38:00 +00:00
|
|
|
}
|
2005-08-26 18:46:49 +00:00
|
|
|
case ISD::SELECT_CC: {
|
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(4))->get();
|
|
|
|
|
2006-06-27 00:04:13 +00:00
|
|
|
// Handle the setcc cases here. select_cc lhs, 0, 1, 0, cc
|
2005-08-26 18:46:49 +00:00
|
|
|
if (ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N->getOperand(1)))
|
|
|
|
if (ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N->getOperand(2)))
|
|
|
|
if (ConstantSDNode *N3C = dyn_cast<ConstantSDNode>(N->getOperand(3)))
|
|
|
|
if (N1C->isNullValue() && N3C->isNullValue() &&
|
2006-06-27 00:04:13 +00:00
|
|
|
N2C->getValue() == 1ULL && CC == ISD::SETNE &&
|
|
|
|
// FIXME: Implement this optzn for PPC64.
|
|
|
|
N->getValueType(0) == MVT::i32) {
|
2006-02-09 00:37:58 +00:00
|
|
|
SDOperand LHS;
|
|
|
|
Select(LHS, N->getOperand(0));
|
2006-02-09 07:17:49 +00:00
|
|
|
SDNode *Tmp =
|
2005-08-26 18:46:49 +00:00
|
|
|
CurDAG->getTargetNode(PPC::ADDIC, MVT::i32, MVT::Flag,
|
|
|
|
LHS, getI32Imm(~0U));
|
2006-02-09 07:17:49 +00:00
|
|
|
Result = CurDAG->SelectNodeTo(N, PPC::SUBFE, MVT::i32,
|
|
|
|
SDOperand(Tmp, 0), LHS,
|
|
|
|
SDOperand(Tmp, 1));
|
2006-02-09 00:37:58 +00:00
|
|
|
return;
|
2005-08-26 18:46:49 +00:00
|
|
|
}
|
2005-08-26 21:23:58 +00:00
|
|
|
|
2005-09-01 19:20:44 +00:00
|
|
|
SDOperand CCReg = SelectCC(N->getOperand(0), N->getOperand(1), CC);
|
2005-08-26 21:23:58 +00:00
|
|
|
unsigned BROpc = getBCCForSetCC(CC);
|
|
|
|
|
|
|
|
bool isFP = MVT::isFloatingPoint(N->getValueType(0));
|
2005-10-01 01:35:02 +00:00
|
|
|
unsigned SelectCCOp;
|
2006-06-27 00:04:13 +00:00
|
|
|
if (N->getValueType(0) == MVT::i32)
|
|
|
|
SelectCCOp = PPC::SELECT_CC_I4;
|
|
|
|
else if (N->getValueType(0) == MVT::i64)
|
|
|
|
SelectCCOp = PPC::SELECT_CC_I8;
|
2005-10-01 01:35:02 +00:00
|
|
|
else if (N->getValueType(0) == MVT::f32)
|
|
|
|
SelectCCOp = PPC::SELECT_CC_F4;
|
2006-04-08 22:45:08 +00:00
|
|
|
else if (N->getValueType(0) == MVT::f64)
|
2005-10-01 01:35:02 +00:00
|
|
|
SelectCCOp = PPC::SELECT_CC_F8;
|
2006-04-08 22:45:08 +00:00
|
|
|
else
|
|
|
|
SelectCCOp = PPC::SELECT_CC_VRRC;
|
|
|
|
|
2006-02-09 00:37:58 +00:00
|
|
|
SDOperand N2, N3;
|
|
|
|
Select(N2, N->getOperand(2));
|
|
|
|
Select(N3, N->getOperand(3));
|
|
|
|
Result = CurDAG->SelectNodeTo(N, SelectCCOp, N->getValueType(0), CCReg,
|
|
|
|
N2, N3, getI32Imm(BROpc));
|
|
|
|
return;
|
2005-08-26 18:46:49 +00:00
|
|
|
}
|
2006-03-17 01:40:33 +00:00
|
|
|
case ISD::BR_CC: {
|
2006-02-09 00:37:58 +00:00
|
|
|
SDOperand Chain;
|
|
|
|
Select(Chain, N->getOperand(0));
|
2005-08-21 18:50:37 +00:00
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(1))->get();
|
|
|
|
SDOperand CondCode = SelectCC(N->getOperand(2), N->getOperand(3), CC);
|
2006-03-17 01:40:33 +00:00
|
|
|
Result = CurDAG->SelectNodeTo(N, PPC::COND_BRANCH, MVT::Other,
|
|
|
|
CondCode, getI32Imm(getBCCForSetCC(CC)),
|
|
|
|
N->getOperand(4), Chain);
|
2006-02-09 00:37:58 +00:00
|
|
|
return;
|
2005-08-21 18:50:37 +00:00
|
|
|
}
|
2006-04-22 18:53:45 +00:00
|
|
|
case ISD::BRIND: {
|
2006-06-10 01:15:02 +00:00
|
|
|
// FIXME: Should custom lower this.
|
2006-04-22 18:53:45 +00:00
|
|
|
SDOperand Chain, Target;
|
|
|
|
Select(Chain, N->getOperand(0));
|
|
|
|
Select(Target,N->getOperand(1));
|
2006-06-27 20:46:17 +00:00
|
|
|
unsigned Opc = Target.getValueType() == MVT::i32 ? PPC::MTCTR : PPC::MTCTR8;
|
|
|
|
Chain = SDOperand(CurDAG->getTargetNode(Opc, MVT::Other, Target,
|
2006-04-22 18:53:45 +00:00
|
|
|
Chain), 0);
|
|
|
|
Result = CurDAG->SelectNodeTo(N, PPC::BCTR, MVT::Other, Chain);
|
|
|
|
return;
|
|
|
|
}
|
2006-06-10 01:15:02 +00:00
|
|
|
// FIXME: These are manually selected because tblgen isn't handling varargs
|
|
|
|
// nodes correctly.
|
|
|
|
case PPCISD::BCTRL: MySelect_PPCbctrl(Result, Op); return;
|
|
|
|
case PPCISD::CALL: MySelect_PPCcall(Result, Op); return;
|
2005-08-17 19:33:03 +00:00
|
|
|
}
|
2005-09-03 00:53:47 +00:00
|
|
|
|
2006-02-09 00:37:58 +00:00
|
|
|
SelectCode(Result, Op);
|
2005-08-17 19:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-06-10 01:15:02 +00:00
|
|
|
// FIXME: This is manually selected because tblgen isn't handling varargs nodes
|
|
|
|
// correctly.
|
|
|
|
void PPCDAGToDAGISel::MySelect_PPCbctrl(SDOperand &Result, SDOperand N) {
|
|
|
|
SDOperand Chain(0, 0);
|
|
|
|
SDOperand InFlag(0, 0);
|
|
|
|
SDNode *ResNode;
|
|
|
|
|
|
|
|
bool hasFlag =
|
|
|
|
N.getOperand(N.getNumOperands()-1).getValueType() == MVT::Flag;
|
|
|
|
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
// Push varargs arguments, including optional flag.
|
|
|
|
for (unsigned i = 1, e = N.getNumOperands()-hasFlag; i != e; ++i) {
|
|
|
|
Select(Chain, N.getOperand(i));
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
}
|
|
|
|
|
|
|
|
Select(Chain, N.getOperand(0));
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
|
|
|
|
if (hasFlag) {
|
|
|
|
Select(Chain, N.getOperand(N.getNumOperands()-1));
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
}
|
|
|
|
|
|
|
|
ResNode = CurDAG->getTargetNode(PPC::BCTRL, MVT::Other, MVT::Flag, Ops);
|
|
|
|
Chain = SDOperand(ResNode, 0);
|
|
|
|
InFlag = SDOperand(ResNode, 1);
|
|
|
|
SelectionDAG::InsertISelMapEntry(CodeGenMap, N.Val, 0, Chain.Val,
|
|
|
|
Chain.ResNo);
|
|
|
|
SelectionDAG::InsertISelMapEntry(CodeGenMap, N.Val, 1, InFlag.Val,
|
|
|
|
InFlag.ResNo);
|
|
|
|
Result = SDOperand(ResNode, N.ResNo);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: This is manually selected because tblgen isn't handling varargs nodes
|
|
|
|
// correctly.
|
|
|
|
void PPCDAGToDAGISel::MySelect_PPCcall(SDOperand &Result, SDOperand N) {
|
|
|
|
SDOperand Chain(0, 0);
|
|
|
|
SDOperand InFlag(0, 0);
|
|
|
|
SDOperand N1(0, 0);
|
|
|
|
SDOperand Tmp0(0, 0);
|
|
|
|
SDNode *ResNode;
|
|
|
|
Chain = N.getOperand(0);
|
|
|
|
N1 = N.getOperand(1);
|
|
|
|
|
|
|
|
// Pattern: (PPCcall:void (imm:i32):$func)
|
|
|
|
// Emits: (BLA:void (imm:i32):$func)
|
|
|
|
// Pattern complexity = 4 cost = 1
|
|
|
|
if (N1.getOpcode() == ISD::Constant) {
|
|
|
|
unsigned Tmp0C = (unsigned)cast<ConstantSDNode>(N1)->getValue();
|
|
|
|
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(CurDAG->getTargetConstant(Tmp0C, MVT::i32));
|
|
|
|
|
|
|
|
bool hasFlag =
|
|
|
|
N.getOperand(N.getNumOperands()-1).getValueType() == MVT::Flag;
|
|
|
|
|
|
|
|
// Push varargs arguments, not including optional flag.
|
|
|
|
for (unsigned i = 2, e = N.getNumOperands()-hasFlag; i != e; ++i) {
|
|
|
|
Select(Chain, N.getOperand(i));
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
}
|
|
|
|
Select(Chain, N.getOperand(0));
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
if (hasFlag) {
|
|
|
|
Select(Chain, N.getOperand(N.getNumOperands()-1));
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
}
|
|
|
|
ResNode = CurDAG->getTargetNode(PPC::BLA, MVT::Other, MVT::Flag, Ops);
|
|
|
|
|
|
|
|
Chain = SDOperand(ResNode, 0);
|
|
|
|
InFlag = SDOperand(ResNode, 1);
|
2006-06-27 00:04:13 +00:00
|
|
|
SelectionDAG::InsertISelMapEntry(CodeGenMap, N.Val, 0, Chain.Val,
|
|
|
|
Chain.ResNo);
|
|
|
|
SelectionDAG::InsertISelMapEntry(CodeGenMap, N.Val, 1, InFlag.Val,
|
|
|
|
InFlag.ResNo);
|
2006-06-10 01:15:02 +00:00
|
|
|
Result = SDOperand(ResNode, N.ResNo);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pattern: (PPCcall:void (tglobaladdr:i32):$dst)
|
|
|
|
// Emits: (BL:void (tglobaladdr:i32):$dst)
|
|
|
|
// Pattern complexity = 4 cost = 1
|
|
|
|
if (N1.getOpcode() == ISD::TargetGlobalAddress) {
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(N1);
|
|
|
|
|
|
|
|
bool hasFlag =
|
|
|
|
N.getOperand(N.getNumOperands()-1).getValueType() == MVT::Flag;
|
|
|
|
|
|
|
|
// Push varargs arguments, not including optional flag.
|
|
|
|
for (unsigned i = 2, e = N.getNumOperands()-hasFlag; i != e; ++i) {
|
|
|
|
Select(Chain, N.getOperand(i));
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
}
|
|
|
|
Select(Chain, N.getOperand(0));
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
if (hasFlag) {
|
|
|
|
Select(Chain, N.getOperand(N.getNumOperands()-1));
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
}
|
|
|
|
|
|
|
|
ResNode = CurDAG->getTargetNode(PPC::BL, MVT::Other, MVT::Flag, Ops);
|
|
|
|
|
|
|
|
Chain = SDOperand(ResNode, 0);
|
|
|
|
InFlag = SDOperand(ResNode, 1);
|
2006-06-27 00:04:13 +00:00
|
|
|
SelectionDAG::InsertISelMapEntry(CodeGenMap, N.Val, 0, Chain.Val,
|
|
|
|
Chain.ResNo);
|
|
|
|
SelectionDAG::InsertISelMapEntry(CodeGenMap, N.Val, 1, InFlag.Val,
|
|
|
|
InFlag.ResNo);
|
2006-06-10 01:15:02 +00:00
|
|
|
Result = SDOperand(ResNode, N.ResNo);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pattern: (PPCcall:void (texternalsym:i32):$dst)
|
|
|
|
// Emits: (BL:void (texternalsym:i32):$dst)
|
|
|
|
// Pattern complexity = 4 cost = 1
|
|
|
|
if (N1.getOpcode() == ISD::TargetExternalSymbol) {
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(N1);
|
|
|
|
|
|
|
|
bool hasFlag =
|
|
|
|
N.getOperand(N.getNumOperands()-1).getValueType() == MVT::Flag;
|
|
|
|
|
|
|
|
// Push varargs arguments, not including optional flag.
|
|
|
|
for (unsigned i = 2, e = N.getNumOperands()-hasFlag; i != e; ++i) {
|
|
|
|
Select(Chain, N.getOperand(i));
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
}
|
|
|
|
Select(Chain, N.getOperand(0));
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
if (hasFlag) {
|
|
|
|
Select(Chain, N.getOperand(N.getNumOperands()-1));
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
}
|
|
|
|
|
|
|
|
ResNode = CurDAG->getTargetNode(PPC::BL, MVT::Other, MVT::Flag, Ops);
|
|
|
|
|
|
|
|
Chain = SDOperand(ResNode, 0);
|
|
|
|
InFlag = SDOperand(ResNode, 1);
|
2006-06-27 00:04:13 +00:00
|
|
|
SelectionDAG::InsertISelMapEntry(CodeGenMap, N.Val, 0, Chain.Val,
|
|
|
|
Chain.ResNo);
|
|
|
|
SelectionDAG::InsertISelMapEntry(CodeGenMap, N.Val, 1, InFlag.Val,
|
|
|
|
InFlag.ResNo);
|
2006-06-10 01:15:02 +00:00
|
|
|
Result = SDOperand(ResNode, N.ResNo);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
std::cerr << "Cannot yet select: ";
|
|
|
|
N.Val->dump(CurDAG);
|
|
|
|
std::cerr << '\n';
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-10-18 00:28:58 +00:00
|
|
|
/// createPPCISelDag - This pass converts a legalized DAG into a
|
2005-08-17 19:33:03 +00:00
|
|
|
/// PowerPC-specific DAG, ready for instruction scheduling.
|
|
|
|
///
|
2006-03-13 23:20:37 +00:00
|
|
|
FunctionPass *llvm::createPPCISelDag(PPCTargetMachine &TM) {
|
2005-10-18 00:28:58 +00:00
|
|
|
return new PPCDAGToDAGISel(TM);
|
2005-08-17 19:33:03 +00:00
|
|
|
}
|
|
|
|
|