2005-03-24 04:41:43 +00:00
|
|
|
//===-- PPC32ISelPattern.cpp - A pattern matching inst selector for PPC32 -===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2005-03-24 06:28:42 +00:00
|
|
|
// This file was developed by Nate Begeman and is distributed under
|
2005-03-24 04:41:43 +00:00
|
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
2005-04-21 23:30:14 +00:00
|
|
|
//
|
2005-03-24 04:41:43 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines a pattern matching instruction selector for 32 bit PowerPC.
|
2005-04-06 00:25:27 +00:00
|
|
|
// Magic number generation for integer divide from the PowerPC Compiler Writer's
|
|
|
|
// Guide, section 3.2.3.5
|
2005-03-24 04:41:43 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "PowerPC.h"
|
|
|
|
#include "PowerPCInstrBuilder.h"
|
|
|
|
#include "PowerPCInstrInfo.h"
|
2005-04-09 20:09:12 +00:00
|
|
|
#include "PPC32TargetMachine.h"
|
2005-08-16 17:14:42 +00:00
|
|
|
#include "PPC32ISelLowering.h"
|
2005-07-19 16:51:05 +00:00
|
|
|
#include "llvm/Constants.h"
|
2005-03-24 04:41:43 +00:00
|
|
|
#include "llvm/Function.h"
|
2005-07-19 16:51:05 +00:00
|
|
|
#include "llvm/CodeGen/MachineConstantPool.h"
|
2005-03-24 04:41:43 +00:00
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
|
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
|
|
#include "llvm/CodeGen/SSARegMap.h"
|
|
|
|
#include "llvm/Target/TargetData.h"
|
2005-04-04 23:40:36 +00:00
|
|
|
#include "llvm/Target/TargetOptions.h"
|
2005-03-24 04:41:43 +00:00
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Support/MathExtras.h"
|
|
|
|
#include "llvm/ADT/Statistic.h"
|
|
|
|
#include <set>
|
|
|
|
#include <algorithm>
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
2005-08-17 01:25:14 +00:00
|
|
|
Statistic<> Recorded("ppc-codegen", "Number of recording ops emitted");
|
|
|
|
Statistic<> FusedFP ("ppc-codegen", "Number of fused fp operations");
|
|
|
|
Statistic<> FrameOff("ppc-codegen", "Number of frame idx offsets collapsed");
|
2005-08-05 22:05:03 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
//===--------------------------------------------------------------------===//
|
2005-08-17 01:25:14 +00:00
|
|
|
// ISel - PPC32 specific code to select PPC32 machine instructions for
|
|
|
|
// SelectionDAG operations.
|
2005-03-24 04:41:43 +00:00
|
|
|
//===--------------------------------------------------------------------===//
|
2005-08-17 01:25:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
class ISel : public SelectionDAGISel {
|
|
|
|
PPC32TargetLowering PPC32Lowering;
|
2005-04-06 00:25:27 +00:00
|
|
|
SelectionDAG *ISelDAG; // Hack to support us having a dag->dag transform
|
|
|
|
// for sdiv and udiv until it is put into the future
|
|
|
|
// dag combiner.
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
/// ExprMap - As shared expressions are codegen'd, we keep track of which
|
|
|
|
/// vreg the value is produced in, so we only emit one copy of each compiled
|
|
|
|
/// tree.
|
|
|
|
std::map<SDOperand, unsigned> ExprMap;
|
2005-03-25 08:34:25 +00:00
|
|
|
|
|
|
|
unsigned GlobalBaseReg;
|
|
|
|
bool GlobalBaseInitialized;
|
2005-04-11 06:34:10 +00:00
|
|
|
bool RecordSuccess;
|
2005-03-24 04:41:43 +00:00
|
|
|
public:
|
2005-04-06 00:25:27 +00:00
|
|
|
ISel(TargetMachine &TM) : SelectionDAGISel(PPC32Lowering), PPC32Lowering(TM),
|
|
|
|
ISelDAG(0) {}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-25 08:34:25 +00:00
|
|
|
/// runOnFunction - Override this function in order to reset our per-function
|
|
|
|
/// variables.
|
|
|
|
virtual bool runOnFunction(Function &Fn) {
|
|
|
|
// Make sure we re-emit a set of the global base reg if necessary
|
|
|
|
GlobalBaseInitialized = false;
|
|
|
|
return SelectionDAGISel::runOnFunction(Fn);
|
2005-04-21 23:30:14 +00:00
|
|
|
}
|
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
/// InstructionSelectBasicBlock - This callback is invoked by
|
|
|
|
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
|
|
|
|
virtual void InstructionSelectBasicBlock(SelectionDAG &DAG) {
|
|
|
|
DEBUG(BB->dump());
|
|
|
|
// Codegen the basic block.
|
2005-04-06 00:25:27 +00:00
|
|
|
ISelDAG = &DAG;
|
2005-03-24 04:41:43 +00:00
|
|
|
Select(DAG.getRoot());
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
// Clear state used for selection.
|
|
|
|
ExprMap.clear();
|
2005-04-06 00:25:27 +00:00
|
|
|
ISelDAG = 0;
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
2005-04-06 00:25:27 +00:00
|
|
|
|
2005-08-11 17:15:31 +00:00
|
|
|
// convenience functions for virtual register creation
|
|
|
|
inline unsigned MakeIntReg() {
|
|
|
|
return RegMap->createVirtualRegister(PPC32::GPRCRegisterClass);
|
|
|
|
}
|
|
|
|
inline unsigned MakeFPReg() {
|
|
|
|
return RegMap->createVirtualRegister(PPC32::FPRCRegisterClass);
|
|
|
|
}
|
|
|
|
|
2005-04-06 00:25:27 +00:00
|
|
|
// dag -> dag expanders for integer divide by constant
|
|
|
|
SDOperand BuildSDIVSequence(SDOperand N);
|
|
|
|
SDOperand BuildUDIVSequence(SDOperand N);
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-04-01 00:32:34 +00:00
|
|
|
unsigned getGlobalBaseReg();
|
2005-04-01 02:59:27 +00:00
|
|
|
unsigned getConstDouble(double floatVal, unsigned Result);
|
2005-08-10 20:52:09 +00:00
|
|
|
void MoveCRtoGPR(unsigned CCReg, ISD::CondCode CC, unsigned Result);
|
2005-04-06 23:51:40 +00:00
|
|
|
bool SelectBitfieldInsert(SDOperand OR, unsigned Result);
|
2005-04-13 22:14:14 +00:00
|
|
|
unsigned FoldIfWideZeroExtend(SDOperand N);
|
2005-08-10 20:52:09 +00:00
|
|
|
unsigned SelectCC(SDOperand LHS, SDOperand RHS, ISD::CondCode CC);
|
2005-08-10 18:11:33 +00:00
|
|
|
bool SelectIntImmediateExpr(SDOperand N, unsigned Result,
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
unsigned OCHi, unsigned OCLo,
|
2005-08-10 18:11:33 +00:00
|
|
|
bool IsArithmetic = false, bool Negate = false);
|
2005-04-11 06:34:10 +00:00
|
|
|
unsigned SelectExpr(SDOperand N, bool Recording=false);
|
2005-03-24 04:41:43 +00:00
|
|
|
void Select(SDOperand N);
|
2005-04-21 23:30:14 +00:00
|
|
|
|
Fold constant adds into loads and stores to frame indices.
For the following code:
double %ext(int %A.0__, long %A.1__) {
%A_addr = alloca %typedef.DComplex ; <%typedef.DComplex*> [#uses=2]
%tmp.1 = cast %typedef.DComplex* %A_addr to int* ; <int*> [#uses=1]
store int %A.0__, int* %tmp.1
%tmp.2 = getelementptr %typedef.DComplex* %A_addr, int 0, uint 1 ; <double*> [#uses=2]
%tmp.3 = cast double* %tmp.2 to long* ; <long*> [#uses=1]
store long %A.1__, long* %tmp.3
%tmp.5 = load double* %tmp.2 ; <double> [#uses=1]
ret double %tmp.5
}
We now generate:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
stw r4, -8(r1)
stw r5, -4(r1)
lfd f1, -8(r1)
blr
Instead of:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
addi r2, r1, -12
stw r4, 4(r2)
stw r5, 8(r2)
lfd f1, 4(r2)
blr
This also fires hundreds of times on MultiSource.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22533 91177308-0d34-0410-b5e6-96231b3b80d8
2005-07-28 03:02:05 +00:00
|
|
|
unsigned SelectAddr(SDOperand N, unsigned& Reg, int& offset);
|
2005-03-24 04:41:43 +00:00
|
|
|
void SelectBranchCC(SDOperand N);
|
2005-08-02 19:07:49 +00:00
|
|
|
|
|
|
|
virtual const char *getPassName() const {
|
|
|
|
return "PowerPC Pattern Instruction Selection";
|
|
|
|
}
|
2005-03-24 04:41:43 +00:00
|
|
|
};
|
|
|
|
|
2005-08-08 21:08:09 +00:00
|
|
|
// isRunOfOnes - Returns true iff Val consists of one contiguous run of 1s with
|
|
|
|
// any number of 0s on either side. The 1s are allowed to wrap from LSB to
|
|
|
|
// MSB, so 0x000FFF0, 0x0000FFFF, and 0xFF0000FF are all runs. 0x0F0F0000 is
|
|
|
|
// not, since all 1s are not contiguous.
|
|
|
|
static bool isRunOfOnes(unsigned Val, unsigned &MB, unsigned &ME) {
|
|
|
|
if (isShiftedMask_32(Val)) {
|
|
|
|
// look for the first non-zero bit
|
|
|
|
MB = CountLeadingZeros_32(Val);
|
|
|
|
// look for the first zero bit after the run of ones
|
|
|
|
ME = CountLeadingZeros_32((Val - 1) ^ Val);
|
|
|
|
return true;
|
|
|
|
} else if (isShiftedMask_32(Val = ~Val)) { // invert mask
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
// no run present
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-08-08 21:10:27 +00:00
|
|
|
// isRotateAndMask - Returns true if Mask and Shift can be folded in to a rotate
|
|
|
|
// and mask opcode and mask operation.
|
|
|
|
static bool isRotateAndMask(unsigned Opcode, unsigned Shift, unsigned Mask,
|
|
|
|
bool IsShiftMask,
|
|
|
|
unsigned &SH, unsigned &MB, unsigned &ME) {
|
|
|
|
if (Shift > 31) return false;
|
|
|
|
unsigned Indeterminant = ~0; // bit mask marking indeterminant results
|
|
|
|
|
|
|
|
if (Opcode == ISD::SHL) { // shift left
|
|
|
|
// apply shift to mask if it comes first
|
|
|
|
if (IsShiftMask) Mask = Mask << Shift;
|
|
|
|
// determine which bits are made indeterminant by shift
|
|
|
|
Indeterminant = ~(0xFFFFFFFFu << Shift);
|
|
|
|
} else if (Opcode == ISD::SRA || Opcode == ISD::SRL) { // shift rights
|
|
|
|
// apply shift 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the mask doesn't intersect any Indeterminant bits
|
2005-08-12 23:52:46 +00:00
|
|
|
if (Mask && !(Mask & Indeterminant)) {
|
2005-08-08 21:10:27 +00:00
|
|
|
SH = Shift;
|
|
|
|
// make sure the mask is still a mask (wrap arounds may not be)
|
|
|
|
return isRunOfOnes(Mask, MB, ME);
|
|
|
|
}
|
|
|
|
|
|
|
|
// can't do it
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-08-09 18:29:55 +00:00
|
|
|
// isIntImmediate - This method tests to see if a constant operand.
|
2005-08-08 21:10:27 +00:00
|
|
|
// If so Imm will receive the 32 bit value.
|
2005-08-09 18:29:55 +00:00
|
|
|
static bool isIntImmediate(SDOperand N, unsigned& Imm) {
|
2005-08-08 21:10:27 +00:00
|
|
|
// test for constant
|
2005-08-09 18:29:55 +00:00
|
|
|
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) {
|
2005-08-08 21:10:27 +00:00
|
|
|
// retrieve value
|
2005-08-18 00:15:15 +00:00
|
|
|
Imm = (unsigned)CN->getValue();
|
2005-08-08 21:10:27 +00:00
|
|
|
// passes muster
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// not a constant
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-08-11 21:59:23 +00: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(SDOperand N, unsigned Opc, unsigned& Imm) {
|
|
|
|
return N.getOpcode() == Opc && isIntImmediate(N.getOperand(1), Imm);
|
|
|
|
}
|
|
|
|
|
2005-08-08 21:10:27 +00:00
|
|
|
// isOprShiftImm - Returns true if the specified operand is a shift opcode with
|
|
|
|
// a immediate shift count less than 32.
|
|
|
|
static bool isOprShiftImm(SDOperand N, unsigned& Opc, unsigned& SH) {
|
|
|
|
Opc = N.getOpcode();
|
|
|
|
return (Opc == ISD::SHL || Opc == ISD::SRL || Opc == ISD::SRA) &&
|
2005-08-09 18:29:55 +00:00
|
|
|
isIntImmediate(N.getOperand(1), SH) && SH < 32;
|
2005-08-08 21:10:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// isOprNot - Returns true if the specified operand is an xor with immediate -1.
|
|
|
|
static bool isOprNot(SDOperand N) {
|
|
|
|
unsigned Imm;
|
2005-08-11 21:59:23 +00:00
|
|
|
return isOpcWithIntImmediate(N, ISD::XOR, Imm) && (signed)Imm == -1;
|
2005-08-08 21:10:27 +00: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); }
|
|
|
|
|
2005-04-11 06:34:10 +00:00
|
|
|
/// NodeHasRecordingVariant - If SelectExpr can always produce code for
|
|
|
|
/// NodeOpcode that also sets CR0 as a side effect, return true. Otherwise,
|
|
|
|
/// return false.
|
|
|
|
static bool NodeHasRecordingVariant(unsigned NodeOpcode) {
|
|
|
|
switch(NodeOpcode) {
|
|
|
|
default: return false;
|
|
|
|
case ISD::AND:
|
2005-04-21 23:30:14 +00:00
|
|
|
case ISD::OR:
|
2005-04-13 02:46:17 +00:00
|
|
|
return true;
|
2005-04-11 06:34:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-31 23:55:40 +00:00
|
|
|
/// getBCCForSetCC - Returns the PowerPC condition branch mnemonic corresponding
|
2005-08-10 20:52:09 +00:00
|
|
|
/// to Condition.
|
|
|
|
static unsigned getBCCForSetCC(ISD::CondCode CC) {
|
|
|
|
switch (CC) {
|
2005-03-31 23:55:40 +00:00
|
|
|
default: assert(0 && "Unknown condition!"); abort();
|
|
|
|
case ISD::SETEQ: return PPC::BEQ;
|
|
|
|
case ISD::SETNE: return PPC::BNE;
|
2005-08-10 20:52:09 +00:00
|
|
|
case ISD::SETULT:
|
2005-03-31 23:55:40 +00:00
|
|
|
case ISD::SETLT: return PPC::BLT;
|
2005-08-10 20:52:09 +00:00
|
|
|
case ISD::SETULE:
|
2005-03-31 23:55:40 +00:00
|
|
|
case ISD::SETLE: return PPC::BLE;
|
2005-08-10 20:52:09 +00:00
|
|
|
case ISD::SETUGT:
|
2005-03-31 23:55:40 +00:00
|
|
|
case ISD::SETGT: return PPC::BGT;
|
2005-08-10 20:52:09 +00:00
|
|
|
case ISD::SETUGE:
|
2005-03-31 23:55:40 +00:00
|
|
|
case ISD::SETGE: return PPC::BGE;
|
|
|
|
}
|
2005-04-01 04:45:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-14 09:45:08 +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.
|
2005-08-10 20:52:09 +00:00
|
|
|
static unsigned getCRIdxForSetCC(ISD::CondCode CC, bool& Inv) {
|
|
|
|
switch (CC) {
|
2005-04-14 09:45:08 +00:00
|
|
|
default: assert(0 && "Unknown condition!"); abort();
|
2005-04-21 23:30:14 +00:00
|
|
|
case ISD::SETULT:
|
2005-04-14 09:45:08 +00:00
|
|
|
case ISD::SETLT: Inv = false; return 0;
|
|
|
|
case ISD::SETUGE:
|
|
|
|
case ISD::SETGE: Inv = true; return 0;
|
|
|
|
case ISD::SETUGT:
|
|
|
|
case ISD::SETGT: Inv = false; return 1;
|
|
|
|
case ISD::SETULE:
|
|
|
|
case ISD::SETLE: Inv = true; return 1;
|
|
|
|
case ISD::SETEQ: Inv = false; return 2;
|
|
|
|
case ISD::SETNE: Inv = true; return 2;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-01 04:45:11 +00:00
|
|
|
/// IndexedOpForOp - Return the indexed variant for each of the PowerPC load
|
|
|
|
/// and store immediate instructions.
|
|
|
|
static unsigned IndexedOpForOp(unsigned Opcode) {
|
|
|
|
switch(Opcode) {
|
|
|
|
default: assert(0 && "Unknown opcode!"); abort();
|
|
|
|
case PPC::LBZ: return PPC::LBZX; case PPC::STB: return PPC::STBX;
|
|
|
|
case PPC::LHZ: return PPC::LHZX; case PPC::STH: return PPC::STHX;
|
|
|
|
case PPC::LHA: return PPC::LHAX; case PPC::STW: return PPC::STWX;
|
|
|
|
case PPC::LWZ: return PPC::LWZX; case PPC::STFS: return PPC::STFSX;
|
|
|
|
case PPC::LFS: return PPC::LFSX; case PPC::STFD: return PPC::STFDX;
|
|
|
|
case PPC::LFD: return PPC::LFDX;
|
|
|
|
}
|
|
|
|
return 0;
|
2005-03-31 23:55:40 +00:00
|
|
|
}
|
2005-04-06 00:25:27 +00:00
|
|
|
|
2005-04-21 23:30:14 +00:00
|
|
|
// Structure used to return the necessary information to codegen an SDIV as
|
2005-04-06 00:25:27 +00:00
|
|
|
// a multiply.
|
|
|
|
struct ms {
|
|
|
|
int m; // magic number
|
|
|
|
int s; // shift amount
|
|
|
|
};
|
|
|
|
|
|
|
|
struct mu {
|
|
|
|
unsigned int m; // magic number
|
|
|
|
int a; // add indicator
|
|
|
|
int s; // shift amount
|
|
|
|
};
|
|
|
|
|
|
|
|
/// magic - calculate the magic numbers required to codegen an integer sdiv as
|
2005-04-21 23:30:14 +00:00
|
|
|
/// a sequence of multiply and shifts. Requires that the divisor not be 0, 1,
|
2005-04-06 00:25:27 +00:00
|
|
|
/// or -1.
|
|
|
|
static struct ms magic(int d) {
|
|
|
|
int p;
|
|
|
|
unsigned int ad, anc, delta, q1, r1, q2, r2, t;
|
2005-08-02 19:26:06 +00:00
|
|
|
const unsigned int two31 = 0x80000000U;
|
2005-04-06 00:25:27 +00:00
|
|
|
struct ms mag;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-04-06 00:25:27 +00:00
|
|
|
ad = abs(d);
|
|
|
|
t = two31 + ((unsigned int)d >> 31);
|
|
|
|
anc = t - 1 - t%ad; // absolute value of nc
|
|
|
|
p = 31; // initialize p
|
|
|
|
q1 = two31/anc; // initialize q1 = 2p/abs(nc)
|
|
|
|
r1 = two31 - q1*anc; // initialize r1 = rem(2p,abs(nc))
|
|
|
|
q2 = two31/ad; // initialize q2 = 2p/abs(d)
|
|
|
|
r2 = two31 - q2*ad; // initialize r2 = rem(2p,abs(d))
|
|
|
|
do {
|
|
|
|
p = p + 1;
|
|
|
|
q1 = 2*q1; // update q1 = 2p/abs(nc)
|
|
|
|
r1 = 2*r1; // update r1 = rem(2p/abs(nc))
|
|
|
|
if (r1 >= anc) { // must be unsigned comparison
|
|
|
|
q1 = q1 + 1;
|
|
|
|
r1 = r1 - anc;
|
|
|
|
}
|
|
|
|
q2 = 2*q2; // update q2 = 2p/abs(d)
|
|
|
|
r2 = 2*r2; // update r2 = rem(2p/abs(d))
|
|
|
|
if (r2 >= ad) { // must be unsigned comparison
|
|
|
|
q2 = q2 + 1;
|
|
|
|
r2 = r2 - ad;
|
|
|
|
}
|
|
|
|
delta = ad - r2;
|
|
|
|
} while (q1 < delta || (q1 == delta && r1 == 0));
|
|
|
|
|
|
|
|
mag.m = q2 + 1;
|
|
|
|
if (d < 0) mag.m = -mag.m; // resulting magic number
|
|
|
|
mag.s = p - 32; // resulting shift
|
|
|
|
return mag;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// magicu - calculate the magic numbers required to codegen an integer udiv as
|
|
|
|
/// a sequence of multiply, add and shifts. Requires that the divisor not be 0.
|
|
|
|
static struct mu magicu(unsigned d)
|
|
|
|
{
|
|
|
|
int p;
|
|
|
|
unsigned int nc, delta, q1, r1, q2, r2;
|
|
|
|
struct mu magu;
|
|
|
|
magu.a = 0; // initialize "add" indicator
|
|
|
|
nc = - 1 - (-d)%d;
|
|
|
|
p = 31; // initialize p
|
|
|
|
q1 = 0x80000000/nc; // initialize q1 = 2p/nc
|
|
|
|
r1 = 0x80000000 - q1*nc; // initialize r1 = rem(2p,nc)
|
|
|
|
q2 = 0x7FFFFFFF/d; // initialize q2 = (2p-1)/d
|
|
|
|
r2 = 0x7FFFFFFF - q2*d; // initialize r2 = rem((2p-1),d)
|
|
|
|
do {
|
|
|
|
p = p + 1;
|
|
|
|
if (r1 >= nc - r1 ) {
|
|
|
|
q1 = 2*q1 + 1; // update q1
|
|
|
|
r1 = 2*r1 - nc; // update r1
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
q1 = 2*q1; // update q1
|
|
|
|
r1 = 2*r1; // update r1
|
|
|
|
}
|
|
|
|
if (r2 + 1 >= d - r2) {
|
|
|
|
if (q2 >= 0x7FFFFFFF) magu.a = 1;
|
|
|
|
q2 = 2*q2 + 1; // update q2
|
|
|
|
r2 = 2*r2 + 1 - d; // update r2
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (q2 >= 0x80000000) magu.a = 1;
|
|
|
|
q2 = 2*q2; // update q2
|
|
|
|
r2 = 2*r2 + 1; // update r2
|
|
|
|
}
|
|
|
|
delta = d - 1 - r2;
|
|
|
|
} while (p < 64 && (q1 < delta || (q1 == delta && r1 == 0)));
|
|
|
|
magu.m = q2 + 1; // resulting magic number
|
|
|
|
magu.s = p - 32; // resulting shift
|
|
|
|
return magu;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// BuildSDIVSequence - Given an ISD::SDIV node expressing a divide by constant,
|
|
|
|
/// return a DAG expression to select that will generate the same value by
|
|
|
|
/// multiplying by a magic number. See:
|
|
|
|
/// <http://the.wall.riscom.net/books/proc/ppc/cwg/code2.html>
|
|
|
|
SDOperand ISel::BuildSDIVSequence(SDOperand N) {
|
|
|
|
int d = (int)cast<ConstantSDNode>(N.getOperand(1))->getSignExtended();
|
|
|
|
ms magics = magic(d);
|
|
|
|
// Multiply the numerator (operand 0) by the magic value
|
2005-04-21 23:30:14 +00:00
|
|
|
SDOperand Q = ISelDAG->getNode(ISD::MULHS, MVT::i32, N.getOperand(0),
|
2005-04-06 00:25:27 +00:00
|
|
|
ISelDAG->getConstant(magics.m, MVT::i32));
|
|
|
|
// If d > 0 and m < 0, add the numerator
|
|
|
|
if (d > 0 && magics.m < 0)
|
|
|
|
Q = ISelDAG->getNode(ISD::ADD, MVT::i32, Q, N.getOperand(0));
|
|
|
|
// If d < 0 and m > 0, subtract the numerator.
|
|
|
|
if (d < 0 && magics.m > 0)
|
|
|
|
Q = ISelDAG->getNode(ISD::SUB, MVT::i32, Q, N.getOperand(0));
|
|
|
|
// Shift right algebraic if shift value is nonzero
|
|
|
|
if (magics.s > 0)
|
2005-04-21 23:30:14 +00:00
|
|
|
Q = ISelDAG->getNode(ISD::SRA, MVT::i32, Q,
|
2005-04-06 00:25:27 +00:00
|
|
|
ISelDAG->getConstant(magics.s, MVT::i32));
|
|
|
|
// Extract the sign bit and add it to the quotient
|
2005-04-21 23:30:14 +00:00
|
|
|
SDOperand T =
|
2005-04-06 00:25:27 +00:00
|
|
|
ISelDAG->getNode(ISD::SRL, MVT::i32, Q, ISelDAG->getConstant(31, MVT::i32));
|
2005-04-06 06:44:57 +00:00
|
|
|
return ISelDAG->getNode(ISD::ADD, MVT::i32, Q, T);
|
2005-04-06 00:25:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// BuildUDIVSequence - Given an ISD::UDIV node expressing a divide by constant,
|
|
|
|
/// return a DAG expression to select that will generate the same value by
|
|
|
|
/// multiplying by a magic number. See:
|
|
|
|
/// <http://the.wall.riscom.net/books/proc/ppc/cwg/code2.html>
|
|
|
|
SDOperand ISel::BuildUDIVSequence(SDOperand N) {
|
2005-04-21 23:30:14 +00:00
|
|
|
unsigned d =
|
2005-04-06 00:25:27 +00:00
|
|
|
(unsigned)cast<ConstantSDNode>(N.getOperand(1))->getSignExtended();
|
|
|
|
mu magics = magicu(d);
|
|
|
|
// Multiply the numerator (operand 0) by the magic value
|
2005-04-21 23:30:14 +00:00
|
|
|
SDOperand Q = ISelDAG->getNode(ISD::MULHU, MVT::i32, N.getOperand(0),
|
2005-04-06 00:25:27 +00:00
|
|
|
ISelDAG->getConstant(magics.m, MVT::i32));
|
|
|
|
if (magics.a == 0) {
|
2005-04-21 23:30:14 +00:00
|
|
|
Q = ISelDAG->getNode(ISD::SRL, MVT::i32, Q,
|
2005-04-06 00:25:27 +00:00
|
|
|
ISelDAG->getConstant(magics.s, MVT::i32));
|
|
|
|
} else {
|
|
|
|
SDOperand NPQ = ISelDAG->getNode(ISD::SUB, MVT::i32, N.getOperand(0), Q);
|
2005-04-21 23:30:14 +00:00
|
|
|
NPQ = ISelDAG->getNode(ISD::SRL, MVT::i32, NPQ,
|
2005-04-06 00:25:27 +00:00
|
|
|
ISelDAG->getConstant(1, MVT::i32));
|
|
|
|
NPQ = ISelDAG->getNode(ISD::ADD, MVT::i32, NPQ, Q);
|
2005-04-21 23:30:14 +00:00
|
|
|
Q = ISelDAG->getNode(ISD::SRL, MVT::i32, NPQ,
|
2005-04-06 00:25:27 +00:00
|
|
|
ISelDAG->getConstant(magics.s-1, MVT::i32));
|
|
|
|
}
|
2005-04-06 06:44:57 +00:00
|
|
|
return Q;
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
|
|
|
|
2005-03-25 08:34:25 +00:00
|
|
|
/// getGlobalBaseReg - Output the instructions required to put the
|
|
|
|
/// base address to use for accessing globals into a register.
|
|
|
|
///
|
|
|
|
unsigned ISel::getGlobalBaseReg() {
|
|
|
|
if (!GlobalBaseInitialized) {
|
|
|
|
// Insert the set of GlobalBaseReg into the first MBB of the function
|
|
|
|
MachineBasicBlock &FirstMBB = BB->getParent()->front();
|
|
|
|
MachineBasicBlock::iterator MBBI = FirstMBB.begin();
|
2005-08-11 17:15:31 +00:00
|
|
|
GlobalBaseReg = MakeIntReg();
|
2005-03-25 08:34:25 +00:00
|
|
|
BuildMI(FirstMBB, MBBI, PPC::MovePCtoLR, 0, PPC::LR);
|
2005-08-18 23:24:50 +00:00
|
|
|
BuildMI(FirstMBB, MBBI, PPC::MFLR, 1, GlobalBaseReg);
|
2005-03-25 08:34:25 +00:00
|
|
|
GlobalBaseInitialized = true;
|
|
|
|
}
|
|
|
|
return GlobalBaseReg;
|
|
|
|
}
|
|
|
|
|
2005-04-21 23:30:14 +00:00
|
|
|
/// getConstDouble - Loads a floating point value into a register, via the
|
2005-04-01 02:59:27 +00:00
|
|
|
/// Constant Pool. Optionally takes a register in which to load the value.
|
|
|
|
unsigned ISel::getConstDouble(double doubleVal, unsigned Result=0) {
|
2005-08-11 17:15:31 +00:00
|
|
|
unsigned Tmp1 = MakeIntReg();
|
|
|
|
if (0 == Result) Result = MakeFPReg();
|
2005-04-01 02:59:27 +00:00
|
|
|
MachineConstantPool *CP = BB->getParent()->getConstantPool();
|
|
|
|
ConstantFP *CFP = ConstantFP::get(Type::DoubleTy, doubleVal);
|
|
|
|
unsigned CPI = CP->getConstantPoolIndex(CFP);
|
2005-07-21 20:44:43 +00:00
|
|
|
if (PICEnabled)
|
|
|
|
BuildMI(BB, PPC::ADDIS, 2, Tmp1).addReg(getGlobalBaseReg())
|
|
|
|
.addConstantPoolIndex(CPI);
|
|
|
|
else
|
|
|
|
BuildMI(BB, PPC::LIS, 1, Tmp1).addConstantPoolIndex(CPI);
|
2005-04-01 02:59:27 +00:00
|
|
|
BuildMI(BB, PPC::LFD, 2, Result).addConstantPoolIndex(CPI).addReg(Tmp1);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2005-04-21 23:30:14 +00:00
|
|
|
/// MoveCRtoGPR - Move CCReg[Idx] to the least significant bit of Result. If
|
Next round of PPC CR optimizations. For the following code:
int %bar(float %a, float %b, float %c, float %d) {
entry:
%tmp.1 = setlt float %a, %d
%tmp.2 = setlt float %b, %d
%or = or bool %tmp.1, %tmp.2
%tmp.3 = setgt float %c, %d
%tmp.4 = or bool %or, %tmp.3
%tmp.5 = and bool %tmp.4, true
%retval = cast bool %tmp.5 to int
ret int %retval
}
We now emit:
_bar:
.LBB_bar_0: ; entry
fcmpu cr0, f1, f4
fcmpu cr1, f2, f4
cror 0, 0, 4
fcmpu cr1, f3, f4
cror 28, 0, 5
mfcr r2
rlwinm r3, r2, 29, 31, 31
blr
Instead of:
_bar:
.LBB_bar_0: ; entry
fcmpu cr7, f1, f4
mfcr r2
rlwinm r2, r2, 29, 31, 31
fcmpu cr7, f2, f4
mfcr r3
rlwinm r3, r3, 29, 31, 31
or r2, r2, r3
fcmpu cr7, f3, f4
mfcr r3
rlwinm r3, r3, 30, 31, 31
or r3, r2, r3
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21321 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-18 07:48:09 +00:00
|
|
|
/// Inv is true, then invert the result.
|
2005-08-10 20:52:09 +00:00
|
|
|
void ISel::MoveCRtoGPR(unsigned CCReg, ISD::CondCode CC, unsigned Result){
|
|
|
|
bool Inv;
|
2005-08-11 17:15:31 +00:00
|
|
|
unsigned IntCR = MakeIntReg();
|
2005-08-10 20:52:09 +00:00
|
|
|
unsigned Idx = getCRIdxForSetCC(CC, Inv);
|
Next round of PPC CR optimizations. For the following code:
int %bar(float %a, float %b, float %c, float %d) {
entry:
%tmp.1 = setlt float %a, %d
%tmp.2 = setlt float %b, %d
%or = or bool %tmp.1, %tmp.2
%tmp.3 = setgt float %c, %d
%tmp.4 = or bool %or, %tmp.3
%tmp.5 = and bool %tmp.4, true
%retval = cast bool %tmp.5 to int
ret int %retval
}
We now emit:
_bar:
.LBB_bar_0: ; entry
fcmpu cr0, f1, f4
fcmpu cr1, f2, f4
cror 0, 0, 4
fcmpu cr1, f3, f4
cror 28, 0, 5
mfcr r2
rlwinm r3, r2, 29, 31, 31
blr
Instead of:
_bar:
.LBB_bar_0: ; entry
fcmpu cr7, f1, f4
mfcr r2
rlwinm r2, r2, 29, 31, 31
fcmpu cr7, f2, f4
mfcr r3
rlwinm r3, r3, 29, 31, 31
or r2, r2, r3
fcmpu cr7, f3, f4
mfcr r3
rlwinm r3, r3, 30, 31, 31
or r3, r2, r3
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21321 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-18 07:48:09 +00:00
|
|
|
BuildMI(BB, PPC::MCRF, 1, PPC::CR7).addReg(CCReg);
|
2005-08-05 22:05:03 +00:00
|
|
|
bool GPOpt =
|
|
|
|
TLI.getTargetMachine().getSubtarget<PPCSubtarget>().isGigaProcessor();
|
2005-08-19 03:42:28 +00:00
|
|
|
if (GPOpt)
|
|
|
|
BuildMI(BB, PPC::MFOCRF, 1, IntCR).addReg(PPC::CR7);
|
|
|
|
else
|
|
|
|
BuildMI(BB, PPC::MFCR, 0, IntCR);
|
Next round of PPC CR optimizations. For the following code:
int %bar(float %a, float %b, float %c, float %d) {
entry:
%tmp.1 = setlt float %a, %d
%tmp.2 = setlt float %b, %d
%or = or bool %tmp.1, %tmp.2
%tmp.3 = setgt float %c, %d
%tmp.4 = or bool %or, %tmp.3
%tmp.5 = and bool %tmp.4, true
%retval = cast bool %tmp.5 to int
ret int %retval
}
We now emit:
_bar:
.LBB_bar_0: ; entry
fcmpu cr0, f1, f4
fcmpu cr1, f2, f4
cror 0, 0, 4
fcmpu cr1, f3, f4
cror 28, 0, 5
mfcr r2
rlwinm r3, r2, 29, 31, 31
blr
Instead of:
_bar:
.LBB_bar_0: ; entry
fcmpu cr7, f1, f4
mfcr r2
rlwinm r2, r2, 29, 31, 31
fcmpu cr7, f2, f4
mfcr r3
rlwinm r3, r3, 29, 31, 31
or r2, r2, r3
fcmpu cr7, f3, f4
mfcr r3
rlwinm r3, r3, 30, 31, 31
or r3, r2, r3
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21321 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-18 07:48:09 +00:00
|
|
|
if (Inv) {
|
2005-08-11 17:15:31 +00:00
|
|
|
unsigned Tmp1 = MakeIntReg();
|
Next round of PPC CR optimizations. For the following code:
int %bar(float %a, float %b, float %c, float %d) {
entry:
%tmp.1 = setlt float %a, %d
%tmp.2 = setlt float %b, %d
%or = or bool %tmp.1, %tmp.2
%tmp.3 = setgt float %c, %d
%tmp.4 = or bool %or, %tmp.3
%tmp.5 = and bool %tmp.4, true
%retval = cast bool %tmp.5 to int
ret int %retval
}
We now emit:
_bar:
.LBB_bar_0: ; entry
fcmpu cr0, f1, f4
fcmpu cr1, f2, f4
cror 0, 0, 4
fcmpu cr1, f3, f4
cror 28, 0, 5
mfcr r2
rlwinm r3, r2, 29, 31, 31
blr
Instead of:
_bar:
.LBB_bar_0: ; entry
fcmpu cr7, f1, f4
mfcr r2
rlwinm r2, r2, 29, 31, 31
fcmpu cr7, f2, f4
mfcr r3
rlwinm r3, r3, 29, 31, 31
or r2, r2, r3
fcmpu cr7, f3, f4
mfcr r3
rlwinm r3, r3, 30, 31, 31
or r3, r2, r3
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21321 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-18 07:48:09 +00:00
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Tmp1).addReg(IntCR).addImm(32-(3-Idx))
|
|
|
|
.addImm(31).addImm(31);
|
|
|
|
BuildMI(BB, PPC::XORI, 2, Result).addReg(Tmp1).addImm(1);
|
|
|
|
} else {
|
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(IntCR).addImm(32-(3-Idx))
|
|
|
|
.addImm(31).addImm(31);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-21 23:30:14 +00:00
|
|
|
/// SelectBitfieldInsert - turn an or of two masked values into
|
2005-04-06 23:51:40 +00:00
|
|
|
/// 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
|
|
|
|
bool ISel::SelectBitfieldInsert(SDOperand OR, unsigned Result) {
|
2005-04-09 20:09:12 +00:00
|
|
|
bool IsRotate = false;
|
2005-04-06 23:51:40 +00:00
|
|
|
unsigned TgtMask = 0xFFFFFFFF, InsMask = 0xFFFFFFFF, Amount = 0;
|
2005-08-11 17:56:50 +00:00
|
|
|
unsigned Value;
|
2005-07-27 06:12:32 +00:00
|
|
|
|
Handle some more real world cases of rlwimi. These don't come up that
regularly in "normal" code, but for things like software graphics, they
make a big difference.
For the following code:
unsigned short Trans16Bit(unsigned srcA,unsigned srcB,unsigned alpha)
{
unsigned tmpA,tmpB,mixed;
tmpA = ((srcA & 0x03E0) << 15) | (srcA & 0x7C1F);
tmpB = ((srcB & 0x03E0) << 15) | (srcB & 0x7C1F);
mixed = (tmpA * alpha) + (tmpB * (32 - alpha));
return ((mixed >> 5) & 0x7C1F) | ((mixed >> 20) & 0x03E0);
}
We now generate:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
andi. r2, r4, 31775
rlwimi r2, r4, 15, 7, 11
subfic r4, r5, 32
mullw r2, r2, r4
andi. r4, r3, 31775
rlwimi r4, r3, 15, 7, 11
mullw r3, r4, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
rlwimi r3, r2, 12, 22, 26
blr
Instead of:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
slwi r2, r4, 15
rlwinm r2, r2, 0, 7, 11
andi. r4, r4, 31775
or r2, r2, r4
subfic r4, r5, 32
mullw r2, r2, r4
slwi r4, r3, 15
rlwinm r4, r4, 0, 7, 11
andi. r3, r3, 31775
or r3, r4, r3
mullw r3, r3, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
srwi r2, r2, 20
rlwimi r3, r2, 0, 22, 26
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22201 91177308-0d34-0410-b5e6-96231b3b80d8
2005-06-08 04:14:27 +00:00
|
|
|
SDOperand Op0 = OR.getOperand(0);
|
|
|
|
SDOperand Op1 = OR.getOperand(1);
|
|
|
|
|
|
|
|
unsigned Op0Opc = Op0.getOpcode();
|
|
|
|
unsigned Op1Opc = Op1.getOpcode();
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-04-06 23:51:40 +00:00
|
|
|
// 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;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-04-06 23:51:40 +00:00
|
|
|
// Generate Mask value for Target
|
2005-08-11 17:56:50 +00:00
|
|
|
if (isIntImmediate(Op0.getOperand(1), Value)) {
|
2005-04-06 23:51:40 +00:00
|
|
|
switch(Op0Opc) {
|
2005-08-11 17:56:50 +00:00
|
|
|
case ISD::SHL: TgtMask <<= Value; break;
|
|
|
|
case ISD::SRL: TgtMask >>= Value; break;
|
|
|
|
case ISD::AND: TgtMask &= Value; break;
|
2005-04-06 23:51:40 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-04-06 23:51:40 +00:00
|
|
|
// Generate Mask value for Insert
|
2005-08-11 17:56:50 +00:00
|
|
|
if (isIntImmediate(Op1.getOperand(1), Value)) {
|
2005-04-06 23:51:40 +00:00
|
|
|
switch(Op1Opc) {
|
2005-04-21 23:30:14 +00:00
|
|
|
case ISD::SHL:
|
2005-08-11 17:56:50 +00:00
|
|
|
Amount = Value;
|
2005-04-09 20:09:12 +00:00
|
|
|
InsMask <<= Amount;
|
|
|
|
if (Op0Opc == ISD::SRL) IsRotate = true;
|
2005-04-06 23:51:40 +00:00
|
|
|
break;
|
2005-04-21 23:30:14 +00:00
|
|
|
case ISD::SRL:
|
2005-08-11 17:56:50 +00:00
|
|
|
Amount = Value;
|
2005-04-21 23:30:14 +00:00
|
|
|
InsMask >>= Amount;
|
2005-04-06 23:51:40 +00:00
|
|
|
Amount = 32-Amount;
|
2005-04-09 20:09:12 +00:00
|
|
|
if (Op0Opc == ISD::SHL) IsRotate = true;
|
2005-04-06 23:51:40 +00:00
|
|
|
break;
|
2005-04-21 23:30:14 +00:00
|
|
|
case ISD::AND:
|
2005-08-11 17:56:50 +00:00
|
|
|
InsMask &= Value;
|
2005-04-06 23:51:40 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
Handle some more real world cases of rlwimi. These don't come up that
regularly in "normal" code, but for things like software graphics, they
make a big difference.
For the following code:
unsigned short Trans16Bit(unsigned srcA,unsigned srcB,unsigned alpha)
{
unsigned tmpA,tmpB,mixed;
tmpA = ((srcA & 0x03E0) << 15) | (srcA & 0x7C1F);
tmpB = ((srcB & 0x03E0) << 15) | (srcB & 0x7C1F);
mixed = (tmpA * alpha) + (tmpB * (32 - alpha));
return ((mixed >> 5) & 0x7C1F) | ((mixed >> 20) & 0x03E0);
}
We now generate:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
andi. r2, r4, 31775
rlwimi r2, r4, 15, 7, 11
subfic r4, r5, 32
mullw r2, r2, r4
andi. r4, r3, 31775
rlwimi r4, r3, 15, 7, 11
mullw r3, r4, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
rlwimi r3, r2, 12, 22, 26
blr
Instead of:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
slwi r2, r4, 15
rlwinm r2, r2, 0, 7, 11
andi. r4, r4, 31775
or r2, r2, r4
subfic r4, r5, 32
mullw r2, r2, r4
slwi r4, r3, 15
rlwinm r4, r4, 0, 7, 11
andi. r3, r3, 31775
or r3, r4, r3
mullw r3, r3, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
srwi r2, r2, 20
rlwimi r3, r2, 0, 22, 26
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22201 91177308-0d34-0410-b5e6-96231b3b80d8
2005-06-08 04:14:27 +00:00
|
|
|
unsigned Tmp3 = 0;
|
|
|
|
|
|
|
|
// If both of the inputs are ANDs and one of them has a logical shift by
|
|
|
|
// constant as its input, make that the inserted value so that we can combine
|
|
|
|
// the shift into the rotate part of the rlwimi instruction
|
|
|
|
if (Op0Opc == ISD::AND && Op1Opc == ISD::AND) {
|
2005-07-27 06:12:32 +00:00
|
|
|
if (Op1.getOperand(0).getOpcode() == ISD::SHL ||
|
Handle some more real world cases of rlwimi. These don't come up that
regularly in "normal" code, but for things like software graphics, they
make a big difference.
For the following code:
unsigned short Trans16Bit(unsigned srcA,unsigned srcB,unsigned alpha)
{
unsigned tmpA,tmpB,mixed;
tmpA = ((srcA & 0x03E0) << 15) | (srcA & 0x7C1F);
tmpB = ((srcB & 0x03E0) << 15) | (srcB & 0x7C1F);
mixed = (tmpA * alpha) + (tmpB * (32 - alpha));
return ((mixed >> 5) & 0x7C1F) | ((mixed >> 20) & 0x03E0);
}
We now generate:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
andi. r2, r4, 31775
rlwimi r2, r4, 15, 7, 11
subfic r4, r5, 32
mullw r2, r2, r4
andi. r4, r3, 31775
rlwimi r4, r3, 15, 7, 11
mullw r3, r4, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
rlwimi r3, r2, 12, 22, 26
blr
Instead of:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
slwi r2, r4, 15
rlwinm r2, r2, 0, 7, 11
andi. r4, r4, 31775
or r2, r2, r4
subfic r4, r5, 32
mullw r2, r2, r4
slwi r4, r3, 15
rlwinm r4, r4, 0, 7, 11
andi. r3, r3, 31775
or r3, r4, r3
mullw r3, r3, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
srwi r2, r2, 20
rlwimi r3, r2, 0, 22, 26
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22201 91177308-0d34-0410-b5e6-96231b3b80d8
2005-06-08 04:14:27 +00:00
|
|
|
Op1.getOperand(0).getOpcode() == ISD::SRL) {
|
2005-08-11 17:56:50 +00:00
|
|
|
if (isIntImmediate(Op1.getOperand(0).getOperand(1), Value)) {
|
2005-07-27 06:12:32 +00:00
|
|
|
Amount = Op1.getOperand(0).getOpcode() == ISD::SHL ?
|
2005-08-11 17:56:50 +00:00
|
|
|
Value : 32 - Value;
|
Handle some more real world cases of rlwimi. These don't come up that
regularly in "normal" code, but for things like software graphics, they
make a big difference.
For the following code:
unsigned short Trans16Bit(unsigned srcA,unsigned srcB,unsigned alpha)
{
unsigned tmpA,tmpB,mixed;
tmpA = ((srcA & 0x03E0) << 15) | (srcA & 0x7C1F);
tmpB = ((srcB & 0x03E0) << 15) | (srcB & 0x7C1F);
mixed = (tmpA * alpha) + (tmpB * (32 - alpha));
return ((mixed >> 5) & 0x7C1F) | ((mixed >> 20) & 0x03E0);
}
We now generate:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
andi. r2, r4, 31775
rlwimi r2, r4, 15, 7, 11
subfic r4, r5, 32
mullw r2, r2, r4
andi. r4, r3, 31775
rlwimi r4, r3, 15, 7, 11
mullw r3, r4, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
rlwimi r3, r2, 12, 22, 26
blr
Instead of:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
slwi r2, r4, 15
rlwinm r2, r2, 0, 7, 11
andi. r4, r4, 31775
or r2, r2, r4
subfic r4, r5, 32
mullw r2, r2, r4
slwi r4, r3, 15
rlwinm r4, r4, 0, 7, 11
andi. r3, r3, 31775
or r3, r4, r3
mullw r3, r3, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
srwi r2, r2, 20
rlwimi r3, r2, 0, 22, 26
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22201 91177308-0d34-0410-b5e6-96231b3b80d8
2005-06-08 04:14:27 +00:00
|
|
|
Tmp3 = SelectExpr(Op1.getOperand(0).getOperand(0));
|
|
|
|
}
|
|
|
|
} else if (Op0.getOperand(0).getOpcode() == ISD::SHL ||
|
|
|
|
Op0.getOperand(0).getOpcode() == ISD::SRL) {
|
2005-08-11 17:56:50 +00:00
|
|
|
if (isIntImmediate(Op0.getOperand(0).getOperand(1), Value)) {
|
Handle some more real world cases of rlwimi. These don't come up that
regularly in "normal" code, but for things like software graphics, they
make a big difference.
For the following code:
unsigned short Trans16Bit(unsigned srcA,unsigned srcB,unsigned alpha)
{
unsigned tmpA,tmpB,mixed;
tmpA = ((srcA & 0x03E0) << 15) | (srcA & 0x7C1F);
tmpB = ((srcB & 0x03E0) << 15) | (srcB & 0x7C1F);
mixed = (tmpA * alpha) + (tmpB * (32 - alpha));
return ((mixed >> 5) & 0x7C1F) | ((mixed >> 20) & 0x03E0);
}
We now generate:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
andi. r2, r4, 31775
rlwimi r2, r4, 15, 7, 11
subfic r4, r5, 32
mullw r2, r2, r4
andi. r4, r3, 31775
rlwimi r4, r3, 15, 7, 11
mullw r3, r4, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
rlwimi r3, r2, 12, 22, 26
blr
Instead of:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
slwi r2, r4, 15
rlwinm r2, r2, 0, 7, 11
andi. r4, r4, 31775
or r2, r2, r4
subfic r4, r5, 32
mullw r2, r2, r4
slwi r4, r3, 15
rlwinm r4, r4, 0, 7, 11
andi. r3, r3, 31775
or r3, r4, r3
mullw r3, r3, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
srwi r2, r2, 20
rlwimi r3, r2, 0, 22, 26
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22201 91177308-0d34-0410-b5e6-96231b3b80d8
2005-06-08 04:14:27 +00:00
|
|
|
std::swap(Op0, Op1);
|
|
|
|
std::swap(TgtMask, InsMask);
|
2005-07-27 06:12:32 +00:00
|
|
|
Amount = Op1.getOperand(0).getOpcode() == ISD::SHL ?
|
2005-08-11 17:56:50 +00:00
|
|
|
Value : 32 - Value;
|
Handle some more real world cases of rlwimi. These don't come up that
regularly in "normal" code, but for things like software graphics, they
make a big difference.
For the following code:
unsigned short Trans16Bit(unsigned srcA,unsigned srcB,unsigned alpha)
{
unsigned tmpA,tmpB,mixed;
tmpA = ((srcA & 0x03E0) << 15) | (srcA & 0x7C1F);
tmpB = ((srcB & 0x03E0) << 15) | (srcB & 0x7C1F);
mixed = (tmpA * alpha) + (tmpB * (32 - alpha));
return ((mixed >> 5) & 0x7C1F) | ((mixed >> 20) & 0x03E0);
}
We now generate:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
andi. r2, r4, 31775
rlwimi r2, r4, 15, 7, 11
subfic r4, r5, 32
mullw r2, r2, r4
andi. r4, r3, 31775
rlwimi r4, r3, 15, 7, 11
mullw r3, r4, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
rlwimi r3, r2, 12, 22, 26
blr
Instead of:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
slwi r2, r4, 15
rlwinm r2, r2, 0, 7, 11
andi. r4, r4, 31775
or r2, r2, r4
subfic r4, r5, 32
mullw r2, r2, r4
slwi r4, r3, 15
rlwinm r4, r4, 0, 7, 11
andi. r3, r3, 31775
or r3, r4, r3
mullw r3, r3, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
srwi r2, r2, 20
rlwimi r3, r2, 0, 22, 26
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22201 91177308-0d34-0410-b5e6-96231b3b80d8
2005-06-08 04:14:27 +00:00
|
|
|
Tmp3 = SelectExpr(Op1.getOperand(0).getOperand(0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-06 23:51:40 +00:00
|
|
|
// 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;
|
2005-08-08 21:08:09 +00:00
|
|
|
if (((TgtMask & InsMask) == 0) && isRunOfOnes(InsMask, MB, ME)) {
|
2005-04-06 23:51:40 +00:00
|
|
|
unsigned Tmp1, Tmp2;
|
Handle some more real world cases of rlwimi. These don't come up that
regularly in "normal" code, but for things like software graphics, they
make a big difference.
For the following code:
unsigned short Trans16Bit(unsigned srcA,unsigned srcB,unsigned alpha)
{
unsigned tmpA,tmpB,mixed;
tmpA = ((srcA & 0x03E0) << 15) | (srcA & 0x7C1F);
tmpB = ((srcB & 0x03E0) << 15) | (srcB & 0x7C1F);
mixed = (tmpA * alpha) + (tmpB * (32 - alpha));
return ((mixed >> 5) & 0x7C1F) | ((mixed >> 20) & 0x03E0);
}
We now generate:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
andi. r2, r4, 31775
rlwimi r2, r4, 15, 7, 11
subfic r4, r5, 32
mullw r2, r2, r4
andi. r4, r3, 31775
rlwimi r4, r3, 15, 7, 11
mullw r3, r4, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
rlwimi r3, r2, 12, 22, 26
blr
Instead of:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
slwi r2, r4, 15
rlwinm r2, r2, 0, 7, 11
andi. r4, r4, 31775
or r2, r2, r4
subfic r4, r5, 32
mullw r2, r2, r4
slwi r4, r3, 15
rlwinm r4, r4, 0, 7, 11
andi. r3, r3, 31775
or r3, r4, r3
mullw r3, r3, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
srwi r2, r2, 20
rlwimi r3, r2, 0, 22, 26
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22201 91177308-0d34-0410-b5e6-96231b3b80d8
2005-06-08 04:14:27 +00:00
|
|
|
bool fullMask = (TgtMask ^ InsMask) == 0xFFFFFFFF;
|
2005-04-09 20:09:12 +00:00
|
|
|
// Check for rotlwi / rotrwi here, a special case of bitfield insert
|
|
|
|
// where both bitfield halves are sourced from the same value.
|
Handle some more real world cases of rlwimi. These don't come up that
regularly in "normal" code, but for things like software graphics, they
make a big difference.
For the following code:
unsigned short Trans16Bit(unsigned srcA,unsigned srcB,unsigned alpha)
{
unsigned tmpA,tmpB,mixed;
tmpA = ((srcA & 0x03E0) << 15) | (srcA & 0x7C1F);
tmpB = ((srcB & 0x03E0) << 15) | (srcB & 0x7C1F);
mixed = (tmpA * alpha) + (tmpB * (32 - alpha));
return ((mixed >> 5) & 0x7C1F) | ((mixed >> 20) & 0x03E0);
}
We now generate:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
andi. r2, r4, 31775
rlwimi r2, r4, 15, 7, 11
subfic r4, r5, 32
mullw r2, r2, r4
andi. r4, r3, 31775
rlwimi r4, r3, 15, 7, 11
mullw r3, r4, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
rlwimi r3, r2, 12, 22, 26
blr
Instead of:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
slwi r2, r4, 15
rlwinm r2, r2, 0, 7, 11
andi. r4, r4, 31775
or r2, r2, r4
subfic r4, r5, 32
mullw r2, r2, r4
slwi r4, r3, 15
rlwinm r4, r4, 0, 7, 11
andi. r3, r3, 31775
or r3, r4, r3
mullw r3, r3, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
srwi r2, r2, 20
rlwimi r3, r2, 0, 22, 26
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22201 91177308-0d34-0410-b5e6-96231b3b80d8
2005-06-08 04:14:27 +00:00
|
|
|
if (IsRotate && fullMask &&
|
2005-04-09 20:09:12 +00:00
|
|
|
OR.getOperand(0).getOperand(0) == OR.getOperand(1).getOperand(0)) {
|
|
|
|
Tmp1 = SelectExpr(OR.getOperand(0).getOperand(0));
|
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm(Amount)
|
|
|
|
.addImm(0).addImm(31);
|
|
|
|
return true;
|
|
|
|
}
|
Handle some more real world cases of rlwimi. These don't come up that
regularly in "normal" code, but for things like software graphics, they
make a big difference.
For the following code:
unsigned short Trans16Bit(unsigned srcA,unsigned srcB,unsigned alpha)
{
unsigned tmpA,tmpB,mixed;
tmpA = ((srcA & 0x03E0) << 15) | (srcA & 0x7C1F);
tmpB = ((srcB & 0x03E0) << 15) | (srcB & 0x7C1F);
mixed = (tmpA * alpha) + (tmpB * (32 - alpha));
return ((mixed >> 5) & 0x7C1F) | ((mixed >> 20) & 0x03E0);
}
We now generate:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
andi. r2, r4, 31775
rlwimi r2, r4, 15, 7, 11
subfic r4, r5, 32
mullw r2, r2, r4
andi. r4, r3, 31775
rlwimi r4, r3, 15, 7, 11
mullw r3, r4, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
rlwimi r3, r2, 12, 22, 26
blr
Instead of:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
slwi r2, r4, 15
rlwinm r2, r2, 0, 7, 11
andi. r4, r4, 31775
or r2, r2, r4
subfic r4, r5, 32
mullw r2, r2, r4
slwi r4, r3, 15
rlwinm r4, r4, 0, 7, 11
andi. r3, r3, 31775
or r3, r4, r3
mullw r3, r3, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
srwi r2, r2, 20
rlwimi r3, r2, 0, 22, 26
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22201 91177308-0d34-0410-b5e6-96231b3b80d8
2005-06-08 04:14:27 +00:00
|
|
|
if (Op0Opc == ISD::AND && fullMask)
|
|
|
|
Tmp1 = SelectExpr(Op0.getOperand(0));
|
2005-04-06 23:51:40 +00:00
|
|
|
else
|
Handle some more real world cases of rlwimi. These don't come up that
regularly in "normal" code, but for things like software graphics, they
make a big difference.
For the following code:
unsigned short Trans16Bit(unsigned srcA,unsigned srcB,unsigned alpha)
{
unsigned tmpA,tmpB,mixed;
tmpA = ((srcA & 0x03E0) << 15) | (srcA & 0x7C1F);
tmpB = ((srcB & 0x03E0) << 15) | (srcB & 0x7C1F);
mixed = (tmpA * alpha) + (tmpB * (32 - alpha));
return ((mixed >> 5) & 0x7C1F) | ((mixed >> 20) & 0x03E0);
}
We now generate:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
andi. r2, r4, 31775
rlwimi r2, r4, 15, 7, 11
subfic r4, r5, 32
mullw r2, r2, r4
andi. r4, r3, 31775
rlwimi r4, r3, 15, 7, 11
mullw r3, r4, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
rlwimi r3, r2, 12, 22, 26
blr
Instead of:
_Trans16Bit:
.LBB_Trans16Bit_0: ; entry
slwi r2, r4, 15
rlwinm r2, r2, 0, 7, 11
andi. r4, r4, 31775
or r2, r2, r4
subfic r4, r5, 32
mullw r2, r2, r4
slwi r4, r3, 15
rlwinm r4, r4, 0, 7, 11
andi. r3, r3, 31775
or r3, r4, r3
mullw r3, r3, r5
add r2, r2, r3
srwi r3, r2, 5
andi. r3, r3, 31775
srwi r2, r2, 20
rlwimi r3, r2, 0, 22, 26
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22201 91177308-0d34-0410-b5e6-96231b3b80d8
2005-06-08 04:14:27 +00:00
|
|
|
Tmp1 = SelectExpr(Op0);
|
|
|
|
Tmp2 = Tmp3 ? Tmp3 : SelectExpr(Op1.getOperand(0));
|
2005-04-06 23:51:40 +00:00
|
|
|
BuildMI(BB, PPC::RLWIMI, 5, Result).addReg(Tmp1).addReg(Tmp2)
|
|
|
|
.addImm(Amount).addImm(MB).addImm(ME);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-04-13 22:14:14 +00:00
|
|
|
/// FoldIfWideZeroExtend - 32 bit PowerPC implicit masks shift amounts to the
|
|
|
|
/// low six bits. If the shift amount is an ISD::AND node with a mask that is
|
|
|
|
/// wider than the implicit mask, then we can get rid of the AND and let the
|
|
|
|
/// shift do the mask.
|
|
|
|
unsigned ISel::FoldIfWideZeroExtend(SDOperand N) {
|
2005-08-11 21:59:23 +00:00
|
|
|
unsigned C;
|
|
|
|
if (isOpcWithIntImmediate(N, ISD::AND, C) && isMask_32(C) && C > 63)
|
2005-04-13 22:14:14 +00:00
|
|
|
return SelectExpr(N.getOperand(0));
|
|
|
|
else
|
|
|
|
return SelectExpr(N);
|
|
|
|
}
|
|
|
|
|
2005-08-10 20:52:09 +00:00
|
|
|
unsigned ISel::SelectCC(SDOperand LHS, SDOperand RHS, ISD::CondCode CC) {
|
2005-04-13 23:15:44 +00:00
|
|
|
unsigned Result, Tmp1, Tmp2;
|
2005-04-12 21:22:28 +00:00
|
|
|
bool AlreadySelected = false;
|
2005-04-21 23:30:14 +00:00
|
|
|
static const unsigned CompareOpcodes[] =
|
2005-04-01 00:32:34 +00:00
|
|
|
{ PPC::FCMPU, PPC::FCMPU, PPC::CMPW, PPC::CMPLW };
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-04-13 23:15:44 +00:00
|
|
|
// Allocate a condition register for this expression
|
|
|
|
Result = RegMap->createVirtualRegister(PPC32::CRRCRegisterClass);
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-08-10 20:52:09 +00:00
|
|
|
// Use U to determine whether the SETCC immediate range is signed or not.
|
|
|
|
bool U = ISD::isUnsignedIntSetCC(CC);
|
|
|
|
if (isIntImmediate(RHS, Tmp2) &&
|
|
|
|
((U && isUInt16(Tmp2)) || (!U && isInt16(Tmp2)))) {
|
|
|
|
Tmp2 = Lo16(Tmp2);
|
|
|
|
// For comparisons against zero, we can implicity set CR0 if a recording
|
|
|
|
// variant (e.g. 'or.' instead of 'or') of the instruction that defines
|
|
|
|
// operand zero of the SetCC node is available.
|
|
|
|
if (Tmp2 == 0 &&
|
|
|
|
NodeHasRecordingVariant(LHS.getOpcode()) && LHS.Val->hasOneUse()) {
|
|
|
|
RecordSuccess = false;
|
|
|
|
Tmp1 = SelectExpr(LHS, true);
|
|
|
|
if (RecordSuccess) {
|
|
|
|
++Recorded;
|
|
|
|
BuildMI(BB, PPC::MCRF, 1, Result).addReg(PPC::CR0);
|
|
|
|
return Result;
|
2005-04-11 06:34:10 +00:00
|
|
|
}
|
2005-08-10 20:52:09 +00:00
|
|
|
AlreadySelected = true;
|
2005-03-31 23:55:40 +00:00
|
|
|
}
|
2005-08-10 20:52:09 +00:00
|
|
|
// If we could not implicitly set CR0, then emit a compare immediate
|
|
|
|
// instead.
|
|
|
|
if (!AlreadySelected) Tmp1 = SelectExpr(LHS);
|
|
|
|
if (U)
|
|
|
|
BuildMI(BB, PPC::CMPLWI, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
|
|
|
else
|
|
|
|
BuildMI(BB, PPC::CMPWI, 2, Result).addReg(Tmp1).addSImm(Tmp2);
|
2005-03-31 23:55:40 +00:00
|
|
|
} else {
|
2005-08-10 20:52:09 +00:00
|
|
|
bool IsInteger = MVT::isInteger(LHS.getValueType());
|
|
|
|
unsigned CompareOpc = CompareOpcodes[2 * IsInteger + U];
|
|
|
|
Tmp1 = SelectExpr(LHS);
|
|
|
|
Tmp2 = SelectExpr(RHS);
|
|
|
|
BuildMI(BB, CompareOpc, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
Next round of PPC CR optimizations. For the following code:
int %bar(float %a, float %b, float %c, float %d) {
entry:
%tmp.1 = setlt float %a, %d
%tmp.2 = setlt float %b, %d
%or = or bool %tmp.1, %tmp.2
%tmp.3 = setgt float %c, %d
%tmp.4 = or bool %or, %tmp.3
%tmp.5 = and bool %tmp.4, true
%retval = cast bool %tmp.5 to int
ret int %retval
}
We now emit:
_bar:
.LBB_bar_0: ; entry
fcmpu cr0, f1, f4
fcmpu cr1, f2, f4
cror 0, 0, 4
fcmpu cr1, f3, f4
cror 28, 0, 5
mfcr r2
rlwinm r3, r2, 29, 31, 31
blr
Instead of:
_bar:
.LBB_bar_0: ; entry
fcmpu cr7, f1, f4
mfcr r2
rlwinm r2, r2, 29, 31, 31
fcmpu cr7, f2, f4
mfcr r3
rlwinm r3, r3, 29, 31, 31
or r2, r2, r3
fcmpu cr7, f3, f4
mfcr r3
rlwinm r3, r3, 30, 31, 31
or r3, r2, r3
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21321 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-18 07:48:09 +00:00
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2005-08-08 22:22:56 +00:00
|
|
|
/// Check to see if the load is a constant offset from a base register.
|
Fold constant adds into loads and stores to frame indices.
For the following code:
double %ext(int %A.0__, long %A.1__) {
%A_addr = alloca %typedef.DComplex ; <%typedef.DComplex*> [#uses=2]
%tmp.1 = cast %typedef.DComplex* %A_addr to int* ; <int*> [#uses=1]
store int %A.0__, int* %tmp.1
%tmp.2 = getelementptr %typedef.DComplex* %A_addr, int 0, uint 1 ; <double*> [#uses=2]
%tmp.3 = cast double* %tmp.2 to long* ; <long*> [#uses=1]
store long %A.1__, long* %tmp.3
%tmp.5 = load double* %tmp.2 ; <double> [#uses=1]
ret double %tmp.5
}
We now generate:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
stw r4, -8(r1)
stw r5, -4(r1)
lfd f1, -8(r1)
blr
Instead of:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
addi r2, r1, -12
stw r4, 4(r2)
stw r5, 8(r2)
lfd f1, 4(r2)
blr
This also fires hundreds of times on MultiSource.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22533 91177308-0d34-0410-b5e6-96231b3b80d8
2005-07-28 03:02:05 +00:00
|
|
|
unsigned ISel::SelectAddr(SDOperand N, unsigned& Reg, int& offset)
|
2005-04-01 00:32:34 +00:00
|
|
|
{
|
|
|
|
unsigned imm = 0, opcode = N.getOpcode();
|
2005-04-01 04:45:11 +00:00
|
|
|
if (N.getOpcode() == ISD::ADD) {
|
Fold constant adds into loads and stores to frame indices.
For the following code:
double %ext(int %A.0__, long %A.1__) {
%A_addr = alloca %typedef.DComplex ; <%typedef.DComplex*> [#uses=2]
%tmp.1 = cast %typedef.DComplex* %A_addr to int* ; <int*> [#uses=1]
store int %A.0__, int* %tmp.1
%tmp.2 = getelementptr %typedef.DComplex* %A_addr, int 0, uint 1 ; <double*> [#uses=2]
%tmp.3 = cast double* %tmp.2 to long* ; <long*> [#uses=1]
store long %A.1__, long* %tmp.3
%tmp.5 = load double* %tmp.2 ; <double> [#uses=1]
ret double %tmp.5
}
We now generate:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
stw r4, -8(r1)
stw r5, -4(r1)
lfd f1, -8(r1)
blr
Instead of:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
addi r2, r1, -12
stw r4, 4(r2)
stw r5, 8(r2)
lfd f1, 4(r2)
blr
This also fires hundreds of times on MultiSource.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22533 91177308-0d34-0410-b5e6-96231b3b80d8
2005-07-28 03:02:05 +00:00
|
|
|
bool isFrame = N.getOperand(0).getOpcode() == ISD::FrameIndex;
|
2005-08-09 18:29:55 +00:00
|
|
|
if (isIntImmediate(N.getOperand(1), imm) && isInt16(imm)) {
|
2005-08-08 21:12:35 +00:00
|
|
|
offset = Lo16(imm);
|
Fold constant adds into loads and stores to frame indices.
For the following code:
double %ext(int %A.0__, long %A.1__) {
%A_addr = alloca %typedef.DComplex ; <%typedef.DComplex*> [#uses=2]
%tmp.1 = cast %typedef.DComplex* %A_addr to int* ; <int*> [#uses=1]
store int %A.0__, int* %tmp.1
%tmp.2 = getelementptr %typedef.DComplex* %A_addr, int 0, uint 1 ; <double*> [#uses=2]
%tmp.3 = cast double* %tmp.2 to long* ; <long*> [#uses=1]
store long %A.1__, long* %tmp.3
%tmp.5 = load double* %tmp.2 ; <double> [#uses=1]
ret double %tmp.5
}
We now generate:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
stw r4, -8(r1)
stw r5, -4(r1)
lfd f1, -8(r1)
blr
Instead of:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
addi r2, r1, -12
stw r4, 4(r2)
stw r5, 8(r2)
lfd f1, 4(r2)
blr
This also fires hundreds of times on MultiSource.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22533 91177308-0d34-0410-b5e6-96231b3b80d8
2005-07-28 03:02:05 +00:00
|
|
|
if (isFrame) {
|
|
|
|
++FrameOff;
|
|
|
|
Reg = cast<FrameIndexSDNode>(N.getOperand(0))->getIndex();
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
Reg = SelectExpr(N.getOperand(0));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Reg = SelectExpr(N.getOperand(0));
|
|
|
|
offset = SelectExpr(N.getOperand(1));
|
|
|
|
return 2;
|
2005-04-21 23:30:14 +00:00
|
|
|
}
|
2005-04-01 04:45:11 +00:00
|
|
|
}
|
2005-08-08 22:22:56 +00:00
|
|
|
// Now check if we're dealing with a global, and whether or not we should emit
|
|
|
|
// an optimized load or store for statics.
|
|
|
|
if(GlobalAddressSDNode *GN = dyn_cast<GlobalAddressSDNode>(N)) {
|
|
|
|
GlobalValue *GV = GN->getGlobal();
|
|
|
|
if (!GV->hasWeakLinkage() && !GV->isExternal()) {
|
2005-08-11 17:15:31 +00:00
|
|
|
unsigned GlobalHi = MakeIntReg();
|
2005-08-08 22:22:56 +00:00
|
|
|
if (PICEnabled)
|
|
|
|
BuildMI(BB, PPC::ADDIS, 2, GlobalHi).addReg(getGlobalBaseReg())
|
|
|
|
.addGlobalAddress(GV);
|
|
|
|
else
|
|
|
|
BuildMI(BB, PPC::LIS, 1, GlobalHi).addGlobalAddress(GV);
|
|
|
|
Reg = GlobalHi;
|
|
|
|
offset = 0;
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
}
|
2005-04-01 00:32:34 +00:00
|
|
|
Reg = SelectExpr(N);
|
|
|
|
offset = 0;
|
Fold constant adds into loads and stores to frame indices.
For the following code:
double %ext(int %A.0__, long %A.1__) {
%A_addr = alloca %typedef.DComplex ; <%typedef.DComplex*> [#uses=2]
%tmp.1 = cast %typedef.DComplex* %A_addr to int* ; <int*> [#uses=1]
store int %A.0__, int* %tmp.1
%tmp.2 = getelementptr %typedef.DComplex* %A_addr, int 0, uint 1 ; <double*> [#uses=2]
%tmp.3 = cast double* %tmp.2 to long* ; <long*> [#uses=1]
store long %A.1__, long* %tmp.3
%tmp.5 = load double* %tmp.2 ; <double> [#uses=1]
ret double %tmp.5
}
We now generate:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
stw r4, -8(r1)
stw r5, -4(r1)
lfd f1, -8(r1)
blr
Instead of:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
addi r2, r1, -12
stw r4, 4(r2)
stw r5, 8(r2)
lfd f1, 4(r2)
blr
This also fires hundreds of times on MultiSource.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22533 91177308-0d34-0410-b5e6-96231b3b80d8
2005-07-28 03:02:05 +00:00
|
|
|
return 0;
|
2005-04-01 00:32:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ISel::SelectBranchCC(SDOperand N)
|
|
|
|
{
|
2005-04-21 23:30:14 +00:00
|
|
|
MachineBasicBlock *Dest =
|
2005-08-16 19:49:35 +00:00
|
|
|
cast<BasicBlockSDNode>(N.getOperand(4))->getBasicBlock();
|
2005-04-01 00:32:34 +00:00
|
|
|
|
|
|
|
Select(N.getOperand(0)); //chain
|
2005-08-16 19:49:35 +00:00
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(N.getOperand(1))->get();
|
|
|
|
unsigned CCReg = SelectCC(N.getOperand(2), N.getOperand(3), CC);
|
2005-08-10 20:52:09 +00:00
|
|
|
unsigned Opc = getBCCForSetCC(CC);
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-04-09 20:09:12 +00:00
|
|
|
// 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.
|
2005-08-16 19:49:35 +00:00
|
|
|
if (N.getOpcode() == ISD::BRTWOWAY_CC) {
|
2005-04-21 23:30:14 +00:00
|
|
|
MachineBasicBlock *Fallthrough =
|
2005-08-16 19:49:35 +00:00
|
|
|
cast<BasicBlockSDNode>(N.getOperand(5))->getBasicBlock();
|
2005-08-21 19:03:28 +00:00
|
|
|
BuildMI(BB, PPC::COND_BRANCH, 4).addReg(CCReg).addImm(Opc)
|
|
|
|
.addMBB(Dest).addMBB(Fallthrough);
|
|
|
|
BuildMI(BB, PPC::B, 1).addMBB(Fallthrough);
|
2005-04-09 20:09:12 +00:00
|
|
|
} else {
|
2005-08-21 19:03:28 +00:00
|
|
|
// Iterate to the next basic block
|
|
|
|
ilist<MachineBasicBlock>::iterator It = BB;
|
|
|
|
++It;
|
|
|
|
|
2005-06-15 18:22:43 +00:00
|
|
|
// 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-04-13 23:15:44 +00:00
|
|
|
BuildMI(BB, PPC::COND_BRANCH, 4).addReg(CCReg).addImm(Opc)
|
2005-04-10 01:48:29 +00:00
|
|
|
.addMBB(Dest).addMBB(It);
|
2005-04-09 20:09:12 +00:00
|
|
|
}
|
2005-03-24 04:41:43 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
// SelectIntImmediateExpr - Choose code for opcodes with immediate value.
|
2005-08-10 18:11:33 +00:00
|
|
|
bool ISel::SelectIntImmediateExpr(SDOperand N, unsigned Result,
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
unsigned OCHi, unsigned OCLo,
|
2005-08-10 18:11:33 +00:00
|
|
|
bool IsArithmetic, bool Negate) {
|
|
|
|
// check constant
|
|
|
|
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1));
|
|
|
|
// exit if not a constant
|
|
|
|
if (!CN) return false;
|
|
|
|
// extract immediate
|
2005-08-17 01:25:14 +00:00
|
|
|
unsigned C = (unsigned)CN->getValue();
|
2005-08-10 18:11:33 +00:00
|
|
|
// negate if required (ISD::SUB)
|
|
|
|
if (Negate) C = -C;
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
// get the hi and lo portions of constant
|
|
|
|
unsigned Hi = IsArithmetic ? HA16(C) : Hi16(C);
|
|
|
|
unsigned Lo = Lo16(C);
|
|
|
|
// assume no intermediate result from lo instruction (same as final result)
|
|
|
|
unsigned Tmp = Result;
|
|
|
|
// check if two instructions are needed
|
|
|
|
if (Hi && Lo) {
|
|
|
|
// exit if usage indicates it would be better to load immediate into a
|
|
|
|
// register
|
2005-08-10 18:11:33 +00:00
|
|
|
if (CN->use_size() > 2) return false;
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
// need intermediate result for two instructions
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp = MakeIntReg();
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
}
|
|
|
|
// get first operand
|
|
|
|
unsigned Opr0 = SelectExpr(N.getOperand(0));
|
|
|
|
// is a lo instruction needed
|
|
|
|
if (Lo) {
|
2005-08-17 01:25:14 +00:00
|
|
|
// generate instruction for lo portion
|
|
|
|
BuildMI(BB, OCLo, 2, Tmp).addReg(Opr0).addImm(Lo);
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
// need to switch out first operand for hi instruction
|
|
|
|
Opr0 = Tmp;
|
|
|
|
}
|
2005-08-17 01:25:14 +00:00
|
|
|
// is a hi instruction needed
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
if (Hi) {
|
|
|
|
// generate instruction for hi portion
|
2005-08-17 01:25:14 +00:00
|
|
|
BuildMI(BB, OCHi, 2, Result).addReg(Opr0).addImm(Hi);
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-04-11 06:34:10 +00:00
|
|
|
unsigned ISel::SelectExpr(SDOperand N, bool Recording) {
|
2005-03-24 04:41:43 +00:00
|
|
|
unsigned Result;
|
|
|
|
unsigned Tmp1, Tmp2, Tmp3;
|
|
|
|
unsigned Opc = 0;
|
|
|
|
unsigned opcode = N.getOpcode();
|
|
|
|
|
|
|
|
SDNode *Node = N.Val;
|
|
|
|
MVT::ValueType DestType = N.getValueType();
|
|
|
|
|
2005-08-16 21:58:15 +00:00
|
|
|
if (Node->getOpcode() == ISD::CopyFromReg) {
|
|
|
|
unsigned Reg = cast<RegisterSDNode>(Node->getOperand(1))->getReg();
|
2005-06-14 03:55:23 +00:00
|
|
|
// Just use the specified register as our input.
|
2005-08-16 21:58:15 +00:00
|
|
|
if (MRegisterInfo::isVirtualRegister(Reg) || Reg == PPC::R1)
|
|
|
|
return Reg;
|
|
|
|
}
|
2005-06-14 03:55:23 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
unsigned &Reg = ExprMap[N];
|
|
|
|
if (Reg) return Reg;
|
|
|
|
|
2005-04-02 05:59:34 +00:00
|
|
|
switch (N.getOpcode()) {
|
|
|
|
default:
|
2005-03-24 04:41:43 +00:00
|
|
|
Reg = Result = (N.getValueType() != MVT::Other) ?
|
2005-04-02 05:59:34 +00:00
|
|
|
MakeReg(N.getValueType()) : 1;
|
|
|
|
break;
|
2005-05-13 20:29:26 +00:00
|
|
|
case ISD::TAILCALL:
|
2005-04-02 05:59:34 +00:00
|
|
|
case ISD::CALL:
|
2005-03-24 23:35:30 +00:00
|
|
|
// If this is a call instruction, make sure to prepare ALL of the result
|
|
|
|
// values as well as the chain.
|
2005-04-02 05:59:34 +00:00
|
|
|
if (Node->getNumValues() == 1)
|
|
|
|
Reg = Result = 1; // Void call, just a chain.
|
|
|
|
else {
|
2005-03-24 23:35:30 +00:00
|
|
|
Result = MakeReg(Node->getValueType(0));
|
|
|
|
ExprMap[N.getValue(0)] = Result;
|
2005-04-02 05:59:34 +00:00
|
|
|
for (unsigned i = 1, e = N.Val->getNumValues()-1; i != e; ++i)
|
2005-03-24 23:35:30 +00:00
|
|
|
ExprMap[N.getValue(i)] = MakeReg(Node->getValueType(i));
|
2005-04-02 05:59:34 +00:00
|
|
|
ExprMap[SDOperand(Node, Node->getNumValues()-1)] = 1;
|
2005-03-24 23:35:30 +00:00
|
|
|
}
|
2005-04-02 05:59:34 +00:00
|
|
|
break;
|
|
|
|
case ISD::ADD_PARTS:
|
|
|
|
case ISD::SUB_PARTS:
|
|
|
|
case ISD::SHL_PARTS:
|
|
|
|
case ISD::SRL_PARTS:
|
|
|
|
case ISD::SRA_PARTS:
|
|
|
|
Result = MakeReg(Node->getValueType(0));
|
|
|
|
ExprMap[N.getValue(0)] = Result;
|
|
|
|
for (unsigned i = 1, e = N.Val->getNumValues(); i != e; ++i)
|
|
|
|
ExprMap[N.getValue(i)] = MakeReg(Node->getValueType(i));
|
|
|
|
break;
|
2005-03-24 23:35:30 +00:00
|
|
|
}
|
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
switch (opcode) {
|
|
|
|
default:
|
Make FP_TO_UINT Illegal. This allows us to generate significantly better
codegen for FP_TO_UINT by using the legalizer's SELECT variant.
Implement a codegen improvement for SELECT_CC, selecting the false node in
the MBB that feeds the phi node. This allows us to codegen:
void foo(int *a, int b, int c) { int d = (a < b) ? 5 : 9; *a = d; }
as:
_foo:
li r2, 5
cmpw cr0, r4, r3
bgt .LBB_foo_2 ; entry
.LBB_foo_1: ; entry
li r2, 9
.LBB_foo_2: ; entry
stw r2, 0(r3)
blr
insted of:
_foo:
li r2, 5
li r5, 9
cmpw cr0, r4, r3
bgt .LBB_foo_2 ; entry
.LBB_foo_1: ; entry
or r2, r5, r5
.LBB_foo_2: ; entry
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22784 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-14 01:17:16 +00:00
|
|
|
Node->dump(); std::cerr << '\n';
|
|
|
|
assert(0 && "Node not handled!\n");
|
2005-08-26 00:52:45 +00:00
|
|
|
case ISD::BUILTIN_OP_END+PPC::FSEL:
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
|
|
|
Tmp3 = SelectExpr(N.getOperand(2));
|
|
|
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
|
|
|
|
return Result;
|
2005-04-01 22:34:39 +00:00
|
|
|
case ISD::UNDEF:
|
2005-08-24 23:08:16 +00:00
|
|
|
if (Node->getValueType(0) == MVT::i32)
|
|
|
|
BuildMI(BB, PPC::IMPLICIT_DEF_GPR, 0, Result);
|
|
|
|
else
|
|
|
|
BuildMI(BB, PPC::IMPLICIT_DEF_FP, 0, Result);
|
2005-04-01 22:34:39 +00:00
|
|
|
return Result;
|
2005-03-24 04:41:43 +00:00
|
|
|
case ISD::DYNAMIC_STACKALLOC:
|
2005-03-24 06:28:42 +00:00
|
|
|
// Generate both result values. FIXME: Need a better commment here?
|
|
|
|
if (Result != 1)
|
|
|
|
ExprMap[N.getValue(1)] = 1;
|
|
|
|
else
|
|
|
|
Result = ExprMap[N.getValue(0)] = MakeReg(N.getValue(0).getValueType());
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
Select(N.getOperand(0));
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(1));
|
|
|
|
// Subtract size from stack pointer, thereby allocating some space.
|
|
|
|
BuildMI(BB, PPC::SUBF, 2, PPC::R1).addReg(Tmp1).addReg(PPC::R1);
|
|
|
|
// Put a pointer to the space into the result register by copying the SP
|
|
|
|
BuildMI(BB, PPC::OR, 2, Result).addReg(PPC::R1).addReg(PPC::R1);
|
|
|
|
return Result;
|
2005-03-24 04:41:43 +00:00
|
|
|
|
|
|
|
case ISD::ConstantPool:
|
2005-03-28 22:28:37 +00:00
|
|
|
Tmp1 = cast<ConstantPoolSDNode>(N)->getIndex();
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp2 = MakeIntReg();
|
2005-07-21 20:44:43 +00:00
|
|
|
if (PICEnabled)
|
|
|
|
BuildMI(BB, PPC::ADDIS, 2, Tmp2).addReg(getGlobalBaseReg())
|
|
|
|
.addConstantPoolIndex(Tmp1);
|
|
|
|
else
|
|
|
|
BuildMI(BB, PPC::LIS, 1, Tmp2).addConstantPoolIndex(Tmp1);
|
2005-03-28 22:28:37 +00:00
|
|
|
BuildMI(BB, PPC::LA, 2, Result).addReg(Tmp2).addConstantPoolIndex(Tmp1);
|
|
|
|
return Result;
|
2005-03-24 04:41:43 +00:00
|
|
|
|
|
|
|
case ISD::FrameIndex:
|
2005-03-29 00:03:27 +00:00
|
|
|
Tmp1 = cast<FrameIndexSDNode>(N)->getIndex();
|
2005-03-30 02:23:08 +00:00
|
|
|
addFrameReference(BuildMI(BB, PPC::ADDI, 2, Result), (int)Tmp1, 0, false);
|
2005-03-29 00:03:27 +00:00
|
|
|
return Result;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 23:35:30 +00:00
|
|
|
case ISD::GlobalAddress: {
|
|
|
|
GlobalValue *GV = cast<GlobalAddressSDNode>(N)->getGlobal();
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp1 = MakeIntReg();
|
2005-07-21 20:44:43 +00:00
|
|
|
if (PICEnabled)
|
|
|
|
BuildMI(BB, PPC::ADDIS, 2, Tmp1).addReg(getGlobalBaseReg())
|
|
|
|
.addGlobalAddress(GV);
|
|
|
|
else
|
2005-07-28 04:42:11 +00:00
|
|
|
BuildMI(BB, PPC::LIS, 1, Tmp1).addGlobalAddress(GV);
|
2005-03-24 23:35:30 +00:00
|
|
|
if (GV->hasWeakLinkage() || GV->isExternal()) {
|
|
|
|
BuildMI(BB, PPC::LWZ, 2, Result).addGlobalAddress(GV).addReg(Tmp1);
|
|
|
|
} else {
|
|
|
|
BuildMI(BB, PPC::LA, 2, Result).addReg(Tmp1).addGlobalAddress(GV);
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2005-03-24 06:28:42 +00:00
|
|
|
case ISD::LOAD:
|
2005-03-24 04:41:43 +00:00
|
|
|
case ISD::EXTLOAD:
|
|
|
|
case ISD::ZEXTLOAD:
|
2005-03-24 23:35:30 +00:00
|
|
|
case ISD::SEXTLOAD: {
|
2005-03-28 19:36:43 +00:00
|
|
|
MVT::ValueType TypeBeingLoaded = (ISD::LOAD == opcode) ?
|
2005-07-10 01:56:13 +00:00
|
|
|
Node->getValueType(0) : cast<VTSDNode>(Node->getOperand(3))->getVT();
|
2005-03-31 00:15:26 +00:00
|
|
|
bool sext = (ISD::SEXTLOAD == opcode);
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 06:28:42 +00:00
|
|
|
// Make sure we generate both values.
|
|
|
|
if (Result != 1)
|
|
|
|
ExprMap[N.getValue(1)] = 1; // Generate the token
|
|
|
|
else
|
|
|
|
Result = ExprMap[N.getValue(0)] = MakeReg(N.getValue(0).getValueType());
|
|
|
|
|
|
|
|
SDOperand Chain = N.getOperand(0);
|
|
|
|
SDOperand Address = N.getOperand(1);
|
|
|
|
Select(Chain);
|
|
|
|
|
2005-03-28 19:36:43 +00:00
|
|
|
switch (TypeBeingLoaded) {
|
2005-03-31 00:15:26 +00:00
|
|
|
default: Node->dump(); assert(0 && "Cannot load this type!");
|
2005-03-28 19:36:43 +00:00
|
|
|
case MVT::i1: Opc = PPC::LBZ; break;
|
|
|
|
case MVT::i8: Opc = PPC::LBZ; break;
|
|
|
|
case MVT::i16: Opc = sext ? PPC::LHA : PPC::LHZ; break;
|
|
|
|
case MVT::i32: Opc = PPC::LWZ; break;
|
2005-03-31 00:15:26 +00:00
|
|
|
case MVT::f32: Opc = PPC::LFS; break;
|
|
|
|
case MVT::f64: Opc = PPC::LFD; break;
|
2005-03-24 06:28:42 +00:00
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-31 00:15:26 +00:00
|
|
|
if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Address)) {
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp1 = MakeIntReg();
|
2005-03-31 00:15:26 +00:00
|
|
|
int CPI = CP->getIndex();
|
2005-07-21 20:44:43 +00:00
|
|
|
if (PICEnabled)
|
|
|
|
BuildMI(BB, PPC::ADDIS, 2, Tmp1).addReg(getGlobalBaseReg())
|
|
|
|
.addConstantPoolIndex(CPI);
|
|
|
|
else
|
|
|
|
BuildMI(BB, PPC::LIS, 1, Tmp1).addConstantPoolIndex(CPI);
|
2005-03-31 00:15:26 +00:00
|
|
|
BuildMI(BB, Opc, 2, Result).addConstantPoolIndex(CPI).addReg(Tmp1);
|
2005-07-21 20:44:43 +00:00
|
|
|
} else if (Address.getOpcode() == ISD::FrameIndex) {
|
2005-03-30 02:23:08 +00:00
|
|
|
Tmp1 = cast<FrameIndexSDNode>(Address)->getIndex();
|
|
|
|
addFrameReference(BuildMI(BB, Opc, 2, Result), (int)Tmp1);
|
2005-03-24 06:28:42 +00:00
|
|
|
} else {
|
|
|
|
int offset;
|
Fold constant adds into loads and stores to frame indices.
For the following code:
double %ext(int %A.0__, long %A.1__) {
%A_addr = alloca %typedef.DComplex ; <%typedef.DComplex*> [#uses=2]
%tmp.1 = cast %typedef.DComplex* %A_addr to int* ; <int*> [#uses=1]
store int %A.0__, int* %tmp.1
%tmp.2 = getelementptr %typedef.DComplex* %A_addr, int 0, uint 1 ; <double*> [#uses=2]
%tmp.3 = cast double* %tmp.2 to long* ; <long*> [#uses=1]
store long %A.1__, long* %tmp.3
%tmp.5 = load double* %tmp.2 ; <double> [#uses=1]
ret double %tmp.5
}
We now generate:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
stw r4, -8(r1)
stw r5, -4(r1)
lfd f1, -8(r1)
blr
Instead of:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
addi r2, r1, -12
stw r4, 4(r2)
stw r5, 8(r2)
lfd f1, 4(r2)
blr
This also fires hundreds of times on MultiSource.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22533 91177308-0d34-0410-b5e6-96231b3b80d8
2005-07-28 03:02:05 +00:00
|
|
|
switch(SelectAddr(Address, Tmp1, offset)) {
|
|
|
|
default: assert(0 && "Unhandled return value from SelectAddr");
|
|
|
|
case 0: // imm offset, no frame, no index
|
|
|
|
BuildMI(BB, Opc, 2, Result).addSImm(offset).addReg(Tmp1);
|
|
|
|
break;
|
|
|
|
case 1: // imm offset + frame index
|
|
|
|
addFrameReference(BuildMI(BB, Opc, 2, Result), (int)Tmp1, offset);
|
|
|
|
break;
|
|
|
|
case 2: // base+index addressing
|
2005-04-01 04:45:11 +00:00
|
|
|
Opc = IndexedOpForOp(Opc);
|
|
|
|
BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(offset);
|
Fold constant adds into loads and stores to frame indices.
For the following code:
double %ext(int %A.0__, long %A.1__) {
%A_addr = alloca %typedef.DComplex ; <%typedef.DComplex*> [#uses=2]
%tmp.1 = cast %typedef.DComplex* %A_addr to int* ; <int*> [#uses=1]
store int %A.0__, int* %tmp.1
%tmp.2 = getelementptr %typedef.DComplex* %A_addr, int 0, uint 1 ; <double*> [#uses=2]
%tmp.3 = cast double* %tmp.2 to long* ; <long*> [#uses=1]
store long %A.1__, long* %tmp.3
%tmp.5 = load double* %tmp.2 ; <double> [#uses=1]
ret double %tmp.5
}
We now generate:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
stw r4, -8(r1)
stw r5, -4(r1)
lfd f1, -8(r1)
blr
Instead of:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
addi r2, r1, -12
stw r4, 4(r2)
stw r5, 8(r2)
lfd f1, 4(r2)
blr
This also fires hundreds of times on MultiSource.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22533 91177308-0d34-0410-b5e6-96231b3b80d8
2005-07-28 03:02:05 +00:00
|
|
|
break;
|
2005-08-08 22:22:56 +00:00
|
|
|
case 3: {
|
|
|
|
GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Address);
|
|
|
|
GlobalValue *GV = GN->getGlobal();
|
|
|
|
BuildMI(BB, Opc, 2, Result).addGlobalAddress(GV).addReg(Tmp1);
|
|
|
|
}
|
2005-04-01 04:45:11 +00:00
|
|
|
}
|
2005-03-24 06:28:42 +00:00
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-05-13 20:29:26 +00:00
|
|
|
case ISD::TAILCALL:
|
2005-03-24 23:35:30 +00:00
|
|
|
case ISD::CALL: {
|
2005-04-01 22:34:39 +00:00
|
|
|
unsigned GPR_idx = 0, FPR_idx = 0;
|
2005-04-21 23:30:14 +00:00
|
|
|
static const unsigned GPR[] = {
|
2005-04-01 22:34:39 +00:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
2005-03-24 23:35:30 +00:00
|
|
|
// Lower the chain for this call.
|
|
|
|
Select(N.getOperand(0));
|
|
|
|
ExprMap[N.getValue(Node->getNumValues()-1)] = 1;
|
|
|
|
|
2005-04-04 22:17:48 +00:00
|
|
|
MachineInstr *CallMI;
|
|
|
|
// Emit the correct call instruction based on the type of symbol called.
|
2005-04-21 23:30:14 +00:00
|
|
|
if (GlobalAddressSDNode *GASD =
|
2005-04-04 22:17:48 +00:00
|
|
|
dyn_cast<GlobalAddressSDNode>(N.getOperand(1))) {
|
2005-04-21 23:30:14 +00:00
|
|
|
CallMI = BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(GASD->getGlobal(),
|
2005-04-04 22:17:48 +00:00
|
|
|
true);
|
2005-04-21 23:30:14 +00:00
|
|
|
} else if (ExternalSymbolSDNode *ESSDN =
|
2005-04-04 22:17:48 +00:00
|
|
|
dyn_cast<ExternalSymbolSDNode>(N.getOperand(1))) {
|
2005-04-21 23:30:14 +00:00
|
|
|
CallMI = BuildMI(PPC::CALLpcrel, 1).addExternalSymbol(ESSDN->getSymbol(),
|
2005-04-04 22:17:48 +00:00
|
|
|
true);
|
|
|
|
} else {
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(1));
|
2005-08-24 22:21:47 +00:00
|
|
|
BuildMI(BB, PPC::MTCTR, 1).addReg(Tmp1);
|
2005-04-04 22:17:48 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, PPC::R12).addReg(Tmp1).addReg(Tmp1);
|
|
|
|
CallMI = BuildMI(PPC::CALLindirect, 3).addImm(20).addImm(0)
|
|
|
|
.addReg(PPC::R12);
|
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-04-01 22:34:39 +00:00
|
|
|
// Load the register args to virtual regs
|
|
|
|
std::vector<unsigned> ArgVR;
|
2005-03-31 00:15:26 +00:00
|
|
|
for(int i = 2, e = Node->getNumOperands(); i < e; ++i)
|
2005-04-01 22:34:39 +00:00
|
|
|
ArgVR.push_back(SelectExpr(N.getOperand(i)));
|
|
|
|
|
|
|
|
// Copy the virtual registers into the appropriate argument register
|
|
|
|
for(int i = 0, e = ArgVR.size(); i < e; ++i) {
|
|
|
|
switch(N.getOperand(i+2).getValueType()) {
|
|
|
|
default: Node->dump(); assert(0 && "Unknown value type for call");
|
|
|
|
case MVT::i32:
|
|
|
|
assert(GPR_idx < 8 && "Too many int args");
|
2005-04-04 22:17:48 +00:00
|
|
|
if (N.getOperand(i+2).getOpcode() != ISD::UNDEF) {
|
2005-04-01 22:34:39 +00:00
|
|
|
BuildMI(BB, PPC::OR,2,GPR[GPR_idx]).addReg(ArgVR[i]).addReg(ArgVR[i]);
|
2005-04-04 22:17:48 +00:00
|
|
|
CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use);
|
|
|
|
}
|
2005-04-01 22:34:39 +00:00
|
|
|
++GPR_idx;
|
|
|
|
break;
|
|
|
|
case MVT::f64:
|
|
|
|
case MVT::f32:
|
|
|
|
assert(FPR_idx < 13 && "Too many fp args");
|
|
|
|
BuildMI(BB, PPC::FMR, 1, FPR[FPR_idx]).addReg(ArgVR[i]);
|
2005-04-04 22:17:48 +00:00
|
|
|
CallMI->addRegOperand(FPR[FPR_idx], MachineOperand::Use);
|
2005-04-01 22:34:39 +00:00
|
|
|
++FPR_idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-04-04 22:17:48 +00:00
|
|
|
// Put the call instruction in the correct place in the MachineBasicBlock
|
|
|
|
BB->push_back(CallMI);
|
2005-03-24 23:35:30 +00:00
|
|
|
|
|
|
|
switch (Node->getValueType(0)) {
|
|
|
|
default: assert(0 && "Unknown value type for call result!");
|
|
|
|
case MVT::Other: return 1;
|
|
|
|
case MVT::i32:
|
2005-04-04 06:52:38 +00:00
|
|
|
if (Node->getValueType(1) == MVT::i32) {
|
|
|
|
BuildMI(BB, PPC::OR, 2, Result+1).addReg(PPC::R3).addReg(PPC::R3);
|
|
|
|
BuildMI(BB, PPC::OR, 2, Result).addReg(PPC::R4).addReg(PPC::R4);
|
|
|
|
} else {
|
|
|
|
BuildMI(BB, PPC::OR, 2, Result).addReg(PPC::R3).addReg(PPC::R3);
|
|
|
|
}
|
2005-03-24 23:35:30 +00:00
|
|
|
break;
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64:
|
|
|
|
BuildMI(BB, PPC::FMR, 1, Result).addReg(PPC::F1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return Result+N.ResNo;
|
|
|
|
}
|
2005-03-24 04:41:43 +00:00
|
|
|
|
|
|
|
case ISD::SIGN_EXTEND:
|
|
|
|
case ISD::SIGN_EXTEND_INREG:
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-07-10 01:56:13 +00:00
|
|
|
switch(cast<VTSDNode>(Node->getOperand(1))->getVT()) {
|
2005-03-28 19:36:43 +00:00
|
|
|
default: Node->dump(); assert(0 && "Unhandled SIGN_EXTEND type"); break;
|
2005-04-11 06:34:10 +00:00
|
|
|
case MVT::i16:
|
2005-04-21 23:30:14 +00:00
|
|
|
BuildMI(BB, PPC::EXTSH, 1, Result).addReg(Tmp1);
|
2005-03-28 19:36:43 +00:00
|
|
|
break;
|
2005-04-11 06:34:10 +00:00
|
|
|
case MVT::i8:
|
2005-04-21 23:30:14 +00:00
|
|
|
BuildMI(BB, PPC::EXTSB, 1, Result).addReg(Tmp1);
|
2005-03-28 19:36:43 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-03-24 04:41:43 +00:00
|
|
|
return Result;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
case ISD::CopyFromReg:
|
2005-07-19 16:51:05 +00:00
|
|
|
DestType = N.getValue(0).getValueType();
|
2005-03-24 04:41:43 +00:00
|
|
|
if (Result == 1)
|
2005-07-19 16:51:05 +00:00
|
|
|
Result = ExprMap[N.getValue(0)] = MakeReg(DestType);
|
2005-08-16 21:58:15 +00:00
|
|
|
Tmp1 = dyn_cast<RegisterSDNode>(Node->getOperand(1))->getReg();
|
2005-07-19 16:51:05 +00:00
|
|
|
if (MVT::isInteger(DestType))
|
|
|
|
BuildMI(BB, PPC::OR, 2, Result).addReg(Tmp1).addReg(Tmp1);
|
|
|
|
else
|
|
|
|
BuildMI(BB, PPC::FMR, 1, Result).addReg(Tmp1);
|
2005-03-24 04:41:43 +00:00
|
|
|
return Result;
|
|
|
|
|
|
|
|
case ISD::SHL:
|
2005-08-11 17:56:50 +00:00
|
|
|
if (isIntImmediate(N.getOperand(1), Tmp2)) {
|
2005-08-11 21:59:23 +00:00
|
|
|
unsigned SH, MB, ME;
|
|
|
|
if (isOpcWithIntImmediate(N.getOperand(0), ISD::AND, Tmp3) &&
|
|
|
|
isRotateAndMask(ISD::SHL, Tmp2, Tmp3, true, SH, MB, ME)) {
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm(SH)
|
|
|
|
.addImm(MB).addImm(ME);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-08-11 17:56:50 +00:00
|
|
|
Tmp2 &= 0x1F;
|
2005-03-29 21:54:38 +00:00
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm(Tmp2).addImm(0)
|
2005-03-24 06:28:42 +00:00
|
|
|
.addImm(31-Tmp2);
|
|
|
|
} else {
|
2005-08-11 21:59:23 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-04-13 22:14:14 +00:00
|
|
|
Tmp2 = FoldIfWideZeroExtend(N.getOperand(1));
|
2005-03-24 06:28:42 +00:00
|
|
|
BuildMI(BB, PPC::SLW, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
}
|
|
|
|
return Result;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
case ISD::SRL:
|
2005-08-11 17:56:50 +00:00
|
|
|
if (isIntImmediate(N.getOperand(1), Tmp2)) {
|
2005-08-11 21:59:23 +00:00
|
|
|
unsigned SH, MB, ME;
|
|
|
|
if (isOpcWithIntImmediate(N.getOperand(0), ISD::AND, Tmp3) &&
|
|
|
|
isRotateAndMask(ISD::SRL, Tmp2, Tmp3, true, SH, MB, ME)) {
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm(SH)
|
|
|
|
.addImm(MB).addImm(ME);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-08-11 17:56:50 +00:00
|
|
|
Tmp2 &= 0x1F;
|
2005-03-29 21:54:38 +00:00
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm(32-Tmp2)
|
2005-03-24 06:28:42 +00:00
|
|
|
.addImm(Tmp2).addImm(31);
|
|
|
|
} else {
|
2005-08-11 21:59:23 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-04-13 22:14:14 +00:00
|
|
|
Tmp2 = FoldIfWideZeroExtend(N.getOperand(1));
|
2005-03-24 06:28:42 +00:00
|
|
|
BuildMI(BB, PPC::SRW, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
}
|
|
|
|
return Result;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 06:28:42 +00:00
|
|
|
case ISD::SRA:
|
2005-08-11 17:56:50 +00:00
|
|
|
if (isIntImmediate(N.getOperand(1), Tmp2)) {
|
2005-08-11 21:59:23 +00:00
|
|
|
unsigned SH, MB, ME;
|
|
|
|
if (isOpcWithIntImmediate(N.getOperand(0), ISD::AND, Tmp3) &&
|
|
|
|
isRotateAndMask(ISD::SRA, Tmp2, Tmp3, true, SH, MB, ME)) {
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm(SH)
|
|
|
|
.addImm(MB).addImm(ME);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-08-11 17:56:50 +00:00
|
|
|
Tmp2 &= 0x1F;
|
2005-03-24 06:28:42 +00:00
|
|
|
BuildMI(BB, PPC::SRAWI, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
|
|
|
} else {
|
2005-08-11 21:59:23 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-04-13 22:14:14 +00:00
|
|
|
Tmp2 = FoldIfWideZeroExtend(N.getOperand(1));
|
2005-03-24 06:28:42 +00:00
|
|
|
BuildMI(BB, PPC::SRAW, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
}
|
|
|
|
return Result;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-05-11 23:43:56 +00:00
|
|
|
case ISD::CTLZ:
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
BuildMI(BB, PPC::CNTLZW, 1, Result).addReg(Tmp1);
|
|
|
|
return Result;
|
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
case ISD::ADD:
|
2005-07-19 16:51:05 +00:00
|
|
|
if (!MVT::isInteger(DestType)) {
|
|
|
|
if (!NoExcessFPPrecision && N.getOperand(0).getOpcode() == ISD::MUL &&
|
|
|
|
N.getOperand(0).Val->hasOneUse()) {
|
|
|
|
++FusedFP; // Statistic
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(0).getOperand(1));
|
|
|
|
Tmp3 = SelectExpr(N.getOperand(1));
|
|
|
|
Opc = DestType == MVT::f64 ? PPC::FMADD : PPC::FMADDS;
|
|
|
|
BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
if (!NoExcessFPPrecision && N.getOperand(1).getOpcode() == ISD::MUL &&
|
|
|
|
N.getOperand(1).Val->hasOneUse()) {
|
|
|
|
++FusedFP; // Statistic
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(1).getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1).getOperand(1));
|
|
|
|
Tmp3 = SelectExpr(N.getOperand(0));
|
|
|
|
Opc = DestType == MVT::f64 ? PPC::FMADD : PPC::FMADDS;
|
|
|
|
BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
Opc = DestType == MVT::f64 ? PPC::FADD : PPC::FADDS;
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
|
|
|
BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
return Result;
|
|
|
|
}
|
2005-08-10 18:11:33 +00:00
|
|
|
if (SelectIntImmediateExpr(N, Result, PPC::ADDIS, PPC::ADDI, true))
|
|
|
|
return Result;
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-08-08 21:21:03 +00:00
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
|
|
|
BuildMI(BB, PPC::ADD, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
2005-03-24 04:41:43 +00:00
|
|
|
return Result;
|
2005-03-24 23:35:30 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
case ISD::AND:
|
2005-08-09 18:29:55 +00:00
|
|
|
if (isIntImmediate(N.getOperand(1), Tmp2)) {
|
2005-08-08 21:24:57 +00:00
|
|
|
if (isShiftedMask_32(Tmp2) || isShiftedMask_32(~Tmp2)) {
|
|
|
|
unsigned SH, MB, ME;
|
|
|
|
Opc = Recording ? PPC::RLWINMo : PPC::RLWINM;
|
|
|
|
unsigned OprOpc;
|
|
|
|
if (isOprShiftImm(N.getOperand(0), OprOpc, Tmp3) &&
|
|
|
|
isRotateAndMask(OprOpc, Tmp3, Tmp2, false, SH, MB, ME)) {
|
2005-05-11 23:43:56 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
|
2005-08-08 21:24:57 +00:00
|
|
|
} else {
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
isRunOfOnes(Tmp2, MB, ME);
|
|
|
|
SH = 0;
|
2005-05-11 23:43:56 +00:00
|
|
|
}
|
2005-08-08 21:24:57 +00:00
|
|
|
BuildMI(BB, Opc, 4, Result).addReg(Tmp1).addImm(SH)
|
|
|
|
.addImm(MB).addImm(ME);
|
|
|
|
RecordSuccess = true;
|
|
|
|
return Result;
|
|
|
|
} else if (isUInt16(Tmp2)) {
|
|
|
|
Tmp2 = Lo16(Tmp2);
|
2005-05-09 17:39:48 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-04-06 23:51:40 +00:00
|
|
|
BuildMI(BB, PPC::ANDIo, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
2005-08-08 21:24:57 +00:00
|
|
|
RecordSuccess = true;
|
|
|
|
return Result;
|
|
|
|
} else if (isUInt16(Tmp2)) {
|
|
|
|
Tmp2 = Hi16(Tmp2);
|
2005-05-09 17:39:48 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-04-06 23:51:40 +00:00
|
|
|
BuildMI(BB, PPC::ANDISo, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
2005-08-08 21:24:57 +00:00
|
|
|
RecordSuccess = true;
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
}
|
2005-08-12 23:38:02 +00:00
|
|
|
if (isOprNot(N.getOperand(1))) {
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1).getOperand(0));
|
|
|
|
BuildMI(BB, PPC::ANDC, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
RecordSuccess = false;
|
|
|
|
return Result;
|
|
|
|
}
|
2005-08-08 21:24:57 +00:00
|
|
|
if (isOprNot(N.getOperand(0))) {
|
2005-08-12 23:38:02 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(1));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
BuildMI(BB, PPC::ANDC, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
2005-08-08 21:24:57 +00:00
|
|
|
RecordSuccess = false;
|
|
|
|
return Result;
|
2005-04-06 23:51:40 +00:00
|
|
|
}
|
2005-08-08 21:24:57 +00:00
|
|
|
// emit a regular and
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
|
|
|
Opc = Recording ? PPC::ANDo : PPC::AND;
|
|
|
|
BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
2005-04-11 06:34:10 +00:00
|
|
|
RecordSuccess = true;
|
2005-04-06 23:51:40 +00:00
|
|
|
return Result;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
case ISD::OR:
|
2005-04-06 23:51:40 +00:00
|
|
|
if (SelectBitfieldInsert(N, Result))
|
|
|
|
return Result;
|
2005-08-10 18:11:33 +00:00
|
|
|
if (SelectIntImmediateExpr(N, Result, PPC::ORIS, PPC::ORI))
|
|
|
|
return Result;
|
2005-08-12 23:38:02 +00:00
|
|
|
if (isOprNot(N.getOperand(1))) {
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1).getOperand(0));
|
|
|
|
BuildMI(BB, PPC::ORC, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
RecordSuccess = false;
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
if (isOprNot(N.getOperand(0))) {
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(1));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
BuildMI(BB, PPC::ORC, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
RecordSuccess = false;
|
|
|
|
return Result;
|
|
|
|
}
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
// emit regular or
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
|
|
|
Opc = Recording ? PPC::ORo : PPC::OR;
|
|
|
|
RecordSuccess = true;
|
|
|
|
BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
2005-03-24 04:41:43 +00:00
|
|
|
return Result;
|
2005-03-24 23:35:30 +00:00
|
|
|
|
2005-04-03 11:20:20 +00:00
|
|
|
case ISD::XOR: {
|
|
|
|
// Check for EQV: xor, (xor a, -1), b
|
2005-08-10 16:35:46 +00:00
|
|
|
if (isOprNot(N.getOperand(0))) {
|
2005-04-03 11:20:20 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
|
|
|
BuildMI(BB, PPC::EQV, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
return Result;
|
|
|
|
}
|
2005-04-21 21:09:11 +00:00
|
|
|
// Check for NOT, NOR, EQV, and NAND: xor (copy, or, xor, and), -1
|
2005-08-08 21:30:29 +00:00
|
|
|
if (isOprNot(N)) {
|
2005-04-03 11:20:20 +00:00
|
|
|
switch(N.getOperand(0).getOpcode()) {
|
|
|
|
case ISD::OR:
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(0).getOperand(1));
|
|
|
|
BuildMI(BB, PPC::NOR, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
break;
|
|
|
|
case ISD::AND:
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(0).getOperand(1));
|
|
|
|
BuildMI(BB, PPC::NAND, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
break;
|
2005-04-21 21:09:11 +00:00
|
|
|
case ISD::XOR:
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(0).getOperand(1));
|
|
|
|
BuildMI(BB, PPC::EQV, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
break;
|
2005-04-03 11:20:20 +00:00
|
|
|
default:
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
BuildMI(BB, PPC::NOR, 2, Result).addReg(Tmp1).addReg(Tmp1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
2005-08-10 18:11:33 +00:00
|
|
|
if (SelectIntImmediateExpr(N, Result, PPC::XORIS, PPC::XORI))
|
|
|
|
return Result;
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
// emit regular xor
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
|
|
|
BuildMI(BB, PPC::XOR, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
2005-04-03 11:20:20 +00:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2005-08-08 21:30:29 +00:00
|
|
|
case ISD::SUB:
|
2005-07-19 16:51:05 +00:00
|
|
|
if (!MVT::isInteger(DestType)) {
|
|
|
|
if (!NoExcessFPPrecision && N.getOperand(0).getOpcode() == ISD::MUL &&
|
|
|
|
N.getOperand(0).Val->hasOneUse()) {
|
|
|
|
++FusedFP; // Statistic
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(0).getOperand(1));
|
|
|
|
Tmp3 = SelectExpr(N.getOperand(1));
|
|
|
|
Opc = DestType == MVT::f64 ? PPC::FMSUB : PPC::FMSUBS;
|
|
|
|
BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
if (!NoExcessFPPrecision && N.getOperand(1).getOpcode() == ISD::MUL &&
|
|
|
|
N.getOperand(1).Val->hasOneUse()) {
|
|
|
|
++FusedFP; // Statistic
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(1).getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1).getOperand(1));
|
|
|
|
Tmp3 = SelectExpr(N.getOperand(0));
|
|
|
|
Opc = DestType == MVT::f64 ? PPC::FNMSUB : PPC::FNMSUBS;
|
|
|
|
BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
Opc = DestType == MVT::f64 ? PPC::FSUB : PPC::FSUBS;
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
|
|
|
BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
return Result;
|
|
|
|
}
|
2005-08-09 18:29:55 +00:00
|
|
|
if (isIntImmediate(N.getOperand(0), Tmp1) && isInt16(Tmp1)) {
|
2005-08-10 18:11:33 +00:00
|
|
|
Tmp1 = Lo16(Tmp1);
|
2005-05-11 23:43:56 +00:00
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
2005-08-24 04:59:21 +00:00
|
|
|
if (0 == Tmp1)
|
|
|
|
BuildMI(BB, PPC::NEG, 1, Result).addReg(Tmp2);
|
|
|
|
else
|
|
|
|
BuildMI(BB, PPC::SUBFIC, 2, Result).addReg(Tmp2).addSImm(Tmp1);
|
2005-08-08 21:30:29 +00:00
|
|
|
return Result;
|
2005-08-10 18:11:33 +00:00
|
|
|
}
|
|
|
|
if (SelectIntImmediateExpr(N, Result, PPC::ADDIS, PPC::ADDI, true, true))
|
1. Refactored handling of integer immediate values for add, or, xor and sub.
New routine: ISel::SelectIntImmediateExpr
2. Now checking use counts of large constants. If use count is > 2 then drop
thru so that the constant gets loaded into a register.
Source:
int %test1(int %a) {
entry:
%tmp.1 = add int %a, 123456789 ; <int> [#uses=1]
%tmp.2 = or int %tmp.1, 123456789 ; <int> [#uses=1]
%tmp.3 = xor int %tmp.2, 123456789 ; <int> [#uses=1]
%tmp.4 = sub int %tmp.3, -123456789 ; <int> [#uses=1]
ret int %tmp.4
}
Did Emit:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
addi r2, r3, -13035
addis r2, r2, 1884
ori r2, r2, 52501
oris r2, r2, 1883
xori r2, r2, 52501
xoris r2, r2, 1883
addi r2, r2, 52501
addis r3, r2, 1883
blr
Now Emits:
.machine ppc970
.text
.align 2
.globl _test1
_test1:
.LBB_test1_0: ; entry
lis r2, 1883
ori r2, r2, 52501
add r3, r3, r2
or r3, r3, r2
xor r3, r3, r2
add r3, r3, r2
blr
Patch by Jim Laskey!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22749 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-10 16:34:52 +00:00
|
|
|
return Result;
|
2005-08-08 21:30:29 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
|
|
|
BuildMI(BB, PPC::SUBF, 2, Result).addReg(Tmp2).addReg(Tmp1);
|
2005-03-24 23:35:30 +00:00
|
|
|
return Result;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 06:28:42 +00:00
|
|
|
case ISD::MUL:
|
2005-03-24 23:35:30 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-08-09 18:29:55 +00:00
|
|
|
if (isIntImmediate(N.getOperand(1), Tmp2) && isInt16(Tmp2)) {
|
2005-08-08 21:33:23 +00:00
|
|
|
Tmp2 = Lo16(Tmp2);
|
2005-03-26 01:28:53 +00:00
|
|
|
BuildMI(BB, PPC::MULLI, 2, Result).addReg(Tmp1).addSImm(Tmp2);
|
2005-08-08 21:33:23 +00:00
|
|
|
} else {
|
2005-03-26 01:28:53 +00:00
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
2005-07-19 16:51:05 +00:00
|
|
|
switch (DestType) {
|
|
|
|
default: assert(0 && "Unknown type to ISD::MUL"); break;
|
|
|
|
case MVT::i32: Opc = PPC::MULLW; break;
|
|
|
|
case MVT::f32: Opc = PPC::FMULS; break;
|
|
|
|
case MVT::f64: Opc = PPC::FMUL; break;
|
|
|
|
}
|
|
|
|
BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
2005-03-26 01:28:53 +00:00
|
|
|
}
|
2005-03-24 23:35:30 +00:00
|
|
|
return Result;
|
|
|
|
|
2005-04-06 00:25:27 +00:00
|
|
|
case ISD::MULHS:
|
|
|
|
case ISD::MULHU:
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
|
|
|
Opc = (ISD::MULHU == opcode) ? PPC::MULHWU : PPC::MULHW;
|
|
|
|
BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
return Result;
|
|
|
|
|
2005-03-29 00:03:27 +00:00
|
|
|
case ISD::SDIV:
|
2005-08-09 18:29:55 +00:00
|
|
|
if (isIntImmediate(N.getOperand(1), Tmp3)) {
|
2005-08-08 21:33:23 +00:00
|
|
|
if ((signed)Tmp3 > 0 && isPowerOf2_32(Tmp3)) {
|
|
|
|
Tmp3 = Log2_32(Tmp3);
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp1 = MakeIntReg();
|
2005-08-08 21:33:23 +00:00
|
|
|
Tmp2 = SelectExpr(N.getOperand(0));
|
|
|
|
BuildMI(BB, PPC::SRAWI, 2, Tmp1).addReg(Tmp2).addImm(Tmp3);
|
|
|
|
BuildMI(BB, PPC::ADDZE, 1, Result).addReg(Tmp1);
|
|
|
|
return Result;
|
|
|
|
} else if ((signed)Tmp3 < 0 && isPowerOf2_32(-Tmp3)) {
|
|
|
|
Tmp3 = Log2_32(-Tmp3);
|
2005-08-09 18:08:41 +00:00
|
|
|
Tmp2 = SelectExpr(N.getOperand(0));
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp1 = MakeIntReg();
|
|
|
|
unsigned Tmp4 = MakeIntReg();
|
2005-08-08 21:33:23 +00:00
|
|
|
BuildMI(BB, PPC::SRAWI, 2, Tmp1).addReg(Tmp2).addImm(Tmp3);
|
2005-04-12 00:10:02 +00:00
|
|
|
BuildMI(BB, PPC::ADDZE, 1, Tmp4).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::NEG, 1, Result).addReg(Tmp4);
|
2005-08-08 21:33:23 +00:00
|
|
|
return Result;
|
2005-08-25 22:03:50 +00:00
|
|
|
} else if (Tmp3) {
|
|
|
|
ExprMap.erase(N);
|
|
|
|
return SelectExpr(BuildSDIVSequence(N));
|
2005-04-12 00:10:02 +00:00
|
|
|
}
|
2005-08-08 21:33:23 +00:00
|
|
|
}
|
|
|
|
// fall thru
|
|
|
|
case ISD::UDIV:
|
2005-04-06 00:25:27 +00:00
|
|
|
// If this is a divide by constant, we can emit code using some magic
|
|
|
|
// constants to implement it as a multiply instead.
|
2005-08-25 23:19:58 +00:00
|
|
|
if (isIntImmediate(N.getOperand(1), Tmp3) && Tmp3) {
|
2005-08-25 22:03:50 +00:00
|
|
|
ExprMap.erase(N);
|
|
|
|
return SelectExpr(BuildUDIVSequence(N));
|
2005-07-27 06:12:32 +00:00
|
|
|
}
|
2005-03-29 00:03:27 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
2005-07-19 16:51:05 +00:00
|
|
|
switch (DestType) {
|
2005-08-25 22:03:50 +00:00
|
|
|
default: assert(0 && "Unknown type to ISD::DIV"); break;
|
2005-07-19 16:51:05 +00:00
|
|
|
case MVT::i32: Opc = (ISD::UDIV == opcode) ? PPC::DIVWU : PPC::DIVW; break;
|
|
|
|
case MVT::f32: Opc = PPC::FDIVS; break;
|
|
|
|
case MVT::f64: Opc = PPC::FDIV; break;
|
|
|
|
}
|
2005-03-29 00:03:27 +00:00
|
|
|
BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
return Result;
|
|
|
|
|
2005-03-24 23:35:30 +00:00
|
|
|
case ISD::ADD_PARTS:
|
2005-03-28 22:28:37 +00:00
|
|
|
case ISD::SUB_PARTS: {
|
|
|
|
assert(N.getNumOperands() == 4 && N.getValueType() == MVT::i32 &&
|
|
|
|
"Not an i64 add/sub!");
|
Implement a couple improvements:
Remove dead code in ISD::Constant handling
Add support for add long, imm16
We now codegen 'long long foo(long long a) { return ++a; }'
as:
addic r4, r4, 1
addze r3, r3
blr
instead of:
li r2, 1
li r5, 0
addc r2, r4, r2
adde r3, r3, r5
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22811 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-17 00:20:08 +00:00
|
|
|
unsigned Tmp4 = 0;
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
|
|
|
|
2005-03-28 22:28:37 +00:00
|
|
|
if (N.getOpcode() == ISD::ADD_PARTS) {
|
2005-08-25 23:19:58 +00:00
|
|
|
bool ME, ZE;
|
|
|
|
if (isIntImmediate(N.getOperand(3), Tmp3)) {
|
|
|
|
ME = (signed)Tmp3 == -1;
|
|
|
|
ZE = Tmp3 == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ZE && !ME)
|
|
|
|
Tmp4 = SelectExpr(N.getOperand(3));
|
|
|
|
|
|
|
|
if (isIntImmediate(N.getOperand(2), Tmp3) &&
|
|
|
|
((signed)Tmp3 >= -32768 || (signed)Tmp3 < 32768)) {
|
|
|
|
// Codegen the low 32 bits of the add. Interestingly, there is no
|
|
|
|
// shifted form of add immediate carrying.
|
Implement a couple improvements:
Remove dead code in ISD::Constant handling
Add support for add long, imm16
We now codegen 'long long foo(long long a) { return ++a; }'
as:
addic r4, r4, 1
addze r3, r3
blr
instead of:
li r2, 1
li r5, 0
addc r2, r4, r2
adde r3, r3, r5
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22811 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-17 00:20:08 +00:00
|
|
|
BuildMI(BB, PPC::ADDIC, 2, Result).addReg(Tmp1).addSImm(Tmp3);
|
2005-08-25 23:19:58 +00:00
|
|
|
} else {
|
|
|
|
Tmp3 = SelectExpr(N.getOperand(2));
|
Implement a couple improvements:
Remove dead code in ISD::Constant handling
Add support for add long, imm16
We now codegen 'long long foo(long long a) { return ++a; }'
as:
addic r4, r4, 1
addze r3, r3
blr
instead of:
li r2, 1
li r5, 0
addc r2, r4, r2
adde r3, r3, r5
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22811 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-17 00:20:08 +00:00
|
|
|
BuildMI(BB, PPC::ADDC, 2, Result).addReg(Tmp1).addReg(Tmp3);
|
2005-08-25 23:19:58 +00:00
|
|
|
}
|
|
|
|
|
Implement a couple improvements:
Remove dead code in ISD::Constant handling
Add support for add long, imm16
We now codegen 'long long foo(long long a) { return ++a; }'
as:
addic r4, r4, 1
addze r3, r3
blr
instead of:
li r2, 1
li r5, 0
addc r2, r4, r2
adde r3, r3, r5
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22811 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-17 00:20:08 +00:00
|
|
|
// Codegen the high 32 bits, adding zero, minus one, or the full value
|
|
|
|
// along with the carry flag produced by addc/addic to tmp2.
|
2005-08-25 23:19:58 +00:00
|
|
|
if (ZE) {
|
Implement a couple improvements:
Remove dead code in ISD::Constant handling
Add support for add long, imm16
We now codegen 'long long foo(long long a) { return ++a; }'
as:
addic r4, r4, 1
addze r3, r3
blr
instead of:
li r2, 1
li r5, 0
addc r2, r4, r2
adde r3, r3, r5
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22811 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-17 00:20:08 +00:00
|
|
|
BuildMI(BB, PPC::ADDZE, 1, Result+1).addReg(Tmp2);
|
2005-08-25 23:19:58 +00:00
|
|
|
} else if (ME) {
|
Implement a couple improvements:
Remove dead code in ISD::Constant handling
Add support for add long, imm16
We now codegen 'long long foo(long long a) { return ++a; }'
as:
addic r4, r4, 1
addze r3, r3
blr
instead of:
li r2, 1
li r5, 0
addc r2, r4, r2
adde r3, r3, r5
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22811 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-17 00:20:08 +00:00
|
|
|
BuildMI(BB, PPC::ADDME, 1, Result+1).addReg(Tmp2);
|
2005-08-25 23:19:58 +00:00
|
|
|
} else {
|
Implement a couple improvements:
Remove dead code in ISD::Constant handling
Add support for add long, imm16
We now codegen 'long long foo(long long a) { return ++a; }'
as:
addic r4, r4, 1
addze r3, r3
blr
instead of:
li r2, 1
li r5, 0
addc r2, r4, r2
adde r3, r3, r5
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22811 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-17 00:20:08 +00:00
|
|
|
BuildMI(BB, PPC::ADDE, 2, Result+1).addReg(Tmp2).addReg(Tmp4);
|
2005-08-25 23:19:58 +00:00
|
|
|
}
|
2005-04-02 05:59:34 +00:00
|
|
|
} else {
|
2005-08-25 23:19:58 +00:00
|
|
|
Tmp3 = SelectExpr(N.getOperand(2));
|
|
|
|
Tmp4 = SelectExpr(N.getOperand(3));
|
Implement a couple improvements:
Remove dead code in ISD::Constant handling
Add support for add long, imm16
We now codegen 'long long foo(long long a) { return ++a; }'
as:
addic r4, r4, 1
addze r3, r3
blr
instead of:
li r2, 1
li r5, 0
addc r2, r4, r2
adde r3, r3, r5
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22811 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-17 00:20:08 +00:00
|
|
|
BuildMI(BB, PPC::SUBFC, 2, Result).addReg(Tmp3).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::SUBFE, 2, Result+1).addReg(Tmp4).addReg(Tmp2);
|
2005-04-02 05:59:34 +00:00
|
|
|
}
|
|
|
|
return Result+N.ResNo;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ISD::SHL_PARTS:
|
|
|
|
case ISD::SRA_PARTS:
|
|
|
|
case ISD::SRL_PARTS: {
|
|
|
|
assert(N.getNumOperands() == 3 && N.getValueType() == MVT::i32 &&
|
|
|
|
"Not an i64 shift!");
|
|
|
|
unsigned ShiftOpLo = SelectExpr(N.getOperand(0));
|
|
|
|
unsigned ShiftOpHi = SelectExpr(N.getOperand(1));
|
2005-04-13 22:14:14 +00:00
|
|
|
unsigned SHReg = FoldIfWideZeroExtend(N.getOperand(2));
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp1 = MakeIntReg();
|
|
|
|
Tmp2 = MakeIntReg();
|
|
|
|
Tmp3 = MakeIntReg();
|
|
|
|
unsigned Tmp4 = MakeIntReg();
|
|
|
|
unsigned Tmp5 = MakeIntReg();
|
|
|
|
unsigned Tmp6 = MakeIntReg();
|
2005-04-02 05:59:34 +00:00
|
|
|
BuildMI(BB, PPC::SUBFIC, 2, Tmp1).addReg(SHReg).addSImm(32);
|
|
|
|
if (ISD::SHL_PARTS == opcode) {
|
|
|
|
BuildMI(BB, PPC::SLW, 2, Tmp2).addReg(ShiftOpHi).addReg(SHReg);
|
|
|
|
BuildMI(BB, PPC::SRW, 2, Tmp3).addReg(ShiftOpLo).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::OR, 2, Tmp4).addReg(Tmp2).addReg(Tmp3);
|
|
|
|
BuildMI(BB, PPC::ADDI, 2, Tmp5).addReg(SHReg).addSImm(-32);
|
2005-04-03 22:13:27 +00:00
|
|
|
BuildMI(BB, PPC::SLW, 2, Tmp6).addReg(ShiftOpLo).addReg(Tmp5);
|
2005-04-02 05:59:34 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, Result+1).addReg(Tmp4).addReg(Tmp6);
|
|
|
|
BuildMI(BB, PPC::SLW, 2, Result).addReg(ShiftOpLo).addReg(SHReg);
|
|
|
|
} else if (ISD::SRL_PARTS == opcode) {
|
|
|
|
BuildMI(BB, PPC::SRW, 2, Tmp2).addReg(ShiftOpLo).addReg(SHReg);
|
|
|
|
BuildMI(BB, PPC::SLW, 2, Tmp3).addReg(ShiftOpHi).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::OR, 2, Tmp4).addReg(Tmp2).addReg(Tmp3);
|
|
|
|
BuildMI(BB, PPC::ADDI, 2, Tmp5).addReg(SHReg).addSImm(-32);
|
|
|
|
BuildMI(BB, PPC::SRW, 2, Tmp6).addReg(ShiftOpHi).addReg(Tmp5);
|
|
|
|
BuildMI(BB, PPC::OR, 2, Result).addReg(Tmp4).addReg(Tmp6);
|
|
|
|
BuildMI(BB, PPC::SRW, 2, Result+1).addReg(ShiftOpHi).addReg(SHReg);
|
2005-03-28 22:28:37 +00:00
|
|
|
} else {
|
2005-04-02 05:59:34 +00:00
|
|
|
MachineBasicBlock *TmpMBB = new MachineBasicBlock(BB->getBasicBlock());
|
|
|
|
MachineBasicBlock *PhiMBB = new MachineBasicBlock(BB->getBasicBlock());
|
|
|
|
MachineBasicBlock *OldMBB = BB;
|
|
|
|
MachineFunction *F = BB->getParent();
|
|
|
|
ilist<MachineBasicBlock>::iterator It = BB; ++It;
|
|
|
|
F->getBasicBlockList().insert(It, TmpMBB);
|
|
|
|
F->getBasicBlockList().insert(It, PhiMBB);
|
|
|
|
BB->addSuccessor(TmpMBB);
|
|
|
|
BB->addSuccessor(PhiMBB);
|
|
|
|
BuildMI(BB, PPC::SRW, 2, Tmp2).addReg(ShiftOpLo).addReg(SHReg);
|
|
|
|
BuildMI(BB, PPC::SLW, 2, Tmp3).addReg(ShiftOpHi).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::OR, 2, Tmp4).addReg(Tmp2).addReg(Tmp3);
|
|
|
|
BuildMI(BB, PPC::ADDICo, 2, Tmp5).addReg(SHReg).addSImm(-32);
|
|
|
|
BuildMI(BB, PPC::SRAW, 2, Tmp6).addReg(ShiftOpHi).addReg(Tmp5);
|
|
|
|
BuildMI(BB, PPC::SRAW, 2, Result+1).addReg(ShiftOpHi).addReg(SHReg);
|
|
|
|
BuildMI(BB, PPC::BLE, 2).addReg(PPC::CR0).addMBB(PhiMBB);
|
|
|
|
// Select correct least significant half if the shift amount > 32
|
|
|
|
BB = TmpMBB;
|
2005-08-11 17:15:31 +00:00
|
|
|
unsigned Tmp7 = MakeIntReg();
|
2005-04-02 05:59:34 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, Tmp7).addReg(Tmp6).addReg(Tmp6);
|
|
|
|
TmpMBB->addSuccessor(PhiMBB);
|
|
|
|
BB = PhiMBB;
|
|
|
|
BuildMI(BB, PPC::PHI, 4, Result).addReg(Tmp4).addMBB(OldMBB)
|
|
|
|
.addReg(Tmp7).addMBB(TmpMBB);
|
2005-03-28 22:28:37 +00:00
|
|
|
}
|
|
|
|
return Result+N.ResNo;
|
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-04-01 02:59:27 +00:00
|
|
|
case ISD::FP_TO_SINT: {
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
Make FP_TO_UINT Illegal. This allows us to generate significantly better
codegen for FP_TO_UINT by using the legalizer's SELECT variant.
Implement a codegen improvement for SELECT_CC, selecting the false node in
the MBB that feeds the phi node. This allows us to codegen:
void foo(int *a, int b, int c) { int d = (a < b) ? 5 : 9; *a = d; }
as:
_foo:
li r2, 5
cmpw cr0, r4, r3
bgt .LBB_foo_2 ; entry
.LBB_foo_1: ; entry
li r2, 9
.LBB_foo_2: ; entry
stw r2, 0(r3)
blr
insted of:
_foo:
li r2, 5
li r5, 9
cmpw cr0, r4, r3
bgt .LBB_foo_2 ; entry
.LBB_foo_1: ; entry
or r2, r5, r5
.LBB_foo_2: ; entry
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22784 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-14 01:17:16 +00:00
|
|
|
Tmp2 = MakeFPReg();
|
|
|
|
BuildMI(BB, PPC::FCTIWZ, 1, Tmp2).addReg(Tmp1);
|
|
|
|
int FrameIdx = BB->getParent()->getFrameInfo()->CreateStackObject(8, 8);
|
|
|
|
addFrameReference(BuildMI(BB, PPC::STFD, 3).addReg(Tmp2), FrameIdx);
|
|
|
|
addFrameReference(BuildMI(BB, PPC::LWZ, 2, Result), FrameIdx, 4);
|
|
|
|
return Result;
|
2005-04-01 02:59:27 +00:00
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-08-09 20:21:10 +00:00
|
|
|
case ISD::SETCC: {
|
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(Node->getOperand(2))->get();
|
|
|
|
if (isIntImmediate(Node->getOperand(1), Tmp3)) {
|
|
|
|
// We can codegen setcc op, imm very efficiently compared to a brcond.
|
|
|
|
// Check for those cases here.
|
|
|
|
// setcc op, 0
|
|
|
|
if (Tmp3 == 0) {
|
|
|
|
Tmp1 = SelectExpr(Node->getOperand(0));
|
|
|
|
switch (CC) {
|
2005-08-25 17:49:31 +00:00
|
|
|
default: Node->dump(); assert(0 && "Unhandled SetCC condition");abort();
|
2005-08-09 20:21:10 +00:00
|
|
|
case ISD::SETEQ:
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp2 = MakeIntReg();
|
2005-08-09 20:21:10 +00:00
|
|
|
BuildMI(BB, PPC::CNTLZW, 1, Tmp2).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp2).addImm(27)
|
|
|
|
.addImm(5).addImm(31);
|
|
|
|
break;
|
|
|
|
case ISD::SETNE:
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp2 = MakeIntReg();
|
2005-08-09 20:21:10 +00:00
|
|
|
BuildMI(BB, PPC::ADDIC, 2, Tmp2).addReg(Tmp1).addSImm(-1);
|
|
|
|
BuildMI(BB, PPC::SUBFE, 2, Result).addReg(Tmp2).addReg(Tmp1);
|
|
|
|
break;
|
|
|
|
case ISD::SETLT:
|
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm(1)
|
|
|
|
.addImm(31).addImm(31);
|
|
|
|
break;
|
|
|
|
case ISD::SETGT:
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp2 = MakeIntReg();
|
|
|
|
Tmp3 = MakeIntReg();
|
2005-08-09 20:21:10 +00:00
|
|
|
BuildMI(BB, PPC::NEG, 2, Tmp2).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::ANDC, 2, Tmp3).addReg(Tmp2).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp3).addImm(1)
|
|
|
|
.addImm(31).addImm(31);
|
|
|
|
break;
|
2005-04-12 21:22:28 +00:00
|
|
|
}
|
2005-08-09 20:21:10 +00:00
|
|
|
return Result;
|
|
|
|
} else if (Tmp3 == ~0U) { // setcc op, -1
|
|
|
|
Tmp1 = SelectExpr(Node->getOperand(0));
|
|
|
|
switch (CC) {
|
|
|
|
default: assert(0 && "Unhandled SetCC condition"); abort();
|
|
|
|
case ISD::SETEQ:
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp2 = MakeIntReg();
|
|
|
|
Tmp3 = MakeIntReg();
|
2005-08-09 20:21:10 +00:00
|
|
|
BuildMI(BB, PPC::ADDIC, 2, Tmp2).addReg(Tmp1).addSImm(1);
|
|
|
|
BuildMI(BB, PPC::LI, 1, Tmp3).addSImm(0);
|
|
|
|
BuildMI(BB, PPC::ADDZE, 1, Result).addReg(Tmp3);
|
|
|
|
break;
|
|
|
|
case ISD::SETNE:
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp2 = MakeIntReg();
|
|
|
|
Tmp3 = MakeIntReg();
|
2005-08-09 20:21:10 +00:00
|
|
|
BuildMI(BB, PPC::NOR, 2, Tmp2).addReg(Tmp1).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::ADDIC, 2, Tmp3).addReg(Tmp2).addSImm(-1);
|
|
|
|
BuildMI(BB, PPC::SUBFE, 2, Result).addReg(Tmp3).addReg(Tmp2);
|
|
|
|
break;
|
|
|
|
case ISD::SETLT:
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp2 = MakeIntReg();
|
|
|
|
Tmp3 = MakeIntReg();
|
2005-08-09 20:21:10 +00:00
|
|
|
BuildMI(BB, PPC::ADDI, 2, Tmp2).addReg(Tmp1).addSImm(1);
|
|
|
|
BuildMI(BB, PPC::AND, 2, Tmp3).addReg(Tmp2).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp3).addImm(1)
|
|
|
|
.addImm(31).addImm(31);
|
|
|
|
break;
|
|
|
|
case ISD::SETGT:
|
2005-08-11 17:15:31 +00:00
|
|
|
Tmp2 = MakeIntReg();
|
2005-08-09 20:21:10 +00:00
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Tmp2).addReg(Tmp1).addImm(1)
|
|
|
|
.addImm(31).addImm(31);
|
|
|
|
BuildMI(BB, PPC::XORI, 2, Result).addReg(Tmp2).addImm(1);
|
|
|
|
break;
|
2005-04-07 20:30:01 +00:00
|
|
|
}
|
2005-08-09 20:21:10 +00:00
|
|
|
return Result;
|
2005-04-07 20:30:01 +00:00
|
|
|
}
|
2005-03-29 21:54:38 +00:00
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-08-10 20:52:09 +00:00
|
|
|
unsigned CCReg = SelectCC(N.getOperand(0), N.getOperand(1), CC);
|
|
|
|
MoveCRtoGPR(CCReg, CC, Result);
|
2005-08-09 20:21:10 +00:00
|
|
|
return Result;
|
|
|
|
}
|
2005-08-10 20:52:09 +00:00
|
|
|
|
|
|
|
case ISD::SELECT_CC: {
|
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(N.getOperand(4))->get();
|
|
|
|
if (!MVT::isInteger(N.getOperand(0).getValueType()) &&
|
|
|
|
!MVT::isInteger(N.getOperand(2).getValueType()) &&
|
|
|
|
CC != ISD::SETEQ && CC != ISD::SETNE) {
|
|
|
|
MVT::ValueType VT = N.getOperand(0).getValueType();
|
|
|
|
unsigned TV = SelectExpr(N.getOperand(2)); // Use if TRUE
|
|
|
|
unsigned FV = SelectExpr(N.getOperand(3)); // Use if FALSE
|
|
|
|
|
|
|
|
ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N.getOperand(1));
|
2005-07-19 16:51:05 +00:00
|
|
|
if (CN && (CN->isExactlyValue(-0.0) || CN->isExactlyValue(0.0))) {
|
2005-08-09 20:21:10 +00:00
|
|
|
switch(CC) {
|
2005-07-19 16:51:05 +00:00
|
|
|
default: assert(0 && "Invalid FSEL condition"); abort();
|
|
|
|
case ISD::SETULT:
|
|
|
|
case ISD::SETLT:
|
|
|
|
std::swap(TV, FV); // fsel is natively setge, swap operands for setlt
|
|
|
|
case ISD::SETUGE:
|
|
|
|
case ISD::SETGE:
|
2005-08-10 20:52:09 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0)); // Val to compare against
|
2005-07-19 16:51:05 +00:00
|
|
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp1).addReg(TV).addReg(FV);
|
|
|
|
return Result;
|
|
|
|
case ISD::SETUGT:
|
|
|
|
case ISD::SETGT:
|
|
|
|
std::swap(TV, FV); // fsel is natively setge, swap operands for setlt
|
|
|
|
case ISD::SETULE:
|
|
|
|
case ISD::SETLE: {
|
2005-08-10 20:52:09 +00:00
|
|
|
if (N.getOperand(0).getOpcode() == ISD::FNEG) {
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(0).getOperand(0));
|
2005-07-19 16:51:05 +00:00
|
|
|
} else {
|
|
|
|
Tmp2 = MakeReg(VT);
|
2005-08-10 20:52:09 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0)); // Val to compare against
|
2005-07-19 16:51:05 +00:00
|
|
|
BuildMI(BB, PPC::FNEG, 1, Tmp2).addReg(Tmp1);
|
|
|
|
}
|
|
|
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp2).addReg(TV).addReg(FV);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Opc = (MVT::f64 == VT) ? PPC::FSUB : PPC::FSUBS;
|
2005-08-10 20:52:09 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0)); // Val to compare against
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
2005-07-19 16:51:05 +00:00
|
|
|
Tmp3 = MakeReg(VT);
|
2005-08-09 20:21:10 +00:00
|
|
|
switch(CC) {
|
2005-07-19 16:51:05 +00:00
|
|
|
default: assert(0 && "Invalid FSEL condition"); abort();
|
|
|
|
case ISD::SETULT:
|
|
|
|
case ISD::SETLT:
|
|
|
|
BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp3).addReg(FV).addReg(TV);
|
|
|
|
return Result;
|
|
|
|
case ISD::SETUGE:
|
|
|
|
case ISD::SETGE:
|
|
|
|
BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp3).addReg(TV).addReg(FV);
|
|
|
|
return Result;
|
|
|
|
case ISD::SETUGT:
|
|
|
|
case ISD::SETGT:
|
|
|
|
BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp2).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp3).addReg(FV).addReg(TV);
|
|
|
|
return Result;
|
|
|
|
case ISD::SETULE:
|
|
|
|
case ISD::SETLE:
|
|
|
|
BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp2).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::FSEL, 3, Result).addReg(Tmp3).addReg(TV).addReg(FV);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(0 && "Should never get here");
|
|
|
|
}
|
|
|
|
|
2005-08-24 04:59:21 +00:00
|
|
|
// handle the setcc cases here. select_cc lhs, 0, 1, 0, cc
|
|
|
|
ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N.getOperand(1));
|
|
|
|
ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N.getOperand(2));
|
|
|
|
ConstantSDNode *N3C = dyn_cast<ConstantSDNode>(N.getOperand(3));
|
|
|
|
if (N1C && N2C && N3C && N1C->isNullValue() && N3C->isNullValue() &&
|
2005-08-24 05:06:48 +00:00
|
|
|
N2C->getValue() == 1ULL && CC == ISD::SETNE) {
|
2005-08-24 04:59:21 +00:00
|
|
|
Tmp1 = SelectExpr(Node->getOperand(0));
|
|
|
|
Tmp2 = MakeIntReg();
|
2005-08-24 05:06:48 +00:00
|
|
|
BuildMI(BB, PPC::ADDIC, 2, Tmp2).addReg(Tmp1).addSImm(-1);
|
|
|
|
BuildMI(BB, PPC::SUBFE, 2, Result).addReg(Tmp2).addReg(Tmp1);
|
2005-08-24 04:59:21 +00:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
Make FP_TO_UINT Illegal. This allows us to generate significantly better
codegen for FP_TO_UINT by using the legalizer's SELECT variant.
Implement a codegen improvement for SELECT_CC, selecting the false node in
the MBB that feeds the phi node. This allows us to codegen:
void foo(int *a, int b, int c) { int d = (a < b) ? 5 : 9; *a = d; }
as:
_foo:
li r2, 5
cmpw cr0, r4, r3
bgt .LBB_foo_2 ; entry
.LBB_foo_1: ; entry
li r2, 9
.LBB_foo_2: ; entry
stw r2, 0(r3)
blr
insted of:
_foo:
li r2, 5
li r5, 9
cmpw cr0, r4, r3
bgt .LBB_foo_2 ; entry
.LBB_foo_1: ; entry
or r2, r5, r5
.LBB_foo_2: ; entry
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22784 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-14 01:17:16 +00:00
|
|
|
// If the False value only has one use, we can generate better code by
|
|
|
|
// selecting it in the fallthrough basic block rather than here, which
|
|
|
|
// increases register pressure.
|
|
|
|
unsigned TrueValue = SelectExpr(N.getOperand(2));
|
If the false value for a select_cc is really simple (has no inputs), evaluate
it in the block. This codegens:
int %test(bool %c) {
%retval = select bool %c, int 17, int 1
ret int %retval
}
as:
_test:
rlwinm r2, r3, 0, 31, 31
li r2, 17
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
li r2, 1
.LBB_test_2: ;
or r3, r2, r2
blr
instead of:
_test:
rlwinm r2, r3, 0, 31, 31
li r2, 17
li r4, 1
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
or r2, r4, r4
.LBB_test_2: ;
or r3, r2, r2
blr
... which is one fewer instruction. The savings are more significant for
global address and constantfp nodes.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22946 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-21 17:41:11 +00:00
|
|
|
unsigned FalseValue;
|
|
|
|
|
|
|
|
// If the false value is simple enough, evaluate it inline in the false
|
|
|
|
// block.
|
2005-08-22 00:47:28 +00:00
|
|
|
if (N.getOperand(3).Val->hasOneUse() &&
|
|
|
|
(isa<ConstantSDNode>(N.getOperand(3)) ||
|
|
|
|
isa<ConstantFPSDNode>(N.getOperand(3)) ||
|
|
|
|
isa<GlobalAddressSDNode>(N.getOperand(3))))
|
If the false value for a select_cc is really simple (has no inputs), evaluate
it in the block. This codegens:
int %test(bool %c) {
%retval = select bool %c, int 17, int 1
ret int %retval
}
as:
_test:
rlwinm r2, r3, 0, 31, 31
li r2, 17
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
li r2, 1
.LBB_test_2: ;
or r3, r2, r2
blr
instead of:
_test:
rlwinm r2, r3, 0, 31, 31
li r2, 17
li r4, 1
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
or r2, r4, r4
.LBB_test_2: ;
or r3, r2, r2
blr
... which is one fewer instruction. The savings are more significant for
global address and constantfp nodes.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22946 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-21 17:41:11 +00:00
|
|
|
FalseValue = 0;
|
|
|
|
else
|
|
|
|
FalseValue = SelectExpr(N.getOperand(3));
|
2005-08-10 20:52:09 +00:00
|
|
|
unsigned CCReg = SelectCC(N.getOperand(0), N.getOperand(1), CC);
|
|
|
|
Opc = getBCCForSetCC(CC);
|
|
|
|
|
2005-04-21 23:30:14 +00:00
|
|
|
// Create an iterator with which to insert the MBB for copying the false
|
2005-03-29 22:24:51 +00:00
|
|
|
// value and the MBB to hold the PHI instruction for this SetCC.
|
|
|
|
MachineBasicBlock *thisMBB = BB;
|
|
|
|
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
|
|
|
ilist<MachineBasicBlock>::iterator It = BB;
|
|
|
|
++It;
|
|
|
|
|
|
|
|
// thisMBB:
|
|
|
|
// ...
|
|
|
|
// TrueVal = ...
|
2005-04-13 23:15:44 +00:00
|
|
|
// cmpTY ccX, r1, r2
|
2005-03-29 22:24:51 +00:00
|
|
|
// bCC copy1MBB
|
|
|
|
// fallthrough --> copy0MBB
|
|
|
|
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
|
|
|
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
2005-04-13 23:15:44 +00:00
|
|
|
BuildMI(BB, Opc, 2).addReg(CCReg).addMBB(sinkMBB);
|
2005-03-29 22:24:51 +00:00
|
|
|
MachineFunction *F = BB->getParent();
|
|
|
|
F->getBasicBlockList().insert(It, copy0MBB);
|
|
|
|
F->getBasicBlockList().insert(It, sinkMBB);
|
|
|
|
// Update machine-CFG edges
|
|
|
|
BB->addSuccessor(copy0MBB);
|
|
|
|
BB->addSuccessor(sinkMBB);
|
|
|
|
|
|
|
|
// copy0MBB:
|
|
|
|
// %FalseValue = ...
|
|
|
|
// # fallthrough to sinkMBB
|
|
|
|
BB = copy0MBB;
|
If the false value for a select_cc is really simple (has no inputs), evaluate
it in the block. This codegens:
int %test(bool %c) {
%retval = select bool %c, int 17, int 1
ret int %retval
}
as:
_test:
rlwinm r2, r3, 0, 31, 31
li r2, 17
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
li r2, 1
.LBB_test_2: ;
or r3, r2, r2
blr
instead of:
_test:
rlwinm r2, r3, 0, 31, 31
li r2, 17
li r4, 1
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
or r2, r4, r4
.LBB_test_2: ;
or r3, r2, r2
blr
... which is one fewer instruction. The savings are more significant for
global address and constantfp nodes.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22946 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-21 17:41:11 +00:00
|
|
|
|
|
|
|
// If the false value is simple enough, evaluate it here, to avoid it being
|
|
|
|
// evaluated on the true edge.
|
|
|
|
if (FalseValue == 0)
|
|
|
|
FalseValue = SelectExpr(N.getOperand(3));
|
|
|
|
|
2005-03-29 22:24:51 +00:00
|
|
|
// Update machine-CFG edges
|
|
|
|
BB->addSuccessor(sinkMBB);
|
|
|
|
|
|
|
|
// sinkMBB:
|
|
|
|
// %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
|
|
|
|
// ...
|
|
|
|
BB = sinkMBB;
|
|
|
|
BuildMI(BB, PPC::PHI, 4, Result).addReg(FalseValue)
|
|
|
|
.addMBB(copy0MBB).addReg(TrueValue).addMBB(thisMBB);
|
|
|
|
return Result;
|
|
|
|
}
|
2005-03-24 04:41:43 +00:00
|
|
|
|
2005-08-18 17:16:52 +00:00
|
|
|
case ISD::Constant: {
|
|
|
|
assert(N.getValueType() == MVT::i32 &&
|
|
|
|
"Only i32 constants are legal on this target!");
|
2005-08-18 18:14:49 +00:00
|
|
|
unsigned v = (unsigned)cast<ConstantSDNode>(N)->getValue();
|
2005-08-18 18:58:23 +00:00
|
|
|
if (isInt16(v)) {
|
|
|
|
BuildMI(BB, PPC::LI, 1, Result).addSImm(Lo16(v));
|
2005-08-18 17:16:52 +00:00
|
|
|
} else {
|
2005-08-18 18:58:23 +00:00
|
|
|
unsigned Hi = Hi16(v);
|
|
|
|
unsigned Lo = Lo16(v);
|
|
|
|
if (Lo) {
|
|
|
|
Tmp1 = MakeIntReg();
|
|
|
|
BuildMI(BB, PPC::LIS, 1, Tmp1).addSImm(Hi);
|
|
|
|
BuildMI(BB, PPC::ORI, 2, Result).addReg(Tmp1).addImm(Lo);
|
|
|
|
} else {
|
|
|
|
BuildMI(BB, PPC::LIS, 1, Result).addSImm(Hi);
|
|
|
|
}
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
|
|
|
return Result;
|
2005-08-18 17:16:52 +00:00
|
|
|
}
|
2005-07-19 16:51:05 +00:00
|
|
|
|
|
|
|
case ISD::ConstantFP: {
|
|
|
|
ConstantFPSDNode *CN = cast<ConstantFPSDNode>(N);
|
|
|
|
Result = getConstDouble(CN->getValue(), Result);
|
|
|
|
return Result;
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
|
|
|
|
2005-07-19 16:51:05 +00:00
|
|
|
case ISD::FNEG:
|
|
|
|
if (!NoExcessFPPrecision &&
|
|
|
|
ISD::ADD == N.getOperand(0).getOpcode() &&
|
|
|
|
N.getOperand(0).Val->hasOneUse() &&
|
|
|
|
ISD::MUL == N.getOperand(0).getOperand(0).getOpcode() &&
|
|
|
|
N.getOperand(0).getOperand(0).Val->hasOneUse()) {
|
|
|
|
++FusedFP; // Statistic
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0).getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(0).getOperand(0).getOperand(1));
|
|
|
|
Tmp3 = SelectExpr(N.getOperand(0).getOperand(1));
|
|
|
|
Opc = DestType == MVT::f64 ? PPC::FNMADD : PPC::FNMADDS;
|
|
|
|
BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
|
|
|
|
} else if (!NoExcessFPPrecision &&
|
|
|
|
ISD::ADD == N.getOperand(0).getOpcode() &&
|
|
|
|
N.getOperand(0).Val->hasOneUse() &&
|
|
|
|
ISD::MUL == N.getOperand(0).getOperand(1).getOpcode() &&
|
|
|
|
N.getOperand(0).getOperand(1).Val->hasOneUse()) {
|
|
|
|
++FusedFP; // Statistic
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(1).getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(0).getOperand(1).getOperand(1));
|
|
|
|
Tmp3 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
Opc = DestType == MVT::f64 ? PPC::FNMADD : PPC::FNMADDS;
|
|
|
|
BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3);
|
|
|
|
} else if (ISD::FABS == N.getOperand(0).getOpcode()) {
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
BuildMI(BB, PPC::FNABS, 1, Result).addReg(Tmp1);
|
|
|
|
} else {
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
BuildMI(BB, PPC::FNEG, 1, Result).addReg(Tmp1);
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
|
|
|
|
case ISD::FABS:
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
BuildMI(BB, PPC::FABS, 1, Result).addReg(Tmp1);
|
|
|
|
return Result;
|
|
|
|
|
2005-07-20 22:42:00 +00:00
|
|
|
case ISD::FSQRT:
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
Opc = DestType == MVT::f64 ? PPC::FSQRT : PPC::FSQRTS;
|
|
|
|
BuildMI(BB, Opc, 1, Result).addReg(Tmp1);
|
|
|
|
return Result;
|
|
|
|
|
2005-07-19 16:51:05 +00:00
|
|
|
case ISD::FP_ROUND:
|
|
|
|
assert (DestType == MVT::f32 &&
|
|
|
|
N.getOperand(0).getValueType() == MVT::f64 &&
|
|
|
|
"only f64 to f32 conversion supported here");
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
BuildMI(BB, PPC::FRSP, 1, Result).addReg(Tmp1);
|
|
|
|
return Result;
|
|
|
|
|
|
|
|
case ISD::FP_EXTEND:
|
|
|
|
assert (DestType == MVT::f64 &&
|
|
|
|
N.getOperand(0).getValueType() == MVT::f32 &&
|
|
|
|
"only f32 to f64 conversion supported here");
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
BuildMI(BB, PPC::FMR, 1, Result).addReg(Tmp1);
|
|
|
|
return Result;
|
|
|
|
}
|
2005-03-24 04:41:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ISel::Select(SDOperand N) {
|
2005-07-21 20:44:43 +00:00
|
|
|
unsigned Tmp1, Tmp2, Tmp3, Opc;
|
2005-03-24 04:41:43 +00:00
|
|
|
unsigned opcode = N.getOpcode();
|
|
|
|
|
|
|
|
if (!ExprMap.insert(std::make_pair(N, 1)).second)
|
|
|
|
return; // Already selected.
|
|
|
|
|
|
|
|
SDNode *Node = N.Val;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
switch (Node->getOpcode()) {
|
|
|
|
default:
|
|
|
|
Node->dump(); std::cerr << "\n";
|
|
|
|
assert(0 && "Node not handled yet!");
|
|
|
|
case ISD::EntryToken: return; // Noop
|
|
|
|
case ISD::TokenFactor:
|
|
|
|
for (unsigned i = 0, e = Node->getNumOperands(); i != e; ++i)
|
|
|
|
Select(Node->getOperand(i));
|
|
|
|
return;
|
2005-05-12 23:24:06 +00:00
|
|
|
case ISD::CALLSEQ_START:
|
|
|
|
case ISD::CALLSEQ_END:
|
2005-03-24 04:41:43 +00:00
|
|
|
Select(N.getOperand(0));
|
|
|
|
Tmp1 = cast<ConstantSDNode>(N.getOperand(1))->getValue();
|
2005-05-12 23:24:06 +00:00
|
|
|
Opc = N.getOpcode() == ISD::CALLSEQ_START ? PPC::ADJCALLSTACKDOWN :
|
2005-03-24 04:41:43 +00:00
|
|
|
PPC::ADJCALLSTACKUP;
|
|
|
|
BuildMI(BB, Opc, 1).addImm(Tmp1);
|
|
|
|
return;
|
|
|
|
case ISD::BR: {
|
|
|
|
MachineBasicBlock *Dest =
|
|
|
|
cast<BasicBlockSDNode>(N.getOperand(1))->getBasicBlock();
|
|
|
|
Select(N.getOperand(0));
|
|
|
|
BuildMI(BB, PPC::B, 1).addMBB(Dest);
|
|
|
|
return;
|
|
|
|
}
|
2005-08-16 19:49:35 +00:00
|
|
|
case ISD::BR_CC:
|
|
|
|
case ISD::BRTWOWAY_CC:
|
2005-03-24 04:41:43 +00:00
|
|
|
SelectBranchCC(N);
|
|
|
|
return;
|
|
|
|
case ISD::CopyToReg:
|
|
|
|
Select(N.getOperand(0));
|
2005-08-16 21:58:15 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(2));
|
|
|
|
Tmp2 = cast<RegisterSDNode>(N.getOperand(1))->getReg();
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
if (Tmp1 != Tmp2) {
|
2005-08-16 21:58:15 +00:00
|
|
|
if (N.getOperand(2).getValueType() == MVT::f64 ||
|
|
|
|
N.getOperand(2).getValueType() == MVT::f32)
|
2005-03-24 04:41:43 +00:00
|
|
|
BuildMI(BB, PPC::FMR, 1, Tmp2).addReg(Tmp1);
|
|
|
|
else
|
|
|
|
BuildMI(BB, PPC::OR, 2, Tmp2).addReg(Tmp1).addReg(Tmp1);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case ISD::ImplicitDef:
|
|
|
|
Select(N.getOperand(0));
|
2005-08-24 23:08:16 +00:00
|
|
|
Tmp1 = cast<RegisterSDNode>(N.getOperand(1))->getReg();
|
|
|
|
if (N.getOperand(1).getValueType() == MVT::i32)
|
|
|
|
BuildMI(BB, PPC::IMPLICIT_DEF_GPR, 0, Tmp1);
|
|
|
|
else
|
|
|
|
BuildMI(BB, PPC::IMPLICIT_DEF_FP, 0, Tmp1);
|
2005-03-24 04:41:43 +00:00
|
|
|
return;
|
|
|
|
case ISD::RET:
|
|
|
|
switch (N.getNumOperands()) {
|
|
|
|
default:
|
|
|
|
assert(0 && "Unknown return instruction!");
|
|
|
|
case 3:
|
|
|
|
assert(N.getOperand(1).getValueType() == MVT::i32 &&
|
|
|
|
N.getOperand(2).getValueType() == MVT::i32 &&
|
2005-04-22 17:54:37 +00:00
|
|
|
"Unknown two-register value!");
|
2005-03-24 04:41:43 +00:00
|
|
|
Select(N.getOperand(0));
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(1));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(2));
|
2005-04-02 00:42:16 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, PPC::R3).addReg(Tmp2).addReg(Tmp2);
|
|
|
|
BuildMI(BB, PPC::OR, 2, PPC::R4).addReg(Tmp1).addReg(Tmp1);
|
2005-03-24 04:41:43 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
Select(N.getOperand(0));
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(1));
|
|
|
|
switch (N.getOperand(1).getValueType()) {
|
|
|
|
default:
|
|
|
|
assert(0 && "Unknown return type!");
|
|
|
|
case MVT::f64:
|
|
|
|
case MVT::f32:
|
|
|
|
BuildMI(BB, PPC::FMR, 1, PPC::F1).addReg(Tmp1);
|
|
|
|
break;
|
|
|
|
case MVT::i32:
|
|
|
|
BuildMI(BB, PPC::OR, 2, PPC::R3).addReg(Tmp1).addReg(Tmp1);
|
|
|
|
break;
|
|
|
|
}
|
2005-03-24 23:35:30 +00:00
|
|
|
case 1:
|
|
|
|
Select(N.getOperand(0));
|
|
|
|
break;
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
|
|
|
BuildMI(BB, PPC::BLR, 0); // Just emit a 'ret' instruction
|
|
|
|
return;
|
2005-04-21 23:30:14 +00:00
|
|
|
case ISD::TRUNCSTORE:
|
2005-07-21 20:44:43 +00:00
|
|
|
case ISD::STORE: {
|
|
|
|
SDOperand Chain = N.getOperand(0);
|
|
|
|
SDOperand Value = N.getOperand(1);
|
|
|
|
SDOperand Address = N.getOperand(2);
|
|
|
|
Select(Chain);
|
2005-03-24 04:41:43 +00:00
|
|
|
|
2005-07-21 20:44:43 +00:00
|
|
|
Tmp1 = SelectExpr(Value); //value
|
|
|
|
|
|
|
|
if (opcode == ISD::STORE) {
|
|
|
|
switch(Value.getValueType()) {
|
|
|
|
default: assert(0 && "unknown Type in store");
|
|
|
|
case MVT::i32: Opc = PPC::STW; break;
|
|
|
|
case MVT::f64: Opc = PPC::STFD; break;
|
|
|
|
case MVT::f32: Opc = PPC::STFS; break;
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
2005-07-21 20:44:43 +00:00
|
|
|
} else { //ISD::TRUNCSTORE
|
|
|
|
switch(cast<VTSDNode>(Node->getOperand(4))->getVT()) {
|
|
|
|
default: assert(0 && "unknown Type in store");
|
|
|
|
case MVT::i1:
|
|
|
|
case MVT::i8: Opc = PPC::STB; break;
|
|
|
|
case MVT::i16: Opc = PPC::STH; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Address.getOpcode() == ISD::FrameIndex) {
|
|
|
|
Tmp2 = cast<FrameIndexSDNode>(Address)->getIndex();
|
|
|
|
addFrameReference(BuildMI(BB, Opc, 3).addReg(Tmp1), (int)Tmp2);
|
|
|
|
} else {
|
|
|
|
int offset;
|
Fold constant adds into loads and stores to frame indices.
For the following code:
double %ext(int %A.0__, long %A.1__) {
%A_addr = alloca %typedef.DComplex ; <%typedef.DComplex*> [#uses=2]
%tmp.1 = cast %typedef.DComplex* %A_addr to int* ; <int*> [#uses=1]
store int %A.0__, int* %tmp.1
%tmp.2 = getelementptr %typedef.DComplex* %A_addr, int 0, uint 1 ; <double*> [#uses=2]
%tmp.3 = cast double* %tmp.2 to long* ; <long*> [#uses=1]
store long %A.1__, long* %tmp.3
%tmp.5 = load double* %tmp.2 ; <double> [#uses=1]
ret double %tmp.5
}
We now generate:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
stw r4, -8(r1)
stw r5, -4(r1)
lfd f1, -8(r1)
blr
Instead of:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
addi r2, r1, -12
stw r4, 4(r2)
stw r5, 8(r2)
lfd f1, 4(r2)
blr
This also fires hundreds of times on MultiSource.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22533 91177308-0d34-0410-b5e6-96231b3b80d8
2005-07-28 03:02:05 +00:00
|
|
|
switch(SelectAddr(Address, Tmp2, offset)) {
|
|
|
|
default: assert(0 && "Unhandled return value from SelectAddr");
|
|
|
|
case 0: // imm offset, no frame, no index
|
|
|
|
BuildMI(BB, Opc, 3).addReg(Tmp1).addSImm(offset).addReg(Tmp2);
|
|
|
|
break;
|
|
|
|
case 1: // imm offset + frame index
|
|
|
|
addFrameReference(BuildMI(BB, Opc, 3).addReg(Tmp1), (int)Tmp2, offset);
|
|
|
|
break;
|
|
|
|
case 2: // base+index addressing
|
2005-07-21 20:44:43 +00:00
|
|
|
Opc = IndexedOpForOp(Opc);
|
|
|
|
BuildMI(BB, Opc, 3).addReg(Tmp1).addReg(Tmp2).addReg(offset);
|
Fold constant adds into loads and stores to frame indices.
For the following code:
double %ext(int %A.0__, long %A.1__) {
%A_addr = alloca %typedef.DComplex ; <%typedef.DComplex*> [#uses=2]
%tmp.1 = cast %typedef.DComplex* %A_addr to int* ; <int*> [#uses=1]
store int %A.0__, int* %tmp.1
%tmp.2 = getelementptr %typedef.DComplex* %A_addr, int 0, uint 1 ; <double*> [#uses=2]
%tmp.3 = cast double* %tmp.2 to long* ; <long*> [#uses=1]
store long %A.1__, long* %tmp.3
%tmp.5 = load double* %tmp.2 ; <double> [#uses=1]
ret double %tmp.5
}
We now generate:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
stw r4, -8(r1)
stw r5, -4(r1)
lfd f1, -8(r1)
blr
Instead of:
_ext:
.LBB_ext_0: ;
stw r3, -12(r1)
addi r2, r1, -12
stw r4, 4(r2)
stw r5, 8(r2)
lfd f1, 4(r2)
blr
This also fires hundreds of times on MultiSource.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22533 91177308-0d34-0410-b5e6-96231b3b80d8
2005-07-28 03:02:05 +00:00
|
|
|
break;
|
2005-08-08 22:22:56 +00:00
|
|
|
case 3: {
|
|
|
|
GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Address);
|
|
|
|
GlobalValue *GV = GN->getGlobal();
|
|
|
|
BuildMI(BB, Opc, 3).addReg(Tmp1).addGlobalAddress(GV).addReg(Tmp2);
|
|
|
|
}
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
|
|
|
}
|
2005-07-21 20:44:43 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-03-24 04:41:43 +00:00
|
|
|
case ISD::EXTLOAD:
|
|
|
|
case ISD::SEXTLOAD:
|
|
|
|
case ISD::ZEXTLOAD:
|
|
|
|
case ISD::LOAD:
|
|
|
|
case ISD::CopyFromReg:
|
2005-05-13 20:29:26 +00:00
|
|
|
case ISD::TAILCALL:
|
2005-03-24 04:41:43 +00:00
|
|
|
case ISD::CALL:
|
|
|
|
case ISD::DYNAMIC_STACKALLOC:
|
|
|
|
ExprMap.erase(N);
|
|
|
|
SelectExpr(N);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
assert(0 && "Should not be reached!");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// createPPC32PatternInstructionSelector - This pass converts an LLVM function
|
|
|
|
/// into a machine code representation using pattern matching and a machine
|
|
|
|
/// description file.
|
|
|
|
///
|
|
|
|
FunctionPass *llvm::createPPC32ISelPattern(TargetMachine &TM) {
|
2005-04-21 23:30:14 +00:00
|
|
|
return new ISel(TM);
|
2005-03-24 06:16:18 +00:00
|
|
|
}
|
|
|
|
|