2005-10-16 13:39:50 +08:00
|
|
|
//===-- PPCISelDAGToDAG.cpp - PPC --pattern matching inst selector --------===//
|
2005-08-18 03:33:03 +08: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 13:39:50 +08:00
|
|
|
// This file defines a pattern matching instruction selector for PowerPC,
|
2005-08-18 03:33:03 +08:00
|
|
|
// converting from a legalized dag to a PPC dag.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2005-10-15 07:51:18 +08:00
|
|
|
#include "PPC.h"
|
2005-10-15 07:59:06 +08:00
|
|
|
#include "PPCTargetMachine.h"
|
|
|
|
#include "PPCISelLowering.h"
|
2005-08-20 06:38:53 +08:00
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
|
|
#include "llvm/CodeGen/SSARegMap.h"
|
2005-08-18 03:33:03 +08:00
|
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
|
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
|
|
#include "llvm/Target/TargetOptions.h"
|
|
|
|
#include "llvm/ADT/Statistic.h"
|
2005-08-25 12:47:18 +08:00
|
|
|
#include "llvm/Constants.h"
|
2005-08-20 06:38:53 +08:00
|
|
|
#include "llvm/GlobalValue.h"
|
2005-08-18 03:33:03 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Support/MathExtras.h"
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
Statistic<> FusedFP ("ppc-codegen", "Number of fused fp operations");
|
|
|
|
Statistic<> FrameOff("ppc-codegen", "Number of frame idx offsets collapsed");
|
|
|
|
|
|
|
|
//===--------------------------------------------------------------------===//
|
2005-10-18 08:28:58 +08:00
|
|
|
/// PPCDAGToDAGISel - PPC specific code to select PPC machine
|
2005-08-18 03:33:03 +08:00
|
|
|
/// instructions for SelectionDAG operations.
|
|
|
|
///
|
2005-10-18 08:28:58 +08:00
|
|
|
class PPCDAGToDAGISel : public SelectionDAGISel {
|
2005-10-16 13:39:50 +08:00
|
|
|
PPCTargetLowering PPCLowering;
|
2005-08-20 06:38:53 +08:00
|
|
|
unsigned GlobalBaseReg;
|
2005-08-18 03:33:03 +08:00
|
|
|
public:
|
2005-10-18 08:28:58 +08:00
|
|
|
PPCDAGToDAGISel(TargetMachine &TM)
|
2005-10-16 13:39:50 +08:00
|
|
|
: SelectionDAGISel(PPCLowering), PPCLowering(TM) {}
|
2005-08-18 03:33:03 +08:00
|
|
|
|
2005-08-20 06:38:53 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2005-08-18 03:33:03 +08: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-20 06:38:53 +08:00
|
|
|
|
|
|
|
/// getGlobalBaseReg - insert code into the entry mbb to materialize the PIC
|
|
|
|
/// base register. Return the virtual register that holds this value.
|
2005-08-22 06:31:09 +08:00
|
|
|
SDOperand getGlobalBaseReg();
|
2005-08-18 03:33:03 +08:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
2005-08-19 08:38:14 +08:00
|
|
|
SDNode *SelectBitfieldInsert(SDNode *N);
|
|
|
|
|
2005-08-22 02:50:37 +08: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-08-22 06:31:09 +08:00
|
|
|
/// 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);
|
2005-11-30 16:22:07 +08:00
|
|
|
|
|
|
|
/// SelectAddrIndexed - Given the specified addressed, force it to be
|
|
|
|
/// represented as an indexed [r+r] operation, rather than possibly
|
|
|
|
/// returning [r+imm] as SelectAddr may.
|
|
|
|
void SelectAddrIndexed(SDOperand Addr, SDOperand &Op1, SDOperand &Op2);
|
2005-08-22 06:31:09 +08:00
|
|
|
|
2005-08-26 06:04:30 +08:00
|
|
|
SDOperand BuildSDIVSequence(SDNode *N);
|
|
|
|
SDOperand BuildUDIVSequence(SDNode *N);
|
|
|
|
|
2005-08-18 03:33:03 +08:00
|
|
|
/// InstructionSelectBasicBlock - This callback is invoked by
|
|
|
|
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
2005-10-07 02:45:51 +08:00
|
|
|
virtual void InstructionSelectBasicBlock(SelectionDAG &DAG);
|
|
|
|
|
2005-08-18 03:33:03 +08:00
|
|
|
virtual const char *getPassName() const {
|
|
|
|
return "PowerPC DAG->DAG Pattern Instruction Selection";
|
|
|
|
}
|
2005-09-14 06:03:06 +08:00
|
|
|
|
|
|
|
// Include the pieces autogenerated from the target description.
|
2005-10-15 07:37:35 +08:00
|
|
|
#include "PPCGenDAGISel.inc"
|
2005-10-07 02:45:51 +08:00
|
|
|
|
|
|
|
private:
|
2005-10-07 03:03:35 +08:00
|
|
|
SDOperand SelectDYNAMIC_STACKALLOC(SDOperand Op);
|
|
|
|
SDOperand SelectADD_PARTS(SDOperand Op);
|
|
|
|
SDOperand SelectSUB_PARTS(SDOperand Op);
|
|
|
|
SDOperand SelectSETCC(SDOperand Op);
|
2005-10-07 03:07:45 +08:00
|
|
|
SDOperand SelectCALL(SDOperand Op);
|
2005-08-18 03:33:03 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2005-10-07 02:45:51 +08:00
|
|
|
/// InstructionSelectBasicBlock - This callback is invoked by
|
|
|
|
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
2005-10-18 08:28:58 +08:00
|
|
|
void PPCDAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) {
|
2005-10-07 02:45:51 +08: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-08 06:10:27 +08: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-07 02:45:51 +08: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.
|
|
|
|
Select(Node);
|
|
|
|
}
|
2005-10-08 06:10:27 +08:00
|
|
|
|
2005-10-07 02:45:51 +08:00
|
|
|
// Select target instructions for the DAG.
|
|
|
|
DAG.setRoot(Select(DAG.getRoot()));
|
|
|
|
CodeGenMap.clear();
|
|
|
|
DAG.RemoveDeadNodes();
|
|
|
|
|
|
|
|
// Emit machine code to BB.
|
|
|
|
ScheduleAndEmitDAG(DAG);
|
|
|
|
}
|
2005-09-03 09:17:22 +08:00
|
|
|
|
2005-08-20 06:38:53 +08:00
|
|
|
/// getGlobalBaseReg - Output the instructions required to put the
|
|
|
|
/// base address to use for accessing globals into a register.
|
|
|
|
///
|
2005-10-18 08:28:58 +08:00
|
|
|
SDOperand PPCDAGToDAGISel::getGlobalBaseReg() {
|
2005-08-20 06:38:53 +08: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();
|
2005-10-18 08:28:58 +08:00
|
|
|
// FIXME: when we get to LP64, we will need to create the appropriate
|
|
|
|
// type of register here.
|
|
|
|
GlobalBaseReg = RegMap->createVirtualRegister(PPC::GPRCRegisterClass);
|
2005-08-20 06:38:53 +08:00
|
|
|
BuildMI(FirstMBB, MBBI, PPC::MovePCtoLR, 0, PPC::LR);
|
|
|
|
BuildMI(FirstMBB, MBBI, PPC::MFLR, 1, GlobalBaseReg);
|
|
|
|
}
|
2005-08-22 06:31:09 +08:00
|
|
|
return CurDAG->getRegister(GlobalBaseReg, MVT::i32);
|
2005-08-20 06:38:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-18 13:00:13 +08:00
|
|
|
// isIntImmediate - This method tests to see if a constant operand.
|
|
|
|
// If so Imm will receive the 32 bit value.
|
|
|
|
static bool isIntImmediate(SDNode *N, unsigned& Imm) {
|
|
|
|
if (N->getOpcode() == ISD::Constant) {
|
|
|
|
Imm = cast<ConstantSDNode>(N)->getValue();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-08-18 15:30:46 +08:00
|
|
|
// isOprShiftImm - Returns true if the specified operand is a shift opcode with
|
|
|
|
// a immediate shift count less than 32.
|
|
|
|
static bool isOprShiftImm(SDNode *N, unsigned& Opc, unsigned& SH) {
|
|
|
|
Opc = N->getOpcode();
|
|
|
|
return (Opc == ISD::SHL || Opc == ISD::SRL || Opc == ISD::SRA) &&
|
|
|
|
isIntImmediate(N->getOperand(1).Val, SH) && SH < 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 12:47:18 +08: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 15:30:46 +08:00
|
|
|
}
|
|
|
|
// no run present
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-10-09 13:36:17 +08:00
|
|
|
// isRotateAndMask - Returns true if Mask and Shift can be folded into a rotate
|
2005-08-18 15:30:46 +08: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 08:05:37 +08: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 15:30:46 +08:00
|
|
|
unsigned Shift = 32;
|
|
|
|
unsigned Indeterminant = ~0; // bit mask marking indeterminant results
|
|
|
|
unsigned Opcode = N->getOpcode();
|
2005-08-30 08:59:16 +08:00
|
|
|
if (N->getNumOperands() != 2 ||
|
|
|
|
!isIntImmediate(N->getOperand(1).Val, Shift) || (Shift > 31))
|
2005-08-18 15:30:46 +08: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-16 05:40:12 +08:00
|
|
|
} else if (Opcode == ISD::SRL) {
|
2005-08-18 15:30:46 +08: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)) {
|
|
|
|
SH = Shift;
|
|
|
|
// make sure the mask is still a mask (wrap arounds may not be)
|
|
|
|
return isRunOfOnes(Mask, MB, ME);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-08-18 13:00:13 +08:00
|
|
|
// 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 && isIntImmediate(N->getOperand(1).Val, Imm);
|
|
|
|
}
|
|
|
|
|
|
|
|
// isOprNot - Returns true if the specified operand is an xor with immediate -1.
|
|
|
|
static bool isOprNot(SDNode *N) {
|
|
|
|
unsigned Imm;
|
|
|
|
return isOpcWithIntImmediate(N, ISD::XOR, Imm) && (signed)Imm == -1;
|
|
|
|
}
|
|
|
|
|
2005-08-18 03:33:03 +08:00
|
|
|
// Immediate constant composers.
|
|
|
|
// Lo16 - grabs the lo 16 bits from a 32 bit constant.
|
|
|
|
// Hi16 - grabs the hi 16 bits from a 32 bit constant.
|
|
|
|
// HA16 - computes the hi bits required if the lo bits are add/subtracted in
|
|
|
|
// arithmethically.
|
|
|
|
static unsigned Lo16(unsigned x) { return x & 0x0000FFFF; }
|
|
|
|
static unsigned Hi16(unsigned x) { return Lo16(x >> 16); }
|
|
|
|
static unsigned HA16(unsigned x) { return Hi16((signed)x - (signed short)x); }
|
|
|
|
|
|
|
|
// isIntImmediate - This method tests to see if a constant operand.
|
|
|
|
// If so Imm will receive the 32 bit value.
|
|
|
|
static bool isIntImmediate(SDOperand N, unsigned& Imm) {
|
|
|
|
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) {
|
|
|
|
Imm = (unsigned)CN->getSignExtended();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-08-19 08:38:14 +08:00
|
|
|
/// SelectBitfieldInsert - turn an or of two masked values into
|
|
|
|
/// the rotate left word immediate then mask insert (rlwimi) instruction.
|
|
|
|
/// Returns true on success, false if the caller still needs to select OR.
|
|
|
|
///
|
|
|
|
/// Patterns matched:
|
|
|
|
/// 1. or shl, and 5. or and, and
|
|
|
|
/// 2. or and, shl 6. or shl, shr
|
|
|
|
/// 3. or shr, and 7. or shr, shl
|
|
|
|
/// 4. or and, shr
|
2005-10-18 08:28:58 +08:00
|
|
|
SDNode *PPCDAGToDAGISel::SelectBitfieldInsert(SDNode *N) {
|
2005-08-19 08:38:14 +08:00
|
|
|
bool IsRotate = false;
|
|
|
|
unsigned TgtMask = 0xFFFFFFFF, InsMask = 0xFFFFFFFF, SH = 0;
|
|
|
|
unsigned Value;
|
|
|
|
|
|
|
|
SDOperand Op0 = N->getOperand(0);
|
|
|
|
SDOperand Op1 = N->getOperand(1);
|
|
|
|
|
|
|
|
unsigned Op0Opc = Op0.getOpcode();
|
|
|
|
unsigned Op1Opc = Op1.getOpcode();
|
|
|
|
|
|
|
|
// Verify that we have the correct opcodes
|
|
|
|
if (ISD::SHL != Op0Opc && ISD::SRL != Op0Opc && ISD::AND != Op0Opc)
|
|
|
|
return false;
|
|
|
|
if (ISD::SHL != Op1Opc && ISD::SRL != Op1Opc && ISD::AND != Op1Opc)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Generate Mask value for Target
|
|
|
|
if (isIntImmediate(Op0.getOperand(1), Value)) {
|
|
|
|
switch(Op0Opc) {
|
2005-08-31 02:37:48 +08:00
|
|
|
case ISD::SHL: TgtMask <<= Value; break;
|
|
|
|
case ISD::SRL: TgtMask >>= Value; break;
|
|
|
|
case ISD::AND: TgtMask &= Value; break;
|
2005-08-19 08:38:14 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate Mask value for Insert
|
2005-08-31 02:37:48 +08:00
|
|
|
if (!isIntImmediate(Op1.getOperand(1), Value))
|
2005-08-19 08:38:14 +08:00
|
|
|
return 0;
|
2005-08-31 02:37:48 +08:00
|
|
|
|
|
|
|
switch(Op1Opc) {
|
|
|
|
case ISD::SHL:
|
|
|
|
SH = Value;
|
|
|
|
InsMask <<= SH;
|
|
|
|
if (Op0Opc == ISD::SRL) IsRotate = true;
|
|
|
|
break;
|
|
|
|
case ISD::SRL:
|
|
|
|
SH = Value;
|
|
|
|
InsMask >>= SH;
|
|
|
|
SH = 32-SH;
|
|
|
|
if (Op0Opc == ISD::SHL) IsRotate = true;
|
|
|
|
break;
|
|
|
|
case ISD::AND:
|
|
|
|
InsMask &= Value;
|
|
|
|
break;
|
2005-08-19 08:38:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If both of the inputs are ANDs and one of them has a logical shift by
|
|
|
|
// constant as its input, make that AND the inserted value so that we can
|
|
|
|
// combine the shift into the rotate part of the rlwimi instruction
|
|
|
|
bool IsAndWithShiftOp = false;
|
|
|
|
if (Op0Opc == ISD::AND && Op1Opc == ISD::AND) {
|
|
|
|
if (Op1.getOperand(0).getOpcode() == ISD::SHL ||
|
|
|
|
Op1.getOperand(0).getOpcode() == ISD::SRL) {
|
|
|
|
if (isIntImmediate(Op1.getOperand(0).getOperand(1), Value)) {
|
|
|
|
SH = Op1.getOperand(0).getOpcode() == ISD::SHL ? Value : 32 - Value;
|
|
|
|
IsAndWithShiftOp = true;
|
|
|
|
}
|
|
|
|
} else if (Op0.getOperand(0).getOpcode() == ISD::SHL ||
|
|
|
|
Op0.getOperand(0).getOpcode() == ISD::SRL) {
|
|
|
|
if (isIntImmediate(Op0.getOperand(0).getOperand(1), Value)) {
|
|
|
|
std::swap(Op0, Op1);
|
|
|
|
std::swap(TgtMask, InsMask);
|
|
|
|
SH = Op1.getOperand(0).getOpcode() == ISD::SHL ? Value : 32 - Value;
|
|
|
|
IsAndWithShiftOp = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that the Target mask and Insert mask together form a full word mask
|
|
|
|
// and that the Insert mask is a run of set bits (which implies both are runs
|
|
|
|
// of set bits). Given that, Select the arguments and generate the rlwimi
|
|
|
|
// instruction.
|
|
|
|
unsigned MB, ME;
|
|
|
|
if (((TgtMask & InsMask) == 0) && isRunOfOnes(InsMask, MB, ME)) {
|
|
|
|
bool fullMask = (TgtMask ^ InsMask) == 0xFFFFFFFF;
|
|
|
|
bool Op0IsAND = Op0Opc == ISD::AND;
|
|
|
|
// Check for rotlwi / rotrwi here, a special case of bitfield insert
|
|
|
|
// where both bitfield halves are sourced from the same value.
|
|
|
|
if (IsRotate && fullMask &&
|
|
|
|
N->getOperand(0).getOperand(0) == N->getOperand(1).getOperand(0)) {
|
|
|
|
Op0 = CurDAG->getTargetNode(PPC::RLWINM, MVT::i32,
|
|
|
|
Select(N->getOperand(0).getOperand(0)),
|
|
|
|
getI32Imm(SH), getI32Imm(0), getI32Imm(31));
|
|
|
|
return Op0.Val;
|
|
|
|
}
|
|
|
|
SDOperand Tmp1 = (Op0IsAND && fullMask) ? Select(Op0.getOperand(0))
|
|
|
|
: Select(Op0);
|
|
|
|
SDOperand Tmp2 = IsAndWithShiftOp ? Select(Op1.getOperand(0).getOperand(0))
|
|
|
|
: Select(Op1.getOperand(0));
|
|
|
|
Op0 = CurDAG->getTargetNode(PPC::RLWIMI, MVT::i32, Tmp1, Tmp2,
|
|
|
|
getI32Imm(SH), getI32Imm(MB), getI32Imm(ME));
|
|
|
|
return Op0.Val;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-08-22 06:31:09 +08:00
|
|
|
/// 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.
|
2005-10-18 08:28:58 +08:00
|
|
|
bool PPCDAGToDAGISel::SelectAddr(SDOperand Addr, SDOperand &Op1,
|
|
|
|
SDOperand &Op2) {
|
2005-08-22 06:31:09 +08:00
|
|
|
unsigned imm = 0;
|
|
|
|
if (Addr.getOpcode() == ISD::ADD) {
|
|
|
|
if (isIntImmediate(Addr.getOperand(1), imm) && isInt16(imm)) {
|
|
|
|
Op1 = getI32Imm(Lo16(imm));
|
2005-08-25 08:45:43 +08:00
|
|
|
if (FrameIndexSDNode *FI =
|
|
|
|
dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
|
2005-08-22 06:31:09 +08:00
|
|
|
++FrameOff;
|
2005-08-25 08:45:43 +08:00
|
|
|
Op2 = CurDAG->getTargetFrameIndex(FI->getIndex(), MVT::i32);
|
2005-08-22 06:31:09 +08:00
|
|
|
} else {
|
|
|
|
Op2 = Select(Addr.getOperand(0));
|
|
|
|
}
|
|
|
|
return false;
|
2005-11-18 02:02:16 +08:00
|
|
|
} else if (Addr.getOperand(1).getOpcode() == PPCISD::Lo) {
|
|
|
|
// Match LOAD (ADD (X, Lo(G))).
|
|
|
|
assert(!cast<ConstantSDNode>(Addr.getOperand(1).getOperand(1))->getValue()
|
|
|
|
&& "Cannot handle constant offsets yet!");
|
|
|
|
Op1 = Addr.getOperand(1).getOperand(0); // The global address.
|
|
|
|
assert(Op1.getOpcode() == ISD::TargetGlobalAddress);
|
|
|
|
Op2 = Select(Addr.getOperand(0));
|
|
|
|
return false; // [&g+r]
|
2005-08-22 06:31:09 +08:00
|
|
|
} else {
|
|
|
|
Op1 = Select(Addr.getOperand(0));
|
|
|
|
Op2 = Select(Addr.getOperand(1));
|
|
|
|
return true; // [r+r]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-30 16:22:07 +08:00
|
|
|
if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Addr)) {
|
2005-08-22 06:31:09 +08:00
|
|
|
Op1 = getI32Imm(0);
|
2005-08-25 08:45:43 +08:00
|
|
|
Op2 = CurDAG->getTargetFrameIndex(FI->getIndex(), MVT::i32);
|
2005-08-22 06:31:09 +08:00
|
|
|
return false;
|
|
|
|
} else if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Addr)) {
|
|
|
|
Op1 = Addr;
|
|
|
|
if (PICEnabled)
|
|
|
|
Op2 = CurDAG->getTargetNode(PPC::ADDIS, MVT::i32, getGlobalBaseReg(),Op1);
|
|
|
|
else
|
|
|
|
Op2 = CurDAG->getTargetNode(PPC::LIS, MVT::i32, Op1);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Op1 = getI32Imm(0);
|
|
|
|
Op2 = Select(Addr);
|
|
|
|
return false;
|
|
|
|
}
|
2005-08-18 03:33:03 +08:00
|
|
|
|
2005-11-30 16:22:07 +08:00
|
|
|
/// SelectAddrIndexed - Given the specified addressed, force it to be
|
|
|
|
/// represented as an indexed [r+r] operation, rather than possibly
|
|
|
|
/// returning [r+imm] as SelectAddr may.
|
|
|
|
void PPCDAGToDAGISel::SelectAddrIndexed(SDOperand Addr, SDOperand &Op1,
|
|
|
|
SDOperand &Op2) {
|
|
|
|
if (Addr.getOpcode() == ISD::ADD) {
|
|
|
|
Op1 = Select(Addr.getOperand(0));
|
|
|
|
Op2 = Select(Addr.getOperand(1));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Addr)) {
|
|
|
|
Op1 = CurDAG->getTargetNode(PPC::LI, MVT::i32, getI32Imm(0));
|
|
|
|
Op2 = CurDAG->getTargetFrameIndex(FI->getIndex(), MVT::i32);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Op1 = CurDAG->getTargetNode(PPC::LI, MVT::i32, getI32Imm(0));
|
|
|
|
Op2 = Select(Addr);
|
|
|
|
}
|
|
|
|
|
2005-08-22 02:50:37 +08:00
|
|
|
/// SelectCC - Select a comparison of the specified values with the specified
|
|
|
|
/// condition code, returning the CR# of the expression.
|
2005-10-18 08:28:58 +08:00
|
|
|
SDOperand PPCDAGToDAGISel::SelectCC(SDOperand LHS, SDOperand RHS,
|
|
|
|
ISD::CondCode CC) {
|
2005-08-22 02:50:37 +08:00
|
|
|
// Always select the LHS.
|
|
|
|
LHS = Select(LHS);
|
|
|
|
|
|
|
|
// Use U to determine whether the SETCC immediate range is signed or not.
|
|
|
|
if (MVT::isInteger(LHS.getValueType())) {
|
|
|
|
bool U = ISD::isUnsignedIntSetCC(CC);
|
|
|
|
unsigned Imm;
|
|
|
|
if (isIntImmediate(RHS, Imm) &&
|
|
|
|
((U && isUInt16(Imm)) || (!U && isInt16(Imm))))
|
|
|
|
return CurDAG->getTargetNode(U ? PPC::CMPLWI : PPC::CMPWI, MVT::i32,
|
|
|
|
LHS, getI32Imm(Lo16(Imm)));
|
|
|
|
return CurDAG->getTargetNode(U ? PPC::CMPLW : PPC::CMPW, MVT::i32,
|
|
|
|
LHS, Select(RHS));
|
2005-10-01 09:35:02 +08:00
|
|
|
} else if (LHS.getValueType() == MVT::f32) {
|
|
|
|
return CurDAG->getTargetNode(PPC::FCMPUS, MVT::i32, LHS, Select(RHS));
|
2005-08-22 02:50:37 +08:00
|
|
|
} else {
|
2005-10-01 09:35:02 +08:00
|
|
|
return CurDAG->getTargetNode(PPC::FCMPUD, MVT::i32, LHS, Select(RHS));
|
2005-08-22 02:50:37 +08: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-29 04:49:47 +08:00
|
|
|
case ISD::SETOEQ: // FIXME: This is incorrect see PR642.
|
2005-08-22 02:50:37 +08:00
|
|
|
case ISD::SETEQ: return PPC::BEQ;
|
2005-10-29 04:49:47 +08:00
|
|
|
case ISD::SETONE: // FIXME: This is incorrect see PR642.
|
2005-08-22 02:50:37 +08:00
|
|
|
case ISD::SETNE: return PPC::BNE;
|
2005-10-29 04:49:47 +08:00
|
|
|
case ISD::SETOLT: // FIXME: This is incorrect see PR642.
|
2005-08-22 02:50:37 +08:00
|
|
|
case ISD::SETULT:
|
|
|
|
case ISD::SETLT: return PPC::BLT;
|
2005-10-29 04:49:47 +08:00
|
|
|
case ISD::SETOLE: // FIXME: This is incorrect see PR642.
|
2005-08-22 02:50:37 +08:00
|
|
|
case ISD::SETULE:
|
|
|
|
case ISD::SETLE: return PPC::BLE;
|
2005-10-29 04:49:47 +08:00
|
|
|
case ISD::SETOGT: // FIXME: This is incorrect see PR642.
|
2005-08-22 02:50:37 +08:00
|
|
|
case ISD::SETUGT:
|
|
|
|
case ISD::SETGT: return PPC::BGT;
|
2005-10-29 04:49:47 +08:00
|
|
|
case ISD::SETOGE: // FIXME: This is incorrect see PR642.
|
2005-08-22 02:50:37 +08:00
|
|
|
case ISD::SETUGE:
|
|
|
|
case ISD::SETGE: return PPC::BGE;
|
2005-10-29 04:32:44 +08:00
|
|
|
|
|
|
|
case ISD::SETO: return PPC::BUN;
|
|
|
|
case ISD::SETUO: return PPC::BNU;
|
2005-08-22 02:50:37 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-08-26 04:08:18 +08: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-29 04:49:47 +08:00
|
|
|
case ISD::SETOLT: // FIXME: This is incorrect see PR642.
|
2005-08-26 04:08:18 +08:00
|
|
|
case ISD::SETULT:
|
|
|
|
case ISD::SETLT: Inv = false; return 0;
|
2005-10-29 04:49:47 +08:00
|
|
|
case ISD::SETOGE: // FIXME: This is incorrect see PR642.
|
2005-08-26 04:08:18 +08:00
|
|
|
case ISD::SETUGE:
|
|
|
|
case ISD::SETGE: Inv = true; return 0;
|
2005-10-29 04:49:47 +08:00
|
|
|
case ISD::SETOGT: // FIXME: This is incorrect see PR642.
|
2005-08-26 04:08:18 +08:00
|
|
|
case ISD::SETUGT:
|
|
|
|
case ISD::SETGT: Inv = false; return 1;
|
2005-10-29 04:49:47 +08:00
|
|
|
case ISD::SETOLE: // FIXME: This is incorrect see PR642.
|
2005-08-26 04:08:18 +08:00
|
|
|
case ISD::SETULE:
|
|
|
|
case ISD::SETLE: Inv = true; return 1;
|
2005-10-29 04:49:47 +08:00
|
|
|
case ISD::SETOEQ: // FIXME: This is incorrect see PR642.
|
2005-08-26 04:08:18 +08:00
|
|
|
case ISD::SETEQ: Inv = false; return 2;
|
2005-10-29 04:49:47 +08:00
|
|
|
case ISD::SETONE: // FIXME: This is incorrect see PR642.
|
2005-08-26 04:08:18 +08:00
|
|
|
case ISD::SETNE: Inv = true; return 2;
|
2005-10-29 04:32:44 +08:00
|
|
|
case ISD::SETO: Inv = true; return 3;
|
|
|
|
case ISD::SETUO: Inv = false; return 3;
|
2005-08-26 04:08:18 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2005-08-22 06:31:09 +08:00
|
|
|
|
2005-10-18 08:28:58 +08:00
|
|
|
SDOperand PPCDAGToDAGISel::SelectDYNAMIC_STACKALLOC(SDOperand Op) {
|
2005-10-07 02:45:51 +08:00
|
|
|
SDNode *N = Op.Val;
|
|
|
|
|
|
|
|
// FIXME: We are currently ignoring the requested alignment for handling
|
|
|
|
// greater than the stack alignment. This will need to be revisited at some
|
|
|
|
// point. Align = N.getOperand(2);
|
|
|
|
if (!isa<ConstantSDNode>(N->getOperand(2)) ||
|
|
|
|
cast<ConstantSDNode>(N->getOperand(2))->getValue() != 0) {
|
|
|
|
std::cerr << "Cannot allocate stack object with greater alignment than"
|
|
|
|
<< " the stack alignment yet!";
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
SDOperand Chain = Select(N->getOperand(0));
|
|
|
|
SDOperand Amt = Select(N->getOperand(1));
|
|
|
|
|
|
|
|
SDOperand R1Reg = CurDAG->getRegister(PPC::R1, MVT::i32);
|
|
|
|
|
|
|
|
SDOperand R1Val = CurDAG->getCopyFromReg(Chain, PPC::R1, MVT::i32);
|
|
|
|
Chain = R1Val.getValue(1);
|
|
|
|
|
|
|
|
// Subtract the amount (guaranteed to be a multiple of the stack alignment)
|
|
|
|
// from the stack pointer, giving us the result pointer.
|
|
|
|
SDOperand Result = CurDAG->getTargetNode(PPC::SUBF, MVT::i32, Amt, R1Val);
|
|
|
|
|
|
|
|
// Copy this result back into R1.
|
|
|
|
Chain = CurDAG->getNode(ISD::CopyToReg, MVT::Other, Chain, R1Reg, Result);
|
|
|
|
|
|
|
|
// Copy this result back out of R1 to make sure we're not using the stack
|
|
|
|
// space without decrementing the stack pointer.
|
|
|
|
Result = CurDAG->getCopyFromReg(Chain, PPC::R1, MVT::i32);
|
|
|
|
|
|
|
|
// Finally, replace the DYNAMIC_STACKALLOC with the copyfromreg.
|
|
|
|
CodeGenMap[Op.getValue(0)] = Result;
|
|
|
|
CodeGenMap[Op.getValue(1)] = Result.getValue(1);
|
|
|
|
return SDOperand(Result.Val, Op.ResNo);
|
|
|
|
}
|
|
|
|
|
2005-10-18 08:28:58 +08:00
|
|
|
SDOperand PPCDAGToDAGISel::SelectADD_PARTS(SDOperand Op) {
|
2005-10-07 02:56:10 +08:00
|
|
|
SDNode *N = Op.Val;
|
|
|
|
SDOperand LHSL = Select(N->getOperand(0));
|
|
|
|
SDOperand LHSH = Select(N->getOperand(1));
|
|
|
|
|
|
|
|
unsigned Imm;
|
|
|
|
bool ME = false, ZE = false;
|
|
|
|
if (isIntImmediate(N->getOperand(3), Imm)) {
|
|
|
|
ME = (signed)Imm == -1;
|
|
|
|
ZE = Imm == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<SDOperand> Result;
|
|
|
|
SDOperand CarryFromLo;
|
|
|
|
if (isIntImmediate(N->getOperand(2), Imm) &&
|
|
|
|
((signed)Imm >= -32768 || (signed)Imm < 32768)) {
|
|
|
|
// Codegen the low 32 bits of the add. Interestingly, there is no
|
|
|
|
// shifted form of add immediate carrying.
|
|
|
|
CarryFromLo = CurDAG->getTargetNode(PPC::ADDIC, MVT::i32, MVT::Flag,
|
|
|
|
LHSL, getI32Imm(Imm));
|
|
|
|
} else {
|
|
|
|
CarryFromLo = CurDAG->getTargetNode(PPC::ADDC, MVT::i32, MVT::Flag,
|
|
|
|
LHSL, Select(N->getOperand(2)));
|
|
|
|
}
|
|
|
|
CarryFromLo = CarryFromLo.getValue(1);
|
|
|
|
|
|
|
|
// Codegen the high 32 bits, adding zero, minus one, or the full value
|
|
|
|
// along with the carry flag produced by addc/addic.
|
|
|
|
SDOperand ResultHi;
|
|
|
|
if (ZE)
|
|
|
|
ResultHi = CurDAG->getTargetNode(PPC::ADDZE, MVT::i32, LHSH, CarryFromLo);
|
|
|
|
else if (ME)
|
|
|
|
ResultHi = CurDAG->getTargetNode(PPC::ADDME, MVT::i32, LHSH, CarryFromLo);
|
|
|
|
else
|
|
|
|
ResultHi = CurDAG->getTargetNode(PPC::ADDE, MVT::i32, LHSH,
|
|
|
|
Select(N->getOperand(3)), CarryFromLo);
|
|
|
|
Result.push_back(CarryFromLo.getValue(0));
|
|
|
|
Result.push_back(ResultHi);
|
|
|
|
|
|
|
|
CodeGenMap[Op.getValue(0)] = Result[0];
|
|
|
|
CodeGenMap[Op.getValue(1)] = Result[1];
|
|
|
|
return Result[Op.ResNo];
|
|
|
|
}
|
2005-10-18 08:28:58 +08:00
|
|
|
SDOperand PPCDAGToDAGISel::SelectSUB_PARTS(SDOperand Op) {
|
2005-10-07 02:56:10 +08:00
|
|
|
SDNode *N = Op.Val;
|
|
|
|
SDOperand LHSL = Select(N->getOperand(0));
|
|
|
|
SDOperand LHSH = Select(N->getOperand(1));
|
|
|
|
SDOperand RHSL = Select(N->getOperand(2));
|
|
|
|
SDOperand RHSH = Select(N->getOperand(3));
|
|
|
|
|
|
|
|
std::vector<SDOperand> Result;
|
|
|
|
Result.push_back(CurDAG->getTargetNode(PPC::SUBFC, MVT::i32, MVT::Flag,
|
|
|
|
RHSL, LHSL));
|
|
|
|
Result.push_back(CurDAG->getTargetNode(PPC::SUBFE, MVT::i32, RHSH, LHSH,
|
|
|
|
Result[0].getValue(1)));
|
|
|
|
CodeGenMap[Op.getValue(0)] = Result[0];
|
|
|
|
CodeGenMap[Op.getValue(1)] = Result[1];
|
|
|
|
return Result[Op.ResNo];
|
|
|
|
}
|
|
|
|
|
2005-10-18 08:28:58 +08:00
|
|
|
SDOperand PPCDAGToDAGISel::SelectSETCC(SDOperand Op) {
|
2005-10-07 03:03:35 +08:00
|
|
|
SDNode *N = Op.Val;
|
|
|
|
unsigned Imm;
|
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
|
|
|
|
if (isIntImmediate(N->getOperand(1), Imm)) {
|
|
|
|
// We can codegen setcc op, imm very efficiently compared to a brcond.
|
|
|
|
// Check for those cases here.
|
|
|
|
// setcc op, 0
|
|
|
|
if (Imm == 0) {
|
|
|
|
SDOperand Op = Select(N->getOperand(0));
|
|
|
|
switch (CC) {
|
2005-10-22 05:17:10 +08:00
|
|
|
default: break;
|
|
|
|
case ISD::SETEQ:
|
|
|
|
Op = CurDAG->getTargetNode(PPC::CNTLZW, MVT::i32, Op);
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Op, getI32Imm(27),
|
|
|
|
getI32Imm(5), getI32Imm(31));
|
2005-10-22 05:17:10 +08:00
|
|
|
case ISD::SETNE: {
|
|
|
|
SDOperand AD = CurDAG->getTargetNode(PPC::ADDIC, MVT::i32, MVT::Flag,
|
|
|
|
Op, getI32Imm(~0U));
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::SUBFE, MVT::i32, AD, Op,
|
|
|
|
AD.getValue(1));
|
2005-10-22 05:17:10 +08:00
|
|
|
}
|
|
|
|
case ISD::SETLT:
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Op, getI32Imm(1),
|
|
|
|
getI32Imm(31), getI32Imm(31));
|
2005-10-22 05:17:10 +08:00
|
|
|
case ISD::SETGT: {
|
|
|
|
SDOperand T = CurDAG->getTargetNode(PPC::NEG, MVT::i32, Op);
|
|
|
|
T = CurDAG->getTargetNode(PPC::ANDC, MVT::i32, T, Op);;
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, T, getI32Imm(1),
|
|
|
|
getI32Imm(31), getI32Imm(31));
|
2005-10-22 05:17:10 +08:00
|
|
|
}
|
2005-10-07 03:03:35 +08:00
|
|
|
}
|
|
|
|
} else if (Imm == ~0U) { // setcc op, -1
|
|
|
|
SDOperand Op = Select(N->getOperand(0));
|
|
|
|
switch (CC) {
|
2005-10-22 05:17:10 +08:00
|
|
|
default: break;
|
|
|
|
case ISD::SETEQ:
|
|
|
|
Op = CurDAG->getTargetNode(PPC::ADDIC, MVT::i32, MVT::Flag,
|
|
|
|
Op, getI32Imm(1));
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::ADDZE, MVT::i32,
|
|
|
|
CurDAG->getTargetNode(PPC::LI, MVT::i32,
|
|
|
|
getI32Imm(0)),
|
|
|
|
Op.getValue(1));
|
2005-10-22 05:17:10 +08:00
|
|
|
case ISD::SETNE: {
|
|
|
|
Op = CurDAG->getTargetNode(PPC::NOR, MVT::i32, Op, Op);
|
|
|
|
SDOperand AD = CurDAG->getTargetNode(PPC::ADDIC, MVT::i32, MVT::Flag,
|
|
|
|
Op, getI32Imm(~0U));
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::SUBFE, MVT::i32, AD, Op,
|
|
|
|
AD.getValue(1));
|
2005-10-22 05:17:10 +08:00
|
|
|
}
|
|
|
|
case ISD::SETLT: {
|
|
|
|
SDOperand AD = CurDAG->getTargetNode(PPC::ADDI, MVT::i32, Op,
|
|
|
|
getI32Imm(1));
|
|
|
|
SDOperand AN = CurDAG->getTargetNode(PPC::AND, MVT::i32, AD, Op);
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, AN, getI32Imm(1),
|
|
|
|
getI32Imm(31), getI32Imm(31));
|
2005-10-22 05:17:10 +08:00
|
|
|
}
|
|
|
|
case ISD::SETGT:
|
|
|
|
Op = CurDAG->getTargetNode(PPC::RLWINM, MVT::i32, Op, getI32Imm(1),
|
|
|
|
getI32Imm(31), getI32Imm(31));
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::XORI, MVT::i32, Op, getI32Imm(1));
|
2005-10-07 03:03:35 +08: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-01 08:41:50 +08:00
|
|
|
SDOperand InFlag; // Null incoming flag value.
|
|
|
|
CCReg = CurDAG->getCopyToReg(CurDAG->getEntryNode(), CR7Reg, CCReg, InFlag);
|
2005-10-07 03:03:35 +08:00
|
|
|
|
|
|
|
if (TLI.getTargetMachine().getSubtarget<PPCSubtarget>().isGigaProcessor())
|
|
|
|
IntCR = CurDAG->getTargetNode(PPC::MFOCRF, MVT::i32, CR7Reg, CCReg);
|
|
|
|
else
|
|
|
|
IntCR = CurDAG->getTargetNode(PPC::MFCR, MVT::i32, CCReg);
|
|
|
|
|
|
|
|
if (!Inv) {
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, IntCR,
|
|
|
|
getI32Imm((32-(3-Idx)) & 31),
|
|
|
|
getI32Imm(31), getI32Imm(31));
|
2005-10-07 03:03:35 +08:00
|
|
|
} else {
|
|
|
|
SDOperand Tmp =
|
|
|
|
CurDAG->getTargetNode(PPC::RLWINM, MVT::i32, IntCR,
|
2005-10-29 06:58:07 +08:00
|
|
|
getI32Imm((32-(3-Idx)) & 31),
|
|
|
|
getI32Imm(31),getI32Imm(31));
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::XORI, MVT::i32, Tmp, getI32Imm(1));
|
2005-10-07 03:03:35 +08:00
|
|
|
}
|
|
|
|
}
|
2005-10-07 02:56:10 +08:00
|
|
|
|
2005-11-16 08:48:01 +08:00
|
|
|
/// isCallCompatibleAddress - Return true if the specified 32-bit value is
|
|
|
|
/// representable in the immediate field of a Bx instruction.
|
|
|
|
static bool isCallCompatibleAddress(ConstantSDNode *C) {
|
|
|
|
int Addr = C->getValue();
|
|
|
|
if (Addr & 3) return false; // Low 2 bits are implicitly zero.
|
|
|
|
return (Addr << 6 >> 6) == Addr; // Top 6 bits have to be sext of immediate.
|
|
|
|
}
|
|
|
|
|
2005-10-18 08:28:58 +08:00
|
|
|
SDOperand PPCDAGToDAGISel::SelectCALL(SDOperand Op) {
|
2005-10-07 03:07:45 +08:00
|
|
|
SDNode *N = Op.Val;
|
|
|
|
SDOperand Chain = Select(N->getOperand(0));
|
|
|
|
|
|
|
|
unsigned CallOpcode;
|
|
|
|
std::vector<SDOperand> CallOperands;
|
|
|
|
|
|
|
|
if (GlobalAddressSDNode *GASD =
|
|
|
|
dyn_cast<GlobalAddressSDNode>(N->getOperand(1))) {
|
2005-11-16 08:48:01 +08:00
|
|
|
CallOpcode = PPC::BL;
|
2005-11-17 13:56:14 +08:00
|
|
|
CallOperands.push_back(N->getOperand(1));
|
2005-10-07 03:07:45 +08:00
|
|
|
} else if (ExternalSymbolSDNode *ESSDN =
|
|
|
|
dyn_cast<ExternalSymbolSDNode>(N->getOperand(1))) {
|
2005-11-16 08:48:01 +08:00
|
|
|
CallOpcode = PPC::BL;
|
2005-10-07 03:07:45 +08:00
|
|
|
CallOperands.push_back(N->getOperand(1));
|
2005-11-16 08:48:01 +08:00
|
|
|
} else if (isa<ConstantSDNode>(N->getOperand(1)) &&
|
|
|
|
isCallCompatibleAddress(cast<ConstantSDNode>(N->getOperand(1)))) {
|
|
|
|
ConstantSDNode *C = cast<ConstantSDNode>(N->getOperand(1));
|
|
|
|
CallOpcode = PPC::BLA;
|
|
|
|
CallOperands.push_back(getI32Imm((int)C->getValue() >> 2));
|
2005-10-07 03:07:45 +08:00
|
|
|
} else {
|
|
|
|
// Copy the callee address into the CTR register.
|
|
|
|
SDOperand Callee = Select(N->getOperand(1));
|
|
|
|
Chain = CurDAG->getTargetNode(PPC::MTCTR, MVT::Other, Callee, Chain);
|
|
|
|
|
|
|
|
// Copy the callee address into R12 on darwin.
|
|
|
|
SDOperand R12 = CurDAG->getRegister(PPC::R12, MVT::i32);
|
|
|
|
Chain = CurDAG->getNode(ISD::CopyToReg, MVT::Other, Chain, R12, Callee);
|
2005-11-16 08:48:01 +08:00
|
|
|
|
2005-10-07 03:07:45 +08:00
|
|
|
CallOperands.push_back(R12);
|
2005-11-16 08:48:01 +08:00
|
|
|
CallOpcode = PPC::BCTRL;
|
2005-10-07 03:07:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned GPR_idx = 0, FPR_idx = 0;
|
|
|
|
static const unsigned GPR[] = {
|
|
|
|
PPC::R3, PPC::R4, PPC::R5, PPC::R6,
|
|
|
|
PPC::R7, PPC::R8, PPC::R9, PPC::R10,
|
|
|
|
};
|
|
|
|
static const unsigned FPR[] = {
|
|
|
|
PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, PPC::F7,
|
|
|
|
PPC::F8, PPC::F9, PPC::F10, PPC::F11, PPC::F12, PPC::F13
|
|
|
|
};
|
|
|
|
|
|
|
|
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::i32) {
|
|
|
|
assert(GPR_idx < 8 && "Too many int args");
|
|
|
|
DestReg = GPR[GPR_idx++];
|
|
|
|
} else {
|
|
|
|
assert(MVT::isFloatingPoint(N->getOperand(i).getValueType()) &&
|
|
|
|
"Unpromoted integer arg?");
|
|
|
|
assert(FPR_idx < 13 && "Too many fp args");
|
|
|
|
DestReg = FPR[FPR_idx++];
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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::i32:
|
|
|
|
if (N->getValueType(1) == MVT::i32) {
|
|
|
|
Chain = CurDAG->getCopyFromReg(Chain, PPC::R4, MVT::i32,
|
|
|
|
Chain.getValue(1)).getValue(1);
|
|
|
|
CallResults.push_back(Chain.getValue(0));
|
|
|
|
Chain = CurDAG->getCopyFromReg(Chain, PPC::R3, MVT::i32,
|
|
|
|
Chain.getValue(2)).getValue(1);
|
|
|
|
CallResults.push_back(Chain.getValue(0));
|
|
|
|
} else {
|
|
|
|
Chain = CurDAG->getCopyFromReg(Chain, PPC::R3, MVT::i32,
|
|
|
|
Chain.getValue(1)).getValue(1);
|
|
|
|
CallResults.push_back(Chain.getValue(0));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64:
|
|
|
|
Chain = CurDAG->getCopyFromReg(Chain, PPC::F1, N->getValueType(0),
|
|
|
|
Chain.getValue(1)).getValue(1);
|
|
|
|
CallResults.push_back(Chain.getValue(0));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
CallResults.push_back(Chain);
|
|
|
|
for (unsigned i = 0, e = CallResults.size(); i != e; ++i)
|
|
|
|
CodeGenMap[Op.getValue(i)] = CallResults[i];
|
|
|
|
return CallResults[Op.ResNo];
|
|
|
|
}
|
|
|
|
|
2005-08-18 03:33:03 +08:00
|
|
|
// Select - Convert the specified operand from a target-independent to a
|
|
|
|
// target-specific node if it hasn't already been changed.
|
2005-10-18 08:28:58 +08:00
|
|
|
SDOperand PPCDAGToDAGISel::Select(SDOperand Op) {
|
2005-08-18 03:33:03 +08:00
|
|
|
SDNode *N = Op.Val;
|
2005-08-27 04:25:03 +08:00
|
|
|
if (N->getOpcode() >= ISD::BUILTIN_OP_END &&
|
|
|
|
N->getOpcode() < PPCISD::FIRST_NUMBER)
|
2005-08-18 03:33:03 +08:00
|
|
|
return Op; // Already selected.
|
2005-09-29 08:59:32 +08:00
|
|
|
|
|
|
|
// If this has already been converted, use it.
|
|
|
|
std::map<SDOperand, SDOperand>::iterator CGMI = CodeGenMap.find(Op);
|
|
|
|
if (CGMI != CodeGenMap.end()) return CGMI->second;
|
2005-08-18 03:33:03 +08:00
|
|
|
|
|
|
|
switch (N->getOpcode()) {
|
2005-09-08 07:45:15 +08:00
|
|
|
default: break;
|
2005-10-07 03:03:35 +08:00
|
|
|
case ISD::DYNAMIC_STACKALLOC: return SelectDYNAMIC_STACKALLOC(Op);
|
|
|
|
case ISD::ADD_PARTS: return SelectADD_PARTS(Op);
|
|
|
|
case ISD::SUB_PARTS: return SelectSUB_PARTS(Op);
|
|
|
|
case ISD::SETCC: return SelectSETCC(Op);
|
2005-10-07 03:07:45 +08:00
|
|
|
case ISD::CALL: return SelectCALL(Op);
|
|
|
|
case ISD::TAILCALL: return SelectCALL(Op);
|
2005-11-17 15:30:41 +08:00
|
|
|
case PPCISD::GlobalBaseReg: return getGlobalBaseReg();
|
|
|
|
|
2005-08-25 08:45:43 +08:00
|
|
|
case ISD::FrameIndex: {
|
|
|
|
int FI = cast<FrameIndexSDNode>(N)->getIndex();
|
2005-12-01 06:53:06 +08:00
|
|
|
if (N->hasOneUse())
|
|
|
|
return CurDAG->SelectNodeTo(N, PPC::ADDI, MVT::i32,
|
|
|
|
CurDAG->getTargetFrameIndex(FI, MVT::i32),
|
|
|
|
getI32Imm(0));
|
2005-10-26 04:26:41 +08:00
|
|
|
return CurDAG->getTargetNode(PPC::ADDI, MVT::i32,
|
|
|
|
CurDAG->getTargetFrameIndex(FI, MVT::i32),
|
|
|
|
getI32Imm(0));
|
2005-08-25 08:45:43 +08:00
|
|
|
}
|
2005-08-25 13:04:11 +08:00
|
|
|
case ISD::ConstantPool: {
|
2005-08-27 01:15:30 +08:00
|
|
|
Constant *C = cast<ConstantPoolSDNode>(N)->get();
|
|
|
|
SDOperand Tmp, CPI = CurDAG->getTargetConstantPool(C, MVT::i32);
|
2005-08-25 13:04:11 +08:00
|
|
|
if (PICEnabled)
|
|
|
|
Tmp = CurDAG->getTargetNode(PPC::ADDIS, MVT::i32, getGlobalBaseReg(),CPI);
|
|
|
|
else
|
|
|
|
Tmp = CurDAG->getTargetNode(PPC::LIS, MVT::i32, CPI);
|
2005-12-01 06:53:06 +08:00
|
|
|
if (N->hasOneUse())
|
|
|
|
return CurDAG->SelectNodeTo(N, PPC::LA, MVT::i32, Tmp, CPI);
|
2005-10-26 03:32:37 +08:00
|
|
|
return CurDAG->getTargetNode(PPC::LA, MVT::i32, Tmp, CPI);
|
2005-08-25 13:04:11 +08:00
|
|
|
}
|
2005-09-29 06:29:58 +08:00
|
|
|
case ISD::FADD: {
|
|
|
|
MVT::ValueType Ty = N->getValueType(0);
|
2005-08-18 03:33:03 +08:00
|
|
|
if (!NoExcessFPPrecision) { // Match FMA ops
|
2005-09-29 06:29:58 +08:00
|
|
|
if (N->getOperand(0).getOpcode() == ISD::FMUL &&
|
2005-08-18 03:33:03 +08:00
|
|
|
N->getOperand(0).Val->hasOneUse()) {
|
|
|
|
++FusedFP; // Statistic
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, Ty == MVT::f64 ? PPC::FMADD :PPC::FMADDS,
|
|
|
|
Ty, Select(N->getOperand(0).getOperand(0)),
|
|
|
|
Select(N->getOperand(0).getOperand(1)),
|
|
|
|
Select(N->getOperand(1)));
|
2005-09-29 06:29:58 +08:00
|
|
|
} else if (N->getOperand(1).getOpcode() == ISD::FMUL &&
|
2005-08-18 03:33:03 +08:00
|
|
|
N->getOperand(1).hasOneUse()) {
|
|
|
|
++FusedFP; // Statistic
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, Ty == MVT::f64 ? PPC::FMADD :PPC::FMADDS,
|
|
|
|
Ty, Select(N->getOperand(1).getOperand(0)),
|
|
|
|
Select(N->getOperand(1).getOperand(1)),
|
|
|
|
Select(N->getOperand(0)));
|
2005-08-18 03:33:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-30 16:22:07 +08:00
|
|
|
// Other cases are autogenerated.
|
|
|
|
break;
|
2005-08-18 03:33:03 +08:00
|
|
|
}
|
2005-09-29 06:29:58 +08:00
|
|
|
case ISD::FSUB: {
|
|
|
|
MVT::ValueType Ty = N->getValueType(0);
|
2005-08-18 03:33:03 +08:00
|
|
|
|
|
|
|
if (!NoExcessFPPrecision) { // Match FMA ops
|
2005-09-29 06:29:58 +08:00
|
|
|
if (N->getOperand(0).getOpcode() == ISD::FMUL &&
|
2005-08-18 03:33:03 +08:00
|
|
|
N->getOperand(0).Val->hasOneUse()) {
|
|
|
|
++FusedFP; // Statistic
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, Ty == MVT::f64 ? PPC::FMSUB:PPC::FMSUBS,
|
|
|
|
Ty, Select(N->getOperand(0).getOperand(0)),
|
|
|
|
Select(N->getOperand(0).getOperand(1)),
|
|
|
|
Select(N->getOperand(1)));
|
2005-09-29 06:29:58 +08:00
|
|
|
} else if (N->getOperand(1).getOpcode() == ISD::FMUL &&
|
2005-08-18 03:33:03 +08:00
|
|
|
N->getOperand(1).Val->hasOneUse()) {
|
|
|
|
++FusedFP; // Statistic
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, Ty == MVT::f64 ?PPC::FNMSUB:PPC::FNMSUBS,
|
|
|
|
Ty, Select(N->getOperand(1).getOperand(0)),
|
|
|
|
Select(N->getOperand(1).getOperand(1)),
|
|
|
|
Select(N->getOperand(0)));
|
2005-08-18 03:33:03 +08:00
|
|
|
}
|
|
|
|
}
|
2005-11-30 16:22:07 +08:00
|
|
|
|
|
|
|
// Other cases are autogenerated.
|
|
|
|
break;
|
2005-08-18 07:46:35 +08:00
|
|
|
}
|
2005-09-29 06:50:24 +08:00
|
|
|
case ISD::SDIV: {
|
2005-10-21 08:02:42 +08: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-26 01:50:06 +08:00
|
|
|
unsigned Imm;
|
|
|
|
if (isIntImmediate(N->getOperand(1), Imm)) {
|
|
|
|
if ((signed)Imm > 0 && isPowerOf2_32(Imm)) {
|
|
|
|
SDOperand Op =
|
|
|
|
CurDAG->getTargetNode(PPC::SRAWI, MVT::i32, MVT::Flag,
|
|
|
|
Select(N->getOperand(0)),
|
|
|
|
getI32Imm(Log2_32(Imm)));
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::ADDZE, MVT::i32,
|
|
|
|
Op.getValue(0), Op.getValue(1));
|
2005-08-26 01:50:06 +08:00
|
|
|
} else if ((signed)Imm < 0 && isPowerOf2_32(-Imm)) {
|
|
|
|
SDOperand Op =
|
2005-08-31 01:13:58 +08:00
|
|
|
CurDAG->getTargetNode(PPC::SRAWI, MVT::i32, MVT::Flag,
|
2005-08-26 01:50:06 +08:00
|
|
|
Select(N->getOperand(0)),
|
|
|
|
getI32Imm(Log2_32(-Imm)));
|
|
|
|
SDOperand PT =
|
2005-08-31 01:13:58 +08:00
|
|
|
CurDAG->getTargetNode(PPC::ADDZE, MVT::i32, Op.getValue(0),
|
|
|
|
Op.getValue(1));
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::NEG, MVT::i32, PT);
|
2005-08-26 01:50:06 +08:00
|
|
|
}
|
|
|
|
}
|
2005-08-26 06:04:30 +08:00
|
|
|
|
2005-09-30 07:33:31 +08:00
|
|
|
// Other cases are autogenerated.
|
|
|
|
break;
|
2005-08-26 06:04:30 +08:00
|
|
|
}
|
2005-08-18 15:30:46 +08:00
|
|
|
case ISD::AND: {
|
2005-08-19 02:01:39 +08:00
|
|
|
unsigned Imm;
|
2005-08-18 15:30:46 +08:00
|
|
|
// If this is an and of a value rotated between 0 and 31 bits and then and'd
|
|
|
|
// with a mask, emit rlwinm
|
|
|
|
if (isIntImmediate(N->getOperand(1), Imm) && (isShiftedMask_32(Imm) ||
|
|
|
|
isShiftedMask_32(~Imm))) {
|
|
|
|
SDOperand Val;
|
2005-08-19 02:01:39 +08:00
|
|
|
unsigned SH, MB, ME;
|
2005-08-18 15:30:46 +08:00
|
|
|
if (isRotateAndMask(N->getOperand(0).Val, Imm, false, SH, MB, ME)) {
|
|
|
|
Val = Select(N->getOperand(0).getOperand(0));
|
2005-10-26 03:32:37 +08:00
|
|
|
} else if (Imm == 0) {
|
|
|
|
// AND X, 0 -> 0, not "rlwinm 32".
|
|
|
|
return Select(N->getOperand(1));
|
|
|
|
} else {
|
2005-08-18 15:30:46 +08:00
|
|
|
Val = Select(N->getOperand(0));
|
|
|
|
isRunOfOnes(Imm, MB, ME);
|
|
|
|
SH = 0;
|
|
|
|
}
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Val, getI32Imm(SH),
|
|
|
|
getI32Imm(MB), getI32Imm(ME));
|
2005-08-18 15:30:46 +08:00
|
|
|
}
|
2005-09-30 07:33:31 +08:00
|
|
|
|
|
|
|
// Other cases are autogenerated.
|
|
|
|
break;
|
2005-08-18 15:30:46 +08:00
|
|
|
}
|
2005-08-19 08:38:14 +08:00
|
|
|
case ISD::OR:
|
2005-09-29 08:59:32 +08:00
|
|
|
if (SDNode *I = SelectBitfieldInsert(N))
|
|
|
|
return CodeGenMap[Op] = SDOperand(I, 0);
|
|
|
|
|
2005-09-30 07:33:31 +08:00
|
|
|
// Other cases are autogenerated.
|
|
|
|
break;
|
2005-08-19 07:38:00 +08:00
|
|
|
case ISD::SHL: {
|
|
|
|
unsigned Imm, SH, MB, ME;
|
|
|
|
if (isOpcWithIntImmediate(N->getOperand(0).Val, ISD::AND, Imm) &&
|
2005-10-20 02:42:01 +08:00
|
|
|
isRotateAndMask(N, Imm, true, SH, MB, ME)) {
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32,
|
|
|
|
Select(N->getOperand(0).getOperand(0)),
|
|
|
|
getI32Imm(SH), getI32Imm(MB), getI32Imm(ME));
|
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
llvm-svn: 23809
2005-10-19 09:12:32 +08:00
|
|
|
}
|
2005-10-20 02:42:01 +08:00
|
|
|
|
|
|
|
// Other cases are autogenerated.
|
|
|
|
break;
|
2005-08-19 07:38:00 +08:00
|
|
|
}
|
|
|
|
case ISD::SRL: {
|
|
|
|
unsigned Imm, SH, MB, ME;
|
|
|
|
if (isOpcWithIntImmediate(N->getOperand(0).Val, ISD::AND, Imm) &&
|
2005-10-20 02:42:01 +08:00
|
|
|
isRotateAndMask(N, Imm, true, SH, MB, ME)) {
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32,
|
|
|
|
Select(N->getOperand(0).getOperand(0)),
|
|
|
|
getI32Imm(SH & 0x1F), getI32Imm(MB),
|
|
|
|
getI32Imm(ME));
|
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
llvm-svn: 23809
2005-10-19 09:12:32 +08:00
|
|
|
}
|
2005-10-20 02:42:01 +08:00
|
|
|
|
|
|
|
// Other cases are autogenerated.
|
|
|
|
break;
|
2005-08-19 07:38:00 +08:00
|
|
|
}
|
2005-08-18 07:46:35 +08:00
|
|
|
case ISD::FNEG: {
|
|
|
|
SDOperand Val = Select(N->getOperand(0));
|
|
|
|
MVT::ValueType Ty = N->getValueType(0);
|
2005-10-16 06:06:18 +08:00
|
|
|
if (N->getOperand(0).Val->hasOneUse()) {
|
2005-08-18 07:46:35 +08:00
|
|
|
unsigned Opc;
|
2005-08-29 07:39:22 +08:00
|
|
|
switch (Val.isTargetOpcode() ? Val.getTargetOpcode() : 0) {
|
2005-08-18 07:46:35 +08:00
|
|
|
default: Opc = 0; break;
|
2005-10-01 09:35:02 +08:00
|
|
|
case PPC::FABSS: Opc = PPC::FNABSS; break;
|
|
|
|
case PPC::FABSD: Opc = PPC::FNABSD; break;
|
2005-08-18 07:46:35 +08:00
|
|
|
case PPC::FMADD: Opc = PPC::FNMADD; break;
|
|
|
|
case PPC::FMADDS: Opc = PPC::FNMADDS; break;
|
|
|
|
case PPC::FMSUB: Opc = PPC::FNMSUB; break;
|
|
|
|
case PPC::FMSUBS: Opc = PPC::FNMSUBS; break;
|
|
|
|
}
|
|
|
|
// If we inverted the opcode, then emit the new instruction with the
|
|
|
|
// inverted opcode and the original instruction's operands. Otherwise,
|
|
|
|
// fall through and generate a fneg instruction.
|
|
|
|
if (Opc) {
|
2005-10-01 09:35:02 +08:00
|
|
|
if (Opc == PPC::FNABSS || Opc == PPC::FNABSD)
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, Opc, Ty, Val.getOperand(0));
|
2005-08-18 07:46:35 +08:00
|
|
|
else
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, Opc, Ty, Val.getOperand(0),
|
|
|
|
Val.getOperand(1), Val.getOperand(2));
|
2005-08-18 07:46:35 +08:00
|
|
|
}
|
|
|
|
}
|
2005-10-01 09:35:02 +08:00
|
|
|
if (Ty == MVT::f32)
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::FNEGS, MVT::f32, Val);
|
2005-10-01 09:35:02 +08:00
|
|
|
else
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::FNEGD, MVT::f64, Val);
|
2005-08-18 07:46:35 +08:00
|
|
|
}
|
2005-08-22 06:31:09 +08:00
|
|
|
case ISD::LOAD:
|
|
|
|
case ISD::EXTLOAD:
|
|
|
|
case ISD::ZEXTLOAD:
|
|
|
|
case ISD::SEXTLOAD: {
|
|
|
|
SDOperand Op1, Op2;
|
2005-11-30 16:22:07 +08:00
|
|
|
// If this is a vector load, then force this to be indexed addressing, since
|
|
|
|
// altivec does not have immediate offsets for loads.
|
|
|
|
bool isIdx = true;
|
|
|
|
if (N->getOpcode() == ISD::LOAD && MVT::isVector(N->getValueType(0))) {
|
|
|
|
SelectAddrIndexed(N->getOperand(1), Op1, Op2);
|
|
|
|
} else {
|
|
|
|
isIdx = SelectAddr(N->getOperand(1), Op1, Op2);
|
|
|
|
}
|
2005-08-22 06:31:09 +08:00
|
|
|
MVT::ValueType TypeBeingLoaded = (N->getOpcode() == ISD::LOAD) ?
|
|
|
|
N->getValueType(0) : cast<VTSDNode>(N->getOperand(3))->getVT();
|
2005-11-30 16:22:07 +08:00
|
|
|
|
2005-08-22 06:31:09 +08:00
|
|
|
unsigned Opc;
|
|
|
|
switch (TypeBeingLoaded) {
|
|
|
|
default: N->dump(); assert(0 && "Cannot load this type!");
|
|
|
|
case MVT::i1:
|
|
|
|
case MVT::i8: Opc = isIdx ? PPC::LBZX : PPC::LBZ; break;
|
|
|
|
case MVT::i16:
|
|
|
|
if (N->getOpcode() == ISD::SEXTLOAD) { // SEXT load?
|
|
|
|
Opc = isIdx ? PPC::LHAX : PPC::LHA;
|
|
|
|
} else {
|
|
|
|
Opc = isIdx ? PPC::LHZX : PPC::LHZ;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MVT::i32: Opc = isIdx ? PPC::LWZX : PPC::LWZ; break;
|
|
|
|
case MVT::f32: Opc = isIdx ? PPC::LFSX : PPC::LFS; break;
|
|
|
|
case MVT::f64: Opc = isIdx ? PPC::LFDX : PPC::LFD; break;
|
2005-11-30 16:22:07 +08:00
|
|
|
case MVT::v4f32: Opc = PPC::LVX; break;
|
2005-08-22 06:31:09 +08:00
|
|
|
}
|
|
|
|
|
2005-10-01 09:35:02 +08:00
|
|
|
// If this is an f32 -> f64 load, emit the f32 load, then use an 'extending
|
|
|
|
// copy'.
|
|
|
|
if (TypeBeingLoaded != MVT::f32 || N->getOpcode() == ISD::LOAD) {
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other,
|
|
|
|
Op1, Op2, Select(N->getOperand(0))).
|
|
|
|
getValue(Op.ResNo);
|
2005-10-01 09:35:02 +08:00
|
|
|
} else {
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Op1);
|
|
|
|
Ops.push_back(Op2);
|
|
|
|
Ops.push_back(Select(N->getOperand(0)));
|
|
|
|
SDOperand Res = CurDAG->getTargetNode(Opc, MVT::f32, MVT::Other, Ops);
|
|
|
|
SDOperand Ext = CurDAG->getTargetNode(PPC::FMRSD, MVT::f64, Res);
|
|
|
|
CodeGenMap[Op.getValue(0)] = Ext;
|
|
|
|
CodeGenMap[Op.getValue(1)] = Res.getValue(1);
|
|
|
|
if (Op.ResNo)
|
|
|
|
return Res.getValue(1);
|
|
|
|
else
|
|
|
|
return Ext;
|
|
|
|
}
|
2005-08-22 06:31:09 +08:00
|
|
|
}
|
2005-08-22 09:27:59 +08:00
|
|
|
case ISD::TRUNCSTORE:
|
|
|
|
case ISD::STORE: {
|
|
|
|
SDOperand AddrOp1, AddrOp2;
|
2005-11-30 16:22:07 +08:00
|
|
|
// If this is a vector store, then force this to be indexed addressing,
|
|
|
|
// since altivec does not have immediate offsets for stores.
|
|
|
|
bool isIdx = true;
|
|
|
|
if (N->getOpcode() == ISD::STORE &&
|
|
|
|
MVT::isVector(N->getOperand(1).getValueType())) {
|
|
|
|
SelectAddrIndexed(N->getOperand(2), AddrOp1, AddrOp2);
|
|
|
|
} else {
|
|
|
|
isIdx = SelectAddr(N->getOperand(2), AddrOp1, AddrOp2);
|
|
|
|
}
|
2005-08-22 09:27:59 +08:00
|
|
|
|
|
|
|
unsigned Opc;
|
|
|
|
if (N->getOpcode() == ISD::STORE) {
|
|
|
|
switch (N->getOperand(1).getValueType()) {
|
|
|
|
default: assert(0 && "unknown Type in store");
|
|
|
|
case MVT::i32: Opc = isIdx ? PPC::STWX : PPC::STW; break;
|
|
|
|
case MVT::f64: Opc = isIdx ? PPC::STFDX : PPC::STFD; break;
|
|
|
|
case MVT::f32: Opc = isIdx ? PPC::STFSX : PPC::STFS; break;
|
2005-11-30 16:22:07 +08:00
|
|
|
case MVT::v4f32: Opc = PPC::STVX;
|
2005-08-22 09:27:59 +08:00
|
|
|
}
|
|
|
|
} else { //ISD::TRUNCSTORE
|
|
|
|
switch(cast<VTSDNode>(N->getOperand(4))->getVT()) {
|
|
|
|
default: assert(0 && "unknown Type in store");
|
|
|
|
case MVT::i8: Opc = isIdx ? PPC::STBX : PPC::STB; break;
|
|
|
|
case MVT::i16: Opc = isIdx ? PPC::STHX : PPC::STH; break;
|
|
|
|
}
|
|
|
|
}
|
2005-08-25 06:45:17 +08:00
|
|
|
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, Opc, MVT::Other, Select(N->getOperand(1)),
|
|
|
|
AddrOp1, AddrOp2, Select(N->getOperand(0)));
|
2005-08-24 08:47:15 +08:00
|
|
|
}
|
2005-08-26 04:08:18 +08:00
|
|
|
|
2005-08-27 02:46:49 +08:00
|
|
|
case ISD::SELECT_CC: {
|
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(4))->get();
|
|
|
|
|
|
|
|
// handle the setcc cases here. select_cc lhs, 0, 1, 0, cc
|
|
|
|
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() &&
|
|
|
|
N2C->getValue() == 1ULL && CC == ISD::SETNE) {
|
|
|
|
SDOperand LHS = Select(N->getOperand(0));
|
|
|
|
SDOperand Tmp =
|
|
|
|
CurDAG->getTargetNode(PPC::ADDIC, MVT::i32, MVT::Flag,
|
|
|
|
LHS, getI32Imm(~0U));
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::SUBFE, MVT::i32, Tmp, LHS,
|
|
|
|
Tmp.getValue(1));
|
2005-08-27 02:46:49 +08:00
|
|
|
}
|
2005-08-27 05:23:58 +08:00
|
|
|
|
2005-09-02 03:20:44 +08:00
|
|
|
SDOperand CCReg = SelectCC(N->getOperand(0), N->getOperand(1), CC);
|
2005-08-27 05:23:58 +08:00
|
|
|
unsigned BROpc = getBCCForSetCC(CC);
|
|
|
|
|
|
|
|
bool isFP = MVT::isFloatingPoint(N->getValueType(0));
|
2005-10-01 09:35:02 +08:00
|
|
|
unsigned SelectCCOp;
|
|
|
|
if (MVT::isInteger(N->getValueType(0)))
|
|
|
|
SelectCCOp = PPC::SELECT_CC_Int;
|
|
|
|
else if (N->getValueType(0) == MVT::f32)
|
|
|
|
SelectCCOp = PPC::SELECT_CC_F4;
|
|
|
|
else
|
|
|
|
SelectCCOp = PPC::SELECT_CC_F8;
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, SelectCCOp, N->getValueType(0), CCReg,
|
|
|
|
Select(N->getOperand(2)),
|
|
|
|
Select(N->getOperand(3)),
|
|
|
|
getI32Imm(BROpc));
|
2005-08-27 02:46:49 +08:00
|
|
|
}
|
|
|
|
|
2005-08-24 08:47:15 +08:00
|
|
|
case ISD::CALLSEQ_START:
|
|
|
|
case ISD::CALLSEQ_END: {
|
|
|
|
unsigned Amt = cast<ConstantSDNode>(N->getOperand(1))->getValue();
|
|
|
|
unsigned Opc = N->getOpcode() == ISD::CALLSEQ_START ?
|
|
|
|
PPC::ADJCALLSTACKDOWN : PPC::ADJCALLSTACKUP;
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, Opc, MVT::Other,
|
|
|
|
getI32Imm(Amt), Select(N->getOperand(0)));
|
2005-08-22 09:27:59 +08:00
|
|
|
}
|
2005-08-18 03:33:03 +08:00
|
|
|
case ISD::RET: {
|
|
|
|
SDOperand Chain = Select(N->getOperand(0)); // Token chain.
|
|
|
|
|
2005-08-31 09:34:29 +08:00
|
|
|
if (N->getNumOperands() == 2) {
|
2005-08-18 03:33:03 +08:00
|
|
|
SDOperand Val = Select(N->getOperand(1));
|
2005-08-31 06:59:48 +08:00
|
|
|
if (N->getOperand(1).getValueType() == MVT::i32) {
|
2005-08-18 03:33:03 +08:00
|
|
|
Chain = CurDAG->getCopyToReg(Chain, PPC::R3, Val);
|
2005-08-31 06:59:48 +08:00
|
|
|
} else {
|
|
|
|
assert(MVT::isFloatingPoint(N->getOperand(1).getValueType()));
|
|
|
|
Chain = CurDAG->getCopyToReg(Chain, PPC::F1, Val);
|
2005-08-18 03:33:03 +08:00
|
|
|
}
|
2005-08-31 09:34:29 +08:00
|
|
|
} else if (N->getNumOperands() > 1) {
|
|
|
|
assert(N->getOperand(1).getValueType() == MVT::i32 &&
|
|
|
|
N->getOperand(2).getValueType() == MVT::i32 &&
|
|
|
|
N->getNumOperands() == 3 && "Unknown two-register ret value!");
|
|
|
|
Chain = CurDAG->getCopyToReg(Chain, PPC::R4, Select(N->getOperand(1)));
|
|
|
|
Chain = CurDAG->getCopyToReg(Chain, PPC::R3, Select(N->getOperand(2)));
|
2005-08-18 03:33:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, select this to a blr (return) instruction.
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::BLR, MVT::Other, Chain);
|
2005-08-18 03:33:03 +08:00
|
|
|
}
|
2005-08-25 08:29:58 +08:00
|
|
|
case ISD::BR:
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::B, MVT::Other, N->getOperand(1),
|
|
|
|
Select(N->getOperand(0)));
|
2005-08-22 02:50:37 +08:00
|
|
|
case ISD::BR_CC:
|
|
|
|
case ISD::BRTWOWAY_CC: {
|
|
|
|
SDOperand Chain = Select(N->getOperand(0));
|
|
|
|
MachineBasicBlock *Dest =
|
|
|
|
cast<BasicBlockSDNode>(N->getOperand(4))->getBasicBlock();
|
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(1))->get();
|
|
|
|
SDOperand CondCode = SelectCC(N->getOperand(2), N->getOperand(3), CC);
|
|
|
|
|
|
|
|
// If this is a two way branch, then grab the fallthrough basic block
|
|
|
|
// argument and build a PowerPC branch pseudo-op, suitable for long branch
|
|
|
|
// conversion if necessary by the branch selection pass. Otherwise, emit a
|
|
|
|
// standard conditional branch.
|
|
|
|
if (N->getOpcode() == ISD::BRTWOWAY_CC) {
|
Minor tweak to the branch selector. When emitting a two-way branch, and if
we're in a single-mbb loop, make sure to emit the backwards branch as the
conditional branch instead of the uncond branch. For example, emit this:
LBBl29_z__44:
stw r9, 0(r15)
stw r9, 4(r15)
stw r9, 8(r15)
stw r9, 12(r15)
addi r15, r15, 16
addi r8, r8, 1
cmpw cr0, r8, r28
ble cr0, LBBl29_z__44
b LBBl29_z__48 *** NOT PART OF LOOP
Instead of:
LBBl29_z__44:
stw r9, 0(r15)
stw r9, 4(r15)
stw r9, 8(r15)
stw r9, 12(r15)
addi r15, r15, 16
addi r8, r8, 1
cmpw cr0, r8, r28
bgt cr0, LBBl29_z__48 *** PART OF LOOP!
b LBBl29_z__44
The former sequence has one fewer dispatch group for the loop body.
llvm-svn: 23582
2005-10-02 07:06:26 +08:00
|
|
|
SDOperand CondTrueBlock = N->getOperand(4);
|
|
|
|
SDOperand CondFalseBlock = N->getOperand(5);
|
|
|
|
|
|
|
|
// If the false case is the current basic block, then this is a self loop.
|
|
|
|
// We do not want to emit "Loop: ... brcond Out; br Loop", as it adds an
|
|
|
|
// extra dispatch group to the loop. Instead, invert the condition and
|
|
|
|
// emit "Loop: ... br!cond Loop; br Out
|
|
|
|
if (cast<BasicBlockSDNode>(CondFalseBlock)->getBasicBlock() == BB) {
|
|
|
|
std::swap(CondTrueBlock, CondFalseBlock);
|
|
|
|
CC = getSetCCInverse(CC,
|
|
|
|
MVT::isInteger(N->getOperand(2).getValueType()));
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Opc = getBCCForSetCC(CC);
|
2005-08-22 02:50:37 +08:00
|
|
|
SDOperand CB = CurDAG->getTargetNode(PPC::COND_BRANCH, MVT::Other,
|
|
|
|
CondCode, getI32Imm(Opc),
|
Minor tweak to the branch selector. When emitting a two-way branch, and if
we're in a single-mbb loop, make sure to emit the backwards branch as the
conditional branch instead of the uncond branch. For example, emit this:
LBBl29_z__44:
stw r9, 0(r15)
stw r9, 4(r15)
stw r9, 8(r15)
stw r9, 12(r15)
addi r15, r15, 16
addi r8, r8, 1
cmpw cr0, r8, r28
ble cr0, LBBl29_z__44
b LBBl29_z__48 *** NOT PART OF LOOP
Instead of:
LBBl29_z__44:
stw r9, 0(r15)
stw r9, 4(r15)
stw r9, 8(r15)
stw r9, 12(r15)
addi r15, r15, 16
addi r8, r8, 1
cmpw cr0, r8, r28
bgt cr0, LBBl29_z__48 *** PART OF LOOP!
b LBBl29_z__44
The former sequence has one fewer dispatch group for the loop body.
llvm-svn: 23582
2005-10-02 07:06:26 +08:00
|
|
|
CondTrueBlock, CondFalseBlock,
|
2005-08-22 02:50:37 +08:00
|
|
|
Chain);
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::B, MVT::Other, CondFalseBlock, CB);
|
2005-08-22 02:50:37 +08:00
|
|
|
} else {
|
|
|
|
// Iterate to the next basic block
|
|
|
|
ilist<MachineBasicBlock>::iterator It = BB;
|
|
|
|
++It;
|
|
|
|
|
|
|
|
// If the fallthrough path is off the end of the function, which would be
|
|
|
|
// undefined behavior, set it to be the same as the current block because
|
|
|
|
// we have nothing better to set it to, and leaving it alone will cause
|
|
|
|
// the PowerPC Branch Selection pass to crash.
|
|
|
|
if (It == BB->getParent()->end()) It = Dest;
|
2005-12-01 06:53:06 +08:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::COND_BRANCH, MVT::Other, CondCode,
|
|
|
|
getI32Imm(getBCCForSetCC(CC)),
|
|
|
|
N->getOperand(4), CurDAG->getBasicBlock(It),
|
|
|
|
Chain);
|
2005-08-22 02:50:37 +08:00
|
|
|
}
|
|
|
|
}
|
2005-08-18 03:33:03 +08:00
|
|
|
}
|
2005-09-03 08:53:47 +08:00
|
|
|
|
2005-09-08 07:45:15 +08:00
|
|
|
return SelectCode(Op);
|
2005-08-18 03:33:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-10-18 08:28:58 +08:00
|
|
|
/// createPPCISelDag - This pass converts a legalized DAG into a
|
2005-08-18 03:33:03 +08:00
|
|
|
/// PowerPC-specific DAG, ready for instruction scheduling.
|
|
|
|
///
|
2005-10-18 08:28:58 +08:00
|
|
|
FunctionPass *llvm::createPPCISelDag(TargetMachine &TM) {
|
|
|
|
return new PPCDAGToDAGISel(TM);
|
2005-08-18 03:33:03 +08:00
|
|
|
}
|
|
|
|
|