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
|
|
|
|
//
|
2007-12-29 20:36:04 +00:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2005-08-17 19:33:03 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
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.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2006-12-19 22:59:26 +00:00
|
|
|
#define DEBUG_TYPE "ppc-codegen"
|
2005-10-14 23:51:18 +00:00
|
|
|
#include "PPC.h"
|
2006-11-17 22:10:59 +00:00
|
|
|
#include "PPCPredicates.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"
|
2007-12-31 04:13:23 +00:00
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
2005-08-17 19:33:03 +00:00
|
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
|
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
|
|
#include "llvm/Target/TargetOptions.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-08-27 12:54:02 +00:00
|
|
|
#include "llvm/Support/Compiler.h"
|
2006-08-07 22:28:20 +00:00
|
|
|
#include <queue>
|
2006-02-05 06:46:41 +00:00
|
|
|
#include <set>
|
2005-08-17 19:33:03 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
//===--------------------------------------------------------------------===//
|
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.
|
|
|
|
///
|
2006-06-28 22:00:36 +00:00
|
|
|
class VISIBILITY_HIDDEN PPCDAGToDAGISel : public SelectionDAGISel {
|
2006-03-16 18:25:23 +00:00
|
|
|
PPCTargetMachine &TM;
|
2005-10-16 05:39:50 +00:00
|
|
|
PPCTargetLowering PPCLowering;
|
2007-10-23 06:42:42 +00:00
|
|
|
const PPCSubtarget &PPCSubTarget;
|
2005-08-19 22:38:53 +00:00
|
|
|
unsigned GlobalBaseReg;
|
2005-08-17 19:33:03 +00:00
|
|
|
public:
|
2008-07-07 18:00:37 +00:00
|
|
|
explicit PPCDAGToDAGISel(PPCTargetMachine &tm)
|
2006-03-16 18:25:23 +00:00
|
|
|
: SelectionDAGISel(PPCLowering), TM(tm),
|
2007-10-23 06:42:42 +00:00
|
|
|
PPCLowering(*TM.getTargetLowering()),
|
|
|
|
PPCSubTarget(*TM.getSubtargetImpl()) {}
|
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.
|
2008-07-27 21:46:04 +00:00
|
|
|
inline SDValue getI32Imm(unsigned Imm) {
|
2005-08-17 19:33:03 +00:00
|
|
|
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.
|
2008-07-27 21:46:04 +00:00
|
|
|
inline SDValue getI64Imm(uint64_t Imm) {
|
2006-06-27 00:04:13 +00:00
|
|
|
return CurDAG->getTargetConstant(Imm, MVT::i64);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getSmallIPtrImm - Return a target constant of pointer type.
|
2008-07-27 21:46:04 +00:00
|
|
|
inline SDValue getSmallIPtrImm(unsigned Imm) {
|
2006-06-27 00:04:13 +00:00
|
|
|
return CurDAG->getTargetConstant(Imm, PPCLowering.getPointerTy());
|
|
|
|
}
|
|
|
|
|
2006-09-22 05:01:56 +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);
|
|
|
|
|
|
|
|
|
|
|
|
/// isRotateAndMask - Returns true if Mask and Shift can be folded into a
|
|
|
|
/// rotate and mask opcode and mask operation.
|
|
|
|
static bool isRotateAndMask(SDNode *N, unsigned Mask, bool IsShiftMask,
|
|
|
|
unsigned &SH, unsigned &MB, unsigned &ME);
|
2006-06-27 00:04:13 +00:00
|
|
|
|
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.
|
2006-08-26 05:34:46 +00:00
|
|
|
SDNode *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.
|
2008-07-27 21:46:04 +00:00
|
|
|
SDNode *Select(SDValue 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.
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue SelectCC(SDValue LHS, SDValue RHS, ISD::CondCode CC);
|
2005-08-21 18:50:37 +00:00
|
|
|
|
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].
|
2008-07-27 21:46:04 +00:00
|
|
|
bool SelectAddrImm(SDValue Op, SDValue N, SDValue &Disp,
|
|
|
|
SDValue &Base) {
|
2006-11-08 02:15:41 +00:00
|
|
|
return PPCLowering.SelectAddressRegImm(N, Disp, Base, *CurDAG);
|
|
|
|
}
|
2006-11-16 00:41:37 +00:00
|
|
|
|
|
|
|
/// SelectAddrImmOffs - Return true if the operand is valid for a preinc
|
|
|
|
/// immediate field. Because preinc imms have already been validated, just
|
|
|
|
/// accept it.
|
2008-07-27 21:46:04 +00:00
|
|
|
bool SelectAddrImmOffs(SDValue Op, SDValue N, SDValue &Out) const {
|
2006-11-16 00:41:37 +00:00
|
|
|
Out = N;
|
|
|
|
return true;
|
|
|
|
}
|
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.
|
2008-07-27 21:46:04 +00:00
|
|
|
bool SelectAddrIdx(SDValue Op, SDValue N, SDValue &Base,
|
|
|
|
SDValue &Index) {
|
2006-11-08 02:15:41 +00:00
|
|
|
return PPCLowering.SelectAddressRegReg(N, Base, Index, *CurDAG);
|
|
|
|
}
|
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.
|
2008-07-27 21:46:04 +00:00
|
|
|
bool SelectAddrIdxOnly(SDValue Op, SDValue N, SDValue &Base,
|
|
|
|
SDValue &Index) {
|
2006-11-08 02:15:41 +00:00
|
|
|
return PPCLowering.SelectAddressRegRegOnly(N, Base, Index, *CurDAG);
|
|
|
|
}
|
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.
|
2008-07-27 21:46:04 +00:00
|
|
|
bool SelectAddrImmShift(SDValue Op, SDValue N, SDValue &Disp,
|
|
|
|
SDValue &Base) {
|
2006-11-08 02:15:41 +00:00
|
|
|
return PPCLowering.SelectAddressRegImmShift(N, Disp, Base, *CurDAG);
|
|
|
|
}
|
|
|
|
|
2006-02-24 02:13:12 +00:00
|
|
|
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
|
|
|
|
/// inline asm expressions.
|
2008-07-27 21:46:04 +00:00
|
|
|
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op,
|
2006-02-24 02:13:12 +00:00
|
|
|
char ConstraintCode,
|
2008-07-27 21:46:04 +00:00
|
|
|
std::vector<SDValue> &OutOps,
|
2006-02-24 02:13:12 +00:00
|
|
|
SelectionDAG &DAG) {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Op0, Op1;
|
2006-02-24 02:13:12 +00:00
|
|
|
switch (ConstraintCode) {
|
|
|
|
default: return true;
|
|
|
|
case 'm': // memory
|
2006-11-08 20:34:28 +00:00
|
|
|
if (!SelectAddrIdx(Op, Op, Op0, Op1))
|
|
|
|
SelectAddrImm(Op, Op, Op0, Op1);
|
2006-02-24 02:13:12 +00:00
|
|
|
break;
|
|
|
|
case 'o': // offsetable
|
2006-11-08 20:34:28 +00:00
|
|
|
if (!SelectAddrImm(Op, Op, Op0, Op1)) {
|
2006-08-26 01:07:58 +00:00
|
|
|
Op0 = Op;
|
|
|
|
AddToISelQueue(Op0); // 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
|
2006-11-08 20:34:28 +00:00
|
|
|
SelectAddrIdxOnly(Op, Op, Op0, Op1);
|
2006-02-24 02:13:12 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
OutOps.push_back(Op0);
|
|
|
|
OutOps.push_back(Op1);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue BuildSDIVSequence(SDNode *N);
|
|
|
|
SDValue BuildUDIVSequence(SDNode *N);
|
2005-08-25 22:04:30 +00:00
|
|
|
|
2008-06-30 20:45:06 +00:00
|
|
|
/// InstructionSelect - This callback is invoked by
|
2005-08-17 19:33:03 +00:00
|
|
|
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
2008-06-30 20:45:06 +00:00
|
|
|
virtual void InstructionSelect(SelectionDAG &DAG);
|
2005-10-06 18:45:51 +00:00
|
|
|
|
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:
|
2008-07-27 21:46:04 +00:00
|
|
|
SDNode *SelectSETCC(SDValue Op);
|
2005-08-17 19:33:03 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2008-06-30 20:45:06 +00:00
|
|
|
/// InstructionSelect - This callback is invoked by
|
2005-10-06 18:45:51 +00:00
|
|
|
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
2008-06-30 20:45:06 +00:00
|
|
|
void PPCDAGToDAGISel::InstructionSelect(SelectionDAG &DAG) {
|
2005-10-06 18:45:51 +00:00
|
|
|
DEBUG(BB->dump());
|
|
|
|
|
|
|
|
// Select target instructions for the DAG.
|
2006-02-05 06:46:41 +00:00
|
|
|
DAG.setRoot(SelectRoot(DAG.getRoot()));
|
2005-10-06 18:45:51 +00:00
|
|
|
DAG.RemoveDeadNodes();
|
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);
|
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;
|
2008-02-10 18:45:23 +00:00
|
|
|
for (unsigned i = TargetRegisterInfo::FirstVirtualRegister,
|
2007-12-31 04:13:23 +00:00
|
|
|
e = RegInfo->getLastVirtReg()+1; i != e; ++i)
|
|
|
|
if (RegInfo->getRegClass(i) == &PPC::VRRCRegClass) {
|
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
|
|
|
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.
|
2007-12-31 04:13:23 +00:00
|
|
|
unsigned InVRSAVE = RegInfo->createVirtualRegister(&PPC::GPRCRegClass);
|
|
|
|
unsigned UpdatedVRSAVE = RegInfo->createVirtualRegister(&PPC::GPRCRegClass);
|
2006-03-16 18:25:23 +00:00
|
|
|
|
2006-11-27 23:37:22 +00:00
|
|
|
const TargetInstrInfo &TII = *TM.getInstrInfo();
|
2006-03-16 18:25:23 +00:00
|
|
|
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
|
2006-11-27 23:37:22 +00:00
|
|
|
BuildMI(EntryBB, IP, TII.get(PPC::MFVRSAVE), InVRSAVE);
|
2008-01-07 01:56:04 +00:00
|
|
|
BuildMI(EntryBB, IP, TII.get(PPC::UPDATE_VRSAVE),
|
|
|
|
UpdatedVRSAVE).addReg(InVRSAVE);
|
2006-11-27 23:37:22 +00:00
|
|
|
BuildMI(EntryBB, IP, TII.get(PPC::MTVRSAVE)).addReg(UpdatedVRSAVE);
|
2006-03-16 18:25:23 +00:00
|
|
|
|
|
|
|
// Find all return blocks, outputting a restore in each epilog.
|
|
|
|
for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) {
|
2008-01-07 07:27:27 +00:00
|
|
|
if (!BB->empty() && BB->back().getDesc().isReturn()) {
|
2006-03-16 18:25:23 +00:00
|
|
|
IP = BB->end(); --IP;
|
|
|
|
|
|
|
|
// Skip over all terminator instructions, which are part of the return
|
|
|
|
// sequence.
|
|
|
|
MachineBasicBlock::iterator I2 = IP;
|
2008-01-07 07:27:27 +00:00
|
|
|
while (I2 != BB->begin() && (--I2)->getDesc().isTerminator())
|
2006-03-16 18:25:23 +00:00
|
|
|
IP = I2;
|
|
|
|
|
|
|
|
// Emit: MTVRSAVE InVRSave
|
2006-11-27 23:37:22 +00:00
|
|
|
BuildMI(*BB, IP, TII.get(PPC::MTVRSAVE)).addReg(InVRSAVE);
|
2006-03-16 18:25:23 +00:00
|
|
|
}
|
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.
|
|
|
|
///
|
2006-08-26 05:34:46 +00:00
|
|
|
SDNode *PPCDAGToDAGISel::getGlobalBaseReg() {
|
2005-08-19 22:38:53 +00:00
|
|
|
if (!GlobalBaseReg) {
|
2006-11-27 23:37:22 +00:00
|
|
|
const TargetInstrInfo &TII = *TM.getInstrInfo();
|
2005-08-19 22:38:53 +00:00
|
|
|
// Insert the set of GlobalBaseReg into the first MBB of the function
|
|
|
|
MachineBasicBlock &FirstMBB = BB->getParent()->front();
|
|
|
|
MachineBasicBlock::iterator MBBI = FirstMBB.begin();
|
2006-06-27 00:04:13 +00:00
|
|
|
|
2006-11-14 18:43:11 +00:00
|
|
|
if (PPCLowering.getPointerTy() == MVT::i32) {
|
2007-12-31 04:13:23 +00:00
|
|
|
GlobalBaseReg = RegInfo->createVirtualRegister(PPC::GPRCRegisterClass);
|
2006-11-27 23:37:22 +00:00
|
|
|
BuildMI(FirstMBB, MBBI, TII.get(PPC::MovePCtoLR), PPC::LR);
|
|
|
|
BuildMI(FirstMBB, MBBI, TII.get(PPC::MFLR), GlobalBaseReg);
|
2006-11-14 18:43:11 +00:00
|
|
|
} else {
|
2007-12-31 04:13:23 +00:00
|
|
|
GlobalBaseReg = RegInfo->createVirtualRegister(PPC::G8RCRegisterClass);
|
2006-11-27 23:37:22 +00:00
|
|
|
BuildMI(FirstMBB, MBBI, TII.get(PPC::MovePCtoLR8), PPC::LR8);
|
|
|
|
BuildMI(FirstMBB, MBBI, TII.get(PPC::MFLR8), GlobalBaseReg);
|
2006-11-14 18:43:11 +00:00
|
|
|
}
|
2005-08-19 22:38:53 +00:00
|
|
|
}
|
2006-08-26 05:34:46 +00:00
|
|
|
return CurDAG->getRegister(GlobalBaseReg, PPCLowering.getPointerTy()).Val;
|
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();
|
|
|
|
}
|
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
static bool isIntS16Immediate(SDValue Op, short &Imm) {
|
2006-06-27 00:04:13 +00:00
|
|
|
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) {
|
2006-09-20 04:33:27 +00:00
|
|
|
if (N->getOpcode() == ISD::Constant && N->getValueType(0) == MVT::i64) {
|
2006-06-27 00:04:13 +00:00
|
|
|
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.
|
2008-07-27 21:46:04 +00:00
|
|
|
static bool isInt32Immediate(SDValue N, unsigned &Imm) {
|
2006-06-27 00:04:13 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2006-09-22 05:01:56 +00:00
|
|
|
bool PPCDAGToDAGISel::isRunOfOnes(unsigned Val, unsigned &MB, unsigned &ME) {
|
2005-08-18 07:30:46 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-09-22 05:01:56 +00:00
|
|
|
bool PPCDAGToDAGISel::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;
|
2006-09-22 05:01:56 +00:00
|
|
|
} else if (Opcode == ISD::ROTL) {
|
|
|
|
Indeterminant = 0;
|
2005-08-18 07:30:46 +00:00
|
|
|
} 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) {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Op0 = N->getOperand(0);
|
|
|
|
SDValue Op1 = N->getOperand(1);
|
2005-08-19 00:38:14 +00:00
|
|
|
|
2008-02-27 01:23:58 +00:00
|
|
|
APInt LKZ, LKO, RKZ, RKO;
|
|
|
|
CurDAG->ComputeMaskedBits(Op0, APInt::getAllOnesValue(32), LKZ, LKO);
|
|
|
|
CurDAG->ComputeMaskedBits(Op1, APInt::getAllOnesValue(32), RKZ, RKO);
|
2005-08-19 00:38:14 +00:00
|
|
|
|
2008-02-27 01:23:58 +00:00
|
|
|
unsigned TargetMask = LKZ.getZExtValue();
|
|
|
|
unsigned InsertMask = RKZ.getZExtValue();
|
2006-05-08 17:38:32 +00:00
|
|
|
|
|
|
|
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)) {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue 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;
|
2006-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(Tmp3);
|
|
|
|
AddToISelQueue(Op1);
|
2006-05-12 16:29:37 +00:00
|
|
|
SH &= 31;
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { Tmp3, Op1, getI32Imm(SH), getI32Imm(MB),
|
2006-08-27 08:14:06 +00:00
|
|
|
getI32Imm(ME) };
|
|
|
|
return CurDAG->getTargetNode(PPC::RLWIMI, MVT::i32, Ops, 5);
|
2005-08-19 00:38:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 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.
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue PPCDAGToDAGISel::SelectCC(SDValue LHS, SDValue RHS,
|
2005-10-18 00:28:58 +00:00
|
|
|
ISD::CondCode CC) {
|
2005-08-21 18:50:37 +00:00
|
|
|
// Always select the LHS.
|
2006-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(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;
|
Two improvements:
1. Codegen this comparison:
if (X == 0x8000)
as:
cmplwi cr0, r3, 32768
bne cr0, LBB1_2 ;cond_next
instead of:
lis r2, 0
ori r2, r2, 32768
cmpw cr0, r3, r2
bne cr0, LBB1_2 ;cond_next
2. Codegen this comparison:
if (X == 0x12345678)
as:
xoris r2, r3, 4660
cmplwi cr0, r2, 22136
bne cr0, LBB1_2 ;cond_next
instead of:
lis r2, 4660
ori r2, r2, 22136
cmpw cr0, r3, r2
bne cr0, LBB1_2 ;cond_next
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30509 91177308-0d34-0410-b5e6-96231b3b80d8
2006-09-20 04:25:47 +00:00
|
|
|
if (CC == ISD::SETEQ || CC == ISD::SETNE) {
|
|
|
|
if (isInt32Immediate(RHS, Imm)) {
|
|
|
|
// SETEQ/SETNE comparison with 16-bit immediate, fold it.
|
|
|
|
if (isUInt16(Imm))
|
2008-07-27 21:46:04 +00:00
|
|
|
return SDValue(CurDAG->getTargetNode(PPC::CMPLWI, MVT::i32, LHS,
|
Two improvements:
1. Codegen this comparison:
if (X == 0x8000)
as:
cmplwi cr0, r3, 32768
bne cr0, LBB1_2 ;cond_next
instead of:
lis r2, 0
ori r2, r2, 32768
cmpw cr0, r3, r2
bne cr0, LBB1_2 ;cond_next
2. Codegen this comparison:
if (X == 0x12345678)
as:
xoris r2, r3, 4660
cmplwi cr0, r2, 22136
bne cr0, LBB1_2 ;cond_next
instead of:
lis r2, 4660
ori r2, r2, 22136
cmpw cr0, r3, r2
bne cr0, LBB1_2 ;cond_next
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30509 91177308-0d34-0410-b5e6-96231b3b80d8
2006-09-20 04:25:47 +00:00
|
|
|
getI32Imm(Imm & 0xFFFF)), 0);
|
|
|
|
// If this is a 16-bit signed immediate, fold it.
|
Fix a bug which caused us to never be able to use signed comparisons for
equality comparisons of a constant. This allows us to codegen the 'sintzero'
loop in PR1288 as:
LBB1_1: ;cond_next
li r4, 0
addi r2, r2, 1
stw r4, 0(r3)
addi r3, r3, 4
cmpwi cr0, r2, -1
bne cr0, LBB1_1 ;cond_next
instead of:
LBB1_1: ;cond_next
addi r2, r2, 1
li r4, 0
xoris r5, r2, 65535
stw r4, 0(r3)
addi r3, r3, 4
cmplwi cr0, r5, 65535
bne cr0, LBB1_1 ;cond_next
This implements CodeGen/PowerPC/compare-simm.ll, and also cuts 74
instructions out of kc++.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@35590 91177308-0d34-0410-b5e6-96231b3b80d8
2007-04-02 05:59:42 +00:00
|
|
|
if (isInt16((int)Imm))
|
2008-07-27 21:46:04 +00:00
|
|
|
return SDValue(CurDAG->getTargetNode(PPC::CMPWI, MVT::i32, LHS,
|
Two improvements:
1. Codegen this comparison:
if (X == 0x8000)
as:
cmplwi cr0, r3, 32768
bne cr0, LBB1_2 ;cond_next
instead of:
lis r2, 0
ori r2, r2, 32768
cmpw cr0, r3, r2
bne cr0, LBB1_2 ;cond_next
2. Codegen this comparison:
if (X == 0x12345678)
as:
xoris r2, r3, 4660
cmplwi cr0, r2, 22136
bne cr0, LBB1_2 ;cond_next
instead of:
lis r2, 4660
ori r2, r2, 22136
cmpw cr0, r3, r2
bne cr0, LBB1_2 ;cond_next
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30509 91177308-0d34-0410-b5e6-96231b3b80d8
2006-09-20 04:25:47 +00:00
|
|
|
getI32Imm(Imm & 0xFFFF)), 0);
|
|
|
|
|
|
|
|
// For non-equality comparisons, the default code would materialize the
|
|
|
|
// constant, then compare against it, like this:
|
|
|
|
// lis r2, 4660
|
|
|
|
// ori r2, r2, 22136
|
|
|
|
// cmpw cr0, r3, r2
|
|
|
|
// Since we are just comparing for equality, we can emit this instead:
|
|
|
|
// xoris r0,r3,0x1234
|
|
|
|
// cmplwi cr0,r0,0x5678
|
|
|
|
// beq cr0,L6
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Xor(CurDAG->getTargetNode(PPC::XORIS, MVT::i32, LHS,
|
Two improvements:
1. Codegen this comparison:
if (X == 0x8000)
as:
cmplwi cr0, r3, 32768
bne cr0, LBB1_2 ;cond_next
instead of:
lis r2, 0
ori r2, r2, 32768
cmpw cr0, r3, r2
bne cr0, LBB1_2 ;cond_next
2. Codegen this comparison:
if (X == 0x12345678)
as:
xoris r2, r3, 4660
cmplwi cr0, r2, 22136
bne cr0, LBB1_2 ;cond_next
instead of:
lis r2, 4660
ori r2, r2, 22136
cmpw cr0, r3, r2
bne cr0, LBB1_2 ;cond_next
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30509 91177308-0d34-0410-b5e6-96231b3b80d8
2006-09-20 04:25:47 +00:00
|
|
|
getI32Imm(Imm >> 16)), 0);
|
2008-07-27 21:46:04 +00:00
|
|
|
return SDValue(CurDAG->getTargetNode(PPC::CMPLWI, MVT::i32, Xor,
|
Two improvements:
1. Codegen this comparison:
if (X == 0x8000)
as:
cmplwi cr0, r3, 32768
bne cr0, LBB1_2 ;cond_next
instead of:
lis r2, 0
ori r2, r2, 32768
cmpw cr0, r3, r2
bne cr0, LBB1_2 ;cond_next
2. Codegen this comparison:
if (X == 0x12345678)
as:
xoris r2, r3, 4660
cmplwi cr0, r2, 22136
bne cr0, LBB1_2 ;cond_next
instead of:
lis r2, 4660
ori r2, r2, 22136
cmpw cr0, r3, r2
bne cr0, LBB1_2 ;cond_next
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30509 91177308-0d34-0410-b5e6-96231b3b80d8
2006-09-20 04:25:47 +00:00
|
|
|
getI32Imm(Imm & 0xFFFF)), 0);
|
|
|
|
}
|
|
|
|
Opc = PPC::CMPLW;
|
|
|
|
} else if (ISD::isUnsignedIntSetCC(CC)) {
|
2006-06-27 00:04:13 +00:00
|
|
|
if (isInt32Immediate(RHS, Imm) && isUInt16(Imm))
|
2008-07-27 21:46:04 +00:00
|
|
|
return SDValue(CurDAG->getTargetNode(PPC::CMPLWI, MVT::i32, LHS,
|
2006-06-27 00:04:13 +00:00
|
|
|
getI32Imm(Imm & 0xFFFF)), 0);
|
|
|
|
Opc = PPC::CMPLW;
|
|
|
|
} else {
|
|
|
|
short SImm;
|
|
|
|
if (isIntS16Immediate(RHS, SImm))
|
2008-07-27 21:46:04 +00:00
|
|
|
return SDValue(CurDAG->getTargetNode(PPC::CMPWI, MVT::i32, LHS,
|
2006-06-27 00:04:13 +00:00
|
|
|
getI32Imm((int)SImm & 0xFFFF)),
|
|
|
|
0);
|
|
|
|
Opc = PPC::CMPW;
|
|
|
|
}
|
|
|
|
} else if (LHS.getValueType() == MVT::i64) {
|
|
|
|
uint64_t Imm;
|
2006-09-20 04:33:27 +00:00
|
|
|
if (CC == ISD::SETEQ || CC == ISD::SETNE) {
|
|
|
|
if (isInt64Immediate(RHS.Val, Imm)) {
|
|
|
|
// SETEQ/SETNE comparison with 16-bit immediate, fold it.
|
|
|
|
if (isUInt16(Imm))
|
2008-07-27 21:46:04 +00:00
|
|
|
return SDValue(CurDAG->getTargetNode(PPC::CMPLDI, MVT::i64, LHS,
|
2006-09-20 04:33:27 +00:00
|
|
|
getI32Imm(Imm & 0xFFFF)), 0);
|
|
|
|
// If this is a 16-bit signed immediate, fold it.
|
|
|
|
if (isInt16(Imm))
|
2008-07-27 21:46:04 +00:00
|
|
|
return SDValue(CurDAG->getTargetNode(PPC::CMPDI, MVT::i64, LHS,
|
2006-09-20 04:33:27 +00:00
|
|
|
getI32Imm(Imm & 0xFFFF)), 0);
|
|
|
|
|
|
|
|
// For non-equality comparisons, the default code would materialize the
|
|
|
|
// constant, then compare against it, like this:
|
|
|
|
// lis r2, 4660
|
|
|
|
// ori r2, r2, 22136
|
|
|
|
// cmpd cr0, r3, r2
|
|
|
|
// Since we are just comparing for equality, we can emit this instead:
|
|
|
|
// xoris r0,r3,0x1234
|
|
|
|
// cmpldi cr0,r0,0x5678
|
|
|
|
// beq cr0,L6
|
|
|
|
if (isUInt32(Imm)) {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Xor(CurDAG->getTargetNode(PPC::XORIS8, MVT::i64, LHS,
|
2006-09-20 04:33:27 +00:00
|
|
|
getI64Imm(Imm >> 16)), 0);
|
2008-07-27 21:46:04 +00:00
|
|
|
return SDValue(CurDAG->getTargetNode(PPC::CMPLDI, MVT::i64, Xor,
|
2006-09-20 04:33:27 +00:00
|
|
|
getI64Imm(Imm & 0xFFFF)), 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Opc = PPC::CMPLD;
|
|
|
|
} else if (ISD::isUnsignedIntSetCC(CC)) {
|
2006-06-27 00:04:13 +00:00
|
|
|
if (isInt64Immediate(RHS.Val, Imm) && isUInt16(Imm))
|
2008-07-27 21:46:04 +00:00
|
|
|
return SDValue(CurDAG->getTargetNode(PPC::CMPLDI, MVT::i64, LHS,
|
2006-06-27 00:04:13 +00:00
|
|
|
getI64Imm(Imm & 0xFFFF)), 0);
|
|
|
|
Opc = PPC::CMPLD;
|
|
|
|
} else {
|
|
|
|
short SImm;
|
|
|
|
if (isIntS16Immediate(RHS, SImm))
|
2008-07-27 21:46:04 +00:00
|
|
|
return SDValue(CurDAG->getTargetNode(PPC::CMPDI, MVT::i64, LHS,
|
2006-09-20 04:33:27 +00:00
|
|
|
getI64Imm(SImm & 0xFFFF)),
|
2006-06-27 00:04:13 +00:00
|
|
|
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-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(RHS);
|
2008-07-27 21:46:04 +00:00
|
|
|
return SDValue(CurDAG->getTargetNode(Opc, MVT::i32, LHS, RHS), 0);
|
2005-08-21 18:50:37 +00:00
|
|
|
}
|
|
|
|
|
2006-11-17 22:10:59 +00:00
|
|
|
static PPC::Predicate getPredicateForSetCC(ISD::CondCode CC) {
|
2005-08-21 18:50:37 +00:00
|
|
|
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:
|
2006-11-17 22:10:59 +00:00
|
|
|
case ISD::SETEQ: return PPC::PRED_EQ;
|
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:
|
2006-11-17 22:10:59 +00:00
|
|
|
case ISD::SETNE: return PPC::PRED_NE;
|
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:
|
2006-11-17 22:10:59 +00:00
|
|
|
case ISD::SETLT: return PPC::PRED_LT;
|
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:
|
2006-11-17 22:10:59 +00:00
|
|
|
case ISD::SETLE: return PPC::PRED_LE;
|
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:
|
2006-11-17 22:10:59 +00:00
|
|
|
case ISD::SETGT: return PPC::PRED_GT;
|
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:
|
2006-11-17 22:10:59 +00:00
|
|
|
case ISD::SETGE: return PPC::PRED_GE;
|
2005-10-28 20:32:44 +00:00
|
|
|
|
2006-11-17 22:10:59 +00:00
|
|
|
case ISD::SETO: return PPC::PRED_NU;
|
|
|
|
case ISD::SETUO: return PPC::PRED_UN;
|
2005-08-21 18:50:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
2008-01-08 06:46:30 +00:00
|
|
|
///
|
|
|
|
/// If this returns with Other != -1, then the returned comparison is an or of
|
|
|
|
/// two simpler comparisons. In this case, Invert is guaranteed to be false.
|
|
|
|
static unsigned getCRIdxForSetCC(ISD::CondCode CC, bool &Invert, int &Other) {
|
|
|
|
Invert = false;
|
|
|
|
Other = -1;
|
2005-08-25 20:08:18 +00:00
|
|
|
switch (CC) {
|
|
|
|
default: assert(0 && "Unknown condition!"); abort();
|
2008-01-08 06:46:30 +00:00
|
|
|
case ISD::SETOLT:
|
|
|
|
case ISD::SETLT: return 0; // Bit #0 = SETOLT
|
|
|
|
case ISD::SETOGT:
|
|
|
|
case ISD::SETGT: return 1; // Bit #1 = SETOGT
|
|
|
|
case ISD::SETOEQ:
|
|
|
|
case ISD::SETEQ: return 2; // Bit #2 = SETOEQ
|
|
|
|
case ISD::SETUO: return 3; // Bit #3 = SETUO
|
2005-08-25 20:08:18 +00:00
|
|
|
case ISD::SETUGE:
|
2008-01-08 06:46:30 +00:00
|
|
|
case ISD::SETGE: Invert = true; return 0; // !Bit #0 = SETUGE
|
2005-08-25 20:08:18 +00:00
|
|
|
case ISD::SETULE:
|
2008-01-08 06:46:30 +00:00
|
|
|
case ISD::SETLE: Invert = true; return 1; // !Bit #1 = SETULE
|
2006-05-25 18:06:16 +00:00
|
|
|
case ISD::SETUNE:
|
2008-01-08 06:46:30 +00:00
|
|
|
case ISD::SETNE: Invert = true; return 2; // !Bit #2 = SETUNE
|
|
|
|
case ISD::SETO: Invert = true; return 3; // !Bit #3 = SETO
|
|
|
|
case ISD::SETULT: Other = 0; return 3; // SETOLT | SETUO
|
|
|
|
case ISD::SETUGT: Other = 1; return 3; // SETOGT | SETUO
|
|
|
|
case ISD::SETUEQ: Other = 2; return 3; // SETOEQ | SETUO
|
|
|
|
case ISD::SETOGE: Other = 1; return 2; // SETOGT | SETOEQ
|
|
|
|
case ISD::SETOLE: Other = 0; return 2; // SETOLT | SETOEQ
|
|
|
|
case ISD::SETONE: Other = 0; return 1; // SETOLT | SETOGT
|
2005-08-25 20:08:18 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2005-08-21 22:31:09 +00:00
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
SDNode *PPCDAGToDAGISel::SelectSETCC(SDValue 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) {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Op = N->getOperand(0);
|
2006-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(Op);
|
2005-10-06 19:03:35 +00:00
|
|
|
switch (CC) {
|
2005-10-21 21:17:10 +00:00
|
|
|
default: break;
|
2006-08-27 08:14:06 +00:00
|
|
|
case ISD::SETEQ: {
|
2008-07-27 21:46:04 +00:00
|
|
|
Op = SDValue(CurDAG->getTargetNode(PPC::CNTLZW, MVT::i32, Op), 0);
|
|
|
|
SDValue Ops[] = { Op, getI32Imm(27), getI32Imm(5), getI32Imm(31) };
|
2006-08-27 08:14:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops, 4);
|
|
|
|
}
|
2005-10-21 21:17:10 +00:00
|
|
|
case ISD::SETNE: {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue AD =
|
|
|
|
SDValue(CurDAG->getTargetNode(PPC::ADDIC, MVT::i32, MVT::Flag,
|
2006-02-09 07:17:49 +00:00
|
|
|
Op, getI32Imm(~0U)), 0);
|
2005-11-30 22:53:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::SUBFE, MVT::i32, AD, Op,
|
2006-08-26 08:00:10 +00:00
|
|
|
AD.getValue(1));
|
2005-10-21 21:17:10 +00:00
|
|
|
}
|
2006-08-27 08:14:06 +00:00
|
|
|
case ISD::SETLT: {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { Op, getI32Imm(1), getI32Imm(31), getI32Imm(31) };
|
2006-08-27 08:14:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops, 4);
|
|
|
|
}
|
2005-10-21 21:17:10 +00:00
|
|
|
case ISD::SETGT: {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue T =
|
|
|
|
SDValue(CurDAG->getTargetNode(PPC::NEG, MVT::i32, Op), 0);
|
|
|
|
T = SDValue(CurDAG->getTargetNode(PPC::ANDC, MVT::i32, T, Op), 0);
|
|
|
|
SDValue Ops[] = { T, getI32Imm(1), getI32Imm(31), getI32Imm(31) };
|
2006-08-27 08:14:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops, 4);
|
2005-10-21 21:17:10 +00:00
|
|
|
}
|
2005-10-06 19:03:35 +00:00
|
|
|
}
|
|
|
|
} else if (Imm == ~0U) { // setcc op, -1
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Op = N->getOperand(0);
|
2006-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(Op);
|
2005-10-06 19:03:35 +00:00
|
|
|
switch (CC) {
|
2005-10-21 21:17:10 +00:00
|
|
|
default: break;
|
|
|
|
case ISD::SETEQ:
|
2008-07-27 21:46:04 +00:00
|
|
|
Op = SDValue(CurDAG->getTargetNode(PPC::ADDIC, MVT::i32, MVT::Flag,
|
2006-02-09 07:17:49 +00:00
|
|
|
Op, getI32Imm(1)), 0);
|
2005-11-30 22:53:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::ADDZE, MVT::i32,
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue(CurDAG->getTargetNode(PPC::LI, MVT::i32,
|
2006-02-09 07:17:49 +00:00
|
|
|
getI32Imm(0)), 0),
|
2006-08-26 08:00:10 +00:00
|
|
|
Op.getValue(1));
|
2005-10-21 21:17:10 +00:00
|
|
|
case ISD::SETNE: {
|
2008-07-27 21:46:04 +00:00
|
|
|
Op = SDValue(CurDAG->getTargetNode(PPC::NOR, MVT::i32, Op, Op), 0);
|
2006-02-09 07:17:49 +00:00
|
|
|
SDNode *AD = CurDAG->getTargetNode(PPC::ADDIC, MVT::i32, MVT::Flag,
|
|
|
|
Op, getI32Imm(~0U));
|
2008-07-27 21:46:04 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::SUBFE, MVT::i32, SDValue(AD, 0),
|
|
|
|
Op, SDValue(AD, 1));
|
2005-10-21 21:17:10 +00:00
|
|
|
}
|
|
|
|
case ISD::SETLT: {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue AD = SDValue(CurDAG->getTargetNode(PPC::ADDI, MVT::i32, Op,
|
2006-02-09 07:17:49 +00:00
|
|
|
getI32Imm(1)), 0);
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue AN = SDValue(CurDAG->getTargetNode(PPC::AND, MVT::i32, AD,
|
2006-02-09 07:17:49 +00:00
|
|
|
Op), 0);
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { AN, getI32Imm(1), getI32Imm(31), getI32Imm(31) };
|
2006-08-27 08:14:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops, 4);
|
2005-10-21 21:17:10 +00:00
|
|
|
}
|
2006-08-27 08:14:06 +00:00
|
|
|
case ISD::SETGT: {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { Op, getI32Imm(1), getI32Imm(31), getI32Imm(31) };
|
|
|
|
Op = SDValue(CurDAG->getTargetNode(PPC::RLWINM, MVT::i32, Ops, 4), 0);
|
2006-08-15 23:48:22 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::XORI, MVT::i32, Op,
|
2006-08-26 08:00:10 +00:00
|
|
|
getI32Imm(1));
|
2005-10-06 19:03:35 +00:00
|
|
|
}
|
2006-08-27 08:14:06 +00:00
|
|
|
}
|
2005-10-06 19:03:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inv;
|
2008-01-08 06:46:30 +00:00
|
|
|
int OtherCondIdx;
|
|
|
|
unsigned Idx = getCRIdxForSetCC(CC, Inv, OtherCondIdx);
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue CCReg = SelectCC(N->getOperand(0), N->getOperand(1), CC);
|
|
|
|
SDValue IntCR;
|
2005-10-06 19:03:35 +00:00
|
|
|
|
|
|
|
// Force the ccreg into CR7.
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue CR7Reg = CurDAG->getRegister(PPC::CR7, MVT::i32);
|
2005-10-06 19:03:35 +00:00
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue 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
|
|
|
|
2008-01-08 06:46:30 +00:00
|
|
|
if (PPCSubTarget.isGigaProcessor() && OtherCondIdx == -1)
|
2008-07-27 21:46:04 +00:00
|
|
|
IntCR = SDValue(CurDAG->getTargetNode(PPC::MFOCRF, MVT::i32, CR7Reg,
|
2006-02-09 07:17:49 +00:00
|
|
|
CCReg), 0);
|
2005-10-06 19:03:35 +00:00
|
|
|
else
|
2008-07-27 21:46:04 +00:00
|
|
|
IntCR = SDValue(CurDAG->getTargetNode(PPC::MFCR, MVT::i32, CCReg), 0);
|
2005-10-06 19:03:35 +00:00
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { IntCR, getI32Imm((32-(3-Idx)) & 31),
|
2006-08-27 08:14:06 +00:00
|
|
|
getI32Imm(31), getI32Imm(31) };
|
2008-01-08 06:46:30 +00:00
|
|
|
if (OtherCondIdx == -1 && !Inv)
|
2006-08-27 08:14:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops, 4);
|
2008-01-08 06:46:30 +00:00
|
|
|
|
|
|
|
// Get the specified bit.
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Tmp =
|
|
|
|
SDValue(CurDAG->getTargetNode(PPC::RLWINM, MVT::i32, Ops, 4), 0);
|
2008-01-08 06:46:30 +00:00
|
|
|
if (Inv) {
|
|
|
|
assert(OtherCondIdx == -1 && "Can't have split plus negation");
|
2006-08-26 08:00:10 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::XORI, MVT::i32, Tmp, getI32Imm(1));
|
2005-10-06 19:03:35 +00:00
|
|
|
}
|
2008-01-08 06:46:30 +00:00
|
|
|
|
|
|
|
// Otherwise, we have to turn an operation like SETONE -> SETOLT | SETOGT.
|
|
|
|
// We already got the bit for the first part of the comparison (e.g. SETULE).
|
|
|
|
|
|
|
|
// Get the other bit of the comparison.
|
|
|
|
Ops[1] = getI32Imm((32-(3-OtherCondIdx)) & 31);
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue OtherCond =
|
|
|
|
SDValue(CurDAG->getTargetNode(PPC::RLWINM, MVT::i32, Ops, 4), 0);
|
2008-01-08 06:46:30 +00:00
|
|
|
|
|
|
|
return CurDAG->SelectNodeTo(N, PPC::OR, MVT::i32, Tmp, OtherCond);
|
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.
|
2008-07-27 21:46:04 +00:00
|
|
|
SDNode *PPCDAGToDAGISel::Select(SDValue Op) {
|
2005-08-17 19:33:03 +00:00
|
|
|
SDNode *N = Op.Val;
|
2008-07-17 19:10:17 +00:00
|
|
|
if (N->isMachineOpcode())
|
2006-08-11 09:08:15 +00:00
|
|
|
return NULL; // Already selected.
|
2005-09-29 00:59:32 +00:00
|
|
|
|
2005-08-17 19:33:03 +00:00
|
|
|
switch (N->getOpcode()) {
|
2005-09-07 23:45:15 +00:00
|
|
|
default: break;
|
2006-12-12 13:23:43 +00:00
|
|
|
|
|
|
|
case ISD::Constant: {
|
|
|
|
if (N->getValueType(0) == MVT::i64) {
|
|
|
|
// Get 64 bit value.
|
|
|
|
int64_t Imm = cast<ConstantSDNode>(N)->getValue();
|
|
|
|
// Assume no remaining bits.
|
|
|
|
unsigned Remainder = 0;
|
|
|
|
// Assume no shift required.
|
|
|
|
unsigned Shift = 0;
|
|
|
|
|
|
|
|
// If it can't be represented as a 32 bit value.
|
|
|
|
if (!isInt32(Imm)) {
|
|
|
|
Shift = CountTrailingZeros_64(Imm);
|
|
|
|
int64_t ImmSh = static_cast<uint64_t>(Imm) >> Shift;
|
|
|
|
|
|
|
|
// If the shifted value fits 32 bits.
|
|
|
|
if (isInt32(ImmSh)) {
|
|
|
|
// Go with the shifted value.
|
|
|
|
Imm = ImmSh;
|
|
|
|
} else {
|
|
|
|
// Still stuck with a 64 bit value.
|
|
|
|
Remainder = Imm;
|
|
|
|
Shift = 32;
|
|
|
|
Imm >>= 32;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Intermediate operand.
|
|
|
|
SDNode *Result;
|
|
|
|
|
|
|
|
// Handle first 32 bits.
|
|
|
|
unsigned Lo = Imm & 0xFFFF;
|
|
|
|
unsigned Hi = (Imm >> 16) & 0xFFFF;
|
|
|
|
|
|
|
|
// Simple value.
|
|
|
|
if (isInt16(Imm)) {
|
|
|
|
// Just the Lo bits.
|
|
|
|
Result = CurDAG->getTargetNode(PPC::LI8, MVT::i64, getI32Imm(Lo));
|
|
|
|
} else if (Lo) {
|
|
|
|
// Handle the Hi bits.
|
|
|
|
unsigned OpC = Hi ? PPC::LIS8 : PPC::LI8;
|
|
|
|
Result = CurDAG->getTargetNode(OpC, MVT::i64, getI32Imm(Hi));
|
|
|
|
// And Lo bits.
|
|
|
|
Result = CurDAG->getTargetNode(PPC::ORI8, MVT::i64,
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue(Result, 0), getI32Imm(Lo));
|
2006-12-12 13:23:43 +00:00
|
|
|
} else {
|
|
|
|
// Just the Hi bits.
|
|
|
|
Result = CurDAG->getTargetNode(PPC::LIS8, MVT::i64, getI32Imm(Hi));
|
|
|
|
}
|
|
|
|
|
|
|
|
// If no shift, we're done.
|
|
|
|
if (!Shift) return Result;
|
|
|
|
|
|
|
|
// Shift for next step if the upper 32-bits were not zero.
|
|
|
|
if (Imm) {
|
|
|
|
Result = CurDAG->getTargetNode(PPC::RLDICR, MVT::i64,
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue(Result, 0),
|
2006-12-12 13:23:43 +00:00
|
|
|
getI32Imm(Shift), getI32Imm(63 - Shift));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add in the last bits as required.
|
|
|
|
if ((Hi = (Remainder >> 16) & 0xFFFF)) {
|
|
|
|
Result = CurDAG->getTargetNode(PPC::ORIS8, MVT::i64,
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue(Result, 0), getI32Imm(Hi));
|
2006-12-12 13:23:43 +00:00
|
|
|
}
|
|
|
|
if ((Lo = Remainder & 0xFFFF)) {
|
|
|
|
Result = CurDAG->getTargetNode(PPC::ORI8, MVT::i64,
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue(Result, 0), getI32Imm(Lo));
|
2006-12-12 13:23:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-02-09 00:37:58 +00:00
|
|
|
case ISD::SETCC:
|
2006-08-15 23:48:22 +00:00
|
|
|
return SelectSETCC(Op);
|
2006-02-09 00:37:58 +00:00
|
|
|
case PPCISD::GlobalBaseReg:
|
2006-08-26 05:34:46 +00:00
|
|
|
return getGlobalBaseReg();
|
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();
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue TFI = CurDAG->getTargetFrameIndex(FI, Op.getValueType());
|
2006-06-27 00:04:13 +00:00
|
|
|
unsigned Opc = Op.getValueType() == MVT::i32 ? PPC::ADDI : PPC::ADDI8;
|
2006-08-15 23:48:22 +00:00
|
|
|
if (N->hasOneUse())
|
|
|
|
return CurDAG->SelectNodeTo(N, Opc, Op.getValueType(), TFI,
|
2006-08-26 08:00:10 +00:00
|
|
|
getSmallIPtrImm(0));
|
2006-08-15 23:48:22 +00:00
|
|
|
return CurDAG->getTargetNode(Opc, Op.getValueType(), TFI,
|
|
|
|
getSmallIPtrImm(0));
|
2005-08-25 00:45:43 +00:00
|
|
|
}
|
2006-03-26 10:06:40 +00:00
|
|
|
|
|
|
|
case PPCISD::MFCR: {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue InFlag = N->getOperand(1);
|
2006-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(InFlag);
|
2006-03-26 10:06:40 +00:00
|
|
|
// Use MFOCRF if supported.
|
2007-10-23 06:42:42 +00:00
|
|
|
if (PPCSubTarget.isGigaProcessor())
|
2006-08-15 23:48:22 +00:00
|
|
|
return CurDAG->getTargetNode(PPC::MFOCRF, MVT::i32,
|
|
|
|
N->getOperand(0), InFlag);
|
2006-03-26 10:06:40 +00:00
|
|
|
else
|
2006-08-15 23:48:22 +00:00
|
|
|
return CurDAG->getTargetNode(PPC::MFCR, MVT::i32, InFlag);
|
2006-03-26 10:06:40 +00:00
|
|
|
}
|
|
|
|
|
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)) {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue N0 = N->getOperand(0);
|
2006-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(N0);
|
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)));
|
2006-08-15 23:48:22 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::ADDZE, MVT::i32,
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue(Op, 0), SDValue(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)));
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue PT =
|
|
|
|
SDValue(CurDAG->getTargetNode(PPC::ADDZE, MVT::i32,
|
|
|
|
SDValue(Op, 0), SDValue(Op, 1)),
|
2006-02-09 07:17:49 +00:00
|
|
|
0);
|
2006-08-26 08:00:10 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::NEG, MVT::i32, PT);
|
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
|
|
|
}
|
2006-11-10 02:08:47 +00:00
|
|
|
|
|
|
|
case ISD::LOAD: {
|
|
|
|
// Handle preincrement loads.
|
|
|
|
LoadSDNode *LD = cast<LoadSDNode>(Op);
|
2008-06-06 12:08:01 +00:00
|
|
|
MVT LoadedVT = LD->getMemoryVT();
|
2006-11-10 02:08:47 +00:00
|
|
|
|
|
|
|
// Normal loads are handled by code generated from the .td file.
|
|
|
|
if (LD->getAddressingMode() != ISD::PRE_INC)
|
|
|
|
break;
|
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Offset = LD->getOffset();
|
allow the offset of a preinc'd load to be the low-part of a global. This
produces this clever code:
_millisecs:
lis r2, ha16(_Time.1182)
lwzu r3, lo16(_Time.1182)(r2)
lwz r2, 4(r2)
addic r4, r2, 1
addze r3, r3
blr
instead of this:
_millisecs:
lis r2, ha16(_Time.1182)
la r3, lo16(_Time.1182)(r2)
lwz r2, lo16(_Time.1182)(r2)
lwz r3, 4(r3)
addic r4, r3, 1
addze r3, r2
blr
for:
long %millisecs() {
%tmp = load long* %Time.1182 ; <long> [#uses=1]
%tmp1 = add long %tmp, 1 ; <long> [#uses=1]
ret long %tmp1
}
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@31673 91177308-0d34-0410-b5e6-96231b3b80d8
2006-11-11 04:53:30 +00:00
|
|
|
if (isa<ConstantSDNode>(Offset) ||
|
|
|
|
Offset.getOpcode() == ISD::TargetGlobalAddress) {
|
2006-11-15 19:55:13 +00:00
|
|
|
|
|
|
|
unsigned Opcode;
|
|
|
|
bool isSExt = LD->getExtensionType() == ISD::SEXTLOAD;
|
|
|
|
if (LD->getValueType(0) != MVT::i64) {
|
|
|
|
// Handle PPC32 integer and normal FP loads.
|
2008-02-20 11:22:39 +00:00
|
|
|
assert((!isSExt || LoadedVT == MVT::i16) && "Invalid sext update load");
|
2008-06-06 12:08:01 +00:00
|
|
|
switch (LoadedVT.getSimpleVT()) {
|
2006-11-15 19:55:13 +00:00
|
|
|
default: assert(0 && "Invalid PPC load type!");
|
|
|
|
case MVT::f64: Opcode = PPC::LFDU; break;
|
|
|
|
case MVT::f32: Opcode = PPC::LFSU; break;
|
|
|
|
case MVT::i32: Opcode = PPC::LWZU; break;
|
|
|
|
case MVT::i16: Opcode = isSExt ? PPC::LHAU : PPC::LHZU; break;
|
|
|
|
case MVT::i1:
|
|
|
|
case MVT::i8: Opcode = PPC::LBZU; break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(LD->getValueType(0) == MVT::i64 && "Unknown load result type!");
|
2008-02-20 11:22:39 +00:00
|
|
|
assert((!isSExt || LoadedVT == MVT::i16) && "Invalid sext update load");
|
2008-06-06 12:08:01 +00:00
|
|
|
switch (LoadedVT.getSimpleVT()) {
|
2006-11-15 19:55:13 +00:00
|
|
|
default: assert(0 && "Invalid PPC load type!");
|
|
|
|
case MVT::i64: Opcode = PPC::LDU; break;
|
|
|
|
case MVT::i32: Opcode = PPC::LWZU8; break;
|
|
|
|
case MVT::i16: Opcode = isSExt ? PPC::LHAU8 : PPC::LHZU8; break;
|
|
|
|
case MVT::i1:
|
|
|
|
case MVT::i8: Opcode = PPC::LBZU8; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Chain = LD->getChain();
|
|
|
|
SDValue Base = LD->getBasePtr();
|
2006-11-10 02:08:47 +00:00
|
|
|
AddToISelQueue(Chain);
|
|
|
|
AddToISelQueue(Base);
|
|
|
|
AddToISelQueue(Offset);
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { Offset, Base, Chain };
|
2006-11-10 02:08:47 +00:00
|
|
|
// FIXME: PPC64
|
2008-07-17 19:10:17 +00:00
|
|
|
return CurDAG->getTargetNode(Opcode, LD->getValueType(0),
|
|
|
|
PPCLowering.getPointerTy(),
|
2006-11-10 02:08:47 +00:00
|
|
|
MVT::Other, Ops, 3);
|
|
|
|
} else {
|
|
|
|
assert(0 && "R+R preindex loads not supported yet!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-18 07:30:46 +00:00
|
|
|
case ISD::AND: {
|
2006-09-22 05:01:56 +00:00
|
|
|
unsigned Imm, Imm2, SH, MB, ME;
|
|
|
|
|
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) &&
|
2006-09-22 05:01:56 +00:00
|
|
|
isRotateAndMask(N->getOperand(0).Val, Imm, false, SH, MB, ME)) {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Val = N->getOperand(0).getOperand(0);
|
2006-09-22 05:01:56 +00:00
|
|
|
AddToISelQueue(Val);
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { Val, getI32Imm(SH), getI32Imm(MB), getI32Imm(ME) };
|
2006-08-27 08:14:06 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops, 4);
|
2005-08-18 07:30:46 +00:00
|
|
|
}
|
2006-09-22 05:01:56 +00:00
|
|
|
// If this is just a masked value where the input is not handled above, and
|
|
|
|
// is not a rotate-left (handled by a pattern in the .td file), emit rlwinm
|
|
|
|
if (isInt32Immediate(N->getOperand(1), Imm) &&
|
|
|
|
isRunOfOnes(Imm, MB, ME) &&
|
|
|
|
N->getOperand(0).getOpcode() != ISD::ROTL) {
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Val = N->getOperand(0);
|
2006-09-22 05:01:56 +00:00
|
|
|
AddToISelQueue(Val);
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { Val, getI32Imm(0), getI32Imm(MB), getI32Imm(ME) };
|
2006-09-22 05:01:56 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops, 4);
|
|
|
|
}
|
|
|
|
// AND X, 0 -> 0, not "rlwinm 32".
|
|
|
|
if (isInt32Immediate(N->getOperand(1), Imm) && (Imm == 0)) {
|
|
|
|
AddToISelQueue(N->getOperand(1));
|
2008-07-27 21:46:04 +00:00
|
|
|
ReplaceUses(SDValue(N, 0), N->getOperand(1));
|
2006-09-22 05:01:56 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
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-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(N->getOperand(0).getOperand(0));
|
|
|
|
AddToISelQueue(N->getOperand(0).getOperand(1));
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { N->getOperand(0).getOperand(0),
|
2006-08-27 08:14:06 +00:00
|
|
|
N->getOperand(0).getOperand(1),
|
|
|
|
getI32Imm(0), getI32Imm(MB),getI32Imm(ME) };
|
|
|
|
return CurDAG->getTargetNode(PPC::RLWIMI, MVT::i32, Ops, 5);
|
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-06-27 21:08:52 +00:00
|
|
|
if (N->getValueType(0) == MVT::i32)
|
2006-08-15 23:48:22 +00:00
|
|
|
if (SDNode *I = SelectBitfieldInsert(N))
|
|
|
|
return I;
|
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-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(N->getOperand(0).getOperand(0));
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { N->getOperand(0).getOperand(0),
|
2006-08-27 08:14:06 +00:00
|
|
|
getI32Imm(SH), getI32Imm(MB), getI32Imm(ME) };
|
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops, 4);
|
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-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(N->getOperand(0).getOperand(0));
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { N->getOperand(0).getOperand(0),
|
2006-08-27 08:14:06 +00:00
|
|
|
getI32Imm(SH), getI32Imm(MB), getI32Imm(ME) };
|
|
|
|
return CurDAG->SelectNodeTo(N, PPC::RLWINM, MVT::i32, Ops, 4);
|
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-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(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,
|
2006-08-26 01:07:58 +00:00
|
|
|
N->getOperand(0), getI32Imm(~0U));
|
2006-08-15 23:48:22 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::SUBFE, MVT::i32,
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue(Tmp, 0), N->getOperand(0),
|
|
|
|
SDValue(Tmp, 1));
|
2005-08-26 18:46:49 +00:00
|
|
|
}
|
2005-08-26 21:23:58 +00:00
|
|
|
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue CCReg = SelectCC(N->getOperand(0), N->getOperand(1), CC);
|
2006-11-17 22:10:59 +00:00
|
|
|
unsigned BROpc = getPredicateForSetCC(CC);
|
2005-08-26 21:23:58 +00:00
|
|
|
|
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-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(N->getOperand(2));
|
|
|
|
AddToISelQueue(N->getOperand(3));
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { CCReg, N->getOperand(2), N->getOperand(3),
|
2006-08-27 08:14:06 +00:00
|
|
|
getI32Imm(BROpc) };
|
|
|
|
return CurDAG->SelectNodeTo(N, SelectCCOp, N->getValueType(0), Ops, 4);
|
2005-08-26 18:46:49 +00:00
|
|
|
}
|
2006-11-17 22:37:34 +00:00
|
|
|
case PPCISD::COND_BRANCH: {
|
|
|
|
AddToISelQueue(N->getOperand(0)); // Op #0 is the Chain.
|
|
|
|
// Op #1 is the PPC::PRED_* number.
|
|
|
|
// Op #2 is the CR#
|
|
|
|
// Op #3 is the Dest MBB
|
|
|
|
AddToISelQueue(N->getOperand(4)); // Op #4 is the Flag.
|
2007-06-29 01:25:06 +00:00
|
|
|
// Prevent PPC::PRED_* from being selected into LI.
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Pred =
|
2007-06-29 01:25:06 +00:00
|
|
|
getI32Imm(cast<ConstantSDNode>(N->getOperand(1))->getValue());
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Ops[] = { Pred, N->getOperand(2), N->getOperand(3),
|
2006-11-17 22:37:34 +00:00
|
|
|
N->getOperand(0), N->getOperand(4) };
|
|
|
|
return CurDAG->SelectNodeTo(N, PPC::BCC, MVT::Other, Ops, 5);
|
|
|
|
}
|
2006-03-17 01:40:33 +00:00
|
|
|
case ISD::BR_CC: {
|
2006-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(N->getOperand(0));
|
2005-08-21 18:50:37 +00:00
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(1))->get();
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue CondCode = SelectCC(N->getOperand(2), N->getOperand(3), CC);
|
|
|
|
SDValue Ops[] = { getI32Imm(getPredicateForSetCC(CC)), CondCode,
|
2006-08-27 08:14:06 +00:00
|
|
|
N->getOperand(4), N->getOperand(0) };
|
2006-11-17 22:14:47 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::BCC, MVT::Other, Ops, 4);
|
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.
|
2008-07-27 21:46:04 +00:00
|
|
|
SDValue Chain = N->getOperand(0);
|
|
|
|
SDValue Target = N->getOperand(1);
|
2006-08-26 01:07:58 +00:00
|
|
|
AddToISelQueue(Chain);
|
|
|
|
AddToISelQueue(Target);
|
2006-06-27 20:46:17 +00:00
|
|
|
unsigned Opc = Target.getValueType() == MVT::i32 ? PPC::MTCTR : PPC::MTCTR8;
|
2008-07-27 21:46:04 +00:00
|
|
|
Chain = SDValue(CurDAG->getTargetNode(Opc, MVT::Other, Target,
|
2006-04-22 18:53:45 +00:00
|
|
|
Chain), 0);
|
2006-08-26 08:00:10 +00:00
|
|
|
return CurDAG->SelectNodeTo(N, PPC::BCTR, MVT::Other, Chain);
|
2006-04-22 18:53:45 +00:00
|
|
|
}
|
2005-08-17 19:33:03 +00:00
|
|
|
}
|
2005-09-03 00:53:47 +00:00
|
|
|
|
2006-08-26 05:34:46 +00:00
|
|
|
return SelectCode(Op);
|
2005-08-17 19:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-06-10 01:15:02 +00:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|