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-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"
|
|
|
|
#include "llvm/Target/TargetLowering.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;
|
|
|
|
|
2005-08-02 19:26:06 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// PPC32TargetLowering - PPC32 Implementation of the TargetLowering interface
|
|
|
|
namespace {
|
|
|
|
class PPC32TargetLowering : public TargetLowering {
|
|
|
|
int VarArgsFrameIndex; // FrameIndex for start of varargs area.
|
|
|
|
int ReturnAddrIndex; // FrameIndex for return slot.
|
|
|
|
public:
|
|
|
|
PPC32TargetLowering(TargetMachine &TM) : TargetLowering(TM) {
|
2005-05-12 02:06:00 +00:00
|
|
|
// Fold away setcc operations if possible.
|
|
|
|
setSetCCIsExpensive();
|
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
// Set up the register classes.
|
|
|
|
addRegisterClass(MVT::i32, PPC32::GPRCRegisterClass);
|
2005-03-26 08:25:22 +00:00
|
|
|
addRegisterClass(MVT::f32, PPC32::FPRCRegisterClass);
|
2005-03-24 04:41:43 +00:00
|
|
|
addRegisterClass(MVT::f64, PPC32::FPRCRegisterClass);
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-31 00:15:26 +00:00
|
|
|
// PowerPC has no intrinsics for these particular operations
|
2005-03-30 01:45:43 +00:00
|
|
|
setOperationAction(ISD::MEMMOVE, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::MEMSET, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::MEMCPY, MVT::Other, Expand);
|
|
|
|
|
2005-03-31 00:15:26 +00:00
|
|
|
// PowerPC has an i16 but no i8 (or i1) SEXTLOAD
|
|
|
|
setOperationAction(ISD::SEXTLOAD, MVT::i1, Expand);
|
|
|
|
setOperationAction(ISD::SEXTLOAD, MVT::i8, Expand);
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-04-06 00:25:27 +00:00
|
|
|
// PowerPC has no SREM/UREM instructions
|
|
|
|
setOperationAction(ISD::SREM, MVT::i32, Expand);
|
|
|
|
setOperationAction(ISD::UREM, MVT::i32, Expand);
|
2005-04-02 05:03:24 +00:00
|
|
|
|
2005-05-13 16:20:22 +00:00
|
|
|
// We don't support sin/cos/sqrt/fmod
|
2005-04-30 04:26:06 +00:00
|
|
|
setOperationAction(ISD::FSIN , MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FCOS , MVT::f64, Expand);
|
2005-05-13 16:20:22 +00:00
|
|
|
setOperationAction(ISD::SREM , MVT::f64, Expand);
|
2005-04-30 04:26:06 +00:00
|
|
|
setOperationAction(ISD::FSIN , MVT::f32, Expand);
|
|
|
|
setOperationAction(ISD::FCOS , MVT::f32, Expand);
|
2005-05-13 16:20:22 +00:00
|
|
|
setOperationAction(ISD::SREM , MVT::f32, Expand);
|
2005-04-30 04:26:06 +00:00
|
|
|
|
2005-07-20 22:42:00 +00:00
|
|
|
// If we're enabling GP optimizations, use hardware square root
|
2005-08-05 22:05:03 +00:00
|
|
|
if (!TM.getSubtarget<PPCSubtarget>().isGigaProcessor()) {
|
2005-07-20 22:42:00 +00:00
|
|
|
setOperationAction(ISD::FSQRT, MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FSQRT, MVT::f32, Expand);
|
|
|
|
}
|
2005-07-27 06:12:32 +00:00
|
|
|
|
2005-05-11 23:43:56 +00:00
|
|
|
//PowerPC does not have CTPOP or CTTZ
|
2005-05-03 17:19:30 +00:00
|
|
|
setOperationAction(ISD::CTPOP, MVT::i32 , Expand);
|
|
|
|
setOperationAction(ISD::CTTZ , MVT::i32 , Expand);
|
|
|
|
|
2005-04-07 19:41:49 +00:00
|
|
|
setSetCCResultContents(ZeroOrOneSetCCResult);
|
2005-03-31 23:55:40 +00:00
|
|
|
addLegalFPImmediate(+0.0); // Necessary for FSEL
|
2005-04-21 23:30:14 +00:00
|
|
|
addLegalFPImmediate(-0.0); //
|
2005-03-31 23:55:40 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
computeRegisterProperties();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// LowerArguments - This hook must be implemented to indicate how we should
|
|
|
|
/// lower the arguments for the specified function, into the specified DAG.
|
|
|
|
virtual std::vector<SDOperand>
|
|
|
|
LowerArguments(Function &F, SelectionDAG &DAG);
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
/// LowerCallTo - This hook lowers an abstract call to a function into an
|
|
|
|
/// actual call.
|
|
|
|
virtual std::pair<SDOperand, SDOperand>
|
2005-05-12 19:56:45 +00:00
|
|
|
LowerCallTo(SDOperand Chain, const Type *RetTy, bool isVarArg, unsigned CC,
|
2005-05-13 18:50:42 +00:00
|
|
|
bool isTailCall, SDOperand Callee, ArgListTy &Args,
|
|
|
|
SelectionDAG &DAG);
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-07-05 19:58:54 +00:00
|
|
|
virtual SDOperand LowerVAStart(SDOperand Chain, SDOperand VAListP,
|
|
|
|
Value *VAListV, SelectionDAG &DAG);
|
2005-07-27 06:12:32 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
virtual std::pair<SDOperand,SDOperand>
|
2005-07-05 19:58:54 +00:00
|
|
|
LowerVAArg(SDOperand Chain, SDOperand VAListP, Value *VAListV,
|
|
|
|
const Type *ArgTy, SelectionDAG &DAG);
|
2005-07-27 06:12:32 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
virtual std::pair<SDOperand, SDOperand>
|
|
|
|
LowerFrameReturnAddress(bool isFrameAddr, SDOperand Chain, unsigned Depth,
|
|
|
|
SelectionDAG &DAG);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<SDOperand>
|
|
|
|
PPC32TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
|
|
|
|
//
|
|
|
|
// add beautiful description of PPC stack frame format, or at least some docs
|
|
|
|
//
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MachineFrameInfo *MFI = MF.getFrameInfo();
|
|
|
|
MachineBasicBlock& BB = MF.front();
|
|
|
|
std::vector<SDOperand> ArgValues;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
|
|
|
// Due to the rather complicated nature of the PowerPC ABI, rather than a
|
2005-03-24 04:41:43 +00:00
|
|
|
// fixed size array of physical args, for the sake of simplicity let the STL
|
|
|
|
// handle tracking them for us.
|
|
|
|
std::vector<unsigned> argVR, argPR, argOp;
|
|
|
|
unsigned ArgOffset = 24;
|
|
|
|
unsigned GPR_remaining = 8;
|
|
|
|
unsigned FPR_remaining = 13;
|
|
|
|
unsigned GPR_idx = 0, FPR_idx = 0;
|
2005-04-21 23:30:14 +00:00
|
|
|
static const unsigned GPR[] = {
|
2005-03-24 04:41:43 +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
|
|
|
|
};
|
|
|
|
|
|
|
|
// Add DAG nodes to load the arguments... On entry to a function on PPC,
|
|
|
|
// the arguments start at offset 24, although they are likely to be passed
|
|
|
|
// in registers.
|
|
|
|
for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I) {
|
|
|
|
SDOperand newroot, argt;
|
|
|
|
unsigned ObjSize;
|
|
|
|
bool needsLoad = false;
|
2005-04-09 20:09:12 +00:00
|
|
|
bool ArgLive = !I->use_empty();
|
2005-03-24 04:41:43 +00:00
|
|
|
MVT::ValueType ObjectVT = getValueType(I->getType());
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
switch (ObjectVT) {
|
|
|
|
default: assert(0 && "Unhandled argument type!");
|
|
|
|
case MVT::i1:
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
2005-04-21 23:30:14 +00:00
|
|
|
case MVT::i32:
|
2005-03-24 04:41:43 +00:00
|
|
|
ObjSize = 4;
|
2005-04-09 20:09:12 +00:00
|
|
|
if (!ArgLive) break;
|
2005-03-24 04:41:43 +00:00
|
|
|
if (GPR_remaining > 0) {
|
2005-04-09 20:09:12 +00:00
|
|
|
MF.addLiveIn(GPR[GPR_idx]);
|
2005-03-28 23:08:54 +00:00
|
|
|
argt = newroot = DAG.getCopyFromReg(GPR[GPR_idx], MVT::i32,
|
|
|
|
DAG.getRoot());
|
2005-03-24 04:41:43 +00:00
|
|
|
if (ObjectVT != MVT::i32)
|
|
|
|
argt = DAG.getNode(ISD::TRUNCATE, ObjectVT, newroot);
|
|
|
|
} else {
|
|
|
|
needsLoad = true;
|
|
|
|
}
|
|
|
|
break;
|
2005-03-26 07:46:36 +00:00
|
|
|
case MVT::i64: ObjSize = 8;
|
2005-04-09 20:09:12 +00:00
|
|
|
if (!ArgLive) break;
|
2005-04-10 05:53:14 +00:00
|
|
|
if (GPR_remaining > 0) {
|
|
|
|
SDOperand argHi, argLo;
|
2005-04-09 20:09:12 +00:00
|
|
|
MF.addLiveIn(GPR[GPR_idx]);
|
2005-04-10 05:53:14 +00:00
|
|
|
argHi = DAG.getCopyFromReg(GPR[GPR_idx], MVT::i32, DAG.getRoot());
|
|
|
|
// If we have two or more remaining argument registers, then both halves
|
|
|
|
// of the i64 can be sourced from there. Otherwise, the lower half will
|
|
|
|
// have to come off the stack. This can happen when an i64 is preceded
|
|
|
|
// by 28 bytes of arguments.
|
|
|
|
if (GPR_remaining > 1) {
|
|
|
|
MF.addLiveIn(GPR[GPR_idx+1]);
|
|
|
|
argLo = DAG.getCopyFromReg(GPR[GPR_idx+1], MVT::i32, argHi);
|
|
|
|
} else {
|
|
|
|
int FI = MFI->CreateFixedObject(4, ArgOffset+4);
|
|
|
|
SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
|
2005-05-15 19:54:37 +00:00
|
|
|
argLo = DAG.getLoad(MVT::i32, DAG.getEntryNode(), FIN,
|
|
|
|
DAG.getSrcValue(NULL));
|
2005-04-10 05:53:14 +00:00
|
|
|
}
|
2005-03-28 22:28:37 +00:00
|
|
|
// Build the outgoing arg thingy
|
2005-03-28 23:08:54 +00:00
|
|
|
argt = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, argLo, argHi);
|
|
|
|
newroot = argLo;
|
2005-03-24 04:41:43 +00:00
|
|
|
} else {
|
2005-04-21 23:30:14 +00:00
|
|
|
needsLoad = true;
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
|
|
|
break;
|
2005-04-09 20:09:12 +00:00
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64:
|
|
|
|
ObjSize = (ObjectVT == MVT::f64) ? 8 : 4;
|
|
|
|
if (!ArgLive) break;
|
2005-03-24 04:41:43 +00:00
|
|
|
if (FPR_remaining > 0) {
|
2005-04-09 20:09:12 +00:00
|
|
|
MF.addLiveIn(FPR[FPR_idx]);
|
2005-04-21 23:30:14 +00:00
|
|
|
argt = newroot = DAG.getCopyFromReg(FPR[FPR_idx], ObjectVT,
|
2005-03-28 23:08:54 +00:00
|
|
|
DAG.getRoot());
|
2005-03-24 04:41:43 +00:00
|
|
|
--FPR_remaining;
|
|
|
|
++FPR_idx;
|
|
|
|
} else {
|
|
|
|
needsLoad = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
// We need to load the argument to a virtual register if we determined above
|
2005-04-21 23:30:14 +00:00
|
|
|
// that we ran out of physical registers of the appropriate type
|
2005-03-24 04:41:43 +00:00
|
|
|
if (needsLoad) {
|
2005-04-04 06:52:38 +00:00
|
|
|
unsigned SubregOffset = 0;
|
2005-04-04 09:09:00 +00:00
|
|
|
if (ObjectVT == MVT::i8 || ObjectVT == MVT::i1) SubregOffset = 3;
|
2005-04-04 06:52:38 +00:00
|
|
|
if (ObjectVT == MVT::i16) SubregOffset = 2;
|
2005-03-24 04:41:43 +00:00
|
|
|
int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
|
|
|
|
SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
|
2005-04-21 23:30:14 +00:00
|
|
|
FIN = DAG.getNode(ISD::ADD, MVT::i32, FIN,
|
2005-04-04 06:52:38 +00:00
|
|
|
DAG.getConstant(SubregOffset, MVT::i32));
|
2005-05-15 19:54:37 +00:00
|
|
|
argt = newroot = DAG.getLoad(ObjectVT, DAG.getEntryNode(), FIN,
|
|
|
|
DAG.getSrcValue(NULL));
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
// Every 4 bytes of argument space consumes one of the GPRs available for
|
|
|
|
// argument passing.
|
|
|
|
if (GPR_remaining > 0) {
|
|
|
|
unsigned delta = (GPR_remaining > 1 && ObjSize == 8) ? 2 : 1;
|
|
|
|
GPR_remaining -= delta;
|
|
|
|
GPR_idx += delta;
|
|
|
|
}
|
|
|
|
ArgOffset += ObjSize;
|
2005-04-09 21:23:24 +00:00
|
|
|
if (newroot.Val)
|
|
|
|
DAG.setRoot(newroot.getValue(1));
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
ArgValues.push_back(argt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the function takes variable number of arguments, make a frame index for
|
|
|
|
// the start of the first vararg value... for expansion of llvm.va_start.
|
2005-04-03 22:13:27 +00:00
|
|
|
if (F.isVarArg()) {
|
2005-03-24 04:41:43 +00:00
|
|
|
VarArgsFrameIndex = MFI->CreateFixedObject(4, ArgOffset);
|
2005-04-03 22:13:27 +00:00
|
|
|
SDOperand FIN = DAG.getFrameIndex(VarArgsFrameIndex, MVT::i32);
|
2005-04-03 23:11:17 +00:00
|
|
|
// If this function is vararg, store any remaining integer argument regs
|
|
|
|
// to their spots on the stack so that they may be loaded by deferencing the
|
|
|
|
// result of va_next.
|
|
|
|
std::vector<SDOperand> MemOps;
|
|
|
|
for (; GPR_remaining > 0; --GPR_remaining, ++GPR_idx) {
|
2005-04-09 20:09:12 +00:00
|
|
|
MF.addLiveIn(GPR[GPR_idx]);
|
2005-04-03 23:11:17 +00:00
|
|
|
SDOperand Val = DAG.getCopyFromReg(GPR[GPR_idx], MVT::i32, DAG.getRoot());
|
2005-04-21 23:30:14 +00:00
|
|
|
SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Val.getValue(1),
|
2005-04-27 20:10:01 +00:00
|
|
|
Val, FIN, DAG.getSrcValue(NULL));
|
2005-04-03 23:11:17 +00:00
|
|
|
MemOps.push_back(Store);
|
|
|
|
// Increment the address by four for the next argument to store
|
|
|
|
SDOperand PtrOff = DAG.getConstant(4, getPointerTy());
|
|
|
|
FIN = DAG.getNode(ISD::ADD, MVT::i32, FIN, PtrOff);
|
|
|
|
}
|
|
|
|
DAG.setRoot(DAG.getNode(ISD::TokenFactor, MVT::Other, MemOps));
|
2005-04-03 22:13:27 +00:00
|
|
|
}
|
2005-03-24 04:41:43 +00:00
|
|
|
|
2005-04-09 20:09:12 +00:00
|
|
|
// Finally, inform the code generator which regs we return values in.
|
|
|
|
switch (getValueType(F.getReturnType())) {
|
|
|
|
default: assert(0 && "Unknown type!");
|
|
|
|
case MVT::isVoid: break;
|
|
|
|
case MVT::i1:
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
|
|
|
MF.addLiveOut(PPC::R3);
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
|
|
|
MF.addLiveOut(PPC::R3);
|
|
|
|
MF.addLiveOut(PPC::R4);
|
|
|
|
break;
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64:
|
|
|
|
MF.addLiveOut(PPC::F1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
return ArgValues;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<SDOperand, SDOperand>
|
|
|
|
PPC32TargetLowering::LowerCallTo(SDOperand Chain,
|
2005-04-22 17:54:37 +00:00
|
|
|
const Type *RetTy, bool isVarArg,
|
2005-07-27 06:12:32 +00:00
|
|
|
unsigned CallingConv, bool isTailCall,
|
2005-04-22 17:54:37 +00:00
|
|
|
SDOperand Callee, ArgListTy &Args,
|
|
|
|
SelectionDAG &DAG) {
|
2005-03-26 01:28:53 +00:00
|
|
|
// args_to_use will accumulate outgoing args for the ISD::CALL case in
|
|
|
|
// SelectExpr to use to put the arguments in the appropriate registers.
|
2005-03-24 04:41:43 +00:00
|
|
|
std::vector<SDOperand> args_to_use;
|
2005-03-26 01:28:53 +00:00
|
|
|
|
|
|
|
// Count how many bytes are to be pushed on the stack, including the linkage
|
|
|
|
// area, and parameter passing area.
|
|
|
|
unsigned NumBytes = 24;
|
|
|
|
|
|
|
|
if (Args.empty()) {
|
2005-05-12 23:24:06 +00:00
|
|
|
Chain = DAG.getNode(ISD::CALLSEQ_START, MVT::Other, Chain,
|
2005-04-01 05:57:17 +00:00
|
|
|
DAG.getConstant(NumBytes, getPointerTy()));
|
2005-03-26 01:28:53 +00:00
|
|
|
} else {
|
|
|
|
for (unsigned i = 0, e = Args.size(); i != e; ++i)
|
|
|
|
switch (getValueType(Args[i].second)) {
|
|
|
|
default: assert(0 && "Unknown value type!");
|
|
|
|
case MVT::i1:
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
|
|
|
case MVT::f32:
|
|
|
|
NumBytes += 4;
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
|
|
|
case MVT::f64:
|
|
|
|
NumBytes += 8;
|
|
|
|
break;
|
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
|
|
|
// Just to be safe, we'll always reserve the full 24 bytes of linkage area
|
2005-03-26 01:28:53 +00:00
|
|
|
// plus 32 bytes of argument space in case any called code gets funky on us.
|
2005-08-02 19:26:06 +00:00
|
|
|
// (Required by ABI to support var arg)
|
2005-03-26 01:28:53 +00:00
|
|
|
if (NumBytes < 56) NumBytes = 56;
|
|
|
|
|
|
|
|
// Adjust the stack pointer for the new arguments...
|
|
|
|
// These operations are automatically eliminated by the prolog/epilog pass
|
2005-05-12 23:24:06 +00:00
|
|
|
Chain = DAG.getNode(ISD::CALLSEQ_START, MVT::Other, Chain,
|
2005-03-26 01:28:53 +00:00
|
|
|
DAG.getConstant(NumBytes, getPointerTy()));
|
|
|
|
|
|
|
|
// Set up a copy of the stack pointer for use loading and storing any
|
|
|
|
// arguments that may not fit in the registers available for argument
|
|
|
|
// passing.
|
|
|
|
SDOperand StackPtr = DAG.getCopyFromReg(PPC::R1, MVT::i32,
|
|
|
|
DAG.getEntryNode());
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-26 01:28:53 +00:00
|
|
|
// Figure out which arguments are going to go in registers, and which in
|
|
|
|
// memory. Also, if this is a vararg function, floating point operations
|
|
|
|
// must be stored to our stack, and loaded into integer regs as well, if
|
|
|
|
// any integer regs are available for argument passing.
|
|
|
|
unsigned ArgOffset = 24;
|
|
|
|
unsigned GPR_remaining = 8;
|
|
|
|
unsigned FPR_remaining = 13;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-31 00:15:26 +00:00
|
|
|
std::vector<SDOperand> MemOps;
|
2005-03-26 01:28:53 +00:00
|
|
|
for (unsigned i = 0, e = Args.size(); i != e; ++i) {
|
|
|
|
// PtrOff will be used to store the current argument to the stack if a
|
|
|
|
// register cannot be found for it.
|
|
|
|
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff);
|
2005-03-26 07:46:36 +00:00
|
|
|
MVT::ValueType ArgVT = getValueType(Args[i].second);
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-26 07:46:36 +00:00
|
|
|
switch (ArgVT) {
|
2005-03-26 01:28:53 +00:00
|
|
|
default: assert(0 && "Unexpected ValueType for argument!");
|
|
|
|
case MVT::i1:
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
// Promote the integer to 32 bits. If the input type is signed use a
|
|
|
|
// sign extend, otherwise use a zero extend.
|
|
|
|
if (Args[i].second->isSigned())
|
|
|
|
Args[i].first =DAG.getNode(ISD::SIGN_EXTEND, MVT::i32, Args[i].first);
|
|
|
|
else
|
|
|
|
Args[i].first =DAG.getNode(ISD::ZERO_EXTEND, MVT::i32, Args[i].first);
|
|
|
|
// FALL THROUGH
|
|
|
|
case MVT::i32:
|
|
|
|
if (GPR_remaining > 0) {
|
2005-04-01 22:34:39 +00:00
|
|
|
args_to_use.push_back(Args[i].first);
|
2005-03-26 01:28:53 +00:00
|
|
|
--GPR_remaining;
|
|
|
|
} else {
|
2005-03-31 00:15:26 +00:00
|
|
|
MemOps.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
2005-05-15 19:54:37 +00:00
|
|
|
Args[i].first, PtrOff,
|
|
|
|
DAG.getSrcValue(NULL)));
|
2005-03-26 01:28:53 +00:00
|
|
|
}
|
|
|
|
ArgOffset += 4;
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
2005-03-26 07:46:36 +00:00
|
|
|
// If we have one free GPR left, we can place the upper half of the i64
|
|
|
|
// in it, and store the other half to the stack. If we have two or more
|
|
|
|
// free GPRs, then we can pass both halves of the i64 in registers.
|
|
|
|
if (GPR_remaining > 0) {
|
2005-04-21 23:30:14 +00:00
|
|
|
SDOperand Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32,
|
2005-03-26 02:17:46 +00:00
|
|
|
Args[i].first, DAG.getConstant(1, MVT::i32));
|
2005-04-21 23:30:14 +00:00
|
|
|
SDOperand Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32,
|
2005-03-26 02:17:46 +00:00
|
|
|
Args[i].first, DAG.getConstant(0, MVT::i32));
|
2005-04-01 22:34:39 +00:00
|
|
|
args_to_use.push_back(Hi);
|
2005-03-31 00:15:26 +00:00
|
|
|
--GPR_remaining;
|
|
|
|
if (GPR_remaining > 0) {
|
2005-04-01 22:34:39 +00:00
|
|
|
args_to_use.push_back(Lo);
|
2005-03-31 00:15:26 +00:00
|
|
|
--GPR_remaining;
|
2005-03-26 07:46:36 +00:00
|
|
|
} else {
|
|
|
|
SDOperand ConstFour = DAG.getConstant(4, getPointerTy());
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, MVT::i32, PtrOff, ConstFour);
|
2005-03-31 00:15:26 +00:00
|
|
|
MemOps.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
2005-04-27 20:10:01 +00:00
|
|
|
Lo, PtrOff, DAG.getSrcValue(NULL)));
|
2005-03-26 07:46:36 +00:00
|
|
|
}
|
2005-03-26 01:28:53 +00:00
|
|
|
} else {
|
2005-03-31 00:15:26 +00:00
|
|
|
MemOps.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
2005-05-15 19:54:37 +00:00
|
|
|
Args[i].first, PtrOff,
|
|
|
|
DAG.getSrcValue(NULL)));
|
2005-03-26 01:28:53 +00:00
|
|
|
}
|
|
|
|
ArgOffset += 8;
|
|
|
|
break;
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64:
|
2005-03-26 07:46:36 +00:00
|
|
|
if (FPR_remaining > 0) {
|
2005-04-01 22:34:39 +00:00
|
|
|
args_to_use.push_back(Args[i].first);
|
|
|
|
--FPR_remaining;
|
2005-03-26 07:46:36 +00:00
|
|
|
if (isVarArg) {
|
2005-03-31 02:05:53 +00:00
|
|
|
SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
2005-05-15 19:54:37 +00:00
|
|
|
Args[i].first, PtrOff,
|
|
|
|
DAG.getSrcValue(NULL));
|
2005-03-31 02:05:53 +00:00
|
|
|
MemOps.push_back(Store);
|
2005-03-31 00:15:26 +00:00
|
|
|
// Float varargs are always shadowed in available integer registers
|
|
|
|
if (GPR_remaining > 0) {
|
2005-05-15 19:54:37 +00:00
|
|
|
SDOperand Load = DAG.getLoad(MVT::i32, Store, PtrOff,
|
|
|
|
DAG.getSrcValue(NULL));
|
2005-03-31 00:15:26 +00:00
|
|
|
MemOps.push_back(Load);
|
2005-04-01 22:34:39 +00:00
|
|
|
args_to_use.push_back(Load);
|
|
|
|
--GPR_remaining;
|
2005-03-31 00:15:26 +00:00
|
|
|
}
|
2005-04-01 22:34:39 +00:00
|
|
|
if (GPR_remaining > 0 && MVT::f64 == ArgVT) {
|
2005-03-31 00:15:26 +00:00
|
|
|
SDOperand ConstFour = DAG.getConstant(4, getPointerTy());
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, MVT::i32, PtrOff, ConstFour);
|
2005-05-15 19:54:37 +00:00
|
|
|
SDOperand Load = DAG.getLoad(MVT::i32, Store, PtrOff,
|
|
|
|
DAG.getSrcValue(NULL));
|
2005-03-31 00:15:26 +00:00
|
|
|
MemOps.push_back(Load);
|
2005-04-01 22:34:39 +00:00
|
|
|
args_to_use.push_back(Load);
|
|
|
|
--GPR_remaining;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// If we have any FPRs remaining, we may also have GPRs remaining.
|
|
|
|
// Args passed in FPRs consume either 1 (f32) or 2 (f64) available
|
|
|
|
// GPRs.
|
|
|
|
if (GPR_remaining > 0) {
|
|
|
|
args_to_use.push_back(DAG.getNode(ISD::UNDEF, MVT::i32));
|
|
|
|
--GPR_remaining;
|
|
|
|
}
|
|
|
|
if (GPR_remaining > 0 && MVT::f64 == ArgVT) {
|
|
|
|
args_to_use.push_back(DAG.getNode(ISD::UNDEF, MVT::i32));
|
|
|
|
--GPR_remaining;
|
2005-03-31 00:15:26 +00:00
|
|
|
}
|
|
|
|
}
|
2005-03-26 01:28:53 +00:00
|
|
|
} else {
|
2005-03-31 00:15:26 +00:00
|
|
|
MemOps.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
2005-05-15 19:54:37 +00:00
|
|
|
Args[i].first, PtrOff,
|
|
|
|
DAG.getSrcValue(NULL)));
|
2005-03-26 01:28:53 +00:00
|
|
|
}
|
2005-03-26 07:46:36 +00:00
|
|
|
ArgOffset += (ArgVT == MVT::f32) ? 4 : 8;
|
2005-03-26 01:28:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
2005-03-31 00:15:26 +00:00
|
|
|
if (!MemOps.empty())
|
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, MemOps);
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
std::vector<MVT::ValueType> RetVals;
|
|
|
|
MVT::ValueType RetTyVT = getValueType(RetTy);
|
|
|
|
if (RetTyVT != MVT::isVoid)
|
|
|
|
RetVals.push_back(RetTyVT);
|
|
|
|
RetVals.push_back(MVT::Other);
|
|
|
|
|
2005-04-21 23:30:14 +00:00
|
|
|
SDOperand TheCall = SDOperand(DAG.getCall(RetVals,
|
2005-03-24 04:41:43 +00:00
|
|
|
Chain, Callee, args_to_use), 0);
|
|
|
|
Chain = TheCall.getValue(RetTyVT != MVT::isVoid);
|
2005-05-12 23:24:06 +00:00
|
|
|
Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
|
2005-03-24 04:41:43 +00:00
|
|
|
DAG.getConstant(NumBytes, getPointerTy()));
|
|
|
|
return std::make_pair(TheCall, Chain);
|
|
|
|
}
|
|
|
|
|
2005-07-05 19:58:54 +00:00
|
|
|
SDOperand PPC32TargetLowering::LowerVAStart(SDOperand Chain, SDOperand VAListP,
|
|
|
|
Value *VAListV, SelectionDAG &DAG) {
|
2005-07-05 17:48:31 +00:00
|
|
|
// vastart just stores the address of the VarArgsFrameIndex slot into the
|
|
|
|
// memory location argument.
|
|
|
|
SDOperand FR = DAG.getFrameIndex(VarArgsFrameIndex, MVT::i32);
|
2005-07-05 19:58:54 +00:00
|
|
|
return DAG.getNode(ISD::STORE, MVT::Other, Chain, FR, VAListP,
|
|
|
|
DAG.getSrcValue(VAListV));
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
|
|
|
|
2005-07-05 19:58:54 +00:00
|
|
|
std::pair<SDOperand,SDOperand>
|
|
|
|
PPC32TargetLowering::LowerVAArg(SDOperand Chain,
|
|
|
|
SDOperand VAListP, Value *VAListV,
|
|
|
|
const Type *ArgTy, SelectionDAG &DAG) {
|
2005-03-25 08:34:25 +00:00
|
|
|
MVT::ValueType ArgVT = getValueType(ArgTy);
|
2005-07-05 17:48:31 +00:00
|
|
|
|
|
|
|
SDOperand VAList =
|
2005-07-05 19:58:54 +00:00
|
|
|
DAG.getLoad(MVT::i32, Chain, VAListP, DAG.getSrcValue(VAListV));
|
|
|
|
SDOperand Result = DAG.getLoad(ArgVT, Chain, VAList, DAG.getSrcValue(NULL));
|
2005-07-05 17:48:31 +00:00
|
|
|
unsigned Amt;
|
|
|
|
if (ArgVT == MVT::i32 || ArgVT == MVT::f32)
|
|
|
|
Amt = 4;
|
|
|
|
else {
|
|
|
|
assert((ArgVT == MVT::i64 || ArgVT == MVT::f64) &&
|
|
|
|
"Other types should have been promoted for varargs!");
|
|
|
|
Amt = 8;
|
2005-03-25 08:34:25 +00:00
|
|
|
}
|
2005-07-05 17:48:31 +00:00
|
|
|
VAList = DAG.getNode(ISD::ADD, VAList.getValueType(), VAList,
|
|
|
|
DAG.getConstant(Amt, VAList.getValueType()));
|
|
|
|
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
2005-07-05 19:58:54 +00:00
|
|
|
VAList, VAListP, DAG.getSrcValue(VAListV));
|
2005-03-25 08:34:25 +00:00
|
|
|
return std::make_pair(Result, Chain);
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
|
|
|
|
std::pair<SDOperand, SDOperand> PPC32TargetLowering::
|
|
|
|
LowerFrameReturnAddress(bool isFrameAddress, SDOperand Chain, unsigned Depth,
|
|
|
|
SelectionDAG &DAG) {
|
2005-03-30 01:45:43 +00:00
|
|
|
assert(0 && "LowerFrameReturnAddress unimplemented");
|
2005-03-24 04:41:43 +00:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
2005-04-11 06:34:10 +00:00
|
|
|
Statistic<>Recorded("ppc-codegen", "Number of recording ops emitted");
|
2005-04-04 23:40:36 +00:00
|
|
|
Statistic<>FusedFP("ppc-codegen", "Number of fused fp operations");
|
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
|
|
|
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
|
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
/// ISel - PPC32 specific code to select PPC32 machine instructions for
|
|
|
|
/// SelectionDAG operations.
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
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
|
|
|
|
|
|
|
// 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);
|
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
|
|
|
void MoveCRtoGPR(unsigned CCReg, bool Inv, unsigned Idx, 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);
|
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
|
|
|
unsigned SelectCC(SDOperand CC, unsigned &Opc, bool &Inv, unsigned &Idx);
|
|
|
|
unsigned SelectCCExpr(SDOperand N, unsigned& Opc, bool &Inv, unsigned &Idx);
|
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
|
|
|
|
if (!(Mask & Indeterminant)) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// isImmediate - This method tests to see if a constant operand.
|
|
|
|
// If so Imm will receive the 32 bit value.
|
|
|
|
static bool isImmediate(SDOperand N, unsigned& Imm) {
|
|
|
|
// test for constant
|
|
|
|
if (N.getOpcode() == ISD::Constant) {
|
|
|
|
// retrieve value
|
|
|
|
Imm = (unsigned)cast<ConstantSDNode>(N)->getSignExtended();
|
|
|
|
// passes muster
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// not a constant
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) &&
|
|
|
|
isImmediate(N.getOperand(1), SH) && SH < 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
// isOprNot - Returns true if the specified operand is an xor with immediate -1.
|
|
|
|
static bool isOprNot(SDOperand N) {
|
|
|
|
unsigned Imm;
|
|
|
|
return N.getOpcode() == ISD::XOR &&
|
|
|
|
isImmediate(N.getOperand(1), Imm) && (signed)Imm == -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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-05 04:22:58 +00:00
|
|
|
/// getImmediateForOpcode - This method returns a value indicating whether
|
2005-03-24 04:41:43 +00:00
|
|
|
/// the ConstantSDNode N can be used as an immediate to Opcode. The return
|
|
|
|
/// values are either 0, 1 or 2. 0 indicates that either N is not a
|
2005-04-12 00:10:02 +00:00
|
|
|
/// ConstantSDNode, or is not suitable for use by that opcode.
|
|
|
|
/// Return value codes for turning into an enum someday:
|
|
|
|
/// 1: constant may be used in normal immediate form.
|
|
|
|
/// 2: constant may be used in shifted immediate form.
|
|
|
|
/// 3: log base 2 of the constant may be used.
|
|
|
|
/// 4: constant is suitable for integer division conversion
|
|
|
|
/// 5: constant is a bitfield mask
|
2005-03-24 04:41:43 +00:00
|
|
|
///
|
2005-04-05 04:22:58 +00:00
|
|
|
static unsigned getImmediateForOpcode(SDOperand N, unsigned Opcode,
|
|
|
|
unsigned& Imm, bool U = false) {
|
2005-03-24 04:41:43 +00:00
|
|
|
if (N.getOpcode() != ISD::Constant) return 0;
|
|
|
|
|
|
|
|
int v = (int)cast<ConstantSDNode>(N)->getSignExtended();
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
switch(Opcode) {
|
|
|
|
default: return 0;
|
|
|
|
case ISD::ADD:
|
2005-08-02 19:26:06 +00:00
|
|
|
if (isInt16(v)) { Imm = v & 0xFFFF; return 1; }
|
2005-03-24 04:41:43 +00:00
|
|
|
if ((v & 0x0000FFFF) == 0) { Imm = v >> 16; return 2; }
|
|
|
|
break;
|
2005-04-12 00:10:02 +00:00
|
|
|
case ISD::AND: {
|
|
|
|
unsigned MB, ME;
|
2005-08-08 21:08:09 +00:00
|
|
|
if (isRunOfOnes(v, MB, ME)) { Imm = MB << 16 | ME & 0xFFFF; return 5; }
|
2005-08-02 19:26:06 +00:00
|
|
|
if (isUInt16(v)) { Imm = v & 0xFFFF; return 1; }
|
2005-04-12 00:10:02 +00:00
|
|
|
if ((v & 0x0000FFFF) == 0) { Imm = v >> 16; return 2; }
|
|
|
|
break;
|
|
|
|
}
|
2005-03-24 04:41:43 +00:00
|
|
|
case ISD::XOR:
|
|
|
|
case ISD::OR:
|
2005-08-02 19:26:06 +00:00
|
|
|
if (isUInt16(v)) { Imm = v & 0xFFFF; return 1; }
|
2005-03-24 04:41:43 +00:00
|
|
|
if ((v & 0x0000FFFF) == 0) { Imm = v >> 16; return 2; }
|
|
|
|
break;
|
2005-03-26 01:28:53 +00:00
|
|
|
case ISD::MUL:
|
2005-08-02 19:26:06 +00:00
|
|
|
if (isInt16(v)) { Imm = v & 0xFFFF; return 1; }
|
2005-03-26 01:28:53 +00:00
|
|
|
break;
|
2005-05-11 23:43:56 +00:00
|
|
|
case ISD::SUB:
|
|
|
|
// handle subtract-from separately from subtract, since subi is really addi
|
2005-08-02 19:26:06 +00:00
|
|
|
if (U && isInt16(v)) { Imm = v & 0xFFFF; return 1; }
|
|
|
|
if (!U && isInt16(-v)) { Imm = (-v) & 0xFFFF; return 1; }
|
2005-05-11 23:43:56 +00:00
|
|
|
break;
|
2005-03-31 23:55:40 +00:00
|
|
|
case ISD::SETCC:
|
2005-08-02 19:26:06 +00:00
|
|
|
if (U && isUInt16(v)) { Imm = v & 0xFFFF; return 1; }
|
|
|
|
if (!U && isInt16(v)) { Imm = v & 0xFFFF; return 1; }
|
2005-03-31 23:55:40 +00:00
|
|
|
break;
|
2005-04-05 00:15:08 +00:00
|
|
|
case ISD::SDIV:
|
2005-08-02 19:26:06 +00:00
|
|
|
if (isPowerOf2_32(v)) { Imm = Log2_32(v); return 3; }
|
|
|
|
if (isPowerOf2_32(-v)) { Imm = Log2_32(-v); return 3; }
|
2005-04-06 00:25:27 +00:00
|
|
|
if (v <= -2 || v >= 2) { return 4; }
|
|
|
|
break;
|
|
|
|
case ISD::UDIV:
|
2005-04-06 06:44:57 +00:00
|
|
|
if (v > 1) { return 4; }
|
2005-04-05 00:15:08 +00:00
|
|
|
break;
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2005-03-31 23:55:40 +00:00
|
|
|
|
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
|
|
|
|
/// to Condition. If the Condition is unordered or unsigned, the bool argument
|
|
|
|
/// U is set to true, otherwise it is set to false.
|
|
|
|
static unsigned getBCCForSetCC(unsigned Condition, bool& U) {
|
|
|
|
U = false;
|
|
|
|
switch (Condition) {
|
|
|
|
default: assert(0 && "Unknown condition!"); abort();
|
|
|
|
case ISD::SETEQ: return PPC::BEQ;
|
|
|
|
case ISD::SETNE: return PPC::BNE;
|
|
|
|
case ISD::SETULT: U = true;
|
|
|
|
case ISD::SETLT: return PPC::BLT;
|
|
|
|
case ISD::SETULE: U = true;
|
|
|
|
case ISD::SETLE: return PPC::BLE;
|
|
|
|
case ISD::SETUGT: U = true;
|
|
|
|
case ISD::SETGT: return PPC::BGT;
|
|
|
|
case ISD::SETUGE: U = true;
|
|
|
|
case ISD::SETGE: return PPC::BGE;
|
|
|
|
}
|
2005-04-01 04:45:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-14 09:45:08 +00:00
|
|
|
/// getCROpForOp - Return the condition register opcode (or inverted opcode)
|
|
|
|
/// associated with the SelectionDAG opcode.
|
|
|
|
static unsigned getCROpForSetCC(unsigned Opcode, bool Inv1, bool Inv2) {
|
|
|
|
switch (Opcode) {
|
|
|
|
default: assert(0 && "Unknown opcode!"); abort();
|
|
|
|
case ISD::AND:
|
|
|
|
if (Inv1 && Inv2) return PPC::CRNOR; // De Morgan's Law
|
|
|
|
if (!Inv1 && !Inv2) return PPC::CRAND;
|
|
|
|
if (Inv1 ^ Inv2) return PPC::CRANDC;
|
|
|
|
case ISD::OR:
|
|
|
|
if (Inv1 && Inv2) return PPC::CRNAND; // De Morgan's Law
|
|
|
|
if (!Inv1 && !Inv2) return PPC::CROR;
|
|
|
|
if (Inv1 ^ Inv2) return PPC::CRORC;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getCRIdxForSetCC - Return the index of the condition register field
|
|
|
|
/// associated with the SetCC condition, and whether or not the field is
|
|
|
|
/// treated as inverted. That is, lt = 0; ge = 0 inverted.
|
|
|
|
static unsigned getCRIdxForSetCC(unsigned Condition, bool& Inv) {
|
|
|
|
switch (Condition) {
|
|
|
|
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();
|
|
|
|
GlobalBaseReg = MakeReg(MVT::i32);
|
|
|
|
BuildMI(FirstMBB, MBBI, PPC::MovePCtoLR, 0, PPC::LR);
|
|
|
|
BuildMI(FirstMBB, MBBI, PPC::MFLR, 1, GlobalBaseReg).addReg(PPC::LR);
|
|
|
|
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) {
|
|
|
|
unsigned Tmp1 = MakeReg(MVT::i32);
|
|
|
|
if (0 == Result) Result = MakeReg(MVT::f64);
|
|
|
|
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.
|
|
|
|
void ISel::MoveCRtoGPR(unsigned CCReg, bool Inv, unsigned Idx, unsigned Result){
|
|
|
|
unsigned IntCR = MakeReg(MVT::i32);
|
|
|
|
BuildMI(BB, PPC::MCRF, 1, PPC::CR7).addReg(CCReg);
|
2005-08-05 22:05:03 +00:00
|
|
|
bool GPOpt =
|
|
|
|
TLI.getTargetMachine().getSubtarget<PPCSubtarget>().isGigaProcessor();
|
|
|
|
BuildMI(BB, GPOpt ? PPC::MFOCRF : PPC::MFCR, 1, IntCR).addReg(PPC::CR7);
|
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) {
|
|
|
|
unsigned Tmp1 = MakeReg(MVT::i32);
|
|
|
|
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-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-04-21 23:30:14 +00:00
|
|
|
if (ConstantSDNode *CN =
|
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
|
|
|
dyn_cast<ConstantSDNode>(Op0.getOperand(1).Val)) {
|
2005-04-06 23:51:40 +00:00
|
|
|
switch(Op0Opc) {
|
|
|
|
case ISD::SHL: TgtMask <<= (unsigned)CN->getValue(); break;
|
|
|
|
case ISD::SRL: TgtMask >>= (unsigned)CN->getValue(); break;
|
|
|
|
case ISD::AND: TgtMask &= (unsigned)CN->getValue(); break;
|
|
|
|
}
|
|
|
|
} 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-04-21 23:30:14 +00:00
|
|
|
if (ConstantSDNode *CN =
|
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
|
|
|
dyn_cast<ConstantSDNode>(Op1.getOperand(1).Val)) {
|
2005-04-06 23:51:40 +00:00
|
|
|
switch(Op1Opc) {
|
2005-04-21 23:30:14 +00:00
|
|
|
case ISD::SHL:
|
|
|
|
Amount = CN->getValue();
|
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:
|
|
|
|
Amount = CN->getValue();
|
|
|
|
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-04-06 23:51:40 +00:00
|
|
|
InsMask &= (unsigned)CN->getValue();
|
|
|
|
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-07-27 06:12:32 +00:00
|
|
|
if (ConstantSDNode *CN =
|
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
|
|
|
dyn_cast<ConstantSDNode>(Op1.getOperand(0).getOperand(1).Val)) {
|
2005-07-27 06:12:32 +00:00
|
|
|
Amount = 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
|
|
|
CN->getValue() : 32 - CN->getValue();
|
|
|
|
Tmp3 = SelectExpr(Op1.getOperand(0).getOperand(0));
|
|
|
|
}
|
|
|
|
} else if (Op0.getOperand(0).getOpcode() == ISD::SHL ||
|
|
|
|
Op0.getOperand(0).getOpcode() == ISD::SRL) {
|
2005-07-27 06:12:32 +00:00
|
|
|
if (ConstantSDNode *CN =
|
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
|
|
|
dyn_cast<ConstantSDNode>(Op0.getOperand(0).getOperand(1).Val)) {
|
|
|
|
std::swap(Op0, Op1);
|
|
|
|
std::swap(TgtMask, InsMask);
|
2005-07-27 06:12:32 +00:00
|
|
|
Amount = 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
|
|
|
CN->getValue() : 32 - CN->getValue();
|
|
|
|
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-08 21:12:35 +00:00
|
|
|
unsigned C, MB, ME;
|
2005-04-13 22:14:14 +00:00
|
|
|
if (N.getOpcode() == ISD::AND &&
|
2005-08-08 21:12:35 +00:00
|
|
|
isImmediate(N.getOperand(1), C) && isRunOfOnes(C, MB, ME) &&
|
|
|
|
MB <= 26 && ME == 31)
|
2005-04-13 22:14:14 +00:00
|
|
|
return SelectExpr(N.getOperand(0));
|
|
|
|
else
|
|
|
|
return SelectExpr(N);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
unsigned ISel::SelectCC(SDOperand CC, unsigned& Opc, bool &Inv, unsigned& Idx) {
|
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-03-31 23:55:40 +00:00
|
|
|
// If the first operand to the select is a SETCC node, then we can fold it
|
|
|
|
// into the branch that selects which value to return.
|
2005-04-18 02:43:24 +00:00
|
|
|
if (SetCCSDNode* SetCC = dyn_cast<SetCCSDNode>(CC.Val)) {
|
2005-03-31 23:55:40 +00:00
|
|
|
bool U;
|
|
|
|
Opc = getBCCForSetCC(SetCC->getCondition(), U);
|
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
|
|
|
Idx = getCRIdxForSetCC(SetCC->getCondition(), Inv);
|
2005-03-31 23:55:40 +00:00
|
|
|
|
2005-08-08 21:12:35 +00:00
|
|
|
// Use U to determine whether the SETCC immediate range is signed or not.
|
|
|
|
if (isImmediate(SetCC->getOperand(1), Tmp2) &&
|
|
|
|
((U && isUInt16(Tmp2)) || (!U && isInt16(Tmp2)))) {
|
|
|
|
Tmp2 = Lo16(Tmp2);
|
2005-04-21 23:30:14 +00:00
|
|
|
// For comparisons against zero, we can implicity set CR0 if a recording
|
2005-04-11 06:34:10 +00:00
|
|
|
// variant (e.g. 'or.' instead of 'or') of the instruction that defines
|
|
|
|
// operand zero of the SetCC node is available.
|
2005-04-21 23:30:14 +00:00
|
|
|
if (0 == Tmp2 &&
|
2005-04-12 21:22:28 +00:00
|
|
|
NodeHasRecordingVariant(SetCC->getOperand(0).getOpcode()) &&
|
|
|
|
SetCC->getOperand(0).Val->hasOneUse()) {
|
2005-04-11 06:34:10 +00:00
|
|
|
RecordSuccess = false;
|
|
|
|
Tmp1 = SelectExpr(SetCC->getOperand(0), true);
|
|
|
|
if (RecordSuccess) {
|
|
|
|
++Recorded;
|
2005-04-14 09:45:08 +00:00
|
|
|
BuildMI(BB, PPC::MCRF, 1, Result).addReg(PPC::CR0);
|
|
|
|
return Result;
|
2005-04-11 06:34:10 +00:00
|
|
|
}
|
|
|
|
AlreadySelected = true;
|
|
|
|
}
|
|
|
|
// If we could not implicitly set CR0, then emit a compare immediate
|
|
|
|
// instead.
|
|
|
|
if (!AlreadySelected) Tmp1 = SelectExpr(SetCC->getOperand(0));
|
2005-03-31 23:55:40 +00:00
|
|
|
if (U)
|
2005-04-13 23:15:44 +00:00
|
|
|
BuildMI(BB, PPC::CMPLWI, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
2005-03-31 23:55:40 +00:00
|
|
|
else
|
2005-04-13 23:15:44 +00:00
|
|
|
BuildMI(BB, PPC::CMPWI, 2, Result).addReg(Tmp1).addSImm(Tmp2);
|
2005-03-31 23:55:40 +00:00
|
|
|
} else {
|
2005-04-01 00:32:34 +00:00
|
|
|
bool IsInteger = MVT::isInteger(SetCC->getOperand(0).getValueType());
|
|
|
|
unsigned CompareOpc = CompareOpcodes[2 * IsInteger + U];
|
2005-04-11 06:34:10 +00:00
|
|
|
Tmp1 = SelectExpr(SetCC->getOperand(0));
|
2005-03-31 23:55:40 +00:00
|
|
|
Tmp2 = SelectExpr(SetCC->getOperand(1));
|
2005-04-13 23:15:44 +00:00
|
|
|
BuildMI(BB, CompareOpc, 2, Result).addReg(Tmp1).addReg(Tmp2);
|
2005-03-31 23:55:40 +00:00
|
|
|
}
|
|
|
|
} else {
|
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 this isn't a SetCC, then select the value and compare it against zero,
|
|
|
|
// treating it as if it were a boolean.
|
2005-04-12 21:22:28 +00:00
|
|
|
Opc = PPC::BNE;
|
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
|
|
|
Idx = getCRIdxForSetCC(ISD::SETNE, Inv);
|
2005-04-01 00:32:34 +00:00
|
|
|
Tmp1 = SelectExpr(CC);
|
2005-04-13 23:15:44 +00:00
|
|
|
BuildMI(BB, PPC::CMPLWI, 2, Result).addReg(Tmp1).addImm(0);
|
2005-03-31 23:55:40 +00:00
|
|
|
}
|
2005-04-13 23:15:44 +00:00
|
|
|
return Result;
|
2005-04-01 00:32:34 +00:00
|
|
|
}
|
2005-03-31 23:55:40 +00:00
|
|
|
|
2005-04-21 23:30:14 +00:00
|
|
|
unsigned ISel::SelectCCExpr(SDOperand N, unsigned& Opc, bool &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
|
|
|
unsigned &Idx) {
|
|
|
|
bool Inv0, Inv1;
|
|
|
|
unsigned Idx0, Idx1, CROpc, Opc1, Tmp1, Tmp2;
|
|
|
|
|
|
|
|
// Allocate a condition register for this expression
|
|
|
|
unsigned Result = RegMap->createVirtualRegister(PPC32::CRRCRegisterClass);
|
|
|
|
|
|
|
|
// Check for the operations we support:
|
|
|
|
switch(N.getOpcode()) {
|
|
|
|
default:
|
|
|
|
Opc = PPC::BNE;
|
|
|
|
Idx = getCRIdxForSetCC(ISD::SETNE, Inv);
|
|
|
|
Tmp1 = SelectExpr(N);
|
|
|
|
BuildMI(BB, PPC::CMPLWI, 2, Result).addReg(Tmp1).addImm(0);
|
|
|
|
break;
|
|
|
|
case ISD::OR:
|
|
|
|
case ISD::AND:
|
|
|
|
Tmp1 = SelectCCExpr(N.getOperand(0), Opc, Inv0, Idx0);
|
|
|
|
Tmp2 = SelectCCExpr(N.getOperand(1), Opc1, Inv1, Idx1);
|
|
|
|
CROpc = getCROpForSetCC(N.getOpcode(), Inv0, Inv1);
|
|
|
|
if (Inv0 && !Inv1) {
|
|
|
|
std::swap(Tmp1, Tmp2);
|
|
|
|
std::swap(Idx0, Idx1);
|
|
|
|
Opc = Opc1;
|
|
|
|
}
|
|
|
|
if (Inv0 && Inv1) Opc = PPC32InstrInfo::invertPPCBranchOpcode(Opc);
|
|
|
|
BuildMI(BB, CROpc, 5, Result).addImm(Idx0).addReg(Tmp1).addImm(Idx0)
|
|
|
|
.addReg(Tmp2).addImm(Idx1);
|
|
|
|
Inv = false;
|
|
|
|
Idx = Idx0;
|
|
|
|
break;
|
|
|
|
case ISD::SETCC:
|
|
|
|
Tmp1 = SelectCC(N, Opc, Inv, Idx);
|
|
|
|
Result = Tmp1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2005-04-01 00:32:34 +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-08 21:12:35 +00:00
|
|
|
if (isImmediate(N.getOperand(1), imm) && isInt16(imm)) {
|
|
|
|
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-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-04-01 00:32:34 +00:00
|
|
|
cast<BasicBlockSDNode>(N.getOperand(2))->getBasicBlock();
|
|
|
|
|
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
|
|
|
bool Inv;
|
|
|
|
unsigned Opc, CCReg, Idx;
|
2005-04-01 00:32:34 +00:00
|
|
|
Select(N.getOperand(0)); //chain
|
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
|
|
|
CCReg = SelectCC(N.getOperand(1), Opc, Inv, Idx);
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-06-15 18:22:43 +00:00
|
|
|
// Iterate to the next basic block
|
|
|
|
ilist<MachineBasicBlock>::iterator It = BB;
|
|
|
|
++It;
|
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.
|
|
|
|
if (N.getOpcode() == ISD::BRCONDTWOWAY) {
|
2005-04-21 23:30:14 +00:00
|
|
|
MachineBasicBlock *Fallthrough =
|
2005-04-09 20:09:12 +00:00
|
|
|
cast<BasicBlockSDNode>(N.getOperand(3))->getBasicBlock();
|
|
|
|
if (Dest != It) {
|
2005-04-13 23:15:44 +00:00
|
|
|
BuildMI(BB, PPC::COND_BRANCH, 4).addReg(CCReg).addImm(Opc)
|
2005-04-09 20:09:12 +00:00
|
|
|
.addMBB(Dest).addMBB(Fallthrough);
|
|
|
|
if (Fallthrough != It)
|
|
|
|
BuildMI(BB, PPC::B, 1).addMBB(Fallthrough);
|
|
|
|
} else {
|
|
|
|
if (Fallthrough != It) {
|
|
|
|
Opc = PPC32InstrInfo::invertPPCBranchOpcode(Opc);
|
2005-04-13 23:15:44 +00:00
|
|
|
BuildMI(BB, PPC::COND_BRANCH, 4).addReg(CCReg).addImm(Opc)
|
2005-04-09 20:09:12 +00:00
|
|
|
.addMBB(Fallthrough).addMBB(Dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
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;
|
|
|
|
}
|
|
|
|
|
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-06-14 03:55:23 +00:00
|
|
|
if (Node->getOpcode() == ISD::CopyFromReg &&
|
2005-07-28 05:23:43 +00:00
|
|
|
(MRegisterInfo::isVirtualRegister(cast<RegSDNode>(Node)->getReg()) ||
|
|
|
|
cast<RegSDNode>(Node)->getReg() == PPC::R1))
|
2005-06-14 03:55:23 +00:00
|
|
|
// Just use the specified register as our input.
|
|
|
|
return cast<RegSDNode>(Node)->getReg();
|
|
|
|
|
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:
|
|
|
|
Node->dump();
|
|
|
|
assert(0 && "Node not handled!\n");
|
2005-04-01 22:34:39 +00:00
|
|
|
case ISD::UNDEF:
|
|
|
|
BuildMI(BB, PPC::IMPLICIT_DEF, 0, Result);
|
|
|
|
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();
|
|
|
|
Tmp2 = MakeReg(MVT::i32);
|
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-03-28 22:28:37 +00:00
|
|
|
Tmp1 = MakeReg(MVT::i32);
|
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)) {
|
|
|
|
Tmp1 = MakeReg(MVT::i32);
|
|
|
|
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-07-21 20:44:43 +00:00
|
|
|
} else if(GlobalAddressSDNode *GN = dyn_cast<GlobalAddressSDNode>(Address)){
|
|
|
|
GlobalValue *GV = GN->getGlobal();
|
|
|
|
Tmp1 = MakeReg(MVT::i32);
|
|
|
|
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-07-21 20:44:43 +00:00
|
|
|
if (GV->hasWeakLinkage() || GV->isExternal()) {
|
|
|
|
Tmp2 = MakeReg(MVT::i32);
|
|
|
|
BuildMI(BB, PPC::LWZ, 2, Tmp2).addGlobalAddress(GV).addReg(Tmp1);
|
2005-07-25 21:15:28 +00:00
|
|
|
BuildMI(BB, Opc, 2, Result).addSImm(0).addReg(Tmp2);
|
|
|
|
} else {
|
|
|
|
BuildMI(BB, Opc, 2, Result).addGlobalAddress(GV).addReg(Tmp1);
|
2005-07-21 20:44:43 +00:00
|
|
|
}
|
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-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));
|
|
|
|
BuildMI(BB, PPC::OR, 2, PPC::R12).addReg(Tmp1).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::MTCTR, 1).addReg(PPC::R12);
|
|
|
|
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::i1:
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
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::i1:
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
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-29 22:24:51 +00:00
|
|
|
case MVT::i1:
|
|
|
|
BuildMI(BB, PPC::SUBFIC, 2, Result).addReg(Tmp1).addSImm(0);
|
|
|
|
break;
|
2005-03-28 19:36:43 +00:00
|
|
|
}
|
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-03-24 04:41:43 +00:00
|
|
|
Tmp1 = dyn_cast<RegSDNode>(Node)->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-03-24 06:28:42 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
|
|
|
|
Tmp2 = CN->getValue() & 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-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-03-24 06:28:42 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
|
|
|
|
Tmp2 = CN->getValue() & 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-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:
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
|
|
|
|
Tmp2 = CN->getValue() & 0x1F;
|
|
|
|
BuildMI(BB, PPC::SRAWI, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
|
|
|
} else {
|
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-03-24 04:41:43 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-08-08 21:21:03 +00:00
|
|
|
if (isImmediate(N.getOperand(1), Tmp2)) {
|
|
|
|
Tmp3 = HA16(Tmp2);
|
|
|
|
Tmp2 = Lo16(Tmp2);
|
|
|
|
if (Tmp2 && Tmp3) {
|
|
|
|
unsigned Reg = MakeReg(MVT::i32);
|
|
|
|
BuildMI(BB, PPC::ADDI, 2, Reg).addReg(Tmp1).addSImm(Tmp2);
|
|
|
|
BuildMI(BB, PPC::ADDIS, 2, Result).addReg(Reg).addSImm(Tmp3);
|
|
|
|
} else if (Tmp2) {
|
2005-03-24 04:41:43 +00:00
|
|
|
BuildMI(BB, PPC::ADDI, 2, Result).addReg(Tmp1).addSImm(Tmp2);
|
2005-08-08 21:21:03 +00:00
|
|
|
} else {
|
|
|
|
BuildMI(BB, PPC::ADDIS, 2, Result).addReg(Tmp1).addSImm(Tmp3);
|
|
|
|
}
|
|
|
|
return Result;
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
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-08 21:24:57 +00:00
|
|
|
if (isImmediate(N.getOperand(1), Tmp2)) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isOprNot(N.getOperand(0))) {
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
|
|
|
BuildMI(BB, PPC::ANDC, 2, Result).addReg(Tmp2).addReg(Tmp1);
|
|
|
|
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-08 21:30:29 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-08-08 21:30:29 +00:00
|
|
|
if (isImmediate(N.getOperand(1), Tmp2)) {
|
|
|
|
Tmp3 = Hi16(Tmp2);
|
|
|
|
Tmp2 = Lo16(Tmp2);
|
|
|
|
if (Tmp2 && Tmp3) {
|
|
|
|
unsigned Reg = MakeReg(MVT::i32);
|
|
|
|
BuildMI(BB, PPC::ORI, 2, Reg).addReg(Tmp1).addImm(Tmp2);
|
|
|
|
BuildMI(BB, PPC::ORIS, 2, Result).addReg(Reg).addImm(Tmp3);
|
|
|
|
} else if (Tmp2) {
|
2005-04-06 23:51:40 +00:00
|
|
|
BuildMI(BB, PPC::ORI, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
2005-08-08 21:30:29 +00:00
|
|
|
} else {
|
|
|
|
BuildMI(BB, PPC::ORIS, 2, Result).addReg(Tmp1).addImm(Tmp3);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
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
|
|
|
|
if (N.getOperand(0).getOpcode() == ISD::XOR &&
|
2005-08-08 21:30:29 +00:00
|
|
|
isImmediate(N.getOperand(0).getOperand(1), Tmp2) &&
|
|
|
|
(signed)Tmp2 == -1) {
|
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;
|
|
|
|
}
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-08-08 21:30:29 +00:00
|
|
|
if (isImmediate(N.getOperand(1), Tmp2)) {
|
|
|
|
Tmp3 = Hi16(Tmp2);
|
|
|
|
Tmp2 = Lo16(Tmp2);
|
|
|
|
if (Tmp2 && Tmp3) {
|
|
|
|
unsigned Reg = MakeReg(MVT::i32);
|
|
|
|
BuildMI(BB, PPC::XORI, 2, Reg).addReg(Tmp1).addImm(Tmp2);
|
|
|
|
BuildMI(BB, PPC::XORIS, 2, Result).addReg(Reg).addImm(Tmp3);
|
|
|
|
} else if (Tmp2) {
|
2005-04-03 11:20:20 +00:00
|
|
|
BuildMI(BB, PPC::XORI, 2, Result).addReg(Tmp1).addImm(Tmp2);
|
2005-08-08 21:30:29 +00:00
|
|
|
} else {
|
|
|
|
BuildMI(BB, PPC::XORIS, 2, Result).addReg(Tmp1).addImm(Tmp3);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
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-08 21:30:29 +00:00
|
|
|
if (isImmediate(N.getOperand(0), Tmp1) && isInt16(Tmp1)) {
|
2005-05-11 23:43:56 +00:00
|
|
|
Tmp2 = SelectExpr(N.getOperand(1));
|
2005-04-02 00:42:16 +00:00
|
|
|
BuildMI(BB, PPC::SUBFIC, 2, Result).addReg(Tmp2).addSImm(Tmp1);
|
2005-08-08 21:30:29 +00:00
|
|
|
return Result;
|
|
|
|
} else if (isImmediate(N.getOperand(1), Tmp2)) {
|
2005-05-11 23:43:56 +00:00
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
2005-08-08 21:30:29 +00:00
|
|
|
Tmp2 = -Tmp2;
|
|
|
|
Tmp3 = HA16(Tmp2);
|
|
|
|
Tmp2 = Lo16(Tmp2);
|
|
|
|
if (Tmp2 && Tmp3) {
|
|
|
|
unsigned Reg = MakeReg(MVT::i32);
|
|
|
|
BuildMI(BB, PPC::ADDI, 2, Reg).addReg(Tmp1).addSImm(Tmp2);
|
|
|
|
BuildMI(BB, PPC::ADDIS, 2, Result).addReg(Reg).addSImm(Tmp3);
|
|
|
|
} else if (Tmp2) {
|
|
|
|
BuildMI(BB, PPC::ADDI, 2, Result).addReg(Tmp1).addSImm(Tmp2);
|
|
|
|
} else {
|
|
|
|
BuildMI(BB, PPC::ADDIS, 2, Result).addReg(Tmp1).addSImm(Tmp3);
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
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-04-05 04:22:58 +00:00
|
|
|
if (1 == getImmediateForOpcode(N.getOperand(1), opcode, Tmp2))
|
2005-03-26 01:28:53 +00:00
|
|
|
BuildMI(BB, PPC::MULLI, 2, Result).addReg(Tmp1).addSImm(Tmp2);
|
|
|
|
else {
|
|
|
|
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:
|
|
|
|
case ISD::UDIV:
|
2005-04-06 00:25:27 +00:00
|
|
|
switch (getImmediateForOpcode(N.getOperand(1), opcode, Tmp3)) {
|
|
|
|
default: break;
|
|
|
|
// If this is an sdiv by a power of two, we can use an srawi/addze pair.
|
|
|
|
case 3:
|
2005-04-05 00:15:08 +00:00
|
|
|
Tmp1 = MakeReg(MVT::i32);
|
|
|
|
Tmp2 = SelectExpr(N.getOperand(0));
|
2005-04-12 00:10:02 +00:00
|
|
|
if ((int)Tmp3 < 0) {
|
|
|
|
unsigned Tmp4 = MakeReg(MVT::i32);
|
|
|
|
BuildMI(BB, PPC::SRAWI, 2, Tmp1).addReg(Tmp2).addImm(-Tmp3);
|
|
|
|
BuildMI(BB, PPC::ADDZE, 1, Tmp4).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::NEG, 1, Result).addReg(Tmp4);
|
|
|
|
} else {
|
|
|
|
BuildMI(BB, PPC::SRAWI, 2, Tmp1).addReg(Tmp2).addImm(Tmp3);
|
|
|
|
BuildMI(BB, PPC::ADDZE, 1, Result).addReg(Tmp1);
|
|
|
|
}
|
2005-04-05 00:15:08 +00:00
|
|
|
return Result;
|
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-04-06 06:44:57 +00:00
|
|
|
case 4:
|
|
|
|
ExprMap.erase(N);
|
2005-04-21 23:30:14 +00:00
|
|
|
if (opcode == ISD::SDIV)
|
2005-04-06 06:44:57 +00:00
|
|
|
return SelectExpr(BuildSDIVSequence(N));
|
|
|
|
else
|
|
|
|
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) {
|
|
|
|
default: assert(0 && "Unknown type to ISD::SDIV"); break;
|
|
|
|
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!");
|
|
|
|
// Emit all of the operands.
|
|
|
|
std::vector<unsigned> InVals;
|
|
|
|
for (unsigned i = 0, e = N.getNumOperands(); i != e; ++i)
|
|
|
|
InVals.push_back(SelectExpr(N.getOperand(i)));
|
|
|
|
if (N.getOpcode() == ISD::ADD_PARTS) {
|
2005-04-02 05:59:34 +00:00
|
|
|
BuildMI(BB, PPC::ADDC, 2, Result).addReg(InVals[0]).addReg(InVals[2]);
|
|
|
|
BuildMI(BB, PPC::ADDE, 2, Result+1).addReg(InVals[1]).addReg(InVals[3]);
|
|
|
|
} else {
|
|
|
|
BuildMI(BB, PPC::SUBFC, 2, Result).addReg(InVals[2]).addReg(InVals[0]);
|
|
|
|
BuildMI(BB, PPC::SUBFE, 2, Result+1).addReg(InVals[3]).addReg(InVals[1]);
|
|
|
|
}
|
|
|
|
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));
|
|
|
|
Tmp1 = MakeReg(MVT::i32);
|
|
|
|
Tmp2 = MakeReg(MVT::i32);
|
2005-04-02 05:59:34 +00:00
|
|
|
Tmp3 = MakeReg(MVT::i32);
|
|
|
|
unsigned Tmp4 = MakeReg(MVT::i32);
|
|
|
|
unsigned Tmp5 = MakeReg(MVT::i32);
|
|
|
|
unsigned Tmp6 = MakeReg(MVT::i32);
|
|
|
|
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;
|
|
|
|
unsigned Tmp7 = MakeReg(MVT::i32);
|
|
|
|
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-03-24 04:41:43 +00:00
|
|
|
case ISD::FP_TO_UINT:
|
2005-04-01 02:59:27 +00:00
|
|
|
case ISD::FP_TO_SINT: {
|
|
|
|
bool U = (ISD::FP_TO_UINT == opcode);
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0));
|
|
|
|
if (!U) {
|
|
|
|
Tmp2 = MakeReg(MVT::f64);
|
|
|
|
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;
|
|
|
|
} else {
|
|
|
|
unsigned Zero = getConstDouble(0.0);
|
|
|
|
unsigned MaxInt = getConstDouble((1LL << 32) - 1);
|
|
|
|
unsigned Border = getConstDouble(1LL << 31);
|
|
|
|
unsigned UseZero = MakeReg(MVT::f64);
|
|
|
|
unsigned UseMaxInt = MakeReg(MVT::f64);
|
|
|
|
unsigned UseChoice = MakeReg(MVT::f64);
|
|
|
|
unsigned TmpReg = MakeReg(MVT::f64);
|
|
|
|
unsigned TmpReg2 = MakeReg(MVT::f64);
|
|
|
|
unsigned ConvReg = MakeReg(MVT::f64);
|
|
|
|
unsigned IntTmp = MakeReg(MVT::i32);
|
|
|
|
unsigned XorReg = MakeReg(MVT::i32);
|
|
|
|
MachineFunction *F = BB->getParent();
|
|
|
|
int FrameIdx = F->getFrameInfo()->CreateStackObject(8, 8);
|
|
|
|
// Update machine-CFG edges
|
|
|
|
MachineBasicBlock *XorMBB = new MachineBasicBlock(BB->getBasicBlock());
|
|
|
|
MachineBasicBlock *PhiMBB = new MachineBasicBlock(BB->getBasicBlock());
|
|
|
|
MachineBasicBlock *OldMBB = BB;
|
|
|
|
ilist<MachineBasicBlock>::iterator It = BB; ++It;
|
|
|
|
F->getBasicBlockList().insert(It, XorMBB);
|
|
|
|
F->getBasicBlockList().insert(It, PhiMBB);
|
|
|
|
BB->addSuccessor(XorMBB);
|
|
|
|
BB->addSuccessor(PhiMBB);
|
|
|
|
// Convert from floating point to unsigned 32-bit value
|
|
|
|
// Use 0 if incoming value is < 0.0
|
|
|
|
BuildMI(BB, PPC::FSEL, 3, UseZero).addReg(Tmp1).addReg(Tmp1).addReg(Zero);
|
|
|
|
// Use 2**32 - 1 if incoming value is >= 2**32
|
|
|
|
BuildMI(BB, PPC::FSUB, 2, UseMaxInt).addReg(MaxInt).addReg(Tmp1);
|
|
|
|
BuildMI(BB, PPC::FSEL, 3, UseChoice).addReg(UseMaxInt).addReg(UseZero)
|
|
|
|
.addReg(MaxInt);
|
|
|
|
// Subtract 2**31
|
|
|
|
BuildMI(BB, PPC::FSUB, 2, TmpReg).addReg(UseChoice).addReg(Border);
|
|
|
|
// Use difference if >= 2**31
|
|
|
|
BuildMI(BB, PPC::FCMPU, 2, PPC::CR0).addReg(UseChoice).addReg(Border);
|
|
|
|
BuildMI(BB, PPC::FSEL, 3, TmpReg2).addReg(TmpReg).addReg(TmpReg)
|
|
|
|
.addReg(UseChoice);
|
|
|
|
// Convert to integer
|
|
|
|
BuildMI(BB, PPC::FCTIWZ, 1, ConvReg).addReg(TmpReg2);
|
|
|
|
addFrameReference(BuildMI(BB, PPC::STFD, 3).addReg(ConvReg), FrameIdx);
|
|
|
|
addFrameReference(BuildMI(BB, PPC::LWZ, 2, IntTmp), FrameIdx, 4);
|
|
|
|
BuildMI(BB, PPC::BLT, 2).addReg(PPC::CR0).addMBB(PhiMBB);
|
|
|
|
BuildMI(BB, PPC::B, 1).addMBB(XorMBB);
|
|
|
|
|
|
|
|
// XorMBB:
|
|
|
|
// add 2**31 if input was >= 2**31
|
|
|
|
BB = XorMBB;
|
|
|
|
BuildMI(BB, PPC::XORIS, 2, XorReg).addReg(IntTmp).addImm(0x8000);
|
|
|
|
XorMBB->addSuccessor(PhiMBB);
|
|
|
|
|
|
|
|
// PhiMBB:
|
|
|
|
// DestReg = phi [ IntTmp, OldMBB ], [ XorReg, XorMBB ]
|
|
|
|
BB = PhiMBB;
|
|
|
|
BuildMI(BB, PPC::PHI, 4, Result).addReg(IntTmp).addMBB(OldMBB)
|
|
|
|
.addReg(XorReg).addMBB(XorMBB);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
assert(0 && "Should never get here");
|
|
|
|
return 0;
|
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 23:35:30 +00:00
|
|
|
case ISD::SETCC:
|
2005-03-29 21:54:38 +00:00
|
|
|
if (SetCCSDNode *SetCC = dyn_cast<SetCCSDNode>(Node)) {
|
2005-04-21 23:30:14 +00:00
|
|
|
if (ConstantSDNode *CN =
|
2005-04-07 20:30:01 +00:00
|
|
|
dyn_cast<ConstantSDNode>(SetCC->getOperand(1).Val)) {
|
2005-04-12 21:22:28 +00:00
|
|
|
// We can codegen setcc op, imm very efficiently compared to a brcond.
|
|
|
|
// Check for those cases here.
|
|
|
|
// setcc op, 0
|
2005-04-07 20:30:01 +00:00
|
|
|
if (CN->getValue() == 0) {
|
|
|
|
Tmp1 = SelectExpr(SetCC->getOperand(0));
|
|
|
|
switch (SetCC->getCondition()) {
|
2005-04-14 09:45:08 +00:00
|
|
|
default: SetCC->dump(); assert(0 && "Unhandled SetCC condition"); abort();
|
2005-04-07 20:30:01 +00:00
|
|
|
case ISD::SETEQ:
|
|
|
|
Tmp2 = MakeReg(MVT::i32);
|
|
|
|
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:
|
|
|
|
Tmp2 = MakeReg(MVT::i32);
|
|
|
|
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;
|
2005-04-12 21:22:28 +00:00
|
|
|
case ISD::SETGT:
|
2005-04-07 20:30:01 +00:00
|
|
|
Tmp2 = MakeReg(MVT::i32);
|
|
|
|
Tmp3 = MakeReg(MVT::i32);
|
|
|
|
BuildMI(BB, PPC::NEG, 2, Tmp2).addReg(Tmp1);
|
2005-04-12 21:22:28 +00:00
|
|
|
BuildMI(BB, PPC::ANDC, 2, Tmp3).addReg(Tmp2).addReg(Tmp1);
|
2005-04-07 20:30:01 +00:00
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp3).addImm(1)
|
|
|
|
.addImm(31).addImm(31);
|
|
|
|
break;
|
2005-04-12 21:22:28 +00:00
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
// setcc op, -1
|
|
|
|
if (CN->isAllOnesValue()) {
|
|
|
|
Tmp1 = SelectExpr(SetCC->getOperand(0));
|
|
|
|
switch (SetCC->getCondition()) {
|
|
|
|
default: assert(0 && "Unhandled SetCC condition"); abort();
|
|
|
|
case ISD::SETEQ:
|
2005-04-07 20:30:01 +00:00
|
|
|
Tmp2 = MakeReg(MVT::i32);
|
|
|
|
Tmp3 = MakeReg(MVT::i32);
|
2005-04-12 21:22:28 +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:
|
|
|
|
Tmp2 = MakeReg(MVT::i32);
|
|
|
|
Tmp3 = MakeReg(MVT::i32);
|
|
|
|
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:
|
|
|
|
Tmp2 = MakeReg(MVT::i32);
|
|
|
|
Tmp3 = MakeReg(MVT::i32);
|
|
|
|
BuildMI(BB, PPC::ADDI, 2, Tmp2).addReg(Tmp1).addSImm(1);
|
|
|
|
BuildMI(BB, PPC::AND, 2, Tmp3).addReg(Tmp2).addReg(Tmp1);
|
2005-04-07 20:30:01 +00:00
|
|
|
BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp3).addImm(1)
|
|
|
|
.addImm(31).addImm(31);
|
|
|
|
break;
|
2005-04-12 21:22:28 +00:00
|
|
|
case ISD::SETGT:
|
|
|
|
Tmp2 = MakeReg(MVT::i32);
|
2005-04-07 20:30:01 +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;
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
}
|
2005-04-21 23:30:14 +00:00
|
|
|
|
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
|
|
|
bool Inv;
|
|
|
|
unsigned CCReg = SelectCC(N, Opc, Inv, Tmp2);
|
|
|
|
MoveCRtoGPR(CCReg, Inv, Tmp2, Result);
|
2005-03-29 21:54:38 +00:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
assert(0 && "Is this legal?");
|
|
|
|
return 0;
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-29 22:24:51 +00:00
|
|
|
case ISD::SELECT: {
|
2005-07-19 16:51:05 +00:00
|
|
|
SetCCSDNode* SetCC = dyn_cast<SetCCSDNode>(N.getOperand(0).Val);
|
|
|
|
if (SetCC && N.getOperand(0).getOpcode() == ISD::SETCC &&
|
|
|
|
!MVT::isInteger(SetCC->getOperand(0).getValueType()) &&
|
|
|
|
!MVT::isInteger(N.getOperand(1).getValueType()) &&
|
|
|
|
!MVT::isInteger(N.getOperand(2).getValueType()) &&
|
|
|
|
SetCC->getCondition() != ISD::SETEQ &&
|
|
|
|
SetCC->getCondition() != ISD::SETNE) {
|
|
|
|
MVT::ValueType VT = SetCC->getOperand(0).getValueType();
|
|
|
|
unsigned TV = SelectExpr(N.getOperand(1)); // Use if TRUE
|
|
|
|
unsigned FV = SelectExpr(N.getOperand(2)); // Use if FALSE
|
|
|
|
|
|
|
|
ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(SetCC->getOperand(1));
|
|
|
|
if (CN && (CN->isExactlyValue(-0.0) || CN->isExactlyValue(0.0))) {
|
|
|
|
switch(SetCC->getCondition()) {
|
|
|
|
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:
|
|
|
|
Tmp1 = SelectExpr(SetCC->getOperand(0)); // Val to compare against
|
|
|
|
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: {
|
|
|
|
if (SetCC->getOperand(0).getOpcode() == ISD::FNEG) {
|
|
|
|
Tmp2 = SelectExpr(SetCC->getOperand(0).getOperand(0));
|
|
|
|
} else {
|
|
|
|
Tmp2 = MakeReg(VT);
|
|
|
|
Tmp1 = SelectExpr(SetCC->getOperand(0)); // Val to compare against
|
|
|
|
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;
|
|
|
|
Tmp1 = SelectExpr(SetCC->getOperand(0)); // Val to compare against
|
|
|
|
Tmp2 = SelectExpr(SetCC->getOperand(1));
|
|
|
|
Tmp3 = MakeReg(VT);
|
|
|
|
switch(SetCC->getCondition()) {
|
|
|
|
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");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
bool Inv;
|
2005-04-01 07:10:02 +00:00
|
|
|
unsigned TrueValue = SelectExpr(N.getOperand(1)); //Use if TRUE
|
|
|
|
unsigned FalseValue = SelectExpr(N.getOperand(2)); //Use if FALSE
|
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
|
|
|
unsigned CCReg = SelectCC(N.getOperand(0), Opc, Inv, Tmp3);
|
2005-04-01 07:10:02 +00:00
|
|
|
|
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;
|
|
|
|
// 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
|
|
|
|
|
|
|
case ISD::Constant:
|
|
|
|
switch (N.getValueType()) {
|
|
|
|
default: assert(0 && "Cannot use constants of this type!");
|
|
|
|
case MVT::i1:
|
|
|
|
BuildMI(BB, PPC::LI, 1, Result)
|
|
|
|
.addSImm(!cast<ConstantSDNode>(N)->isNullValue());
|
|
|
|
break;
|
|
|
|
case MVT::i32:
|
|
|
|
{
|
|
|
|
int v = (int)cast<ConstantSDNode>(N)->getSignExtended();
|
|
|
|
if (v < 32768 && v >= -32768) {
|
|
|
|
BuildMI(BB, PPC::LI, 1, Result).addSImm(v);
|
|
|
|
} else {
|
2005-03-24 06:28:42 +00:00
|
|
|
Tmp1 = MakeReg(MVT::i32);
|
|
|
|
BuildMI(BB, PPC::LIS, 1, Tmp1).addSImm(v >> 16);
|
|
|
|
BuildMI(BB, PPC::ORI, 2, Result).addReg(Tmp1).addImm(v & 0xFFFF);
|
2005-03-24 04:41:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Result;
|
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;
|
|
|
|
|
|
|
|
case ISD::UINT_TO_FP:
|
|
|
|
case ISD::SINT_TO_FP: {
|
|
|
|
assert (N.getOperand(0).getValueType() == MVT::i32
|
|
|
|
&& "int to float must operate on i32");
|
|
|
|
bool IsUnsigned = (ISD::UINT_TO_FP == opcode);
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(0)); // Get the operand register
|
|
|
|
Tmp2 = MakeReg(MVT::f64); // temp reg to load the integer value into
|
|
|
|
Tmp3 = MakeReg(MVT::i32); // temp reg to hold the conversion constant
|
|
|
|
|
|
|
|
int FrameIdx = BB->getParent()->getFrameInfo()->CreateStackObject(8, 8);
|
|
|
|
MachineConstantPool *CP = BB->getParent()->getConstantPool();
|
|
|
|
|
|
|
|
if (IsUnsigned) {
|
|
|
|
unsigned ConstF = getConstDouble(0x1.000000p52);
|
|
|
|
// Store the hi & low halves of the fp value, currently in int regs
|
|
|
|
BuildMI(BB, PPC::LIS, 1, Tmp3).addSImm(0x4330);
|
|
|
|
addFrameReference(BuildMI(BB, PPC::STW, 3).addReg(Tmp3), FrameIdx);
|
|
|
|
addFrameReference(BuildMI(BB, PPC::STW, 3).addReg(Tmp1), FrameIdx, 4);
|
|
|
|
addFrameReference(BuildMI(BB, PPC::LFD, 2, Tmp2), FrameIdx);
|
|
|
|
// Generate the return value with a subtract
|
|
|
|
BuildMI(BB, PPC::FSUB, 2, Result).addReg(Tmp2).addReg(ConstF);
|
|
|
|
} else {
|
|
|
|
unsigned ConstF = getConstDouble(0x1.000008p52);
|
|
|
|
unsigned TmpL = MakeReg(MVT::i32);
|
|
|
|
// Store the hi & low halves of the fp value, currently in int regs
|
|
|
|
BuildMI(BB, PPC::LIS, 1, Tmp3).addSImm(0x4330);
|
|
|
|
addFrameReference(BuildMI(BB, PPC::STW, 3).addReg(Tmp3), FrameIdx);
|
|
|
|
BuildMI(BB, PPC::XORIS, 2, TmpL).addReg(Tmp1).addImm(0x8000);
|
|
|
|
addFrameReference(BuildMI(BB, PPC::STW, 3).addReg(TmpL), FrameIdx, 4);
|
|
|
|
addFrameReference(BuildMI(BB, PPC::LFD, 2, Tmp2), FrameIdx);
|
|
|
|
// Generate the return value with a subtract
|
|
|
|
BuildMI(BB, PPC::FSUB, 2, Result).addReg(Tmp2).addReg(ConstF);
|
|
|
|
}
|
|
|
|
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-04-21 23:30:14 +00:00
|
|
|
case ISD::BRCOND:
|
2005-04-09 20:09:12 +00:00
|
|
|
case ISD::BRCONDTWOWAY:
|
2005-03-24 04:41:43 +00:00
|
|
|
SelectBranchCC(N);
|
|
|
|
return;
|
|
|
|
case ISD::CopyToReg:
|
|
|
|
Select(N.getOperand(0));
|
|
|
|
Tmp1 = SelectExpr(N.getOperand(1));
|
|
|
|
Tmp2 = cast<RegSDNode>(N)->getReg();
|
2005-04-21 23:30:14 +00:00
|
|
|
|
2005-03-24 04:41:43 +00:00
|
|
|
if (Tmp1 != Tmp2) {
|
2005-04-21 23:30:14 +00:00
|
|
|
if (N.getOperand(1).getValueType() == MVT::f64 ||
|
2005-03-24 04:41:43 +00:00
|
|
|
N.getOperand(1).getValueType() == MVT::f32)
|
|
|
|
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));
|
|
|
|
BuildMI(BB, PPC::IMPLICIT_DEF, 0, cast<RegSDNode>(N)->getReg());
|
|
|
|
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 if(GlobalAddressSDNode *GN = dyn_cast<GlobalAddressSDNode>(Address)){
|
|
|
|
GlobalValue *GV = GN->getGlobal();
|
|
|
|
Tmp2 = MakeReg(MVT::i32);
|
|
|
|
if (PICEnabled)
|
|
|
|
BuildMI(BB, PPC::ADDIS, 2, Tmp2).addReg(getGlobalBaseReg())
|
|
|
|
.addGlobalAddress(GV);
|
2005-03-24 04:41:43 +00:00
|
|
|
else
|
2005-07-28 04:42:11 +00:00
|
|
|
BuildMI(BB, PPC::LIS, 1, Tmp2).addGlobalAddress(GV);
|
2005-07-21 20:44:43 +00:00
|
|
|
if (GV->hasWeakLinkage() || GV->isExternal()) {
|
|
|
|
Tmp3 = MakeReg(MVT::i32);
|
|
|
|
BuildMI(BB, PPC::LWZ, 2, Tmp3).addGlobalAddress(GV).addReg(Tmp2);
|
2005-07-25 21:15:28 +00:00
|
|
|
BuildMI(BB, Opc, 3).addReg(Tmp1).addSImm(0).addReg(Tmp3);
|
|
|
|
} else {
|
|
|
|
BuildMI(BB, Opc, 3).addReg(Tmp1).addGlobalAddress(GV).addReg(Tmp2);
|
2005-07-21 20:44:43 +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, 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-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
|
|
|
}
|
|
|
|
|