2004-08-17 04:55:41 +00:00
|
|
|
//===-- PPC32ISelSimple.cpp - A simple instruction selector PowerPC32 -----===//
|
2004-06-21 16:55:25 +00:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file was developed by the LLVM research group and is distributed under
|
|
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2004-06-24 21:54:47 +00:00
|
|
|
#define DEBUG_TYPE "isel"
|
2004-06-21 16:55:25 +00:00
|
|
|
#include "PowerPC.h"
|
|
|
|
#include "PowerPCInstrBuilder.h"
|
|
|
|
#include "PowerPCInstrInfo.h"
|
2004-08-11 00:09:42 +00:00
|
|
|
#include "PPC32TargetMachine.h"
|
2004-06-21 16:55:25 +00:00
|
|
|
#include "llvm/Constants.h"
|
|
|
|
#include "llvm/DerivedTypes.h"
|
|
|
|
#include "llvm/Function.h"
|
|
|
|
#include "llvm/Instructions.h"
|
|
|
|
#include "llvm/Pass.h"
|
2004-06-21 18:30:31 +00:00
|
|
|
#include "llvm/CodeGen/IntrinsicLowering.h"
|
2004-06-21 16:55:25 +00:00
|
|
|
#include "llvm/CodeGen/MachineConstantPool.h"
|
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
|
|
#include "llvm/CodeGen/SSARegMap.h"
|
|
|
|
#include "llvm/Target/MRegisterInfo.h"
|
|
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
#include "llvm/Support/GetElementPtrTypeIterator.h"
|
|
|
|
#include "llvm/Support/InstVisitor.h"
|
2004-09-01 22:55:40 +00:00
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/ADT/Statistic.h"
|
2004-06-24 21:54:47 +00:00
|
|
|
#include <vector>
|
2004-06-21 16:55:25 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
2004-06-21 17:41:12 +00:00
|
|
|
/// TypeClass - Used by the PowerPC backend to group LLVM types by their basic
|
|
|
|
/// PPC Representation.
|
2004-06-21 16:55:25 +00:00
|
|
|
///
|
|
|
|
enum TypeClass {
|
2004-07-20 00:41:46 +00:00
|
|
|
cByte, cShort, cInt, cFP32, cFP64, cLong
|
2004-06-21 16:55:25 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getClass - Turn a primitive type into a "class" number which is based on the
|
|
|
|
/// size of the type, and whether or not it is floating point.
|
|
|
|
///
|
|
|
|
static inline TypeClass getClass(const Type *Ty) {
|
2004-06-21 17:25:55 +00:00
|
|
|
switch (Ty->getTypeID()) {
|
2004-06-21 16:55:25 +00:00
|
|
|
case Type::SByteTyID:
|
|
|
|
case Type::UByteTyID: return cByte; // Byte operands are class #0
|
|
|
|
case Type::ShortTyID:
|
|
|
|
case Type::UShortTyID: return cShort; // Short operands are class #1
|
|
|
|
case Type::IntTyID:
|
|
|
|
case Type::UIntTyID:
|
2004-07-07 20:07:22 +00:00
|
|
|
case Type::PointerTyID: return cInt; // Ints and pointers are class #2
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-07-20 00:41:46 +00:00
|
|
|
case Type::FloatTyID: return cFP32; // Single float is #3
|
|
|
|
case Type::DoubleTyID: return cFP64; // Double Point is #4
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
case Type::LongTyID:
|
2004-07-20 00:41:46 +00:00
|
|
|
case Type::ULongTyID: return cLong; // Longs are class #5
|
2004-06-21 16:55:25 +00:00
|
|
|
default:
|
|
|
|
assert(0 && "Invalid type to getClass!");
|
|
|
|
return cByte; // not reached
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// getClassB - Just like getClass, but treat boolean values as ints.
|
|
|
|
static inline TypeClass getClassB(const Type *Ty) {
|
2004-08-13 09:32:01 +00:00
|
|
|
if (Ty == Type::BoolTy) return cByte;
|
2004-06-21 16:55:25 +00:00
|
|
|
return getClass(Ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
2004-09-21 18:22:19 +00:00
|
|
|
struct PPC32ISel : public FunctionPass, InstVisitor<PPC32ISel> {
|
2004-08-11 00:09:42 +00:00
|
|
|
PPC32TargetMachine &TM;
|
2004-06-21 16:55:25 +00:00
|
|
|
MachineFunction *F; // The function we are compiling into
|
|
|
|
MachineBasicBlock *BB; // The current MBB we are compiling
|
|
|
|
int VarArgsFrameIndex; // FrameIndex for start of varargs area
|
2004-07-26 18:13:24 +00:00
|
|
|
|
2004-09-23 05:31:33 +00:00
|
|
|
/// CollapsedGepOp - This struct is for recording the intermediate results
|
|
|
|
/// used to calculate the base, index, and offset of a GEP instruction.
|
|
|
|
struct CollapsedGepOp {
|
|
|
|
ConstantSInt *offset; // the current offset into the struct/array
|
|
|
|
Value *index; // the index of the array element
|
|
|
|
ConstantUInt *size; // the size of each array element
|
|
|
|
CollapsedGepOp(ConstantSInt *o, Value *i, ConstantUInt *s) :
|
|
|
|
offset(o), index(i), size(s) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
/// FoldedGEP - This struct is for recording the necessary information to
|
|
|
|
/// emit the GEP in a load or store instruction, used by emitGEPOperation.
|
|
|
|
struct FoldedGEP {
|
|
|
|
unsigned base;
|
|
|
|
unsigned index;
|
|
|
|
ConstantSInt *offset;
|
|
|
|
FoldedGEP() : base(0), index(0), offset(0) {}
|
|
|
|
FoldedGEP(unsigned b, unsigned i, ConstantSInt *o) :
|
|
|
|
base(b), index(i), offset(o) {}
|
|
|
|
};
|
2004-10-24 10:33:30 +00:00
|
|
|
|
|
|
|
/// RlwimiRec - This struct is for recording the arguments to a PowerPC
|
|
|
|
/// rlwimi instruction to be output for a particular Instruction::Or when
|
|
|
|
/// we recognize the pattern for rlwimi, starting with a shift or and.
|
|
|
|
struct RlwimiRec {
|
|
|
|
Value *Target, *Insert;
|
|
|
|
unsigned Shift, MB, ME;
|
|
|
|
RlwimiRec() : Target(0), Insert(0), Shift(0), MB(0), ME(0) {}
|
|
|
|
RlwimiRec(Value *tgt, Value *ins, unsigned s, unsigned b, unsigned e) :
|
|
|
|
Target(tgt), Insert(ins), Shift(s), MB(b), ME(e) {}
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
};
|
2004-10-24 10:33:30 +00:00
|
|
|
|
2005-03-21 19:22:14 +00:00
|
|
|
// External functions we may use in compiling the Module
|
2004-08-10 20:42:36 +00:00
|
|
|
Function *fmodfFn, *fmodFn, *__cmpdi2Fn, *__moddi3Fn, *__divdi3Fn,
|
|
|
|
*__umoddi3Fn, *__udivdi3Fn, *__fixsfdiFn, *__fixdfdiFn, *__fixunssfdiFn,
|
|
|
|
*__fixunsdfdiFn, *__floatdisfFn, *__floatdidfFn, *mallocFn, *freeFn;
|
2004-07-07 20:07:22 +00:00
|
|
|
|
2004-09-23 05:31:33 +00:00
|
|
|
// Mapping between Values and SSA Regs
|
|
|
|
std::map<Value*, unsigned> RegMap;
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
// MBBMap - Mapping between LLVM BB -> Machine BB
|
|
|
|
std::map<const BasicBlock*, MachineBasicBlock*> MBBMap;
|
|
|
|
|
|
|
|
// AllocaMap - Mapping from fixed sized alloca instructions to the
|
|
|
|
// FrameIndex for the alloca.
|
|
|
|
std::map<AllocaInst*, unsigned> AllocaMap;
|
|
|
|
|
2004-09-23 05:31:33 +00:00
|
|
|
// GEPMap - Mapping between basic blocks and GEP definitions
|
|
|
|
std::map<GetElementPtrInst*, FoldedGEP> GEPMap;
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
|
|
|
|
// RlwimiMap - Mapping between BinaryOperand (Or) instructions and info
|
|
|
|
// needed to properly emit a rlwimi instruction in its place.
|
2004-10-24 10:33:30 +00:00
|
|
|
std::map<Instruction *, RlwimiRec> InsertMap;
|
|
|
|
|
|
|
|
// A rlwimi instruction is the combination of at least three instructions.
|
|
|
|
// Keep a vector of instructions to skip around so that we do not try to
|
|
|
|
// emit instructions that were folded into a rlwimi.
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
std::vector<Instruction *> SkipList;
|
2004-09-23 05:31:33 +00:00
|
|
|
|
2004-07-26 18:13:24 +00:00
|
|
|
// A Reg to hold the base address used for global loads and stores, and a
|
|
|
|
// flag to set whether or not we need to emit it for this function.
|
|
|
|
unsigned GlobalBaseReg;
|
|
|
|
bool GlobalBaseInitialized;
|
|
|
|
|
2004-09-21 18:22:19 +00:00
|
|
|
PPC32ISel(TargetMachine &tm):TM(reinterpret_cast<PPC32TargetMachine&>(tm)),
|
2004-07-23 16:08:20 +00:00
|
|
|
F(0), BB(0) {}
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-07-07 20:07:22 +00:00
|
|
|
bool doInitialization(Module &M) {
|
2004-07-07 15:36:18 +00:00
|
|
|
// Add external functions that we may call
|
2004-08-10 20:42:36 +00:00
|
|
|
Type *i = Type::IntTy;
|
2004-07-07 20:07:22 +00:00
|
|
|
Type *d = Type::DoubleTy;
|
2004-07-08 19:41:16 +00:00
|
|
|
Type *f = Type::FloatTy;
|
2004-07-07 20:07:22 +00:00
|
|
|
Type *l = Type::LongTy;
|
|
|
|
Type *ul = Type::ULongTy;
|
2004-07-09 15:45:07 +00:00
|
|
|
Type *voidPtr = PointerType::get(Type::SByteTy);
|
2004-07-20 00:41:46 +00:00
|
|
|
// float fmodf(float, float);
|
|
|
|
fmodfFn = M.getOrInsertFunction("fmodf", f, f, f, 0);
|
2004-07-07 20:07:22 +00:00
|
|
|
// double fmod(double, double);
|
2004-07-08 18:27:59 +00:00
|
|
|
fmodFn = M.getOrInsertFunction("fmod", d, d, d, 0);
|
2004-08-10 20:42:36 +00:00
|
|
|
// int __cmpdi2(long, long);
|
|
|
|
__cmpdi2Fn = M.getOrInsertFunction("__cmpdi2", i, l, l, 0);
|
2004-07-07 20:07:22 +00:00
|
|
|
// long __moddi3(long, long);
|
2004-07-08 18:27:59 +00:00
|
|
|
__moddi3Fn = M.getOrInsertFunction("__moddi3", l, l, l, 0);
|
2004-07-07 20:07:22 +00:00
|
|
|
// long __divdi3(long, long);
|
2004-07-08 18:27:59 +00:00
|
|
|
__divdi3Fn = M.getOrInsertFunction("__divdi3", l, l, l, 0);
|
2004-07-07 20:07:22 +00:00
|
|
|
// unsigned long __umoddi3(unsigned long, unsigned long);
|
2004-07-08 18:27:59 +00:00
|
|
|
__umoddi3Fn = M.getOrInsertFunction("__umoddi3", ul, ul, ul, 0);
|
2004-07-07 20:07:22 +00:00
|
|
|
// unsigned long __udivdi3(unsigned long, unsigned long);
|
2004-07-08 18:27:59 +00:00
|
|
|
__udivdi3Fn = M.getOrInsertFunction("__udivdi3", ul, ul, ul, 0);
|
2004-07-20 00:41:46 +00:00
|
|
|
// long __fixsfdi(float)
|
2004-08-10 20:42:36 +00:00
|
|
|
__fixsfdiFn = M.getOrInsertFunction("__fixsfdi", l, f, 0);
|
2004-07-08 19:41:16 +00:00
|
|
|
// long __fixdfdi(double)
|
|
|
|
__fixdfdiFn = M.getOrInsertFunction("__fixdfdi", l, d, 0);
|
2004-08-10 20:42:36 +00:00
|
|
|
// unsigned long __fixunssfdi(float)
|
|
|
|
__fixunssfdiFn = M.getOrInsertFunction("__fixunssfdi", ul, f, 0);
|
|
|
|
// unsigned long __fixunsdfdi(double)
|
|
|
|
__fixunsdfdiFn = M.getOrInsertFunction("__fixunsdfdi", ul, d, 0);
|
2004-07-08 19:41:16 +00:00
|
|
|
// float __floatdisf(long)
|
|
|
|
__floatdisfFn = M.getOrInsertFunction("__floatdisf", f, l, 0);
|
|
|
|
// double __floatdidf(long)
|
|
|
|
__floatdidfFn = M.getOrInsertFunction("__floatdidf", d, l, 0);
|
2004-07-09 15:45:07 +00:00
|
|
|
// void* malloc(size_t)
|
|
|
|
mallocFn = M.getOrInsertFunction("malloc", voidPtr, Type::UIntTy, 0);
|
|
|
|
// void free(void*)
|
|
|
|
freeFn = M.getOrInsertFunction("free", Type::VoidTy, voidPtr, 0);
|
2005-03-21 19:22:14 +00:00
|
|
|
return true;
|
2004-07-07 20:07:22 +00:00
|
|
|
}
|
2004-07-06 22:51:53 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
/// runOnFunction - Top level implementation of instruction selection for
|
|
|
|
/// the entire function.
|
|
|
|
///
|
|
|
|
bool runOnFunction(Function &Fn) {
|
|
|
|
// First pass over the function, lower any unknown intrinsic functions
|
|
|
|
// with the IntrinsicLowering class.
|
|
|
|
LowerUnknownIntrinsicFunctionCalls(Fn);
|
|
|
|
|
|
|
|
F = &MachineFunction::construct(&Fn, TM);
|
|
|
|
|
|
|
|
// Create all of the machine basic blocks for the function...
|
|
|
|
for (Function::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I)
|
|
|
|
F->getBasicBlockList().push_back(MBBMap[I] = new MachineBasicBlock(I));
|
|
|
|
|
|
|
|
BB = &F->front();
|
|
|
|
|
2004-07-26 18:13:24 +00:00
|
|
|
// Make sure we re-emit a set of the global base reg if necessary
|
|
|
|
GlobalBaseInitialized = false;
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
// Copy incoming arguments off of the stack...
|
|
|
|
LoadArgumentsToVirtualRegs(Fn);
|
|
|
|
|
|
|
|
// Instruction select everything except PHI nodes
|
|
|
|
visit(Fn);
|
|
|
|
|
|
|
|
// Select the PHI nodes
|
|
|
|
SelectPHINodes();
|
|
|
|
|
2004-09-23 05:31:33 +00:00
|
|
|
GEPMap.clear();
|
2004-06-21 16:55:25 +00:00
|
|
|
RegMap.clear();
|
|
|
|
MBBMap.clear();
|
2004-10-24 10:33:30 +00:00
|
|
|
InsertMap.clear();
|
2004-06-21 16:55:25 +00:00
|
|
|
AllocaMap.clear();
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
SkipList.clear();
|
2004-06-21 16:55:25 +00:00
|
|
|
F = 0;
|
|
|
|
// We always build a machine code representation for the function
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual const char *getPassName() const {
|
|
|
|
return "PowerPC Simple Instruction Selection";
|
|
|
|
}
|
|
|
|
|
|
|
|
/// visitBasicBlock - This method is called when we are visiting a new basic
|
|
|
|
/// block. This simply creates a new MachineBasicBlock to emit code into
|
|
|
|
/// and adds it to the current MachineFunction. Subsequent visit* for
|
|
|
|
/// instructions will be invoked for all instructions in the basic block.
|
|
|
|
///
|
|
|
|
void visitBasicBlock(BasicBlock &LLVM_BB) {
|
|
|
|
BB = MBBMap[&LLVM_BB];
|
|
|
|
}
|
|
|
|
|
|
|
|
/// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the
|
|
|
|
/// function, lowering any calls to unknown intrinsic functions into the
|
|
|
|
/// equivalent LLVM code.
|
|
|
|
///
|
|
|
|
void LowerUnknownIntrinsicFunctionCalls(Function &F);
|
|
|
|
|
|
|
|
/// LoadArgumentsToVirtualRegs - Load all of the arguments to this function
|
|
|
|
/// from the stack into virtual registers.
|
|
|
|
///
|
|
|
|
void LoadArgumentsToVirtualRegs(Function &F);
|
|
|
|
|
|
|
|
/// SelectPHINodes - Insert machine code to generate phis. This is tricky
|
|
|
|
/// because we have to generate our sources into the source basic blocks,
|
|
|
|
/// not the current one.
|
|
|
|
///
|
|
|
|
void SelectPHINodes();
|
|
|
|
|
|
|
|
// Visitation methods for various instructions. These methods simply emit
|
|
|
|
// fixed PowerPC code for each instruction.
|
|
|
|
|
2004-10-16 18:13:47 +00:00
|
|
|
// Control flow operators.
|
2004-06-21 16:55:25 +00:00
|
|
|
void visitReturnInst(ReturnInst &RI);
|
|
|
|
void visitBranchInst(BranchInst &BI);
|
2004-10-16 18:13:47 +00:00
|
|
|
void visitUnreachableInst(UnreachableInst &UI) {}
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
struct ValueRecord {
|
|
|
|
Value *Val;
|
|
|
|
unsigned Reg;
|
|
|
|
const Type *Ty;
|
|
|
|
ValueRecord(unsigned R, const Type *T) : Val(0), Reg(R), Ty(T) {}
|
|
|
|
ValueRecord(Value *V) : Val(V), Reg(0), Ty(V->getType()) {}
|
|
|
|
};
|
2004-07-26 18:13:24 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
void doCall(const ValueRecord &Ret, MachineInstr *CallMI,
|
2004-07-06 22:51:53 +00:00
|
|
|
const std::vector<ValueRecord> &Args, bool isVarArg);
|
2004-06-21 16:55:25 +00:00
|
|
|
void visitCallInst(CallInst &I);
|
|
|
|
void visitIntrinsicCall(Intrinsic::ID ID, CallInst &I);
|
|
|
|
|
|
|
|
// Arithmetic operators
|
|
|
|
void visitSimpleBinary(BinaryOperator &B, unsigned OpcodeClass);
|
|
|
|
void visitAdd(BinaryOperator &B) { visitSimpleBinary(B, 0); }
|
|
|
|
void visitSub(BinaryOperator &B) { visitSimpleBinary(B, 1); }
|
|
|
|
void visitMul(BinaryOperator &B);
|
|
|
|
|
|
|
|
void visitDiv(BinaryOperator &B) { visitDivRem(B); }
|
|
|
|
void visitRem(BinaryOperator &B) { visitDivRem(B); }
|
|
|
|
void visitDivRem(BinaryOperator &B);
|
|
|
|
|
|
|
|
// Bitwise operators
|
|
|
|
void visitAnd(BinaryOperator &B) { visitSimpleBinary(B, 2); }
|
|
|
|
void visitOr (BinaryOperator &B) { visitSimpleBinary(B, 3); }
|
|
|
|
void visitXor(BinaryOperator &B) { visitSimpleBinary(B, 4); }
|
|
|
|
|
|
|
|
// Comparison operators...
|
|
|
|
void visitSetCondInst(SetCondInst &I);
|
2005-04-10 01:03:31 +00:00
|
|
|
void EmitComparison(unsigned OpNum, Value *Op0, Value *Op1,
|
|
|
|
MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator MBBI);
|
2004-06-21 16:55:25 +00:00
|
|
|
void visitSelectInst(SelectInst &SI);
|
|
|
|
|
|
|
|
|
|
|
|
// Memory Instructions
|
|
|
|
void visitLoadInst(LoadInst &I);
|
|
|
|
void visitStoreInst(StoreInst &I);
|
|
|
|
void visitGetElementPtrInst(GetElementPtrInst &I);
|
|
|
|
void visitAllocaInst(AllocaInst &I);
|
|
|
|
void visitMallocInst(MallocInst &I);
|
|
|
|
void visitFreeInst(FreeInst &I);
|
|
|
|
|
|
|
|
// Other operators
|
|
|
|
void visitShiftInst(ShiftInst &I);
|
|
|
|
void visitPHINode(PHINode &I) {} // PHI nodes handled by second pass
|
|
|
|
void visitCastInst(CastInst &I);
|
|
|
|
void visitVANextInst(VANextInst &I);
|
|
|
|
void visitVAArgInst(VAArgInst &I);
|
|
|
|
|
|
|
|
void visitInstruction(Instruction &I) {
|
|
|
|
std::cerr << "Cannot instruction select: " << I;
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2004-08-20 09:56:22 +00:00
|
|
|
unsigned ExtendOrClear(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
2004-09-22 04:40:25 +00:00
|
|
|
Value *Op0);
|
2004-08-20 09:56:22 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
/// promote32 - Make a value 32-bits wide, and put it somewhere.
|
|
|
|
///
|
|
|
|
void promote32(unsigned targetReg, const ValueRecord &VR);
|
|
|
|
|
|
|
|
/// emitGEPOperation - Common code shared between visitGetElementPtrInst and
|
|
|
|
/// constant expression GEP support.
|
|
|
|
///
|
|
|
|
void emitGEPOperation(MachineBasicBlock *BB, MachineBasicBlock::iterator IP,
|
2004-09-23 05:31:33 +00:00
|
|
|
GetElementPtrInst *GEPI, bool foldGEP);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
/// emitCastOperation - Common code shared between visitCastInst and
|
|
|
|
/// constant expression cast support.
|
|
|
|
///
|
|
|
|
void emitCastOperation(MachineBasicBlock *BB,MachineBasicBlock::iterator IP,
|
|
|
|
Value *Src, const Type *DestTy, unsigned TargetReg);
|
|
|
|
|
2004-10-07 22:30:03 +00:00
|
|
|
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
/// emitBitfieldInsert - return true if we were able to fold the sequence of
|
2004-10-24 10:33:30 +00:00
|
|
|
/// instructions into a bitfield insert (rlwimi).
|
2004-10-26 03:48:25 +00:00
|
|
|
bool emitBitfieldInsert(User *OpUser, unsigned DestReg);
|
2004-10-24 10:33:30 +00:00
|
|
|
|
|
|
|
/// emitBitfieldExtract - return true if we were able to fold the sequence
|
|
|
|
/// of instructions into a bitfield extract (rlwinm).
|
|
|
|
bool emitBitfieldExtract(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
2004-10-26 03:48:25 +00:00
|
|
|
User *OpUser, unsigned DestReg);
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
|
2004-10-07 22:30:03 +00:00
|
|
|
/// emitBinaryConstOperation - Used by several functions to emit simple
|
|
|
|
/// arithmetic and logical operations with constants on a register rather
|
|
|
|
/// than a Value.
|
|
|
|
///
|
|
|
|
void emitBinaryConstOperation(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
unsigned Op0Reg, ConstantInt *Op1,
|
|
|
|
unsigned Opcode, unsigned DestReg);
|
|
|
|
|
|
|
|
/// emitSimpleBinaryOperation - Implement simple binary operators for
|
|
|
|
/// integral types. OperatorClass is one of: 0 for Add, 1 for Sub,
|
|
|
|
/// 2 for And, 3 for Or, 4 for Xor.
|
2004-06-21 16:55:25 +00:00
|
|
|
///
|
|
|
|
void emitSimpleBinaryOperation(MachineBasicBlock *BB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
2004-10-24 10:33:30 +00:00
|
|
|
BinaryOperator *BO, Value *Op0, Value *Op1,
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned OperatorClass, unsigned TargetReg);
|
|
|
|
|
|
|
|
/// emitBinaryFPOperation - This method handles emission of floating point
|
|
|
|
/// Add (0), Sub (1), Mul (2), and Div (3) operations.
|
|
|
|
void emitBinaryFPOperation(MachineBasicBlock *BB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
Value *Op0, Value *Op1,
|
|
|
|
unsigned OperatorClass, unsigned TargetReg);
|
|
|
|
|
|
|
|
void emitMultiply(MachineBasicBlock *BB, MachineBasicBlock::iterator IP,
|
|
|
|
Value *Op0, Value *Op1, unsigned TargetReg);
|
|
|
|
|
2004-07-21 20:09:08 +00:00
|
|
|
void doMultiply(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
unsigned DestReg, Value *Op0, Value *Op1);
|
|
|
|
|
|
|
|
/// doMultiplyConst - This method will multiply the value in Op0Reg by the
|
|
|
|
/// value of the ContantInt *CI
|
2004-06-21 16:55:25 +00:00
|
|
|
void doMultiplyConst(MachineBasicBlock *MBB,
|
2004-07-21 20:09:08 +00:00
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
unsigned DestReg, Value *Op0, ConstantInt *CI);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
void emitDivRemOperation(MachineBasicBlock *BB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
Value *Op0, Value *Op1, bool isDiv,
|
|
|
|
unsigned TargetReg);
|
|
|
|
|
|
|
|
/// emitSetCCOperation - Common code shared between visitSetCondInst and
|
|
|
|
/// constant expression support.
|
|
|
|
///
|
|
|
|
void emitSetCCOperation(MachineBasicBlock *BB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
Value *Op0, Value *Op1, unsigned Opcode,
|
|
|
|
unsigned TargetReg);
|
|
|
|
|
|
|
|
/// emitShiftOperation - Common code shared between visitShiftInst and
|
|
|
|
/// constant expression support.
|
|
|
|
///
|
|
|
|
void emitShiftOperation(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
Value *Op, Value *ShiftAmount, bool isLeftShift,
|
2004-10-26 03:48:25 +00:00
|
|
|
const Type *ResultTy, ShiftInst *SI,
|
|
|
|
unsigned DestReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
/// emitSelectOperation - Common code shared between visitSelectInst and the
|
|
|
|
/// constant expression support.
|
2004-07-26 18:13:24 +00:00
|
|
|
///
|
2004-06-21 16:55:25 +00:00
|
|
|
void emitSelectOperation(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
Value *Cond, Value *TrueVal, Value *FalseVal,
|
|
|
|
unsigned DestReg);
|
|
|
|
|
2004-11-18 06:51:29 +00:00
|
|
|
/// getGlobalBaseReg - Output the instructions required to put the
|
|
|
|
/// base address to use for accessing globals into a register. Returns the
|
|
|
|
/// register containing the base address.
|
2004-07-26 18:13:24 +00:00
|
|
|
///
|
2005-03-24 06:28:42 +00:00
|
|
|
unsigned getGlobalBaseReg();
|
2004-07-26 18:13:24 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
/// copyConstantToRegister - Output the instructions required to put the
|
|
|
|
/// specified constant into the specified register.
|
|
|
|
///
|
|
|
|
void copyConstantToRegister(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator MBBI,
|
|
|
|
Constant *C, unsigned Reg);
|
|
|
|
|
|
|
|
void emitUCOM(MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI,
|
|
|
|
unsigned LHS, unsigned RHS);
|
|
|
|
|
|
|
|
/// makeAnotherReg - This method returns the next register number we haven't
|
|
|
|
/// yet used.
|
|
|
|
///
|
|
|
|
/// Long values are handled somewhat specially. They are always allocated
|
|
|
|
/// as pairs of 32 bit integer values. The register number returned is the
|
2004-07-21 20:09:08 +00:00
|
|
|
/// high 32 bits of the long value, and the regNum+1 is the low 32 bits.
|
2004-06-21 16:55:25 +00:00
|
|
|
///
|
|
|
|
unsigned makeAnotherReg(const Type *Ty) {
|
2004-08-17 04:55:41 +00:00
|
|
|
assert(dynamic_cast<const PPC32RegisterInfo*>(TM.getRegisterInfo()) &&
|
2004-06-21 16:55:25 +00:00
|
|
|
"Current target doesn't have PPC reg info??");
|
2004-08-17 04:55:41 +00:00
|
|
|
const PPC32RegisterInfo *PPCRI =
|
|
|
|
static_cast<const PPC32RegisterInfo*>(TM.getRegisterInfo());
|
2004-06-21 16:55:25 +00:00
|
|
|
if (Ty == Type::LongTy || Ty == Type::ULongTy) {
|
2004-08-10 20:42:36 +00:00
|
|
|
const TargetRegisterClass *RC = PPCRI->getRegClassForType(Type::IntTy);
|
|
|
|
// Create the upper part
|
2004-06-21 16:55:25 +00:00
|
|
|
F->getSSARegMap()->createVirtualRegister(RC);
|
2004-08-10 20:42:36 +00:00
|
|
|
// Create the lower part.
|
2004-06-21 16:55:25 +00:00
|
|
|
return F->getSSARegMap()->createVirtualRegister(RC)-1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the mapping of regnumber => reg class to MachineFunction
|
2004-08-10 20:42:36 +00:00
|
|
|
const TargetRegisterClass *RC = PPCRI->getRegClassForType(Ty);
|
2004-06-21 16:55:25 +00:00
|
|
|
return F->getSSARegMap()->createVirtualRegister(RC);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getReg - This method turns an LLVM value into a register number.
|
|
|
|
///
|
|
|
|
unsigned getReg(Value &V) { return getReg(&V); } // Allow references
|
|
|
|
unsigned getReg(Value *V) {
|
|
|
|
// Just append to the end of the current bb.
|
|
|
|
MachineBasicBlock::iterator It = BB->end();
|
|
|
|
return getReg(V, BB, It);
|
|
|
|
}
|
|
|
|
unsigned getReg(Value *V, MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IPt);
|
2004-07-21 20:09:08 +00:00
|
|
|
|
|
|
|
/// canUseAsImmediateForOpcode - This method returns whether a ConstantInt
|
|
|
|
/// is okay to use as an immediate argument to a certain binary operation
|
2004-10-07 22:30:03 +00:00
|
|
|
bool canUseAsImmediateForOpcode(ConstantInt *CI, unsigned Opcode,
|
|
|
|
bool Shifted);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
/// getFixedSizedAllocaFI - Return the frame index for a fixed sized alloca
|
|
|
|
/// that is to be statically allocated with the initial stack frame
|
|
|
|
/// adjustment.
|
|
|
|
unsigned getFixedSizedAllocaFI(AllocaInst *AI);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// dyn_castFixedAlloca - If the specified value is a fixed size alloca
|
|
|
|
/// instruction in the entry block, return it. Otherwise, return a null
|
|
|
|
/// pointer.
|
|
|
|
static AllocaInst *dyn_castFixedAlloca(Value *V) {
|
|
|
|
if (AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
|
|
|
|
BasicBlock *BB = AI->getParent();
|
|
|
|
if (isa<ConstantUInt>(AI->getArraySize()) && BB ==&BB->getParent()->front())
|
|
|
|
return AI;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getReg - This method turns an LLVM value into a register number.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
unsigned PPC32ISel::getReg(Value *V, MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IPt) {
|
2004-07-20 00:59:38 +00:00
|
|
|
if (Constant *C = dyn_cast<Constant>(V)) {
|
2004-07-18 18:45:01 +00:00
|
|
|
unsigned Reg = makeAnotherReg(V->getType());
|
|
|
|
copyConstantToRegister(MBB, IPt, C, Reg);
|
|
|
|
return Reg;
|
2004-11-08 02:25:40 +00:00
|
|
|
} else if (CastInst *CI = dyn_cast<CastInst>(V)) {
|
|
|
|
// Do not emit noop casts at all, unless it's a double -> float cast.
|
|
|
|
if (getClassB(CI->getType()) == getClassB(CI->getOperand(0)->getType()))
|
|
|
|
return getReg(CI->getOperand(0), MBB, IPt);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else if (AllocaInst *AI = dyn_castFixedAlloca(V)) {
|
|
|
|
unsigned Reg = makeAnotherReg(V->getType());
|
|
|
|
unsigned FI = getFixedSizedAllocaFI(AI);
|
2004-08-10 22:47:03 +00:00
|
|
|
addFrameReference(BuildMI(*MBB, IPt, PPC::ADDI, 2, Reg), FI, 0, false);
|
2004-06-21 16:55:25 +00:00
|
|
|
return Reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned &Reg = RegMap[V];
|
|
|
|
if (Reg == 0) {
|
|
|
|
Reg = makeAnotherReg(V->getType());
|
|
|
|
RegMap[V] = Reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Reg;
|
|
|
|
}
|
|
|
|
|
2004-07-21 20:09:08 +00:00
|
|
|
/// canUseAsImmediateForOpcode - This method returns whether a ConstantInt
|
|
|
|
/// is okay to use as an immediate argument to a certain binary operator.
|
2004-10-07 22:30:03 +00:00
|
|
|
/// The shifted argument determines if the immediate is suitable to be used with
|
|
|
|
/// the PowerPC instructions such as addis which concatenate 16 bits of the
|
|
|
|
/// immediate with 16 bits of zeroes.
|
2004-07-21 20:09:08 +00:00
|
|
|
///
|
2004-10-07 22:30:03 +00:00
|
|
|
bool PPC32ISel::canUseAsImmediateForOpcode(ConstantInt *CI, unsigned Opcode,
|
|
|
|
bool Shifted) {
|
2004-07-21 20:09:08 +00:00
|
|
|
ConstantSInt *Op1Cs;
|
|
|
|
ConstantUInt *Op1Cu;
|
2004-10-07 22:30:03 +00:00
|
|
|
|
|
|
|
// For shifted immediates, any value with the low halfword cleared may be used
|
|
|
|
if (Shifted) {
|
Implement logical and with an immediate that consists of a contiguous block
of one or more 1 bits (may wrap from least significant bit to most
significant bit) as the rlwinm rather than andi., andis., or some longer
instructons sequence.
int andn4(int z) { return z & -4; }
int clearhi(int z) { return z & 0x0000FFFF; }
int clearlo(int z) { return z & 0xFFFF0000; }
int clearmid(int z) { return z & 0x00FFFF00; }
int clearwrap(int z) { return z & 0xFF0000FF; }
_andn4:
rlwinm r3, r3, 0, 0, 29
blr
_clearhi:
rlwinm r3, r3, 0, 16, 31
blr
_clearlo:
rlwinm r3, r3, 0, 0, 15
blr
_clearmid:
rlwinm r3, r3, 0, 8, 23
blr
_clearwrap:
rlwinm r3, r3, 0, 24, 7
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16832 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-08 02:49:24 +00:00
|
|
|
if (((int32_t)CI->getRawValue() & 0x0000FFFF) == 0)
|
2004-10-07 22:30:03 +00:00
|
|
|
return true;
|
Implement logical and with an immediate that consists of a contiguous block
of one or more 1 bits (may wrap from least significant bit to most
significant bit) as the rlwinm rather than andi., andis., or some longer
instructons sequence.
int andn4(int z) { return z & -4; }
int clearhi(int z) { return z & 0x0000FFFF; }
int clearlo(int z) { return z & 0xFFFF0000; }
int clearmid(int z) { return z & 0x00FFFF00; }
int clearwrap(int z) { return z & 0xFF0000FF; }
_andn4:
rlwinm r3, r3, 0, 0, 29
blr
_clearhi:
rlwinm r3, r3, 0, 16, 31
blr
_clearlo:
rlwinm r3, r3, 0, 0, 15
blr
_clearmid:
rlwinm r3, r3, 0, 8, 23
blr
_clearwrap:
rlwinm r3, r3, 0, 24, 7
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16832 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-08 02:49:24 +00:00
|
|
|
else
|
|
|
|
return false;
|
2004-10-07 22:30:03 +00:00
|
|
|
}
|
2004-11-04 19:43:18 +00:00
|
|
|
|
|
|
|
// Treat subfic like addi for the purposes of constant validation
|
|
|
|
if (Opcode == 5) Opcode = 0;
|
2004-07-21 20:09:08 +00:00
|
|
|
|
2004-11-04 19:43:18 +00:00
|
|
|
// addi, subfic, compare, and non-indexed load take SIMM
|
2004-10-07 22:30:03 +00:00
|
|
|
bool cond1 = (Opcode < 2)
|
To go along with sabre's improved InstCombining, improve recognition of
integers that we can use as immediate values in instructions.
Example from yacr2:
- lis r10, -1
- ori r10, r10, 65535
- add r28, r28, r10
+ addi r28, r28, -1
addi r7, r7, 1
addi r9, r9, 1
b .LBB_main_9 ; loopentry.1.i214
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16566 91177308-0d34-0410-b5e6-96231b3b80d8
2004-09-29 02:35:05 +00:00
|
|
|
&& ((int32_t)CI->getRawValue() <= 32767)
|
|
|
|
&& ((int32_t)CI->getRawValue() >= -32768);
|
2004-07-21 20:09:08 +00:00
|
|
|
|
|
|
|
// ANDIo, ORI, and XORI take unsigned values
|
2004-10-07 22:30:03 +00:00
|
|
|
bool cond2 = (Opcode >= 2)
|
2004-07-22 15:58:04 +00:00
|
|
|
&& (Op1Cs = dyn_cast<ConstantSInt>(CI))
|
|
|
|
&& (Op1Cs->getValue() >= 0)
|
To go along with sabre's improved InstCombining, improve recognition of
integers that we can use as immediate values in instructions.
Example from yacr2:
- lis r10, -1
- ori r10, r10, 65535
- add r28, r28, r10
+ addi r28, r28, -1
addi r7, r7, 1
addi r9, r9, 1
b .LBB_main_9 ; loopentry.1.i214
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16566 91177308-0d34-0410-b5e6-96231b3b80d8
2004-09-29 02:35:05 +00:00
|
|
|
&& (Op1Cs->getValue() <= 65535);
|
2004-07-21 20:09:08 +00:00
|
|
|
|
|
|
|
// ANDIo, ORI, and XORI take UIMMs, so they can be larger
|
2004-10-07 22:30:03 +00:00
|
|
|
bool cond3 = (Opcode >= 2)
|
2004-07-21 20:22:06 +00:00
|
|
|
&& (Op1Cu = dyn_cast<ConstantUInt>(CI))
|
|
|
|
&& (Op1Cu->getValue() <= 65535);
|
2004-07-21 20:09:08 +00:00
|
|
|
|
2004-10-07 22:30:03 +00:00
|
|
|
if (cond1 || cond2 || cond3)
|
2004-07-21 20:09:08 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
/// getFixedSizedAllocaFI - Return the frame index for a fixed sized alloca
|
|
|
|
/// that is to be statically allocated with the initial stack frame
|
|
|
|
/// adjustment.
|
2004-09-21 18:22:19 +00:00
|
|
|
unsigned PPC32ISel::getFixedSizedAllocaFI(AllocaInst *AI) {
|
2004-06-21 16:55:25 +00:00
|
|
|
// Already computed this?
|
|
|
|
std::map<AllocaInst*, unsigned>::iterator I = AllocaMap.lower_bound(AI);
|
|
|
|
if (I != AllocaMap.end() && I->first == AI) return I->second;
|
|
|
|
|
|
|
|
const Type *Ty = AI->getAllocatedType();
|
|
|
|
ConstantUInt *CUI = cast<ConstantUInt>(AI->getArraySize());
|
|
|
|
unsigned TySize = TM.getTargetData().getTypeSize(Ty);
|
|
|
|
TySize *= CUI->getValue(); // Get total allocated size...
|
|
|
|
unsigned Alignment = TM.getTargetData().getTypeAlignment(Ty);
|
|
|
|
|
|
|
|
// Create a new stack object using the frame manager...
|
|
|
|
int FrameIdx = F->getFrameInfo()->CreateStackObject(TySize, Alignment);
|
|
|
|
AllocaMap.insert(I, std::make_pair(AI, FrameIdx));
|
|
|
|
return FrameIdx;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-11-18 06:51:29 +00:00
|
|
|
/// getGlobalBaseReg - Output the instructions required to put the
|
2004-07-26 18:13:24 +00:00
|
|
|
/// base address to use for accessing globals into a register.
|
|
|
|
///
|
2005-03-24 06:28:42 +00:00
|
|
|
unsigned PPC32ISel::getGlobalBaseReg() {
|
2004-07-26 18:13:24 +00:00
|
|
|
if (!GlobalBaseInitialized) {
|
|
|
|
// Insert the set of GlobalBaseReg into the first MBB of the function
|
|
|
|
MachineBasicBlock &FirstMBB = F->front();
|
|
|
|
MachineBasicBlock::iterator MBBI = FirstMBB.begin();
|
|
|
|
GlobalBaseReg = makeAnotherReg(Type::IntTy);
|
2004-09-02 08:13:00 +00:00
|
|
|
BuildMI(FirstMBB, MBBI, PPC::MovePCtoLR, 0, PPC::LR);
|
2004-09-27 05:08:17 +00:00
|
|
|
BuildMI(FirstMBB, MBBI, PPC::MFLR, 1, GlobalBaseReg).addReg(PPC::LR);
|
2004-07-26 18:13:24 +00:00
|
|
|
GlobalBaseInitialized = true;
|
|
|
|
}
|
2004-11-18 06:51:29 +00:00
|
|
|
return GlobalBaseReg;
|
2004-07-26 18:13:24 +00:00
|
|
|
}
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
/// copyConstantToRegister - Output the instructions required to put the
|
|
|
|
/// specified constant into the specified register.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::copyConstantToRegister(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
Constant *C, unsigned R) {
|
2004-10-16 18:13:47 +00:00
|
|
|
if (isa<UndefValue>(C)) {
|
|
|
|
BuildMI(*MBB, IP, PPC::IMPLICIT_DEF, 0, R);
|
2005-03-08 22:53:09 +00:00
|
|
|
if (getClassB(C->getType()) == cLong)
|
2005-01-14 20:22:02 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::IMPLICIT_DEF, 0, R+1);
|
2004-10-16 18:13:47 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
if (C->getType()->isIntegral()) {
|
|
|
|
unsigned Class = getClassB(C->getType());
|
|
|
|
|
|
|
|
if (Class == cLong) {
|
2004-07-28 19:13:49 +00:00
|
|
|
if (ConstantUInt *CUI = dyn_cast<ConstantUInt>(C)) {
|
|
|
|
uint64_t uval = CUI->getValue();
|
|
|
|
unsigned hiUVal = uval >> 32;
|
|
|
|
unsigned loUVal = uval;
|
|
|
|
ConstantUInt *CUHi = ConstantUInt::get(Type::UIntTy, hiUVal);
|
|
|
|
ConstantUInt *CULo = ConstantUInt::get(Type::UIntTy, loUVal);
|
|
|
|
copyConstantToRegister(MBB, IP, CUHi, R);
|
|
|
|
copyConstantToRegister(MBB, IP, CULo, R+1);
|
|
|
|
return;
|
|
|
|
} else if (ConstantSInt *CSI = dyn_cast<ConstantSInt>(C)) {
|
|
|
|
int64_t sval = CSI->getValue();
|
|
|
|
int hiSVal = sval >> 32;
|
|
|
|
int loSVal = sval;
|
|
|
|
ConstantSInt *CSHi = ConstantSInt::get(Type::IntTy, hiSVal);
|
|
|
|
ConstantSInt *CSLo = ConstantSInt::get(Type::IntTy, loSVal);
|
|
|
|
copyConstantToRegister(MBB, IP, CSHi, R);
|
|
|
|
copyConstantToRegister(MBB, IP, CSLo, R+1);
|
|
|
|
return;
|
2004-07-20 00:41:46 +00:00
|
|
|
} else {
|
2004-07-28 19:13:49 +00:00
|
|
|
std::cerr << "Unhandled long constant type!\n";
|
|
|
|
abort();
|
2004-07-20 00:41:46 +00:00
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
2004-07-28 19:13:49 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
assert(Class <= cInt && "Type not handled yet!");
|
|
|
|
|
2004-07-28 19:13:49 +00:00
|
|
|
// Handle bool
|
2004-06-21 16:55:25 +00:00
|
|
|
if (C->getType() == Type::BoolTy) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(C == ConstantBool::True);
|
2004-07-28 19:13:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle int
|
|
|
|
if (ConstantUInt *CUI = dyn_cast<ConstantUInt>(C)) {
|
|
|
|
unsigned uval = CUI->getValue();
|
|
|
|
if (uval < 32768) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(uval);
|
2004-07-28 19:13:49 +00:00
|
|
|
} else {
|
|
|
|
unsigned Temp = makeAnotherReg(Type::IntTy);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LIS, 1, Temp).addSImm(uval >> 16);
|
2004-10-07 22:30:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::ORI, 2, R).addReg(Temp).addImm(uval & 0xFFFF);
|
2004-07-28 19:13:49 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else if (ConstantSInt *CSI = dyn_cast<ConstantSInt>(C)) {
|
|
|
|
int sval = CSI->getValue();
|
|
|
|
if (sval < 32768 && sval >= -32768) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(sval);
|
2004-06-21 17:41:12 +00:00
|
|
|
} else {
|
2004-07-28 19:13:49 +00:00
|
|
|
unsigned Temp = makeAnotherReg(Type::IntTy);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LIS, 1, Temp).addSImm(sval >> 16);
|
2004-10-07 22:30:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::ORI, 2, R).addReg(Temp).addImm(sval & 0xFFFF);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
2004-07-28 19:13:49 +00:00
|
|
|
return;
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
2004-07-28 19:13:49 +00:00
|
|
|
std::cerr << "Unhandled integer constant!\n";
|
|
|
|
abort();
|
2004-06-21 16:55:25 +00:00
|
|
|
} else if (ConstantFP *CFP = dyn_cast<ConstantFP>(C)) {
|
2004-07-06 22:51:53 +00:00
|
|
|
// We need to spill the constant to memory...
|
|
|
|
MachineConstantPool *CP = F->getConstantPool();
|
|
|
|
unsigned CPI = CP->getConstantPoolIndex(CFP);
|
|
|
|
const Type *Ty = CFP->getType();
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-07-06 22:51:53 +00:00
|
|
|
assert(Ty == Type::FloatTy || Ty == Type::DoubleTy && "Unknown FP type!");
|
2004-07-08 18:02:38 +00:00
|
|
|
|
2004-07-26 18:13:24 +00:00
|
|
|
// Load addr of constant to reg; constant is located at base + distance
|
2004-07-08 18:02:38 +00:00
|
|
|
unsigned Reg1 = makeAnotherReg(Type::IntTy);
|
2004-08-17 07:17:44 +00:00
|
|
|
unsigned Opcode = (Ty == Type::FloatTy) ? PPC::LFS : PPC::LFD;
|
2004-07-26 18:13:24 +00:00
|
|
|
// Move value at base + distance into return reg
|
2004-11-18 06:51:29 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LOADHiAddr, 2, Reg1)
|
2005-03-24 06:28:42 +00:00
|
|
|
.addReg(getGlobalBaseReg()).addConstantPoolIndex(CPI);
|
2004-09-04 05:00:00 +00:00
|
|
|
BuildMI(*MBB, IP, Opcode, 2, R).addConstantPoolIndex(CPI).addReg(Reg1);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else if (isa<ConstantPointerNull>(C)) {
|
|
|
|
// Copy zero (null pointer) to the register.
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(0);
|
2004-07-18 07:29:35 +00:00
|
|
|
} else if (GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
|
2004-07-26 18:13:24 +00:00
|
|
|
// GV is located at base + distance
|
2004-07-20 00:59:38 +00:00
|
|
|
unsigned TmpReg = makeAnotherReg(GV->getType());
|
2004-07-26 18:13:24 +00:00
|
|
|
|
|
|
|
// Move value at base + distance into return reg
|
2004-11-18 06:51:29 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LOADHiAddr, 2, TmpReg)
|
2005-03-24 06:28:42 +00:00
|
|
|
.addReg(getGlobalBaseReg()).addGlobalAddress(GV);
|
2004-11-23 05:54:25 +00:00
|
|
|
|
2004-11-25 07:09:01 +00:00
|
|
|
if (GV->hasWeakLinkage() || GV->isExternal()) {
|
2004-11-23 05:54:25 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LWZ, 2, R).addGlobalAddress(GV).addReg(TmpReg);
|
|
|
|
} else {
|
|
|
|
BuildMI(*MBB, IP, PPC::LA, 2, R).addReg(TmpReg).addGlobalAddress(GV);
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
2004-07-15 02:14:30 +00:00
|
|
|
std::cerr << "Offending constant: " << *C << "\n";
|
2004-06-21 16:55:25 +00:00
|
|
|
assert(0 && "Type not handled yet!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// LoadArgumentsToVirtualRegs - Load all of the arguments to this function from
|
|
|
|
/// the stack into virtual registers.
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::LoadArgumentsToVirtualRegs(Function &Fn) {
|
2004-08-06 06:58:50 +00:00
|
|
|
unsigned ArgOffset = 24;
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned GPR_remaining = 8;
|
|
|
|
unsigned FPR_remaining = 13;
|
2004-07-06 22:51:53 +00:00
|
|
|
unsigned GPR_idx = 0, FPR_idx = 0;
|
|
|
|
static const unsigned GPR[] = {
|
2004-08-10 22:47:03 +00:00
|
|
|
PPC::R3, PPC::R4, PPC::R5, PPC::R6,
|
|
|
|
PPC::R7, PPC::R8, PPC::R9, PPC::R10,
|
2004-07-06 22:51:53 +00:00
|
|
|
};
|
|
|
|
static const unsigned FPR[] = {
|
2004-08-10 22:47:03 +00:00
|
|
|
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
|
2004-07-06 22:51:53 +00:00
|
|
|
};
|
2004-06-21 17:41:12 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
MachineFrameInfo *MFI = F->getFrameInfo();
|
2004-07-06 22:51:53 +00:00
|
|
|
|
2005-04-09 16:32:30 +00:00
|
|
|
for (Function::arg_iterator I = Fn.arg_begin(), E = Fn.arg_end();
|
|
|
|
I != E; ++I) {
|
2004-06-21 16:55:25 +00:00
|
|
|
bool ArgLive = !I->use_empty();
|
|
|
|
unsigned Reg = ArgLive ? getReg(*I) : 0;
|
|
|
|
int FI; // Frame object index
|
|
|
|
|
|
|
|
switch (getClassB(I->getType())) {
|
|
|
|
case cByte:
|
|
|
|
if (ArgLive) {
|
2004-07-20 15:51:37 +00:00
|
|
|
FI = MFI->CreateFixedObject(4, ArgOffset);
|
2004-06-21 17:41:12 +00:00
|
|
|
if (GPR_remaining > 0) {
|
2005-04-09 16:32:30 +00:00
|
|
|
F->addLiveIn(GPR[GPR_idx]);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, Reg).addReg(GPR[GPR_idx])
|
2004-07-06 22:51:53 +00:00
|
|
|
.addReg(GPR[GPR_idx]);
|
2004-06-21 17:41:12 +00:00
|
|
|
} else {
|
2004-08-10 22:47:03 +00:00
|
|
|
addFrameReference(BuildMI(BB, PPC::LBZ, 2, Reg), FI);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
case cShort:
|
|
|
|
if (ArgLive) {
|
2004-07-20 15:51:37 +00:00
|
|
|
FI = MFI->CreateFixedObject(4, ArgOffset);
|
2004-06-21 17:41:12 +00:00
|
|
|
if (GPR_remaining > 0) {
|
2005-04-09 16:32:30 +00:00
|
|
|
F->addLiveIn(GPR[GPR_idx]);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, Reg).addReg(GPR[GPR_idx])
|
2004-07-06 22:51:53 +00:00
|
|
|
.addReg(GPR[GPR_idx]);
|
2004-06-21 17:41:12 +00:00
|
|
|
} else {
|
2004-08-10 22:47:03 +00:00
|
|
|
addFrameReference(BuildMI(BB, PPC::LHZ, 2, Reg), FI);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
case cInt:
|
|
|
|
if (ArgLive) {
|
|
|
|
FI = MFI->CreateFixedObject(4, ArgOffset);
|
2004-06-21 17:41:12 +00:00
|
|
|
if (GPR_remaining > 0) {
|
2005-04-09 16:32:30 +00:00
|
|
|
F->addLiveIn(GPR[GPR_idx]);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, Reg).addReg(GPR[GPR_idx])
|
2004-07-06 22:51:53 +00:00
|
|
|
.addReg(GPR[GPR_idx]);
|
2004-06-21 17:41:12 +00:00
|
|
|
} else {
|
2004-08-10 22:47:03 +00:00
|
|
|
addFrameReference(BuildMI(BB, PPC::LWZ, 2, Reg), FI);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
case cLong:
|
|
|
|
if (ArgLive) {
|
|
|
|
FI = MFI->CreateFixedObject(8, ArgOffset);
|
2004-06-21 17:41:12 +00:00
|
|
|
if (GPR_remaining > 1) {
|
2005-04-09 16:32:30 +00:00
|
|
|
F->addLiveIn(GPR[GPR_idx]);
|
|
|
|
F->addLiveIn(GPR[GPR_idx+1]);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, Reg).addReg(GPR[GPR_idx])
|
2004-07-09 15:45:07 +00:00
|
|
|
.addReg(GPR[GPR_idx]);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, Reg+1).addReg(GPR[GPR_idx+1])
|
2004-07-09 15:45:07 +00:00
|
|
|
.addReg(GPR[GPR_idx+1]);
|
2004-06-21 17:41:12 +00:00
|
|
|
} else {
|
2004-08-10 22:47:03 +00:00
|
|
|
addFrameReference(BuildMI(BB, PPC::LWZ, 2, Reg), FI);
|
|
|
|
addFrameReference(BuildMI(BB, PPC::LWZ, 2, Reg+1), FI, 4);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
|
|
|
}
|
2004-07-21 20:09:08 +00:00
|
|
|
// longs require 4 additional bytes and use 2 GPRs
|
|
|
|
ArgOffset += 4;
|
2004-06-21 17:41:12 +00:00
|
|
|
if (GPR_remaining > 1) {
|
2004-07-21 20:09:08 +00:00
|
|
|
GPR_remaining--;
|
2004-06-21 17:41:12 +00:00
|
|
|
GPR_idx++;
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
2004-07-20 00:41:46 +00:00
|
|
|
case cFP32:
|
|
|
|
if (ArgLive) {
|
|
|
|
FI = MFI->CreateFixedObject(4, ArgOffset);
|
|
|
|
|
|
|
|
if (FPR_remaining > 0) {
|
2005-04-09 16:32:30 +00:00
|
|
|
F->addLiveIn(FPR[FPR_idx]);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::FMR, 1, Reg).addReg(FPR[FPR_idx]);
|
2004-07-20 00:41:46 +00:00
|
|
|
FPR_remaining--;
|
|
|
|
FPR_idx++;
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
2004-08-10 22:47:03 +00:00
|
|
|
addFrameReference(BuildMI(BB, PPC::LFS, 2, Reg), FI);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
2004-07-20 00:41:46 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case cFP64:
|
|
|
|
if (ArgLive) {
|
|
|
|
FI = MFI->CreateFixedObject(8, ArgOffset);
|
|
|
|
|
2004-06-21 17:41:12 +00:00
|
|
|
if (FPR_remaining > 0) {
|
2005-04-09 16:32:30 +00:00
|
|
|
F->addLiveIn(FPR[FPR_idx]);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::FMR, 1, Reg).addReg(FPR[FPR_idx]);
|
2004-07-06 22:51:53 +00:00
|
|
|
FPR_remaining--;
|
|
|
|
FPR_idx++;
|
2004-06-21 17:41:12 +00:00
|
|
|
} else {
|
2004-08-10 22:47:03 +00:00
|
|
|
addFrameReference(BuildMI(BB, PPC::LFD, 2, Reg), FI);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
|
|
|
}
|
2004-07-20 00:41:46 +00:00
|
|
|
|
|
|
|
// doubles require 4 additional bytes and use 2 GPRs of param space
|
|
|
|
ArgOffset += 4;
|
|
|
|
if (GPR_remaining > 0) {
|
|
|
|
GPR_remaining--;
|
|
|
|
GPR_idx++;
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0 && "Unhandled argument type!");
|
|
|
|
}
|
|
|
|
ArgOffset += 4; // Each argument takes at least 4 bytes on the stack...
|
2004-06-21 17:41:12 +00:00
|
|
|
if (GPR_remaining > 0) {
|
2004-07-06 22:51:53 +00:00
|
|
|
GPR_remaining--; // uses up 2 GPRs
|
|
|
|
GPR_idx++;
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the function takes variable number of arguments, add a frame offset for
|
|
|
|
// the start of the first vararg value... this is used to expand
|
|
|
|
// llvm.va_start.
|
|
|
|
if (Fn.getFunctionType()->isVarArg())
|
2004-07-26 18:13:24 +00:00
|
|
|
VarArgsFrameIndex = MFI->CreateFixedObject(4, ArgOffset);
|
2005-04-09 16:32:30 +00:00
|
|
|
|
|
|
|
if (Fn.getReturnType() != Type::VoidTy)
|
|
|
|
switch (getClassB(Fn.getReturnType())) {
|
|
|
|
case cByte:
|
|
|
|
case cShort:
|
|
|
|
case cInt:
|
|
|
|
F->addLiveOut(PPC::R3);
|
|
|
|
break;
|
|
|
|
case cLong:
|
|
|
|
F->addLiveOut(PPC::R3);
|
|
|
|
F->addLiveOut(PPC::R4);
|
|
|
|
break;
|
|
|
|
case cFP32:
|
|
|
|
case cFP64:
|
|
|
|
F->addLiveOut(PPC::F1);
|
|
|
|
break;
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// SelectPHINodes - Insert machine code to generate phis. This is tricky
|
|
|
|
/// because we have to generate our sources into the source basic blocks, not
|
|
|
|
/// the current one.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::SelectPHINodes() {
|
2004-06-21 16:55:25 +00:00
|
|
|
const TargetInstrInfo &TII = *TM.getInstrInfo();
|
|
|
|
const Function &LF = *F->getFunction(); // The LLVM function...
|
2005-04-09 22:05:17 +00:00
|
|
|
|
|
|
|
MachineBasicBlock::iterator MFLRIt = F->begin()->begin();
|
|
|
|
if (GlobalBaseInitialized) {
|
|
|
|
// If we emitted a MFLR for the global base reg, get an iterator to an
|
|
|
|
// instruction after it.
|
|
|
|
while (MFLRIt->getOpcode() != PPC::MFLR)
|
|
|
|
++MFLRIt;
|
|
|
|
++MFLRIt; // step one MI past it.
|
|
|
|
}
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
for (Function::const_iterator I = LF.begin(), E = LF.end(); I != E; ++I) {
|
|
|
|
const BasicBlock *BB = I;
|
|
|
|
MachineBasicBlock &MBB = *MBBMap[I];
|
|
|
|
|
|
|
|
// Loop over all of the PHI nodes in the LLVM basic block...
|
|
|
|
MachineBasicBlock::iterator PHIInsertPoint = MBB.begin();
|
|
|
|
for (BasicBlock::const_iterator I = BB->begin();
|
|
|
|
PHINode *PN = const_cast<PHINode*>(dyn_cast<PHINode>(I)); ++I) {
|
|
|
|
|
|
|
|
// Create a new machine instr PHI node, and insert it.
|
|
|
|
unsigned PHIReg = getReg(*PN);
|
|
|
|
MachineInstr *PhiMI = BuildMI(MBB, PHIInsertPoint,
|
2004-08-10 22:47:03 +00:00
|
|
|
PPC::PHI, PN->getNumOperands(), PHIReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
MachineInstr *LongPhiMI = 0;
|
|
|
|
if (PN->getType() == Type::LongTy || PN->getType() == Type::ULongTy)
|
|
|
|
LongPhiMI = BuildMI(MBB, PHIInsertPoint,
|
2004-08-10 22:47:03 +00:00
|
|
|
PPC::PHI, PN->getNumOperands(), PHIReg+1);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
// PHIValues - Map of blocks to incoming virtual registers. We use this
|
|
|
|
// so that we only initialize one incoming value for a particular block,
|
|
|
|
// even if the block has multiple entries in the PHI node.
|
|
|
|
//
|
|
|
|
std::map<MachineBasicBlock*, unsigned> PHIValues;
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
|
2004-07-09 15:45:07 +00:00
|
|
|
MachineBasicBlock *PredMBB = 0;
|
|
|
|
for (MachineBasicBlock::pred_iterator PI = MBB.pred_begin (),
|
|
|
|
PE = MBB.pred_end (); PI != PE; ++PI)
|
|
|
|
if (PN->getIncomingBlock(i) == (*PI)->getBasicBlock()) {
|
|
|
|
PredMBB = *PI;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
assert (PredMBB && "Couldn't find incoming machine-cfg edge for phi");
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned ValReg;
|
|
|
|
std::map<MachineBasicBlock*, unsigned>::iterator EntryIt =
|
|
|
|
PHIValues.lower_bound(PredMBB);
|
|
|
|
|
|
|
|
if (EntryIt != PHIValues.end() && EntryIt->first == PredMBB) {
|
|
|
|
// We already inserted an initialization of the register for this
|
|
|
|
// predecessor. Recycle it.
|
|
|
|
ValReg = EntryIt->second;
|
2004-07-23 22:35:49 +00:00
|
|
|
} else {
|
2004-06-21 16:55:25 +00:00
|
|
|
// Get the incoming value into a virtual register.
|
|
|
|
//
|
|
|
|
Value *Val = PN->getIncomingValue(i);
|
|
|
|
|
|
|
|
// If this is a constant or GlobalValue, we may have to insert code
|
|
|
|
// into the basic block to compute it into a virtual register.
|
|
|
|
if ((isa<Constant>(Val) && !isa<ConstantExpr>(Val)) ||
|
|
|
|
isa<GlobalValue>(Val)) {
|
|
|
|
// Simple constants get emitted at the end of the basic block,
|
|
|
|
// before any terminator instructions. We "know" that the code to
|
|
|
|
// move a constant into a register will never clobber any flags.
|
|
|
|
ValReg = getReg(Val, PredMBB, PredMBB->getFirstTerminator());
|
|
|
|
} else {
|
|
|
|
// Because we don't want to clobber any values which might be in
|
|
|
|
// physical registers with the computation of this constant (which
|
|
|
|
// might be arbitrarily complex if it is a constant expression),
|
|
|
|
// just insert the computation at the top of the basic block.
|
|
|
|
MachineBasicBlock::iterator PI = PredMBB->begin();
|
2004-07-23 22:35:49 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
// Skip over any PHI nodes though!
|
2004-08-10 22:47:03 +00:00
|
|
|
while (PI != PredMBB->end() && PI->getOpcode() == PPC::PHI)
|
2004-06-21 16:55:25 +00:00
|
|
|
++PI;
|
2004-07-23 22:35:49 +00:00
|
|
|
|
2005-04-09 22:05:17 +00:00
|
|
|
// If this is the entry block, and if the entry block contains a
|
|
|
|
// MFLR instruction, emit this operation after it. This is needed
|
|
|
|
// because global addresses use it.
|
|
|
|
if (PredMBB == F->begin())
|
|
|
|
PI = MFLRIt;
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
ValReg = getReg(Val, PredMBB, PI);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remember that we inserted a value for this PHI for this predecessor
|
|
|
|
PHIValues.insert(EntryIt, std::make_pair(PredMBB, ValReg));
|
|
|
|
}
|
|
|
|
|
|
|
|
PhiMI->addRegOperand(ValReg);
|
|
|
|
PhiMI->addMachineBasicBlockOperand(PredMBB);
|
|
|
|
if (LongPhiMI) {
|
|
|
|
LongPhiMI->addRegOperand(ValReg+1);
|
|
|
|
LongPhiMI->addMachineBasicBlockOperand(PredMBB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that we emitted all of the incoming values for the PHI node, make
|
|
|
|
// sure to reposition the InsertPoint after the PHI that we just added.
|
|
|
|
// This is needed because we might have inserted a constant into this
|
|
|
|
// block, right after the PHI's which is before the old insert point!
|
|
|
|
PHIInsertPoint = LongPhiMI ? LongPhiMI : PhiMI;
|
|
|
|
++PHIInsertPoint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// canFoldSetCCIntoBranchOrSelect - Return the setcc instruction if we can fold
|
|
|
|
// it into the conditional branch or select instruction which is the only user
|
|
|
|
// of the cc instruction. This is the case if the conditional branch is the
|
|
|
|
// only user of the setcc, and if the setcc is in the same basic block as the
|
2004-07-21 20:09:08 +00:00
|
|
|
// conditional branch.
|
2004-06-21 16:55:25 +00:00
|
|
|
//
|
|
|
|
static SetCondInst *canFoldSetCCIntoBranchOrSelect(Value *V) {
|
|
|
|
if (SetCondInst *SCI = dyn_cast<SetCondInst>(V))
|
|
|
|
if (SCI->hasOneUse()) {
|
|
|
|
Instruction *User = cast<Instruction>(SCI->use_back());
|
2005-01-14 19:31:00 +00:00
|
|
|
if ((isa<BranchInst>(User) ||
|
|
|
|
(isa<SelectInst>(User) && User->getOperand(0) == V)) &&
|
2004-07-16 21:06:24 +00:00
|
|
|
SCI->getParent() == User->getParent())
|
2004-06-21 16:55:25 +00:00
|
|
|
return SCI;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-07-26 18:13:24 +00:00
|
|
|
// canFoldGEPIntoLoadOrStore - Return the GEP instruction if we can fold it into
|
|
|
|
// the load or store instruction that is the only user of the GEP.
|
|
|
|
//
|
|
|
|
static GetElementPtrInst *canFoldGEPIntoLoadOrStore(Value *V) {
|
2004-09-23 05:31:33 +00:00
|
|
|
if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(V)) {
|
|
|
|
bool AllUsesAreMem = true;
|
|
|
|
for (Value::use_iterator I = GEPI->use_begin(), E = GEPI->use_end();
|
|
|
|
I != E; ++I) {
|
|
|
|
Instruction *User = cast<Instruction>(*I);
|
|
|
|
|
|
|
|
// If the GEP is the target of a store, but not the source, then we are ok
|
|
|
|
// to fold it.
|
2004-07-26 18:13:24 +00:00
|
|
|
if (isa<StoreInst>(User) &&
|
|
|
|
GEPI->getParent() == User->getParent() &&
|
|
|
|
User->getOperand(0) != GEPI &&
|
2004-09-23 05:31:33 +00:00
|
|
|
User->getOperand(1) == GEPI)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// If the GEP is the source of a load, then we're always ok to fold it
|
2004-07-26 18:13:24 +00:00
|
|
|
if (isa<LoadInst>(User) &&
|
|
|
|
GEPI->getParent() == User->getParent() &&
|
2004-09-23 05:31:33 +00:00
|
|
|
User->getOperand(0) == GEPI)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// if we got to this point, than the instruction was not a load or store
|
|
|
|
// that we are capable of folding the GEP into.
|
|
|
|
AllUsesAreMem = false;
|
|
|
|
break;
|
2004-07-26 18:13:24 +00:00
|
|
|
}
|
2004-09-23 05:31:33 +00:00
|
|
|
if (AllUsesAreMem)
|
|
|
|
return GEPI;
|
|
|
|
}
|
2004-07-26 18:13:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
// Return a fixed numbering for setcc instructions which does not depend on the
|
|
|
|
// order of the opcodes.
|
|
|
|
//
|
|
|
|
static unsigned getSetCCNumber(unsigned Opcode) {
|
2004-07-06 15:32:44 +00:00
|
|
|
switch (Opcode) {
|
2004-06-21 16:55:25 +00:00
|
|
|
default: assert(0 && "Unknown setcc instruction!");
|
|
|
|
case Instruction::SetEQ: return 0;
|
|
|
|
case Instruction::SetNE: return 1;
|
|
|
|
case Instruction::SetLT: return 2;
|
|
|
|
case Instruction::SetGE: return 3;
|
|
|
|
case Instruction::SetGT: return 4;
|
|
|
|
case Instruction::SetLE: return 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-10 01:03:31 +00:00
|
|
|
static unsigned getPPCOpcodeForSetCCOpcode(unsigned Opcode) {
|
2004-07-06 15:32:44 +00:00
|
|
|
switch (Opcode) {
|
|
|
|
default: assert(0 && "Unknown setcc instruction!");
|
2004-08-10 22:47:03 +00:00
|
|
|
case Instruction::SetEQ: return PPC::BEQ;
|
|
|
|
case Instruction::SetNE: return PPC::BNE;
|
|
|
|
case Instruction::SetLT: return PPC::BLT;
|
|
|
|
case Instruction::SetGE: return PPC::BGE;
|
|
|
|
case Instruction::SetGT: return PPC::BGT;
|
|
|
|
case Instruction::SetLE: return PPC::BLE;
|
2004-07-06 15:32:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
/// emitUCOM - emits an unordered FP compare.
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::emitUCOM(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP,
|
|
|
|
unsigned LHS, unsigned RHS) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::FCMPU, 2, PPC::CR0).addReg(LHS).addReg(RHS);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
2004-09-21 18:22:19 +00:00
|
|
|
unsigned PPC32ISel::ExtendOrClear(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
2004-09-22 04:40:25 +00:00
|
|
|
Value *Op0) {
|
2004-08-22 08:10:15 +00:00
|
|
|
const Type *CompTy = Op0->getType();
|
|
|
|
unsigned Reg = getReg(Op0, MBB, IP);
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned Class = getClassB(CompTy);
|
2004-07-23 22:35:49 +00:00
|
|
|
|
2004-09-29 03:45:33 +00:00
|
|
|
// Since we know that boolean values will be either zero or one, we don't
|
|
|
|
// have to extend or clear them.
|
|
|
|
if (CompTy == Type::BoolTy)
|
|
|
|
return Reg;
|
|
|
|
|
2004-08-20 09:56:22 +00:00
|
|
|
// Before we do a comparison or SetCC, we have to make sure that we truncate
|
|
|
|
// the source registers appropriately.
|
2004-07-26 18:13:24 +00:00
|
|
|
if (Class == cByte) {
|
|
|
|
unsigned TmpReg = makeAnotherReg(CompTy);
|
|
|
|
if (CompTy->isSigned())
|
2004-08-20 09:56:22 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSB, 1, TmpReg).addReg(Reg);
|
2004-07-26 18:13:24 +00:00
|
|
|
else
|
2004-08-20 09:56:22 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, TmpReg).addReg(Reg).addImm(0)
|
2004-07-26 18:13:24 +00:00
|
|
|
.addImm(24).addImm(31);
|
2004-08-20 09:56:22 +00:00
|
|
|
Reg = TmpReg;
|
2004-07-26 18:13:24 +00:00
|
|
|
} else if (Class == cShort) {
|
|
|
|
unsigned TmpReg = makeAnotherReg(CompTy);
|
|
|
|
if (CompTy->isSigned())
|
2004-08-20 09:56:22 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSH, 1, TmpReg).addReg(Reg);
|
2004-07-26 18:13:24 +00:00
|
|
|
else
|
2004-08-20 09:56:22 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, TmpReg).addReg(Reg).addImm(0)
|
2004-07-26 18:13:24 +00:00
|
|
|
.addImm(16).addImm(31);
|
2004-08-20 09:56:22 +00:00
|
|
|
Reg = TmpReg;
|
2004-07-26 18:13:24 +00:00
|
|
|
}
|
2004-08-20 09:56:22 +00:00
|
|
|
return Reg;
|
|
|
|
}
|
|
|
|
|
2005-04-10 01:03:31 +00:00
|
|
|
/// EmitComparison - emits a comparison of the two operands. The result is in
|
|
|
|
/// CR0.
|
2004-08-20 09:56:22 +00:00
|
|
|
///
|
2005-04-10 01:03:31 +00:00
|
|
|
void PPC32ISel::EmitComparison(unsigned OpNum, Value *Op0, Value *Op1,
|
|
|
|
MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP) {
|
2004-08-20 09:56:22 +00:00
|
|
|
// The arguments are already supposed to be of the same type.
|
|
|
|
const Type *CompTy = Op0->getType();
|
|
|
|
unsigned Class = getClassB(CompTy);
|
2004-09-22 04:40:25 +00:00
|
|
|
unsigned Op0r = ExtendOrClear(MBB, IP, Op0);
|
2004-07-26 18:13:24 +00:00
|
|
|
|
2004-07-21 20:09:08 +00:00
|
|
|
// Use crand for lt, gt and crandc for le, ge
|
2004-08-10 22:47:03 +00:00
|
|
|
unsigned CROpcode = (OpNum == 2 || OpNum == 4) ? PPC::CRAND : PPC::CRANDC;
|
2004-07-21 20:09:08 +00:00
|
|
|
// ? cr1[lt] : cr1[gt]
|
|
|
|
unsigned CR1field = (OpNum == 2 || OpNum == 3) ? 4 : 5;
|
|
|
|
// ? cr0[lt] : cr0[gt]
|
|
|
|
unsigned CR0field = (OpNum == 2 || OpNum == 5) ? 0 : 1;
|
2004-08-10 22:47:03 +00:00
|
|
|
unsigned Opcode = CompTy->isSigned() ? PPC::CMPW : PPC::CMPLW;
|
|
|
|
unsigned OpcodeImm = CompTy->isSigned() ? PPC::CMPWI : PPC::CMPLWI;
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
// Special case handling of: cmp R, i
|
2004-07-22 15:58:04 +00:00
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(Op1)) {
|
2004-06-21 16:55:25 +00:00
|
|
|
if (Class == cByte || Class == cShort || Class == cInt) {
|
2004-07-21 20:09:08 +00:00
|
|
|
unsigned Op1v = CI->getRawValue() & 0xFFFF;
|
2004-08-15 06:42:28 +00:00
|
|
|
unsigned OpClass = (CompTy->isSigned()) ? 0 : 2;
|
|
|
|
|
2004-07-21 20:09:08 +00:00
|
|
|
// Treat compare like ADDI for the purposes of immediate suitability
|
2004-10-07 22:30:03 +00:00
|
|
|
if (canUseAsImmediateForOpcode(CI, OpClass, false)) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, OpcodeImm, 2, PPC::CR0).addReg(Op0r).addSImm(Op1v);
|
2004-06-21 17:41:12 +00:00
|
|
|
} else {
|
|
|
|
unsigned Op1r = getReg(Op1, MBB, IP);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, Opcode, 2, PPC::CR0).addReg(Op0r).addReg(Op1r);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
2005-04-10 01:03:31 +00:00
|
|
|
return;
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
|
|
|
assert(Class == cLong && "Unknown integer class!");
|
|
|
|
unsigned LowCst = CI->getRawValue();
|
|
|
|
unsigned HiCst = CI->getRawValue() >> 32;
|
|
|
|
if (OpNum < 2) { // seteq, setne
|
2004-07-21 20:09:08 +00:00
|
|
|
unsigned LoLow = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned LoTmp = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned HiLow = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned HiTmp = makeAnotherReg(Type::IntTy);
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned FinalTmp = makeAnotherReg(Type::IntTy);
|
2004-07-23 22:35:49 +00:00
|
|
|
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::XORI, 2, LoLow).addReg(Op0r+1)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addImm(LowCst & 0xFFFF);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::XORIS, 2, LoTmp).addReg(LoLow)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addImm(LowCst >> 16);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::XORI, 2, HiLow).addReg(Op0r)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addImm(HiCst & 0xFFFF);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::XORIS, 2, HiTmp).addReg(HiLow)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addImm(HiCst >> 16);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::ORo, 2, FinalTmp).addReg(LoTmp).addReg(HiTmp);
|
2005-04-10 01:03:31 +00:00
|
|
|
return;
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
2004-07-16 21:06:24 +00:00
|
|
|
unsigned ConstReg = makeAnotherReg(CompTy);
|
|
|
|
copyConstantToRegister(MBB, IP, CI, ConstReg);
|
2004-07-23 22:35:49 +00:00
|
|
|
|
2004-07-21 20:09:08 +00:00
|
|
|
// cr0 = r3 ccOpcode r5 or (r3 == r5 AND r4 ccOpcode r6)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, Opcode, 2, PPC::CR0).addReg(Op0r)
|
2004-07-16 21:06:24 +00:00
|
|
|
.addReg(ConstReg);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, Opcode, 2, PPC::CR1).addReg(Op0r+1)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addReg(ConstReg+1);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::CRAND, 3).addImm(2).addImm(2).addImm(CR1field);
|
|
|
|
BuildMI(*MBB, IP, PPC::CROR, 3).addImm(CR0field).addImm(CR0field)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addImm(2);
|
2005-04-10 01:03:31 +00:00
|
|
|
return;
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Op1r = getReg(Op1, MBB, IP);
|
2004-07-21 20:09:08 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
switch (Class) {
|
|
|
|
default: assert(0 && "Unknown type class!");
|
|
|
|
case cByte:
|
|
|
|
case cShort:
|
|
|
|
case cInt:
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, Opcode, 2, PPC::CR0).addReg(Op0r).addReg(Op1r);
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
2004-07-06 22:51:53 +00:00
|
|
|
|
2004-07-20 00:41:46 +00:00
|
|
|
case cFP32:
|
|
|
|
case cFP64:
|
2004-06-21 16:55:25 +00:00
|
|
|
emitUCOM(MBB, IP, Op0r, Op1r);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case cLong:
|
|
|
|
if (OpNum < 2) { // seteq, setne
|
|
|
|
unsigned LoTmp = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned HiTmp = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned FinalTmp = makeAnotherReg(Type::IntTy);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::XOR, 2, HiTmp).addReg(Op0r).addReg(Op1r);
|
|
|
|
BuildMI(*MBB, IP, PPC::XOR, 2, LoTmp).addReg(Op0r+1).addReg(Op1r+1);
|
|
|
|
BuildMI(*MBB, IP, PPC::ORo, 2, FinalTmp).addReg(LoTmp).addReg(HiTmp);
|
2004-06-21 16:55:25 +00:00
|
|
|
break; // Allow the sete or setne to be generated from flags set by OR
|
|
|
|
} else {
|
2004-07-16 21:06:24 +00:00
|
|
|
unsigned TmpReg1 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned TmpReg2 = makeAnotherReg(Type::IntTy);
|
2004-07-21 20:09:08 +00:00
|
|
|
|
|
|
|
// cr0 = r3 ccOpcode r5 or (r3 == r5 AND r4 ccOpcode r6)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, Opcode, 2, PPC::CR0).addReg(Op0r).addReg(Op1r);
|
|
|
|
BuildMI(*MBB, IP, Opcode, 2, PPC::CR1).addReg(Op0r+1).addReg(Op1r+1);
|
|
|
|
BuildMI(*MBB, IP, PPC::CRAND, 3).addImm(2).addImm(2).addImm(CR1field);
|
|
|
|
BuildMI(*MBB, IP, PPC::CROR, 3).addImm(CR0field).addImm(CR0field)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addImm(2);
|
2005-04-10 01:03:31 +00:00
|
|
|
return;
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
}
|
2005-04-10 01:03:31 +00:00
|
|
|
return;
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
2004-07-06 22:51:53 +00:00
|
|
|
/// visitSetCondInst - emit code to calculate the condition via
|
|
|
|
/// EmitComparison(), and possibly store a 0 or 1 to a register as a result
|
2004-06-21 16:55:25 +00:00
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitSetCondInst(SetCondInst &I) {
|
2004-07-06 22:51:53 +00:00
|
|
|
if (canFoldSetCCIntoBranchOrSelect(&I))
|
2004-07-06 15:32:44 +00:00
|
|
|
return;
|
2004-07-16 21:06:24 +00:00
|
|
|
|
2004-09-22 04:40:25 +00:00
|
|
|
MachineBasicBlock::iterator MI = BB->end();
|
|
|
|
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
|
|
|
const Type *Ty = Op0->getType();
|
|
|
|
unsigned Class = getClassB(Ty);
|
2004-08-21 20:42:14 +00:00
|
|
|
unsigned Opcode = I.getOpcode();
|
2004-09-22 04:40:25 +00:00
|
|
|
unsigned OpNum = getSetCCNumber(Opcode);
|
|
|
|
unsigned DestReg = getReg(I);
|
|
|
|
|
|
|
|
// If the comparison type is byte, short, or int, then we can emit a
|
|
|
|
// branchless version of the SetCC that puts 0 (false) or 1 (true) in the
|
|
|
|
// destination register.
|
|
|
|
if (Class <= cInt) {
|
|
|
|
ConstantInt *CI = dyn_cast<ConstantInt>(Op1);
|
|
|
|
|
|
|
|
if (CI && CI->getRawValue() == 0) {
|
|
|
|
unsigned Op0Reg = ExtendOrClear(BB, MI, Op0);
|
|
|
|
|
|
|
|
// comparisons against constant zero and negative one often have shorter
|
|
|
|
// and/or faster sequences than the set-and-branch general case, handled
|
|
|
|
// below.
|
|
|
|
switch(OpNum) {
|
|
|
|
case 0: { // eq0
|
|
|
|
unsigned TempReg = makeAnotherReg(Type::IntTy);
|
|
|
|
BuildMI(*BB, MI, PPC::CNTLZW, 1, TempReg).addReg(Op0Reg);
|
|
|
|
BuildMI(*BB, MI, PPC::RLWINM, 4, DestReg).addReg(TempReg).addImm(27)
|
|
|
|
.addImm(5).addImm(31);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 1: { // ne0
|
|
|
|
unsigned TempReg = makeAnotherReg(Type::IntTy);
|
|
|
|
BuildMI(*BB, MI, PPC::ADDIC, 2, TempReg).addReg(Op0Reg).addSImm(-1);
|
|
|
|
BuildMI(*BB, MI, PPC::SUBFE, 2, DestReg).addReg(TempReg).addReg(Op0Reg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 2: { // lt0, always false if unsigned
|
|
|
|
if (Ty->isSigned())
|
|
|
|
BuildMI(*BB, MI, PPC::RLWINM, 4, DestReg).addReg(Op0Reg).addImm(1)
|
|
|
|
.addImm(31).addImm(31);
|
|
|
|
else
|
|
|
|
BuildMI(*BB, MI, PPC::LI, 1, DestReg).addSImm(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3: { // ge0, always true if unsigned
|
|
|
|
if (Ty->isSigned()) {
|
|
|
|
unsigned TempReg = makeAnotherReg(Type::IntTy);
|
|
|
|
BuildMI(*BB, MI, PPC::RLWINM, 4, TempReg).addReg(Op0Reg).addImm(1)
|
|
|
|
.addImm(31).addImm(31);
|
|
|
|
BuildMI(*BB, MI, PPC::XORI, 2, DestReg).addReg(TempReg).addImm(1);
|
|
|
|
} else {
|
|
|
|
BuildMI(*BB, MI, PPC::LI, 1, DestReg).addSImm(1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 4: { // gt0, equivalent to ne0 if unsigned
|
|
|
|
unsigned Temp1 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned Temp2 = makeAnotherReg(Type::IntTy);
|
|
|
|
if (Ty->isSigned()) {
|
|
|
|
BuildMI(*BB, MI, PPC::NEG, 2, Temp1).addReg(Op0Reg);
|
|
|
|
BuildMI(*BB, MI, PPC::ANDC, 2, Temp2).addReg(Temp1).addReg(Op0Reg);
|
|
|
|
BuildMI(*BB, MI, PPC::RLWINM, 4, DestReg).addReg(Temp2).addImm(1)
|
|
|
|
.addImm(31).addImm(31);
|
|
|
|
} else {
|
|
|
|
BuildMI(*BB, MI, PPC::ADDIC, 2, Temp1).addReg(Op0Reg).addSImm(-1);
|
|
|
|
BuildMI(*BB, MI, PPC::SUBFE, 2, DestReg).addReg(Temp1).addReg(Op0Reg);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 5: { // le0, equivalent to eq0 if unsigned
|
|
|
|
unsigned Temp1 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned Temp2 = makeAnotherReg(Type::IntTy);
|
|
|
|
if (Ty->isSigned()) {
|
|
|
|
BuildMI(*BB, MI, PPC::NEG, 2, Temp1).addReg(Op0Reg);
|
|
|
|
BuildMI(*BB, MI, PPC::ORC, 2, Temp2).addReg(Op0Reg).addReg(Temp1);
|
|
|
|
BuildMI(*BB, MI, PPC::RLWINM, 4, DestReg).addReg(Temp2).addImm(1)
|
|
|
|
.addImm(31).addImm(31);
|
|
|
|
} else {
|
|
|
|
BuildMI(*BB, MI, PPC::CNTLZW, 1, Temp1).addReg(Op0Reg);
|
|
|
|
BuildMI(*BB, MI, PPC::RLWINM, 4, DestReg).addReg(Temp1).addImm(27)
|
|
|
|
.addImm(5).addImm(31);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} // switch
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2005-04-10 01:03:31 +00:00
|
|
|
unsigned PPCOpcode = getPPCOpcodeForSetCCOpcode(Opcode);
|
2004-08-21 20:42:14 +00:00
|
|
|
|
|
|
|
// Create an iterator with which to insert the MBB for copying the false value
|
|
|
|
// and the MBB to hold the PHI instruction for this SetCC.
|
2004-07-01 21:34:10 +00:00
|
|
|
MachineBasicBlock *thisMBB = BB;
|
|
|
|
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
2004-07-20 00:41:46 +00:00
|
|
|
ilist<MachineBasicBlock>::iterator It = BB;
|
|
|
|
++It;
|
|
|
|
|
2004-07-01 21:34:10 +00:00
|
|
|
// thisMBB:
|
|
|
|
// ...
|
|
|
|
// cmpTY cr0, r1, r2
|
2004-08-21 20:42:14 +00:00
|
|
|
// %TrueValue = li 1
|
|
|
|
// bCC sinkMBB
|
2005-04-10 01:03:31 +00:00
|
|
|
EmitComparison(OpNum, Op0, Op1, BB, BB->end());
|
2004-08-21 20:42:14 +00:00
|
|
|
unsigned TrueValue = makeAnotherReg(I.getType());
|
|
|
|
BuildMI(BB, PPC::LI, 1, TrueValue).addSImm(1);
|
2004-07-01 21:34:10 +00:00
|
|
|
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
|
|
|
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
2004-08-21 20:42:14 +00:00
|
|
|
BuildMI(BB, PPCOpcode, 2).addReg(PPC::CR0).addMBB(sinkMBB);
|
|
|
|
F->getBasicBlockList().insert(It, copy0MBB);
|
2004-07-20 00:41:46 +00:00
|
|
|
F->getBasicBlockList().insert(It, sinkMBB);
|
2004-07-01 21:34:10 +00:00
|
|
|
// Update machine-CFG edges
|
2004-07-21 20:09:08 +00:00
|
|
|
BB->addSuccessor(copy0MBB);
|
2004-07-01 21:34:10 +00:00
|
|
|
BB->addSuccessor(sinkMBB);
|
|
|
|
|
2004-07-21 20:09:08 +00:00
|
|
|
// copy0MBB:
|
|
|
|
// %FalseValue = li 0
|
|
|
|
// fallthrough
|
|
|
|
BB = copy0MBB;
|
|
|
|
unsigned FalseValue = makeAnotherReg(I.getType());
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::LI, 1, FalseValue).addSImm(0);
|
2004-07-21 20:09:08 +00:00
|
|
|
// Update machine-CFG edges
|
|
|
|
BB->addSuccessor(sinkMBB);
|
|
|
|
|
2004-07-01 21:34:10 +00:00
|
|
|
// sinkMBB:
|
2004-08-21 20:42:14 +00:00
|
|
|
// %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
|
2004-07-01 21:34:10 +00:00
|
|
|
// ...
|
|
|
|
BB = sinkMBB;
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::PHI, 4, DestReg).addReg(FalseValue)
|
2004-08-21 20:42:14 +00:00
|
|
|
.addMBB(copy0MBB).addReg(TrueValue).addMBB(thisMBB);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitSelectInst(SelectInst &SI) {
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned DestReg = getReg(SI);
|
|
|
|
MachineBasicBlock::iterator MII = BB->end();
|
2004-06-21 20:22:03 +00:00
|
|
|
emitSelectOperation(BB, MII, SI.getCondition(), SI.getTrueValue(),
|
|
|
|
SI.getFalseValue(), DestReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// emitSelect - Common code shared between visitSelectInst and the constant
|
|
|
|
/// expression support.
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::emitSelectOperation(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
Value *Cond, Value *TrueVal,
|
|
|
|
Value *FalseVal, unsigned DestReg) {
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned SelectClass = getClassB(TrueVal->getType());
|
2004-07-20 00:41:46 +00:00
|
|
|
unsigned Opcode;
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-07-16 21:06:24 +00:00
|
|
|
// See if we can fold the setcc into the select instruction, or if we have
|
|
|
|
// to get the register of the Cond value
|
|
|
|
if (SetCondInst *SCI = canFoldSetCCIntoBranchOrSelect(Cond)) {
|
|
|
|
// We successfully folded the setcc into the select instruction.
|
|
|
|
unsigned OpNum = getSetCCNumber(SCI->getOpcode());
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
if (OpNum >= 2 && OpNum <= 5) {
|
|
|
|
unsigned SetCondClass = getClassB(SCI->getOperand(0)->getType());
|
|
|
|
if ((SetCondClass == cFP32 || SetCondClass == cFP64) &&
|
|
|
|
(SelectClass == cFP32 || SelectClass == cFP64)) {
|
|
|
|
unsigned CondReg = getReg(SCI->getOperand(0), MBB, IP);
|
|
|
|
unsigned TrueReg = getReg(TrueVal, MBB, IP);
|
|
|
|
unsigned FalseReg = getReg(FalseVal, MBB, IP);
|
|
|
|
// if the comparison of the floating point value used to for the select
|
|
|
|
// is against 0, then we can emit an fsel without subtraction.
|
|
|
|
ConstantFP *Op1C = dyn_cast<ConstantFP>(SCI->getOperand(1));
|
|
|
|
if (Op1C && (Op1C->isExactlyValue(-0.0) || Op1C->isExactlyValue(0.0))) {
|
|
|
|
switch(OpNum) {
|
|
|
|
case 2: // LT
|
|
|
|
BuildMI(*MBB, IP, PPC::FSEL, 3, DestReg).addReg(CondReg)
|
|
|
|
.addReg(FalseReg).addReg(TrueReg);
|
|
|
|
break;
|
|
|
|
case 3: // GE == !LT
|
|
|
|
BuildMI(*MBB, IP, PPC::FSEL, 3, DestReg).addReg(CondReg)
|
|
|
|
.addReg(TrueReg).addReg(FalseReg);
|
|
|
|
break;
|
|
|
|
case 4: { // GT
|
|
|
|
unsigned NegatedReg = makeAnotherReg(SCI->getOperand(0)->getType());
|
|
|
|
BuildMI(*MBB, IP, PPC::FNEG, 1, NegatedReg).addReg(CondReg);
|
|
|
|
BuildMI(*MBB, IP, PPC::FSEL, 3, DestReg).addReg(NegatedReg)
|
|
|
|
.addReg(FalseReg).addReg(TrueReg);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 5: { // LE == !GT
|
|
|
|
unsigned NegatedReg = makeAnotherReg(SCI->getOperand(0)->getType());
|
|
|
|
BuildMI(*MBB, IP, PPC::FNEG, 1, NegatedReg).addReg(CondReg);
|
|
|
|
BuildMI(*MBB, IP, PPC::FSEL, 3, DestReg).addReg(NegatedReg)
|
|
|
|
.addReg(TrueReg).addReg(FalseReg);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0 && "Invalid SetCC opcode to fsel");
|
|
|
|
abort();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unsigned OtherCondReg = getReg(SCI->getOperand(1), MBB, IP);
|
|
|
|
unsigned SelectReg = makeAnotherReg(SCI->getOperand(0)->getType());
|
|
|
|
switch(OpNum) {
|
|
|
|
case 2: // LT
|
|
|
|
BuildMI(*MBB, IP, PPC::FSUB, 2, SelectReg).addReg(CondReg)
|
|
|
|
.addReg(OtherCondReg);
|
|
|
|
BuildMI(*MBB, IP, PPC::FSEL, 3, DestReg).addReg(SelectReg)
|
|
|
|
.addReg(FalseReg).addReg(TrueReg);
|
|
|
|
break;
|
|
|
|
case 3: // GE == !LT
|
|
|
|
BuildMI(*MBB, IP, PPC::FSUB, 2, SelectReg).addReg(CondReg)
|
|
|
|
.addReg(OtherCondReg);
|
|
|
|
BuildMI(*MBB, IP, PPC::FSEL, 3, DestReg).addReg(SelectReg)
|
|
|
|
.addReg(TrueReg).addReg(FalseReg);
|
|
|
|
break;
|
|
|
|
case 4: // GT
|
|
|
|
BuildMI(*MBB, IP, PPC::FSUB, 2, SelectReg).addReg(OtherCondReg)
|
|
|
|
.addReg(CondReg);
|
|
|
|
BuildMI(*MBB, IP, PPC::FSEL, 3, DestReg).addReg(SelectReg)
|
|
|
|
.addReg(FalseReg).addReg(TrueReg);
|
|
|
|
break;
|
|
|
|
case 5: // LE == !GT
|
|
|
|
BuildMI(*MBB, IP, PPC::FSUB, 2, SelectReg).addReg(OtherCondReg)
|
|
|
|
.addReg(CondReg);
|
|
|
|
BuildMI(*MBB, IP, PPC::FSEL, 3, DestReg).addReg(SelectReg)
|
|
|
|
.addReg(TrueReg).addReg(FalseReg);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0 && "Invalid SetCC opcode to fsel");
|
|
|
|
abort();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2005-04-10 01:03:31 +00:00
|
|
|
EmitComparison(OpNum, SCI->getOperand(0),SCI->getOperand(1),MBB,IP);
|
|
|
|
Opcode = getPPCOpcodeForSetCCOpcode(SCI->getOpcode());
|
2004-07-16 21:06:24 +00:00
|
|
|
} else {
|
|
|
|
unsigned CondReg = getReg(Cond, MBB, IP);
|
2004-09-04 05:00:00 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::CMPWI, 2, PPC::CR0).addReg(CondReg).addSImm(0);
|
2005-04-10 01:03:31 +00:00
|
|
|
Opcode = getPPCOpcodeForSetCCOpcode(Instruction::SetNE);
|
2004-07-16 21:06:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MachineBasicBlock *thisMBB = BB;
|
|
|
|
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
2004-07-20 00:41:46 +00:00
|
|
|
ilist<MachineBasicBlock>::iterator It = BB;
|
|
|
|
++It;
|
2004-07-16 21:06:24 +00:00
|
|
|
|
2004-08-21 20:42:14 +00:00
|
|
|
// thisMBB:
|
|
|
|
// ...
|
Fix a FIXME: Select instructions on longs were miscompiled.
While we're at it, improve codegen of select instructions. For this
testcase:
int %test(bool %C, int %A, int %B) {
%D = select bool %C, int %A, int %B
ret int %D
}
We used to generate this code:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
b .LBB_test_3 ;
.LBB_test_2: ;
or r5, r4, r4
.LBB_test_3: ;
or r3, r5, r5
blr
Now we emit:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
or r4, r5, r5
.LBB_test_2: ;
or r3, r4, r4
blr
-Chris
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19214 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-01 16:10:12 +00:00
|
|
|
// TrueVal = ...
|
2004-08-21 20:42:14 +00:00
|
|
|
// cmpTY cr0, r1, r2
|
2004-09-29 05:00:31 +00:00
|
|
|
// bCC copy1MBB
|
|
|
|
// fallthrough --> copy0MBB
|
2004-07-16 21:06:24 +00:00
|
|
|
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
|
|
|
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
2005-01-02 23:07:31 +00:00
|
|
|
unsigned TrueValue = getReg(TrueVal);
|
Fix a FIXME: Select instructions on longs were miscompiled.
While we're at it, improve codegen of select instructions. For this
testcase:
int %test(bool %C, int %A, int %B) {
%D = select bool %C, int %A, int %B
ret int %D
}
We used to generate this code:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
b .LBB_test_3 ;
.LBB_test_2: ;
or r5, r4, r4
.LBB_test_3: ;
or r3, r5, r5
blr
Now we emit:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
or r4, r5, r5
.LBB_test_2: ;
or r3, r4, r4
blr
-Chris
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19214 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-01 16:10:12 +00:00
|
|
|
BuildMI(BB, Opcode, 2).addReg(PPC::CR0).addMBB(sinkMBB);
|
2004-08-21 20:42:14 +00:00
|
|
|
F->getBasicBlockList().insert(It, copy0MBB);
|
2004-07-20 00:41:46 +00:00
|
|
|
F->getBasicBlockList().insert(It, sinkMBB);
|
2004-07-16 21:06:24 +00:00
|
|
|
// Update machine-CFG edges
|
2004-07-21 20:09:08 +00:00
|
|
|
BB->addSuccessor(copy0MBB);
|
Fix a FIXME: Select instructions on longs were miscompiled.
While we're at it, improve codegen of select instructions. For this
testcase:
int %test(bool %C, int %A, int %B) {
%D = select bool %C, int %A, int %B
ret int %D
}
We used to generate this code:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
b .LBB_test_3 ;
.LBB_test_2: ;
or r5, r4, r4
.LBB_test_3: ;
or r3, r5, r5
blr
Now we emit:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
or r4, r5, r5
.LBB_test_2: ;
or r3, r4, r4
blr
-Chris
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19214 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-01 16:10:12 +00:00
|
|
|
BB->addSuccessor(sinkMBB);
|
2004-07-16 21:06:24 +00:00
|
|
|
|
2004-07-21 20:09:08 +00:00
|
|
|
// copy0MBB:
|
|
|
|
// %FalseValue = ...
|
Fix a FIXME: Select instructions on longs were miscompiled.
While we're at it, improve codegen of select instructions. For this
testcase:
int %test(bool %C, int %A, int %B) {
%D = select bool %C, int %A, int %B
ret int %D
}
We used to generate this code:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
b .LBB_test_3 ;
.LBB_test_2: ;
or r5, r4, r4
.LBB_test_3: ;
or r3, r5, r5
blr
Now we emit:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
or r4, r5, r5
.LBB_test_2: ;
or r3, r4, r4
blr
-Chris
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19214 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-01 16:10:12 +00:00
|
|
|
// # fallthrough to sinkMBB
|
2004-07-21 20:09:08 +00:00
|
|
|
BB = copy0MBB;
|
2005-01-02 23:07:31 +00:00
|
|
|
unsigned FalseValue = getReg(FalseVal);
|
2004-07-21 20:09:08 +00:00
|
|
|
// Update machine-CFG edges
|
|
|
|
BB->addSuccessor(sinkMBB);
|
|
|
|
|
2004-07-16 21:06:24 +00:00
|
|
|
// sinkMBB:
|
2004-08-21 20:42:14 +00:00
|
|
|
// %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
|
2004-07-16 21:06:24 +00:00
|
|
|
// ...
|
|
|
|
BB = sinkMBB;
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::PHI, 4, DestReg).addReg(FalseValue)
|
Fix a FIXME: Select instructions on longs were miscompiled.
While we're at it, improve codegen of select instructions. For this
testcase:
int %test(bool %C, int %A, int %B) {
%D = select bool %C, int %A, int %B
ret int %D
}
We used to generate this code:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
b .LBB_test_3 ;
.LBB_test_2: ;
or r5, r4, r4
.LBB_test_3: ;
or r3, r5, r5
blr
Now we emit:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
or r4, r5, r5
.LBB_test_2: ;
or r3, r4, r4
blr
-Chris
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19214 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-01 16:10:12 +00:00
|
|
|
.addMBB(copy0MBB).addReg(TrueValue).addMBB(thisMBB);
|
2004-08-21 20:42:14 +00:00
|
|
|
|
Fix a FIXME: Select instructions on longs were miscompiled.
While we're at it, improve codegen of select instructions. For this
testcase:
int %test(bool %C, int %A, int %B) {
%D = select bool %C, int %A, int %B
ret int %D
}
We used to generate this code:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
b .LBB_test_3 ;
.LBB_test_2: ;
or r5, r4, r4
.LBB_test_3: ;
or r3, r5, r5
blr
Now we emit:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
or r4, r5, r5
.LBB_test_2: ;
or r3, r4, r4
blr
-Chris
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19214 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-01 16:10:12 +00:00
|
|
|
// For a register pair representing a long value, define the top part.
|
2004-08-11 03:30:55 +00:00
|
|
|
if (getClassB(TrueVal->getType()) == cLong)
|
Fix a FIXME: Select instructions on longs were miscompiled.
While we're at it, improve codegen of select instructions. For this
testcase:
int %test(bool %C, int %A, int %B) {
%D = select bool %C, int %A, int %B
ret int %D
}
We used to generate this code:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
b .LBB_test_3 ;
.LBB_test_2: ;
or r5, r4, r4
.LBB_test_3: ;
or r3, r5, r5
blr
Now we emit:
_test:
cmpwi cr0, r3, 0
bne .LBB_test_2 ;
.LBB_test_1: ;
or r4, r5, r5
.LBB_test_2: ;
or r3, r4, r4
blr
-Chris
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19214 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-01 16:10:12 +00:00
|
|
|
BuildMI(BB, PPC::PHI, 4, DestReg+1).addReg(FalseValue+1)
|
|
|
|
.addMBB(copy0MBB).addReg(TrueValue+1).addMBB(thisMBB);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// promote32 - Emit instructions to turn a narrow operand into a 32-bit-wide
|
|
|
|
/// operand, in the specified target register.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::promote32(unsigned targetReg, const ValueRecord &VR) {
|
2004-06-21 16:55:25 +00:00
|
|
|
bool isUnsigned = VR.Ty->isUnsigned() || VR.Ty == Type::BoolTy;
|
|
|
|
|
|
|
|
Value *Val = VR.Val;
|
|
|
|
const Type *Ty = VR.Ty;
|
|
|
|
if (Val) {
|
|
|
|
if (Constant *C = dyn_cast<Constant>(Val)) {
|
|
|
|
Val = ConstantExpr::getCast(C, Type::IntTy);
|
2004-08-11 07:34:50 +00:00
|
|
|
if (isa<ConstantExpr>(Val)) // Could not fold
|
|
|
|
Val = C;
|
|
|
|
else
|
|
|
|
Ty = Type::IntTy; // Folded!
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
2004-06-21 20:22:03 +00:00
|
|
|
// If this is a simple constant, just emit a load directly to avoid the copy
|
2004-06-21 16:55:25 +00:00
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(Val)) {
|
2004-11-19 02:06:40 +00:00
|
|
|
copyConstantToRegister(BB, BB->end(), CI, targetReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure we have the register number for this value...
|
|
|
|
unsigned Reg = Val ? getReg(Val) : VR.Reg;
|
|
|
|
switch (getClassB(Ty)) {
|
|
|
|
case cByte:
|
|
|
|
// Extend value into target register (8->32)
|
2004-09-29 03:45:33 +00:00
|
|
|
if (Ty == Type::BoolTy)
|
|
|
|
BuildMI(BB, PPC::OR, 2, targetReg).addReg(Reg).addReg(Reg);
|
|
|
|
else if (isUnsigned)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::RLWINM, 4, targetReg).addReg(Reg).addZImm(0)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addZImm(24).addZImm(31);
|
2004-06-21 16:55:25 +00:00
|
|
|
else
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::EXTSB, 1, targetReg).addReg(Reg);
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
case cShort:
|
|
|
|
// Extend value into target register (16->32)
|
|
|
|
if (isUnsigned)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::RLWINM, 4, targetReg).addReg(Reg).addZImm(0)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addZImm(16).addZImm(31);
|
2004-06-21 16:55:25 +00:00
|
|
|
else
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::EXTSH, 1, targetReg).addReg(Reg);
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
case cInt:
|
|
|
|
// Move value into target register (32->32)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, targetReg).addReg(Reg).addReg(Reg);
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0 && "Unpromotable operand class in promote32");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-21 20:22:03 +00:00
|
|
|
/// visitReturnInst - implemented with BLR
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitReturnInst(ReturnInst &I) {
|
2004-06-25 19:04:27 +00:00
|
|
|
// Only do the processing if this is a non-void return
|
|
|
|
if (I.getNumOperands() > 0) {
|
|
|
|
Value *RetVal = I.getOperand(0);
|
|
|
|
switch (getClassB(RetVal->getType())) {
|
|
|
|
case cByte: // integral return values: extend or move into r3 and return
|
|
|
|
case cShort:
|
|
|
|
case cInt:
|
2004-08-10 22:47:03 +00:00
|
|
|
promote32(PPC::R3, ValueRecord(RetVal));
|
2004-06-25 19:04:27 +00:00
|
|
|
break;
|
2004-07-20 00:41:46 +00:00
|
|
|
case cFP32:
|
|
|
|
case cFP64: { // Floats & Doubles: Return in f1
|
2004-06-25 19:04:27 +00:00
|
|
|
unsigned RetReg = getReg(RetVal);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::FMR, 1, PPC::F1).addReg(RetReg);
|
2004-06-25 19:04:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case cLong: {
|
|
|
|
unsigned RetReg = getReg(RetVal);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, PPC::R3).addReg(RetReg).addReg(RetReg);
|
|
|
|
BuildMI(BB, PPC::OR, 2, PPC::R4).addReg(RetReg+1).addReg(RetReg+1);
|
2004-06-25 19:04:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
visitInstruction(I);
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::BLR, 1).addImm(0);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// getBlockAfter - Return the basic block which occurs lexically after the
|
|
|
|
// specified one.
|
|
|
|
static inline BasicBlock *getBlockAfter(BasicBlock *BB) {
|
|
|
|
Function::iterator I = BB; ++I; // Get iterator to next block
|
|
|
|
return I != BB->getParent()->end() ? &*I : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// visitBranchInst - Handle conditional and unconditional branches here. Note
|
|
|
|
/// that since code layout is frozen at this point, that if we are trying to
|
|
|
|
/// jump to a block that is the immediate successor of the current block, we can
|
|
|
|
/// just make a fall-through (but we don't currently).
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitBranchInst(BranchInst &BI) {
|
2004-06-21 20:22:03 +00:00
|
|
|
// Update machine-CFG edges
|
2004-07-23 16:08:20 +00:00
|
|
|
BB->addSuccessor(MBBMap[BI.getSuccessor(0)]);
|
2004-06-21 20:22:03 +00:00
|
|
|
if (BI.isConditional())
|
2004-07-23 16:08:20 +00:00
|
|
|
BB->addSuccessor(MBBMap[BI.getSuccessor(1)]);
|
2004-06-21 20:22:03 +00:00
|
|
|
|
|
|
|
BasicBlock *NextBB = getBlockAfter(BI.getParent()); // BB after current one
|
2004-07-06 15:32:44 +00:00
|
|
|
|
2004-06-21 20:22:03 +00:00
|
|
|
if (!BI.isConditional()) { // Unconditional branch?
|
2004-07-06 15:32:44 +00:00
|
|
|
if (BI.getSuccessor(0) != NextBB)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::B, 1).addMBB(MBBMap[BI.getSuccessor(0)]);
|
2004-06-24 22:00:15 +00:00
|
|
|
return;
|
2004-06-21 20:22:03 +00:00
|
|
|
}
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
// See if we can fold the setcc into the branch itself...
|
|
|
|
SetCondInst *SCI = canFoldSetCCIntoBranchOrSelect(BI.getCondition());
|
|
|
|
if (SCI == 0) {
|
|
|
|
// Nope, cannot fold setcc into this branch. Emit a branch on a condition
|
|
|
|
// computed some other way...
|
|
|
|
unsigned condReg = getReg(BI.getCondition());
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::CMPLI, 3, PPC::CR0).addImm(0).addReg(condReg)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addImm(0);
|
2004-06-21 16:55:25 +00:00
|
|
|
if (BI.getSuccessor(1) == NextBB) {
|
|
|
|
if (BI.getSuccessor(0) != NextBB)
|
2005-04-05 04:22:58 +00:00
|
|
|
BuildMI(BB, PPC::COND_BRANCH, 4).addReg(PPC::CR0).addImm(PPC::BNE)
|
2004-07-27 18:35:23 +00:00
|
|
|
.addMBB(MBBMap[BI.getSuccessor(0)])
|
|
|
|
.addMBB(MBBMap[BI.getSuccessor(1)]);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
2005-04-05 04:22:58 +00:00
|
|
|
BuildMI(BB, PPC::COND_BRANCH, 4).addReg(PPC::CR0).addImm(PPC::BEQ)
|
2004-07-27 18:35:23 +00:00
|
|
|
.addMBB(MBBMap[BI.getSuccessor(1)])
|
|
|
|
.addMBB(MBBMap[BI.getSuccessor(0)]);
|
2004-06-21 16:55:25 +00:00
|
|
|
if (BI.getSuccessor(0) != NextBB)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::B, 1).addMBB(MBBMap[BI.getSuccessor(0)]);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned OpNum = getSetCCNumber(SCI->getOpcode());
|
2005-04-10 01:03:31 +00:00
|
|
|
unsigned Opcode = getPPCOpcodeForSetCCOpcode(SCI->getOpcode());
|
2004-06-21 16:55:25 +00:00
|
|
|
MachineBasicBlock::iterator MII = BB->end();
|
2005-04-10 01:03:31 +00:00
|
|
|
EmitComparison(OpNum, SCI->getOperand(0), SCI->getOperand(1), BB,MII);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
if (BI.getSuccessor(0) != NextBB) {
|
2005-04-05 04:22:58 +00:00
|
|
|
BuildMI(BB, PPC::COND_BRANCH, 4).addReg(PPC::CR0).addImm(Opcode)
|
2004-07-27 18:35:23 +00:00
|
|
|
.addMBB(MBBMap[BI.getSuccessor(0)])
|
|
|
|
.addMBB(MBBMap[BI.getSuccessor(1)]);
|
2004-06-21 16:55:25 +00:00
|
|
|
if (BI.getSuccessor(1) != NextBB)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::B, 1).addMBB(MBBMap[BI.getSuccessor(1)]);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
|
|
|
// Change to the inverse condition...
|
|
|
|
if (BI.getSuccessor(1) != NextBB) {
|
2004-08-17 04:55:41 +00:00
|
|
|
Opcode = PPC32InstrInfo::invertPPCBranchOpcode(Opcode);
|
2005-04-05 04:22:58 +00:00
|
|
|
BuildMI(BB, PPC::COND_BRANCH, 4).addReg(PPC::CR0).addImm(Opcode)
|
2004-07-27 18:35:23 +00:00
|
|
|
.addMBB(MBBMap[BI.getSuccessor(1)])
|
|
|
|
.addMBB(MBBMap[BI.getSuccessor(0)]);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// doCall - This emits an abstract call instruction, setting up the arguments
|
|
|
|
/// and the return value as appropriate. For the actual function call itself,
|
|
|
|
/// it inserts the specified CallMI instruction into the stream.
|
|
|
|
///
|
|
|
|
/// FIXME: See Documentation at the following URL for "correct" behavior
|
2005-03-26 01:28:05 +00:00
|
|
|
/// <http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/PowerPCConventions/chapter_3_section_5.html>
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::doCall(const ValueRecord &Ret, MachineInstr *CallMI,
|
|
|
|
const std::vector<ValueRecord> &Args, bool isVarArg) {
|
2004-08-06 06:58:50 +00:00
|
|
|
// Count how many bytes are to be pushed on the stack, including the linkage
|
|
|
|
// area, and parameter passing area.
|
|
|
|
unsigned NumBytes = 24;
|
|
|
|
unsigned ArgOffset = 24;
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
if (!Args.empty()) {
|
|
|
|
for (unsigned i = 0, e = Args.size(); i != e; ++i)
|
|
|
|
switch (getClassB(Args[i].Ty)) {
|
|
|
|
case cByte: case cShort: case cInt:
|
|
|
|
NumBytes += 4; break;
|
|
|
|
case cLong:
|
|
|
|
NumBytes += 8; break;
|
2004-07-20 00:41:46 +00:00
|
|
|
case cFP32:
|
|
|
|
NumBytes += 4; break;
|
|
|
|
case cFP64:
|
|
|
|
NumBytes += 8; break;
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
default: assert(0 && "Unknown class!");
|
|
|
|
}
|
|
|
|
|
2004-08-16 01:50:22 +00:00
|
|
|
// Just to be safe, we'll always reserve the full 24 bytes of linkage area
|
|
|
|
// plus 32 bytes of argument space in case any called code gets funky on us.
|
|
|
|
if (NumBytes < 56) NumBytes = 56;
|
2004-08-06 06:58:50 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
// Adjust the stack pointer for the new arguments...
|
2005-03-26 01:28:05 +00:00
|
|
|
// These operations are automatically eliminated by the prolog/epilog pass
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::ADJCALLSTACKDOWN, 1).addImm(NumBytes);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
// Arguments go on the stack in reverse order, as specified by the ABI.
|
2004-07-20 00:41:46 +00:00
|
|
|
// Offset to the paramater area on the stack is 24.
|
2004-07-06 22:51:53 +00:00
|
|
|
int GPR_remaining = 8, FPR_remaining = 13;
|
2004-07-08 18:02:38 +00:00
|
|
|
unsigned GPR_idx = 0, FPR_idx = 0;
|
2004-07-06 22:51:53 +00:00
|
|
|
static const unsigned GPR[] = {
|
2004-08-10 22:47:03 +00:00
|
|
|
PPC::R3, PPC::R4, PPC::R5, PPC::R6,
|
|
|
|
PPC::R7, PPC::R8, PPC::R9, PPC::R10,
|
2004-06-29 23:45:05 +00:00
|
|
|
};
|
2004-07-06 22:51:53 +00:00
|
|
|
static const unsigned FPR[] = {
|
2004-08-10 22:47:03 +00:00
|
|
|
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
|
2004-06-29 23:45:05 +00:00
|
|
|
};
|
2004-06-21 17:41:12 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
for (unsigned i = 0, e = Args.size(); i != e; ++i) {
|
|
|
|
unsigned ArgReg;
|
|
|
|
switch (getClassB(Args[i].Ty)) {
|
|
|
|
case cByte:
|
|
|
|
case cShort:
|
|
|
|
// Promote arg to 32 bits wide into a temporary register...
|
|
|
|
ArgReg = makeAnotherReg(Type::UIntTy);
|
|
|
|
promote32(ArgReg, Args[i]);
|
2004-06-21 17:41:12 +00:00
|
|
|
|
|
|
|
// Reg or stack?
|
|
|
|
if (GPR_remaining > 0) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, GPR[GPR_idx]).addReg(ArgReg)
|
2004-06-24 22:00:15 +00:00
|
|
|
.addReg(ArgReg);
|
2004-07-20 00:41:46 +00:00
|
|
|
CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use);
|
2004-07-26 18:13:24 +00:00
|
|
|
}
|
|
|
|
if (GPR_remaining <= 0 || isVarArg) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::STW, 3).addReg(ArgReg).addSImm(ArgOffset)
|
|
|
|
.addReg(PPC::R1);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
|
|
|
break;
|
2004-06-21 16:55:25 +00:00
|
|
|
case cInt:
|
|
|
|
ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg;
|
|
|
|
|
2004-06-21 17:41:12 +00:00
|
|
|
// Reg or stack?
|
|
|
|
if (GPR_remaining > 0) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, GPR[GPR_idx]).addReg(ArgReg)
|
2004-06-24 22:00:15 +00:00
|
|
|
.addReg(ArgReg);
|
2004-07-20 00:41:46 +00:00
|
|
|
CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use);
|
2004-07-26 18:13:24 +00:00
|
|
|
}
|
|
|
|
if (GPR_remaining <= 0 || isVarArg) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::STW, 3).addReg(ArgReg).addSImm(ArgOffset)
|
|
|
|
.addReg(PPC::R1);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
|
|
|
break;
|
2004-06-21 16:55:25 +00:00
|
|
|
case cLong:
|
2004-06-21 17:41:12 +00:00
|
|
|
ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg;
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-07-20 15:51:37 +00:00
|
|
|
// Reg or stack? Note that PPC calling conventions state that long args
|
|
|
|
// are passed rN = hi, rN+1 = lo, opposite of LLVM.
|
2004-06-21 17:41:12 +00:00
|
|
|
if (GPR_remaining > 1) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, GPR[GPR_idx]).addReg(ArgReg)
|
2004-07-20 15:51:37 +00:00
|
|
|
.addReg(ArgReg);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, GPR[GPR_idx+1]).addReg(ArgReg+1)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addReg(ArgReg+1);
|
2004-07-20 00:41:46 +00:00
|
|
|
CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use);
|
|
|
|
CallMI->addRegOperand(GPR[GPR_idx+1], MachineOperand::Use);
|
2004-07-26 18:13:24 +00:00
|
|
|
}
|
|
|
|
if (GPR_remaining <= 1 || isVarArg) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::STW, 3).addReg(ArgReg).addSImm(ArgOffset)
|
|
|
|
.addReg(PPC::R1);
|
|
|
|
BuildMI(BB, PPC::STW, 3).addReg(ArgReg+1).addSImm(ArgOffset+4)
|
|
|
|
.addReg(PPC::R1);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
ArgOffset += 4; // 8 byte entry, not 4.
|
2004-06-29 23:45:05 +00:00
|
|
|
GPR_remaining -= 1; // uses up 2 GPRs
|
|
|
|
GPR_idx += 1;
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
2004-07-20 00:41:46 +00:00
|
|
|
case cFP32:
|
2004-06-21 16:55:25 +00:00
|
|
|
ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg;
|
2004-07-20 00:41:46 +00:00
|
|
|
// Reg or stack?
|
|
|
|
if (FPR_remaining > 0) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::FMR, 1, FPR[FPR_idx]).addReg(ArgReg);
|
2004-07-20 00:41:46 +00:00
|
|
|
CallMI->addRegOperand(FPR[FPR_idx], MachineOperand::Use);
|
|
|
|
FPR_remaining--;
|
|
|
|
FPR_idx++;
|
|
|
|
|
|
|
|
// If this is a vararg function, and there are GPRs left, also
|
|
|
|
// pass the float in an int. Otherwise, put it on the stack.
|
|
|
|
if (isVarArg) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::STFS, 3).addReg(ArgReg).addSImm(ArgOffset)
|
|
|
|
.addReg(PPC::R1);
|
2004-07-20 00:41:46 +00:00
|
|
|
if (GPR_remaining > 0) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::LWZ, 2, GPR[GPR_idx])
|
2004-08-13 04:45:14 +00:00
|
|
|
.addSImm(ArgOffset).addReg(PPC::R1);
|
2004-07-20 00:41:46 +00:00
|
|
|
CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use);
|
|
|
|
}
|
2004-06-24 21:56:15 +00:00
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::STFS, 3).addReg(ArgReg).addSImm(ArgOffset)
|
|
|
|
.addReg(PPC::R1);
|
2004-07-20 00:41:46 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case cFP64:
|
|
|
|
ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg;
|
|
|
|
// Reg or stack?
|
|
|
|
if (FPR_remaining > 0) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::FMR, 1, FPR[FPR_idx]).addReg(ArgReg);
|
2004-07-20 00:41:46 +00:00
|
|
|
CallMI->addRegOperand(FPR[FPR_idx], MachineOperand::Use);
|
|
|
|
FPR_remaining--;
|
|
|
|
FPR_idx++;
|
|
|
|
// For vararg functions, must pass doubles via int regs as well
|
|
|
|
if (isVarArg) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::STFD, 3).addReg(ArgReg).addSImm(ArgOffset)
|
|
|
|
.addReg(PPC::R1);
|
2004-07-20 00:41:46 +00:00
|
|
|
|
2004-07-22 15:58:04 +00:00
|
|
|
// Doubles can be split across reg + stack for varargs
|
|
|
|
if (GPR_remaining > 0) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::LWZ, 2, GPR[GPR_idx]).addSImm(ArgOffset)
|
|
|
|
.addReg(PPC::R1);
|
2004-07-22 15:58:04 +00:00
|
|
|
CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use);
|
|
|
|
}
|
|
|
|
if (GPR_remaining > 1) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::LWZ, 2, GPR[GPR_idx+1])
|
|
|
|
.addSImm(ArgOffset+4).addReg(PPC::R1);
|
2004-07-20 00:41:46 +00:00
|
|
|
CallMI->addRegOperand(GPR[GPR_idx+1], MachineOperand::Use);
|
|
|
|
}
|
2004-06-24 21:56:15 +00:00
|
|
|
}
|
2004-07-20 00:41:46 +00:00
|
|
|
} else {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::STFD, 3).addReg(ArgReg).addSImm(ArgOffset)
|
|
|
|
.addReg(PPC::R1);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
2004-07-20 00:41:46 +00:00
|
|
|
// Doubles use 8 bytes, and 2 GPRs worth of param space
|
|
|
|
ArgOffset += 4;
|
|
|
|
GPR_remaining--;
|
|
|
|
GPR_idx++;
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
2004-07-20 00:41:46 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
default: assert(0 && "Unknown class!");
|
|
|
|
}
|
|
|
|
ArgOffset += 4;
|
2004-06-29 23:45:05 +00:00
|
|
|
GPR_remaining--;
|
|
|
|
GPR_idx++;
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
} else {
|
2004-08-16 01:50:22 +00:00
|
|
|
BuildMI(BB, PPC::ADJCALLSTACKDOWN, 1).addImm(NumBytes);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
2004-08-15 06:42:28 +00:00
|
|
|
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::IMPLICIT_DEF, 0, PPC::LR);
|
2004-06-21 16:55:25 +00:00
|
|
|
BB->push_back(CallMI);
|
2004-08-06 06:58:50 +00:00
|
|
|
|
|
|
|
// These functions are automatically eliminated by the prolog/epilog pass
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::ADJCALLSTACKUP, 1).addImm(NumBytes);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
// If there is a return value, scavenge the result from the location the call
|
|
|
|
// leaves it in...
|
|
|
|
//
|
|
|
|
if (Ret.Ty != Type::VoidTy) {
|
|
|
|
unsigned DestClass = getClassB(Ret.Ty);
|
|
|
|
switch (DestClass) {
|
|
|
|
case cByte:
|
|
|
|
case cShort:
|
|
|
|
case cInt:
|
|
|
|
// Integral results are in r3
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, Ret.Reg).addReg(PPC::R3).addReg(PPC::R3);
|
2004-06-24 23:53:24 +00:00
|
|
|
break;
|
2004-08-06 06:58:50 +00:00
|
|
|
case cFP32: // Floating-point return values live in f1
|
2004-07-20 00:41:46 +00:00
|
|
|
case cFP64:
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::FMR, 1, Ret.Reg).addReg(PPC::F1);
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
2004-08-06 06:58:50 +00:00
|
|
|
case cLong: // Long values are in r3:r4
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, Ret.Reg).addReg(PPC::R3).addReg(PPC::R3);
|
|
|
|
BuildMI(BB, PPC::OR, 2, Ret.Reg+1).addReg(PPC::R4).addReg(PPC::R4);
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
default: assert(0 && "Unknown class!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// visitCallInst - Push args on stack and do a procedure call instruction.
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitCallInst(CallInst &CI) {
|
2004-06-21 16:55:25 +00:00
|
|
|
MachineInstr *TheCall;
|
2004-07-06 22:51:53 +00:00
|
|
|
Function *F = CI.getCalledFunction();
|
|
|
|
if (F) {
|
2004-06-21 16:55:25 +00:00
|
|
|
// Is it an intrinsic function call?
|
|
|
|
if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) {
|
|
|
|
visitIntrinsicCall(ID, CI); // Special intrinsics are not handled here
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Emit a CALL instruction with PC-relative displacement.
|
2004-08-10 22:47:03 +00:00
|
|
|
TheCall = BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(F, true);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else { // Emit an indirect call through the CTR
|
|
|
|
unsigned Reg = getReg(CI.getCalledValue());
|
2004-08-15 06:42:28 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, PPC::R12).addReg(Reg).addReg(Reg);
|
|
|
|
BuildMI(BB, PPC::MTCTR, 1).addReg(PPC::R12);
|
2005-03-24 23:34:38 +00:00
|
|
|
TheCall = BuildMI(PPC::CALLindirect, 3).addZImm(20).addZImm(0)
|
2004-08-15 06:42:28 +00:00
|
|
|
.addReg(PPC::R12);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<ValueRecord> Args;
|
|
|
|
for (unsigned i = 1, e = CI.getNumOperands(); i != e; ++i)
|
|
|
|
Args.push_back(ValueRecord(CI.getOperand(i)));
|
|
|
|
|
|
|
|
unsigned DestReg = CI.getType() != Type::VoidTy ? getReg(CI) : 0;
|
2004-07-06 22:51:53 +00:00
|
|
|
bool isVarArg = F ? F->getFunctionType()->isVarArg() : true;
|
|
|
|
doCall(ValueRecord(DestReg, CI.getType()), TheCall, Args, isVarArg);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// dyncastIsNan - Return the operand of an isnan operation if this is an isnan.
|
|
|
|
///
|
|
|
|
static Value *dyncastIsNan(Value *V) {
|
|
|
|
if (CallInst *CI = dyn_cast<CallInst>(V))
|
|
|
|
if (Function *F = CI->getCalledFunction())
|
2004-06-21 17:58:36 +00:00
|
|
|
if (F->getIntrinsicID() == Intrinsic::isunordered)
|
2004-06-21 16:55:25 +00:00
|
|
|
return CI->getOperand(1);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isOnlyUsedByUnorderedComparisons - Return true if this value is only used by
|
|
|
|
/// or's whos operands are all calls to the isnan predicate.
|
|
|
|
static bool isOnlyUsedByUnorderedComparisons(Value *V) {
|
|
|
|
assert(dyncastIsNan(V) && "The value isn't an isnan call!");
|
|
|
|
|
|
|
|
// Check all uses, which will be or's of isnans if this predicate is true.
|
|
|
|
for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI){
|
|
|
|
Instruction *I = cast<Instruction>(*UI);
|
|
|
|
if (I->getOpcode() != Instruction::Or) return false;
|
|
|
|
if (I->getOperand(0) != V && !dyncastIsNan(I->getOperand(0))) return false;
|
|
|
|
if (I->getOperand(1) != V && !dyncastIsNan(I->getOperand(1))) return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// LowerUnknownIntrinsicFunctionCalls - This performs a prepass over the
|
|
|
|
/// function, lowering any calls to unknown intrinsic functions into the
|
|
|
|
/// equivalent LLVM code.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::LowerUnknownIntrinsicFunctionCalls(Function &F) {
|
2004-06-21 16:55:25 +00:00
|
|
|
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
|
|
|
|
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; )
|
|
|
|
if (CallInst *CI = dyn_cast<CallInst>(I++))
|
|
|
|
if (Function *F = CI->getCalledFunction())
|
|
|
|
switch (F->getIntrinsicID()) {
|
|
|
|
case Intrinsic::not_intrinsic:
|
|
|
|
case Intrinsic::vastart:
|
|
|
|
case Intrinsic::vacopy:
|
|
|
|
case Intrinsic::vaend:
|
|
|
|
case Intrinsic::returnaddress:
|
|
|
|
case Intrinsic::frameaddress:
|
2004-07-26 18:13:24 +00:00
|
|
|
// FIXME: should lower these ourselves
|
2004-06-21 17:58:36 +00:00
|
|
|
// case Intrinsic::isunordered:
|
2004-07-26 18:13:24 +00:00
|
|
|
// case Intrinsic::memcpy: -> doCall(). system memcpy almost
|
|
|
|
// guaranteed to be faster than anything we generate ourselves
|
2004-06-21 16:55:25 +00:00
|
|
|
// We directly implement these intrinsics
|
|
|
|
break;
|
|
|
|
case Intrinsic::readio: {
|
|
|
|
// On PPC, memory operations are in-order. Lower this intrinsic
|
|
|
|
// into a volatile load.
|
|
|
|
LoadInst * LI = new LoadInst(CI->getOperand(1), "", true, CI);
|
|
|
|
CI->replaceAllUsesWith(LI);
|
|
|
|
BB->getInstList().erase(CI);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Intrinsic::writeio: {
|
|
|
|
// On PPC, memory operations are in-order. Lower this intrinsic
|
|
|
|
// into a volatile store.
|
2004-07-14 15:29:51 +00:00
|
|
|
StoreInst *SI = new StoreInst(CI->getOperand(1),
|
2004-06-21 16:55:25 +00:00
|
|
|
CI->getOperand(2), true, CI);
|
2004-07-14 15:29:51 +00:00
|
|
|
CI->replaceAllUsesWith(SI);
|
2004-06-21 16:55:25 +00:00
|
|
|
BB->getInstList().erase(CI);
|
|
|
|
break;
|
|
|
|
}
|
2005-03-24 20:07:16 +00:00
|
|
|
default: {
|
2004-06-21 16:55:25 +00:00
|
|
|
// All other intrinsic calls we must lower.
|
2005-03-24 20:07:16 +00:00
|
|
|
BasicBlock::iterator me(CI);
|
|
|
|
bool atBegin(BB->begin() == me);
|
|
|
|
if (!atBegin)
|
|
|
|
--me;
|
2004-06-21 16:55:25 +00:00
|
|
|
TM.getIntrinsicLowering().LowerIntrinsicCall(CI);
|
2005-03-24 20:07:16 +00:00
|
|
|
// Move iterator to instruction after call
|
|
|
|
I = atBegin ? BB->begin() : ++me;
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI) {
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned TmpReg1, TmpReg2, TmpReg3;
|
|
|
|
switch (ID) {
|
|
|
|
case Intrinsic::vastart:
|
|
|
|
// Get the address of the first vararg value...
|
|
|
|
TmpReg1 = getReg(CI);
|
2004-08-10 22:47:03 +00:00
|
|
|
addFrameReference(BuildMI(BB, PPC::ADDI, 2, TmpReg1), VarArgsFrameIndex,
|
2004-07-20 15:51:37 +00:00
|
|
|
0, false);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
case Intrinsic::vacopy:
|
|
|
|
TmpReg1 = getReg(CI);
|
|
|
|
TmpReg2 = getReg(CI.getOperand(1));
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, TmpReg1).addReg(TmpReg2).addReg(TmpReg2);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
case Intrinsic::vaend: return;
|
|
|
|
|
|
|
|
case Intrinsic::returnaddress:
|
2004-07-20 15:51:37 +00:00
|
|
|
TmpReg1 = getReg(CI);
|
|
|
|
if (cast<Constant>(CI.getOperand(1))->isNullValue()) {
|
|
|
|
MachineFrameInfo *MFI = F->getFrameInfo();
|
|
|
|
unsigned NumBytes = MFI->getStackSize();
|
|
|
|
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::LWZ, 2, TmpReg1).addSImm(NumBytes+8)
|
|
|
|
.addReg(PPC::R1);
|
2004-07-20 15:51:37 +00:00
|
|
|
} else {
|
|
|
|
// Values other than zero are not implemented yet.
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::LI, 1, TmpReg1).addSImm(0);
|
2004-07-20 15:51:37 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
case Intrinsic::frameaddress:
|
|
|
|
TmpReg1 = getReg(CI);
|
|
|
|
if (cast<Constant>(CI.getOperand(1))->isNullValue()) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, TmpReg1).addReg(PPC::R1).addReg(PPC::R1);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
|
|
|
// Values other than zero are not implemented yet.
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::LI, 1, TmpReg1).addSImm(0);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
return;
|
2004-07-26 18:13:24 +00:00
|
|
|
|
2004-06-21 17:58:36 +00:00
|
|
|
#if 0
|
|
|
|
// This may be useful for supporting isunordered
|
2004-06-21 16:55:25 +00:00
|
|
|
case Intrinsic::isnan:
|
|
|
|
// If this is only used by 'isunordered' style comparisons, don't emit it.
|
|
|
|
if (isOnlyUsedByUnorderedComparisons(&CI)) return;
|
|
|
|
TmpReg1 = getReg(CI.getOperand(1));
|
|
|
|
emitUCOM(BB, BB->end(), TmpReg1, TmpReg1);
|
2004-06-21 17:41:12 +00:00
|
|
|
TmpReg2 = makeAnotherReg(Type::IntTy);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::MFCR, TmpReg2);
|
2004-06-21 16:55:25 +00:00
|
|
|
TmpReg3 = getReg(CI);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::RLWINM, 4, TmpReg3).addReg(TmpReg2).addImm(4).addImm(31).addImm(31);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
2004-06-21 17:58:36 +00:00
|
|
|
#endif
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
default: assert(0 && "Error: unknown intrinsics should have been lowered!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// visitSimpleBinary - Implement simple binary operators for integral types...
|
|
|
|
/// OperatorClass is one of: 0 for Add, 1 for Sub, 2 for And, 3 for Or, 4 for
|
|
|
|
/// Xor.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitSimpleBinary(BinaryOperator &B, unsigned OperatorClass) {
|
2004-10-24 10:33:30 +00:00
|
|
|
if (std::find(SkipList.begin(), SkipList.end(), &B) != SkipList.end())
|
|
|
|
return;
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned DestReg = getReg(B);
|
|
|
|
MachineBasicBlock::iterator MI = BB->end();
|
2004-10-24 10:33:30 +00:00
|
|
|
RlwimiRec RR = InsertMap[&B];
|
|
|
|
if (RR.Target != 0) {
|
|
|
|
unsigned TargetReg = getReg(RR.Target, BB, MI);
|
|
|
|
unsigned InsertReg = getReg(RR.Insert, BB, MI);
|
|
|
|
BuildMI(*BB, MI, PPC::RLWIMI, 5, DestReg).addReg(TargetReg)
|
|
|
|
.addReg(InsertReg).addImm(RR.Shift).addImm(RR.MB).addImm(RR.ME);
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-10-24 10:33:30 +00:00
|
|
|
|
|
|
|
unsigned Class = getClassB(B.getType());
|
|
|
|
Value *Op0 = B.getOperand(0), *Op1 = B.getOperand(1);
|
|
|
|
emitSimpleBinaryOperation(BB, MI, &B, Op0, Op1, OperatorClass, DestReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// emitBinaryFPOperation - This method handles emission of floating point
|
|
|
|
/// Add (0), Sub (1), Mul (2), and Div (3) operations.
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::emitBinaryFPOperation(MachineBasicBlock *BB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
Value *Op0, Value *Op1,
|
|
|
|
unsigned OperatorClass, unsigned DestReg){
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-08-14 22:11:38 +00:00
|
|
|
static const unsigned OpcodeTab[][4] = {
|
|
|
|
{ PPC::FADDS, PPC::FSUBS, PPC::FMULS, PPC::FDIVS }, // Float
|
|
|
|
{ PPC::FADD, PPC::FSUB, PPC::FMUL, PPC::FDIV }, // Double
|
|
|
|
};
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
// Special case: R1 = op <const fp>, R2
|
2004-07-13 15:35:45 +00:00
|
|
|
if (ConstantFP *Op0C = dyn_cast<ConstantFP>(Op0))
|
|
|
|
if (Op0C->isExactlyValue(-0.0) && OperatorClass == 1) {
|
2004-06-21 16:55:25 +00:00
|
|
|
// -0.0 - X === -X
|
|
|
|
unsigned op1Reg = getReg(Op1, BB, IP);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*BB, IP, PPC::FNEG, 1, DestReg).addReg(op1Reg);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-08-19 05:20:54 +00:00
|
|
|
unsigned Opcode = OpcodeTab[Op0->getType() == Type::DoubleTy][OperatorClass];
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned Op0r = getReg(Op0, BB, IP);
|
|
|
|
unsigned Op1r = getReg(Op1, BB, IP);
|
|
|
|
BuildMI(*BB, IP, Opcode, 2, DestReg).addReg(Op0r).addReg(Op1r);
|
|
|
|
}
|
|
|
|
|
2004-10-07 22:30:03 +00:00
|
|
|
// ExactLog2 - This function solves for (Val == 1 << (N-1)) and returns N. It
|
|
|
|
// returns zero when the input is not exactly a power of two.
|
|
|
|
static unsigned ExactLog2(unsigned Val) {
|
|
|
|
if (Val == 0 || (Val & (Val-1))) return 0;
|
|
|
|
unsigned Count = 0;
|
|
|
|
while (Val != 1) {
|
|
|
|
Val >>= 1;
|
|
|
|
++Count;
|
|
|
|
}
|
|
|
|
return Count;
|
|
|
|
}
|
|
|
|
|
Implement logical and with an immediate that consists of a contiguous block
of one or more 1 bits (may wrap from least significant bit to most
significant bit) as the rlwinm rather than andi., andis., or some longer
instructons sequence.
int andn4(int z) { return z & -4; }
int clearhi(int z) { return z & 0x0000FFFF; }
int clearlo(int z) { return z & 0xFFFF0000; }
int clearmid(int z) { return z & 0x00FFFF00; }
int clearwrap(int z) { return z & 0xFF0000FF; }
_andn4:
rlwinm r3, r3, 0, 0, 29
blr
_clearhi:
rlwinm r3, r3, 0, 16, 31
blr
_clearlo:
rlwinm r3, r3, 0, 0, 15
blr
_clearmid:
rlwinm r3, r3, 0, 8, 23
blr
_clearwrap:
rlwinm r3, r3, 0, 24, 7
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16832 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-08 02:49:24 +00:00
|
|
|
// isRunOfOnes - returns true if Val consists of one contiguous run of 1's with
|
|
|
|
// any number of 0's on either side. the 1's are allowed to wrap from LSB to
|
|
|
|
// MSB. so 0x000FFF0, 0x0000FFFF, and 0xFF0000FF are all runs. 0x0F0F0000 is
|
|
|
|
// not, since all 1's are not contiguous.
|
|
|
|
static bool isRunOfOnes(unsigned Val, unsigned &MB, unsigned &ME) {
|
|
|
|
bool isRun = true;
|
|
|
|
MB = 0;
|
|
|
|
ME = 0;
|
|
|
|
|
|
|
|
// look for first set bit
|
|
|
|
int i = 0;
|
|
|
|
for (; i < 32; i++) {
|
|
|
|
if ((Val & (1 << (31 - i))) != 0) {
|
|
|
|
MB = i;
|
|
|
|
ME = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// look for last set bit
|
|
|
|
for (; i < 32; i++) {
|
|
|
|
if ((Val & (1 << (31 - i))) == 0)
|
|
|
|
break;
|
|
|
|
ME = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// look for next set bit
|
|
|
|
for (; i < 32; i++) {
|
|
|
|
if ((Val & (1 << (31 - i))) != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we exhausted all the bits, we found a match at this point for 0*1*0*
|
|
|
|
if (i == 32)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// since we just encountered more 1's, if it doesn't wrap around to the
|
|
|
|
// most significant bit of the word, then we did not find a match to 1*0*1* so
|
|
|
|
// exit.
|
|
|
|
if (MB != 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// look for last set bit
|
|
|
|
for (MB = i; i < 32; i++) {
|
|
|
|
if ((Val & (1 << (31 - i))) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we exhausted all the bits, then we found a match for 1*0*1*, otherwise,
|
|
|
|
// the value is not a run of ones.
|
|
|
|
if (i == 32)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2004-10-24 10:33:30 +00:00
|
|
|
/// isInsertAndHalf - Helper function for emitBitfieldInsert. Returns true if
|
|
|
|
/// OpUser has one use, is used by an or instruction, and is itself an and whose
|
|
|
|
/// second operand is a constant int. Optionally, set OrI to the Or instruction
|
|
|
|
/// that is the sole user of OpUser, and Op1User to the other operand of the Or
|
|
|
|
/// instruction.
|
|
|
|
static bool isInsertAndHalf(User *OpUser, Instruction **Op1User,
|
|
|
|
Instruction **OrI, unsigned &Mask) {
|
|
|
|
// If this instruction doesn't have one use, then return false.
|
|
|
|
if (!OpUser->hasOneUse())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Mask = 0xFFFFFFFF;
|
|
|
|
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(OpUser))
|
|
|
|
if (BO->getOpcode() == Instruction::And) {
|
|
|
|
Value *AndUse = *(OpUser->use_begin());
|
|
|
|
if (BinaryOperator *Or = dyn_cast<BinaryOperator>(AndUse)) {
|
|
|
|
if (Or->getOpcode() == Instruction::Or) {
|
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(OpUser->getOperand(1))) {
|
|
|
|
if (OrI) *OrI = Or;
|
|
|
|
if (Op1User) {
|
|
|
|
if (Or->getOperand(0) == OpUser)
|
|
|
|
*Op1User = dyn_cast<Instruction>(Or->getOperand(1));
|
|
|
|
else
|
|
|
|
*Op1User = dyn_cast<Instruction>(Or->getOperand(0));
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
}
|
2004-10-24 10:33:30 +00:00
|
|
|
Mask &= CI->getRawValue();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isInsertShiftHalf - Helper function for emitBitfieldInsert. Returns true if
|
|
|
|
/// OpUser has one use, is used by an or instruction, and is itself a shift
|
|
|
|
/// instruction that is either used directly by the or instruction, or is used
|
|
|
|
/// by an and instruction whose second operand is a constant int, and which is
|
|
|
|
/// used by the or instruction.
|
|
|
|
static bool isInsertShiftHalf(User *OpUser, Instruction **Op1User,
|
|
|
|
Instruction **OrI, Instruction **OptAndI,
|
|
|
|
unsigned &Shift, unsigned &Mask) {
|
|
|
|
// If this instruction doesn't have one use, then return false.
|
|
|
|
if (!OpUser->hasOneUse())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Mask = 0xFFFFFFFF;
|
|
|
|
if (ShiftInst *SI = dyn_cast<ShiftInst>(OpUser)) {
|
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(SI->getOperand(1))) {
|
|
|
|
Shift = CI->getRawValue();
|
|
|
|
if (SI->getOpcode() == Instruction::Shl)
|
|
|
|
Mask <<= Shift;
|
|
|
|
else if (!SI->getOperand(0)->getType()->isSigned()) {
|
|
|
|
Mask >>= Shift;
|
|
|
|
Shift = 32 - Shift;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now check to see if the shift instruction is used by an or.
|
|
|
|
Value *ShiftUse = *(OpUser->use_begin());
|
|
|
|
Value *OptAndICopy = 0;
|
|
|
|
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(ShiftUse)) {
|
|
|
|
if (BO->getOpcode() == Instruction::And && BO->hasOneUse()) {
|
|
|
|
if (ConstantInt *ACI = dyn_cast<ConstantInt>(BO->getOperand(1))) {
|
|
|
|
if (OptAndI) *OptAndI = BO;
|
|
|
|
OptAndICopy = BO;
|
|
|
|
Mask &= ACI->getRawValue();
|
|
|
|
BO = dyn_cast<BinaryOperator>(*(BO->use_begin()));
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
}
|
|
|
|
}
|
2004-10-24 10:33:30 +00:00
|
|
|
if (BO && BO->getOpcode() == Instruction::Or) {
|
|
|
|
if (OrI) *OrI = BO;
|
|
|
|
if (Op1User) {
|
|
|
|
if (BO->getOperand(0) == OpUser || BO->getOperand(0) == OptAndICopy)
|
|
|
|
*Op1User = dyn_cast<Instruction>(BO->getOperand(1));
|
|
|
|
else
|
|
|
|
*Op1User = dyn_cast<Instruction>(BO->getOperand(0));
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// emitBitfieldInsert - turn a shift used only by an and with immediate into
|
|
|
|
/// the rotate left word immediate then mask insert (rlwimi) instruction.
|
|
|
|
/// Patterns matched:
|
|
|
|
/// 1. or shl, and 5. or (shl-and), and 9. or and, and
|
|
|
|
/// 2. or and, shl 6. or and, (shl-and)
|
|
|
|
/// 3. or shr, and 7. or (shr-and), and
|
|
|
|
/// 4. or and, shr 8. or and, (shr-and)
|
2004-10-26 03:48:25 +00:00
|
|
|
bool PPC32ISel::emitBitfieldInsert(User *OpUser, unsigned DestReg) {
|
2004-10-24 10:33:30 +00:00
|
|
|
// Instructions to skip if we match any of the patterns
|
|
|
|
Instruction *Op0User, *Op1User = 0, *OptAndI = 0, *OrI = 0;
|
|
|
|
unsigned TgtMask, InsMask, Amount = 0;
|
|
|
|
bool matched = false;
|
|
|
|
|
|
|
|
// We require OpUser to be an instruction to continue
|
|
|
|
Op0User = dyn_cast<Instruction>(OpUser);
|
|
|
|
if (0 == Op0User)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Look for cases 2, 4, 6, 8, and 9
|
|
|
|
if (isInsertAndHalf(Op0User, &Op1User, &OrI, TgtMask))
|
|
|
|
if (Op1User)
|
|
|
|
if (isInsertAndHalf(Op1User, 0, 0, InsMask))
|
|
|
|
matched = true;
|
|
|
|
else if (isInsertShiftHalf(Op1User, 0, 0, &OptAndI, Amount, InsMask))
|
|
|
|
matched = true;
|
|
|
|
|
|
|
|
// Look for cases 1, 3, 5, and 7. Force the shift argument to be the one
|
|
|
|
// inserted into the target, since rlwimi can only rotate the value inserted,
|
|
|
|
// not the value being inserted into.
|
|
|
|
if (matched == false)
|
|
|
|
if (isInsertShiftHalf(Op0User, &Op1User, &OrI, &OptAndI, Amount, InsMask))
|
|
|
|
if (Op1User && isInsertAndHalf(Op1User, 0, 0, TgtMask)) {
|
|
|
|
std::swap(Op0User, Op1User);
|
|
|
|
matched = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We didn't succeed in matching one of the patterns, so return false
|
|
|
|
if (matched == false)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If the masks xor to -1, and the insert mask is a run of ones, then we have
|
|
|
|
// succeeded in matching one of the cases for generating rlwimi. Update the
|
|
|
|
// skip lists and users of the Instruction::Or.
|
|
|
|
unsigned MB, ME;
|
|
|
|
if (((TgtMask ^ InsMask) == 0xFFFFFFFF) && isRunOfOnes(InsMask, MB, ME)) {
|
|
|
|
SkipList.push_back(Op0User);
|
|
|
|
SkipList.push_back(Op1User);
|
|
|
|
SkipList.push_back(OptAndI);
|
|
|
|
InsertMap[OrI] = RlwimiRec(Op0User->getOperand(0), Op1User->getOperand(0),
|
|
|
|
Amount, MB, ME);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// emitBitfieldExtract - turn a shift used only by an and with immediate into the
|
|
|
|
/// rotate left word immediate then and with mask (rlwinm) instruction.
|
|
|
|
bool PPC32ISel::emitBitfieldExtract(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
2004-10-26 03:48:25 +00:00
|
|
|
User *OpUser, unsigned DestReg) {
|
2004-10-24 10:33:30 +00:00
|
|
|
return false;
|
2004-10-26 03:48:25 +00:00
|
|
|
/*
|
|
|
|
// Instructions to skip if we match any of the patterns
|
|
|
|
Instruction *Op0User, *Op1User = 0;
|
|
|
|
unsigned ShiftMask, AndMask, Amount = 0;
|
|
|
|
bool matched = false;
|
|
|
|
|
|
|
|
// We require OpUser to be an instruction to continue
|
|
|
|
Op0User = dyn_cast<Instruction>(OpUser);
|
|
|
|
if (0 == Op0User)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (isExtractShiftHalf)
|
|
|
|
if (isExtractAndHalf)
|
|
|
|
matched = true;
|
|
|
|
|
|
|
|
if (matched == false && isExtractAndHalf)
|
|
|
|
if (isExtractShiftHalf)
|
|
|
|
matched = true;
|
|
|
|
|
|
|
|
if (matched == false)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (isRunOfOnes(Imm, MB, ME)) {
|
|
|
|
unsigned SrcReg = getReg(Op, MBB, IP);
|
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg).addImm(Rotate)
|
|
|
|
.addImm(MB).addImm(ME);
|
|
|
|
Op1User->replaceAllUsesWith(Op0User);
|
|
|
|
SkipList.push_back(BO);
|
|
|
|
return true;
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
}
|
2004-10-26 03:48:25 +00:00
|
|
|
*/
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
}
|
|
|
|
|
2004-10-07 22:30:03 +00:00
|
|
|
/// emitBinaryConstOperation - Implement simple binary operators for integral
|
|
|
|
/// types with a constant operand. Opcode is one of: 0 for Add, 1 for Sub,
|
|
|
|
/// 2 for And, 3 for Or, 4 for Xor, and 5 for Subtract-From.
|
|
|
|
///
|
|
|
|
void PPC32ISel::emitBinaryConstOperation(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
unsigned Op0Reg, ConstantInt *Op1,
|
|
|
|
unsigned Opcode, unsigned DestReg) {
|
|
|
|
static const unsigned OpTab[] = {
|
|
|
|
PPC::ADD, PPC::SUB, PPC::AND, PPC::OR, PPC::XOR, PPC::SUBF
|
|
|
|
};
|
|
|
|
static const unsigned ImmOpTab[2][6] = {
|
|
|
|
{ PPC::ADDI, PPC::ADDI, PPC::ANDIo, PPC::ORI, PPC::XORI, PPC::SUBFIC },
|
|
|
|
{ PPC::ADDIS, PPC::ADDIS, PPC::ANDISo, PPC::ORIS, PPC::XORIS, PPC::SUBFIC }
|
|
|
|
};
|
|
|
|
|
2004-11-30 07:30:20 +00:00
|
|
|
// Handle subtract now by inverting the constant value: X-4 == X+(-4)
|
2004-10-07 22:30:03 +00:00
|
|
|
if (Opcode == 1) {
|
2004-11-30 07:30:20 +00:00
|
|
|
Op1 = cast<ConstantInt>(ConstantExpr::getNeg(Op1));
|
|
|
|
Opcode = 0;
|
2004-10-07 22:30:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// xor X, -1 -> not X
|
2004-11-30 07:30:20 +00:00
|
|
|
if (Opcode == 4 && Op1->isAllOnesValue()) {
|
|
|
|
BuildMI(*MBB, IP, PPC::NOR, 2, DestReg).addReg(Op0Reg).addReg(Op0Reg);
|
|
|
|
return;
|
2004-10-07 22:30:03 +00:00
|
|
|
}
|
Implement logical and with an immediate that consists of a contiguous block
of one or more 1 bits (may wrap from least significant bit to most
significant bit) as the rlwinm rather than andi., andis., or some longer
instructons sequence.
int andn4(int z) { return z & -4; }
int clearhi(int z) { return z & 0x0000FFFF; }
int clearlo(int z) { return z & 0xFFFF0000; }
int clearmid(int z) { return z & 0x00FFFF00; }
int clearwrap(int z) { return z & 0xFF0000FF; }
_andn4:
rlwinm r3, r3, 0, 0, 29
blr
_clearhi:
rlwinm r3, r3, 0, 16, 31
blr
_clearlo:
rlwinm r3, r3, 0, 0, 15
blr
_clearmid:
rlwinm r3, r3, 0, 8, 23
blr
_clearwrap:
rlwinm r3, r3, 0, 24, 7
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16832 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-08 02:49:24 +00:00
|
|
|
|
2004-11-30 07:30:20 +00:00
|
|
|
if (Opcode == 2 && !Op1->isNullValue()) {
|
|
|
|
unsigned MB, ME, mask = Op1->getRawValue();
|
Implement logical and with an immediate that consists of a contiguous block
of one or more 1 bits (may wrap from least significant bit to most
significant bit) as the rlwinm rather than andi., andis., or some longer
instructons sequence.
int andn4(int z) { return z & -4; }
int clearhi(int z) { return z & 0x0000FFFF; }
int clearlo(int z) { return z & 0xFFFF0000; }
int clearmid(int z) { return z & 0x00FFFF00; }
int clearwrap(int z) { return z & 0xFF0000FF; }
_andn4:
rlwinm r3, r3, 0, 0, 29
blr
_clearhi:
rlwinm r3, r3, 0, 16, 31
blr
_clearlo:
rlwinm r3, r3, 0, 0, 15
blr
_clearmid:
rlwinm r3, r3, 0, 8, 23
blr
_clearwrap:
rlwinm r3, r3, 0, 24, 7
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16832 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-08 02:49:24 +00:00
|
|
|
if (isRunOfOnes(mask, MB, ME)) {
|
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(Op0Reg).addImm(0)
|
|
|
|
.addImm(MB).addImm(ME);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2004-10-07 22:30:03 +00:00
|
|
|
|
Better codegen of binary integer ops with 32 bit immediate operands.
This transformation fires a few dozen times across the testsuite.
For example, int test2(int X) { return X ^ 0x0FF00FF0; }
Old:
_test2:
lis r2, 4080
ori r2, r2, 4080
xor r3, r3, r2
blr
New:
_test2:
xoris r3, r3, 4080
xori r3, r3, 4080
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17004 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-15 00:50:19 +00:00
|
|
|
// PowerPC 16 bit signed immediates are sign extended before use by the
|
|
|
|
// instruction. Therefore, we can only split up an add of a reg with a 32 bit
|
|
|
|
// immediate into addis and addi if the sign bit of the low 16 bits is cleared
|
|
|
|
// so that for register A, const imm X, we don't end up with
|
|
|
|
// A + XXXX0000 + FFFFXXXX.
|
|
|
|
bool WontSignExtend = (0 == (Op1->getRawValue() & 0x8000));
|
|
|
|
|
2004-10-07 22:30:03 +00:00
|
|
|
// For Add, Sub, and SubF the instruction takes a signed immediate. For And,
|
|
|
|
// Or, and Xor, the instruction takes an unsigned immediate. There is no
|
|
|
|
// shifted immediate form of SubF so disallow its opcode for those constants.
|
2004-11-30 07:30:20 +00:00
|
|
|
if (canUseAsImmediateForOpcode(Op1, Opcode, false)) {
|
2004-10-07 22:30:03 +00:00
|
|
|
if (Opcode < 2 || Opcode == 5)
|
|
|
|
BuildMI(*MBB, IP, ImmOpTab[0][Opcode], 2, DestReg).addReg(Op0Reg)
|
|
|
|
.addSImm(Op1->getRawValue());
|
|
|
|
else
|
|
|
|
BuildMI(*MBB, IP, ImmOpTab[0][Opcode], 2, DestReg).addReg(Op0Reg)
|
|
|
|
.addZImm(Op1->getRawValue());
|
2004-11-30 07:30:20 +00:00
|
|
|
} else if (canUseAsImmediateForOpcode(Op1, Opcode, true) && (Opcode < 5)) {
|
2004-10-07 22:30:03 +00:00
|
|
|
if (Opcode < 2)
|
|
|
|
BuildMI(*MBB, IP, ImmOpTab[1][Opcode], 2, DestReg).addReg(Op0Reg)
|
|
|
|
.addSImm(Op1->getRawValue() >> 16);
|
|
|
|
else
|
|
|
|
BuildMI(*MBB, IP, ImmOpTab[1][Opcode], 2, DestReg).addReg(Op0Reg)
|
|
|
|
.addZImm(Op1->getRawValue() >> 16);
|
Better codegen of binary integer ops with 32 bit immediate operands.
This transformation fires a few dozen times across the testsuite.
For example, int test2(int X) { return X ^ 0x0FF00FF0; }
Old:
_test2:
lis r2, 4080
ori r2, r2, 4080
xor r3, r3, r2
blr
New:
_test2:
xoris r3, r3, 4080
xori r3, r3, 4080
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17004 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-15 00:50:19 +00:00
|
|
|
} else if ((Opcode < 2 && WontSignExtend) || Opcode == 3 || Opcode == 4) {
|
|
|
|
unsigned TmpReg = makeAnotherReg(Op1->getType());
|
|
|
|
if (Opcode < 2) {
|
|
|
|
BuildMI(*MBB, IP, ImmOpTab[1][Opcode], 2, TmpReg).addReg(Op0Reg)
|
|
|
|
.addSImm(Op1->getRawValue() >> 16);
|
|
|
|
BuildMI(*MBB, IP, ImmOpTab[0][Opcode], 2, DestReg).addReg(TmpReg)
|
|
|
|
.addSImm(Op1->getRawValue());
|
|
|
|
} else {
|
|
|
|
BuildMI(*MBB, IP, ImmOpTab[1][Opcode], 2, TmpReg).addReg(Op0Reg)
|
|
|
|
.addZImm(Op1->getRawValue() >> 16);
|
|
|
|
BuildMI(*MBB, IP, ImmOpTab[0][Opcode], 2, DestReg).addReg(TmpReg)
|
|
|
|
.addZImm(Op1->getRawValue());
|
|
|
|
}
|
2004-10-07 22:30:03 +00:00
|
|
|
} else {
|
|
|
|
unsigned Op1Reg = getReg(Op1, MBB, IP);
|
|
|
|
BuildMI(*MBB, IP, OpTab[Opcode], 2, DestReg).addReg(Op0Reg).addReg(Op1Reg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
/// emitSimpleBinaryOperation - Implement simple binary operators for integral
|
|
|
|
/// types... OperatorClass is one of: 0 for Add, 1 for Sub, 2 for And, 3 for
|
|
|
|
/// Or, 4 for Xor.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::emitSimpleBinaryOperation(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
BinaryOperator *BO,
|
2004-09-21 18:22:19 +00:00
|
|
|
Value *Op0, Value *Op1,
|
|
|
|
unsigned OperatorClass,
|
|
|
|
unsigned DestReg) {
|
2004-06-21 17:41:12 +00:00
|
|
|
// Arithmetic and Bitwise operators
|
2004-06-25 14:50:41 +00:00
|
|
|
static const unsigned OpcodeTab[] = {
|
2005-03-28 23:08:54 +00:00
|
|
|
PPC::ADD, PPC::SUBF, PPC::AND, PPC::OR, PPC::XOR
|
2004-06-21 17:41:12 +00:00
|
|
|
};
|
2004-10-07 22:30:03 +00:00
|
|
|
static const unsigned LongOpTab[2][5] = {
|
2005-03-28 22:28:37 +00:00
|
|
|
{ PPC::ADDC, PPC::SUBFC, PPC::AND, PPC::OR, PPC::XOR },
|
2004-10-07 22:30:03 +00:00
|
|
|
{ PPC::ADDE, PPC::SUBFE, PPC::AND, PPC::OR, PPC::XOR }
|
2004-06-21 17:41:12 +00:00
|
|
|
};
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-10-07 22:30:03 +00:00
|
|
|
unsigned Class = getClassB(Op0->getType());
|
|
|
|
|
2004-07-20 00:41:46 +00:00
|
|
|
if (Class == cFP32 || Class == cFP64) {
|
2004-06-21 16:55:25 +00:00
|
|
|
assert(OperatorClass < 2 && "No logical ops for FP!");
|
|
|
|
emitBinaryFPOperation(MBB, IP, Op0, Op1, OperatorClass, DestReg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Op0->getType() == Type::BoolTy) {
|
|
|
|
if (OperatorClass == 3)
|
|
|
|
// If this is an or of two isnan's, emit an FP comparison directly instead
|
|
|
|
// of or'ing two isnan's together.
|
|
|
|
if (Value *LHS = dyncastIsNan(Op0))
|
|
|
|
if (Value *RHS = dyncastIsNan(Op1)) {
|
|
|
|
unsigned Op0Reg = getReg(RHS, MBB, IP), Op1Reg = getReg(LHS, MBB, IP);
|
2004-06-21 17:41:12 +00:00
|
|
|
unsigned TmpReg = makeAnotherReg(Type::IntTy);
|
2004-06-21 16:55:25 +00:00
|
|
|
emitUCOM(MBB, IP, Op0Reg, Op1Reg);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::MFCR, TmpReg);
|
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(TmpReg).addImm(4)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addImm(31).addImm(31);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-22 15:58:04 +00:00
|
|
|
// Special case: op <const int>, Reg
|
2004-10-07 22:30:03 +00:00
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(Op0))
|
|
|
|
if (Class != cLong) {
|
|
|
|
unsigned Opcode = (OperatorClass == 1) ? 5 : OperatorClass;
|
2004-07-22 15:58:04 +00:00
|
|
|
unsigned Op1r = getReg(Op1, MBB, IP);
|
2004-10-07 22:30:03 +00:00
|
|
|
emitBinaryConstOperation(MBB, IP, Op1r, CI, Opcode, DestReg);
|
2004-07-22 15:58:04 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
// Special case: op Reg, <const int>
|
2004-10-07 22:30:03 +00:00
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(Op1))
|
2004-07-21 20:09:08 +00:00
|
|
|
if (Class != cLong) {
|
2004-10-26 03:48:25 +00:00
|
|
|
if (emitBitfieldInsert(BO, DestReg))
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
return;
|
2004-10-24 10:33:30 +00:00
|
|
|
|
2004-10-07 22:30:03 +00:00
|
|
|
unsigned Op0r = getReg(Op0, MBB, IP);
|
|
|
|
emitBinaryConstOperation(MBB, IP, Op0r, CI, OperatorClass, DestReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-07-21 20:09:08 +00:00
|
|
|
|
2004-07-22 15:58:04 +00:00
|
|
|
// We couldn't generate an immediate variant of the op, load both halves into
|
|
|
|
// registers and emit the appropriate opcode.
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned Op0r = getReg(Op0, MBB, IP);
|
|
|
|
unsigned Op1r = getReg(Op1, MBB, IP);
|
|
|
|
|
2005-03-28 23:08:54 +00:00
|
|
|
// Subtracts have their operands swapped
|
|
|
|
if (OperatorClass == 1) {
|
|
|
|
if (Class != cLong) {
|
|
|
|
BuildMI(*MBB, IP, PPC::SUBF, 2, DestReg).addReg(Op1r).addReg(Op0r);
|
|
|
|
} else {
|
|
|
|
BuildMI(*MBB, IP, PPC::SUBFC, 2, DestReg+1).addReg(Op1r+1).addReg(Op0r+1);
|
|
|
|
BuildMI(*MBB, IP, PPC::SUBFE, 2, DestReg).addReg(Op1r).addReg(Op0r);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
if (Class != cLong) {
|
2004-06-21 17:41:12 +00:00
|
|
|
unsigned Opcode = OpcodeTab[OperatorClass];
|
|
|
|
BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addReg(Op1r);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
2004-10-07 22:30:03 +00:00
|
|
|
BuildMI(*MBB, IP, LongOpTab[0][OperatorClass], 2, DestReg+1).addReg(Op0r+1)
|
2004-07-20 00:41:46 +00:00
|
|
|
.addReg(Op1r+1);
|
2004-10-07 22:30:03 +00:00
|
|
|
BuildMI(*MBB, IP, LongOpTab[1][OperatorClass], 2, DestReg).addReg(Op0r)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addReg(Op1r);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-07-21 20:09:08 +00:00
|
|
|
/// doMultiply - Emit appropriate instructions to multiply together the
|
|
|
|
/// Values Op0 and Op1, and put the result in DestReg.
|
2004-06-21 20:22:03 +00:00
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::doMultiply(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
unsigned DestReg, Value *Op0, Value *Op1) {
|
2004-07-21 20:09:08 +00:00
|
|
|
unsigned Class0 = getClass(Op0->getType());
|
|
|
|
unsigned Class1 = getClass(Op1->getType());
|
|
|
|
|
|
|
|
unsigned Op0r = getReg(Op0, MBB, IP);
|
|
|
|
unsigned Op1r = getReg(Op1, MBB, IP);
|
|
|
|
|
|
|
|
// 64 x 64 -> 64
|
|
|
|
if (Class0 == cLong && Class1 == cLong) {
|
|
|
|
unsigned Tmp1 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned Tmp2 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned Tmp3 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned Tmp4 = makeAnotherReg(Type::IntTy);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::MULHWU, 2, Tmp1).addReg(Op0r+1).addReg(Op1r+1);
|
|
|
|
BuildMI(*MBB, IP, PPC::MULLW, 2, DestReg+1).addReg(Op0r+1).addReg(Op1r+1);
|
|
|
|
BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp2).addReg(Op0r+1).addReg(Op1r);
|
|
|
|
BuildMI(*MBB, IP, PPC::ADD, 2, Tmp3).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp4).addReg(Op0r).addReg(Op1r+1);
|
|
|
|
BuildMI(*MBB, IP, PPC::ADD, 2, DestReg).addReg(Tmp3).addReg(Tmp4);
|
2004-07-21 20:09:08 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 64 x 32 or less, promote 32 to 64 and do a 64 x 64
|
|
|
|
if (Class0 == cLong && Class1 <= cInt) {
|
|
|
|
unsigned Tmp0 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned Tmp1 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned Tmp2 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned Tmp3 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned Tmp4 = makeAnotherReg(Type::IntTy);
|
|
|
|
if (Op1->getType()->isSigned())
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SRAWI, 2, Tmp0).addReg(Op1r).addImm(31);
|
2004-07-21 20:09:08 +00:00
|
|
|
else
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LI, 2, Tmp0).addSImm(0);
|
|
|
|
BuildMI(*MBB, IP, PPC::MULHWU, 2, Tmp1).addReg(Op0r+1).addReg(Op1r);
|
|
|
|
BuildMI(*MBB, IP, PPC::MULLW, 2, DestReg+1).addReg(Op0r+1).addReg(Op1r);
|
|
|
|
BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp2).addReg(Op0r+1).addReg(Tmp0);
|
|
|
|
BuildMI(*MBB, IP, PPC::ADD, 2, Tmp3).addReg(Tmp1).addReg(Tmp2);
|
|
|
|
BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp4).addReg(Op0r).addReg(Op1r);
|
|
|
|
BuildMI(*MBB, IP, PPC::ADD, 2, DestReg).addReg(Tmp3).addReg(Tmp4);
|
2004-07-21 20:09:08 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 32 x 32 -> 32
|
|
|
|
if (Class0 <= cInt && Class1 <= cInt) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::MULLW, 2, DestReg).addReg(Op0r).addReg(Op1r);
|
2004-07-21 20:09:08 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(0 && "doMultiply cannot operate on unknown type!");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// doMultiplyConst - This method will multiply the value in Op0 by the
|
|
|
|
/// value of the ContantInt *CI
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::doMultiplyConst(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
unsigned DestReg, Value *Op0, ConstantInt *CI) {
|
2004-07-21 20:09:08 +00:00
|
|
|
unsigned Class = getClass(Op0->getType());
|
|
|
|
|
|
|
|
// Mul op0, 0 ==> 0
|
|
|
|
if (CI->isNullValue()) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LI, 1, DestReg).addSImm(0);
|
2004-07-21 20:09:08 +00:00
|
|
|
if (Class == cLong)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LI, 1, DestReg+1).addSImm(0);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
2004-07-21 20:09:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Mul op0, 1 ==> op0
|
|
|
|
if (CI->equalsInt(1)) {
|
|
|
|
unsigned Op0r = getReg(Op0, MBB, IP);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(Op0r).addReg(Op0r);
|
2004-07-21 20:09:08 +00:00
|
|
|
if (Class == cLong)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(Op0r+1).addReg(Op0r+1);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the element size is exactly a power of 2, use a shift to get it.
|
2004-07-21 20:09:08 +00:00
|
|
|
if (unsigned Shift = ExactLog2(CI->getRawValue())) {
|
|
|
|
ConstantUInt *ShiftCI = ConstantUInt::get(Type::UByteTy, Shift);
|
2004-10-26 03:48:25 +00:00
|
|
|
emitShiftOperation(MBB, IP, Op0, ShiftCI, true, Op0->getType(), 0, DestReg);
|
2004-07-21 20:09:08 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If 32 bits or less and immediate is in right range, emit mul by immediate
|
2004-07-22 15:58:04 +00:00
|
|
|
if (Class == cByte || Class == cShort || Class == cInt) {
|
2004-10-07 22:30:03 +00:00
|
|
|
if (canUseAsImmediateForOpcode(CI, 0, false)) {
|
2004-07-21 20:09:08 +00:00
|
|
|
unsigned Op0r = getReg(Op0, MBB, IP);
|
|
|
|
unsigned imm = CI->getRawValue() & 0xFFFF;
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::MULLI, 2, DestReg).addReg(Op0r).addSImm(imm);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-21 20:09:08 +00:00
|
|
|
doMultiply(MBB, IP, DestReg, Op0, CI);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitMul(BinaryOperator &I) {
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned ResultReg = getReg(I);
|
|
|
|
|
|
|
|
Value *Op0 = I.getOperand(0);
|
|
|
|
Value *Op1 = I.getOperand(1);
|
|
|
|
|
|
|
|
MachineBasicBlock::iterator IP = BB->end();
|
|
|
|
emitMultiply(BB, IP, Op0, Op1, ResultReg);
|
|
|
|
}
|
|
|
|
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::emitMultiply(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
Value *Op0, Value *Op1, unsigned DestReg) {
|
2004-06-21 16:55:25 +00:00
|
|
|
TypeClass Class = getClass(Op0->getType());
|
|
|
|
|
|
|
|
switch (Class) {
|
|
|
|
case cByte:
|
|
|
|
case cShort:
|
|
|
|
case cInt:
|
2004-07-21 20:09:08 +00:00
|
|
|
case cLong:
|
2004-06-21 16:55:25 +00:00
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(Op1)) {
|
2004-07-21 20:09:08 +00:00
|
|
|
doMultiplyConst(MBB, IP, DestReg, Op0, CI);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
2004-07-21 20:09:08 +00:00
|
|
|
doMultiply(MBB, IP, DestReg, Op0, Op1);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
return;
|
2004-07-20 00:41:46 +00:00
|
|
|
case cFP32:
|
|
|
|
case cFP64:
|
2004-06-21 16:55:25 +00:00
|
|
|
emitBinaryFPOperation(MBB, IP, Op0, Op1, 2, DestReg);
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// visitDivRem - Handle division and remainder instructions... these
|
|
|
|
/// instruction both require the same instructions to be generated, they just
|
|
|
|
/// select the result from a different register. Note that both of these
|
|
|
|
/// instructions work differently for signed and unsigned operands.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitDivRem(BinaryOperator &I) {
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned ResultReg = getReg(I);
|
|
|
|
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
|
|
|
|
|
|
|
|
MachineBasicBlock::iterator IP = BB->end();
|
2004-06-21 20:22:03 +00:00
|
|
|
emitDivRemOperation(BB, IP, Op0, Op1, I.getOpcode() == Instruction::Div,
|
|
|
|
ResultReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
void PPC32ISel::emitDivRemOperation(MachineBasicBlock *MBB,
|
2004-09-21 18:22:19 +00:00
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
Value *Op0, Value *Op1, bool isDiv,
|
|
|
|
unsigned ResultReg) {
|
2004-06-21 16:55:25 +00:00
|
|
|
const Type *Ty = Op0->getType();
|
|
|
|
unsigned Class = getClass(Ty);
|
|
|
|
switch (Class) {
|
2004-07-20 00:41:46 +00:00
|
|
|
case cFP32:
|
2004-06-21 16:55:25 +00:00
|
|
|
if (isDiv) {
|
2004-07-20 00:41:46 +00:00
|
|
|
// Floating point divide...
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
emitBinaryFPOperation(MBB, IP, Op0, Op1, 3, ResultReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
2004-07-20 00:41:46 +00:00
|
|
|
} else {
|
|
|
|
// Floating point remainder via fmodf(float x, float y);
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
unsigned Op0Reg = getReg(Op0, MBB, IP);
|
|
|
|
unsigned Op1Reg = getReg(Op1, MBB, IP);
|
2004-07-20 00:41:46 +00:00
|
|
|
MachineInstr *TheCall =
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(fmodfFn, true);
|
2004-07-20 00:41:46 +00:00
|
|
|
std::vector<ValueRecord> Args;
|
|
|
|
Args.push_back(ValueRecord(Op0Reg, Type::FloatTy));
|
|
|
|
Args.push_back(ValueRecord(Op1Reg, Type::FloatTy));
|
|
|
|
doCall(ValueRecord(ResultReg, Type::FloatTy), TheCall, Args, false);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
case cFP64:
|
|
|
|
if (isDiv) {
|
|
|
|
// Floating point divide...
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
emitBinaryFPOperation(MBB, IP, Op0, Op1, 3, ResultReg);
|
2004-07-20 00:41:46 +00:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
// Floating point remainder via fmod(double x, double y);
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
unsigned Op0Reg = getReg(Op0, MBB, IP);
|
|
|
|
unsigned Op1Reg = getReg(Op1, MBB, IP);
|
2004-06-21 16:55:25 +00:00
|
|
|
MachineInstr *TheCall =
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(fmodFn, true);
|
2004-06-21 16:55:25 +00:00
|
|
|
std::vector<ValueRecord> Args;
|
|
|
|
Args.push_back(ValueRecord(Op0Reg, Type::DoubleTy));
|
|
|
|
Args.push_back(ValueRecord(Op1Reg, Type::DoubleTy));
|
2004-07-06 22:51:53 +00:00
|
|
|
doCall(ValueRecord(ResultReg, Type::DoubleTy), TheCall, Args, false);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
case cLong: {
|
2004-07-20 00:41:46 +00:00
|
|
|
static Function* const Funcs[] =
|
2004-07-08 18:27:59 +00:00
|
|
|
{ __moddi3Fn, __divdi3Fn, __umoddi3Fn, __udivdi3Fn };
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
unsigned Op0Reg = getReg(Op0, MBB, IP);
|
|
|
|
unsigned Op1Reg = getReg(Op1, MBB, IP);
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned NameIdx = Ty->isUnsigned()*2 + isDiv;
|
|
|
|
MachineInstr *TheCall =
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(Funcs[NameIdx], true);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
std::vector<ValueRecord> Args;
|
|
|
|
Args.push_back(ValueRecord(Op0Reg, Type::LongTy));
|
|
|
|
Args.push_back(ValueRecord(Op1Reg, Type::LongTy));
|
2004-07-06 22:51:53 +00:00
|
|
|
doCall(ValueRecord(ResultReg, Type::LongTy), TheCall, Args, false);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
case cByte: case cShort: case cInt:
|
|
|
|
break; // Small integrals, handled below...
|
|
|
|
default: assert(0 && "Unknown class!");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Special case signed division by power of 2.
|
|
|
|
if (isDiv)
|
|
|
|
if (ConstantSInt *CI = dyn_cast<ConstantSInt>(Op1)) {
|
|
|
|
assert(Class != cLong && "This doesn't handle 64-bit divides!");
|
|
|
|
int V = CI->getValue();
|
|
|
|
|
|
|
|
if (V == 1) { // X /s 1 => X
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
unsigned Op0Reg = getReg(Op0, MBB, IP);
|
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, ResultReg).addReg(Op0Reg).addReg(Op0Reg);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (V == -1) { // X /s -1 => -X
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
unsigned Op0Reg = getReg(Op0, MBB, IP);
|
|
|
|
BuildMI(*MBB, IP, PPC::NEG, 1, ResultReg).addReg(Op0Reg);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-07-20 15:51:37 +00:00
|
|
|
unsigned log2V = ExactLog2(V);
|
|
|
|
if (log2V != 0 && Ty->isSigned()) {
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
unsigned Op0Reg = getReg(Op0, MBB, IP);
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned TmpReg = makeAnotherReg(Op0->getType());
|
2004-07-20 15:51:37 +00:00
|
|
|
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SRAWI, 2, TmpReg).addReg(Op0Reg).addImm(log2V);
|
|
|
|
BuildMI(*MBB, IP, PPC::ADDZE, 1, ResultReg).addReg(TmpReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
unsigned Op0Reg = getReg(Op0, MBB, IP);
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
if (isDiv) {
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
unsigned Op1Reg = getReg(Op1, MBB, IP);
|
|
|
|
unsigned Opcode = Ty->isSigned() ? PPC::DIVW : PPC::DIVWU;
|
|
|
|
BuildMI(*MBB, IP, Opcode, 2, ResultReg).addReg(Op0Reg).addReg(Op1Reg);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else { // Remainder
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
// FIXME: don't load the CI part of a CI divide twice
|
|
|
|
ConstantInt *CI = dyn_cast<ConstantInt>(Op1);
|
2004-06-21 17:41:12 +00:00
|
|
|
unsigned TmpReg1 = makeAnotherReg(Op0->getType());
|
|
|
|
unsigned TmpReg2 = makeAnotherReg(Op0->getType());
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
emitDivRemOperation(MBB, IP, Op0, Op1, true, TmpReg1);
|
2004-10-07 22:30:03 +00:00
|
|
|
if (CI && canUseAsImmediateForOpcode(CI, 0, false)) {
|
Implement floating point select for lt, gt, le, ge using the powerpc fsel
instruction.
Now, rather than emitting the following loop out of bisect:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f4
bge .LBB_main_64 ; no_exit.0.i
.LBB_main_63: ; no_exit.0.i
b .LBB_main_65 ; no_exit.0.i
.LBB_main_64: ; no_exit.0.i
fmr f2, f1
.LBB_main_65: ; no_exit.0.i
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f1
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f5, lo16(.CPI_main_1-"L00000$pb")(r3)
fcmpu cr0, f1, f5
bge .LBB_main_67 ; no_exit.0.i
.LBB_main_66: ; no_exit.0.i
b .LBB_main_68 ; no_exit.0.i
.LBB_main_67: ; no_exit.0.i
fmr f4, f1
.LBB_main_68: ; no_exit.0.i
fadd f1, f2, f4
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fcmpu cr0, f4, f0
bgt .LBB_main_70 ; no_exit.0.i
.LBB_main_69: ; no_exit.0.i
b .LBB_main_71 ; no_exit.0.i
.LBB_main_70: ; no_exit.0.i
fmr f0, f4
.LBB_main_71: ; no_exit.0.i
fsub f1, f2, f1
addi r2, r2, -1
fcmpu cr0, f1, f3
blt .LBB_main_73 ; no_exit.0.i
.LBB_main_72: ; no_exit.0.i
b .LBB_main_74 ; no_exit.0.i
.LBB_main_73: ; no_exit.0.i
fmr f3, f1
.LBB_main_74: ; no_exit.0.i
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
We emit this instead:
.LBB_main_19: ; no_exit.0.i
rlwinm r3, r2, 3, 0, 28
lfdx f1, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f2, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f2, f2, f1
fsel f1, f1, f1, f2
addi r3, r2, 1
rlwinm r3, r3, 3, 0, 28
lfdx f2, r3, r27
addis r3, r30, ha16(.CPI_main_1-"L00000$pb")
lfd f4, lo16(.CPI_main_1-"L00000$pb")(r3)
fsub f4, f4, f2
fsel f2, f2, f2, f4
fadd f1, f1, f2
addis r3, r30, ha16(.CPI_main_2-"L00000$pb")
lfd f2, lo16(.CPI_main_2-"L00000$pb")(r3)
fmul f1, f1, f2
rlwinm r3, r2, 3, 0, 28
lfdx f2, r3, r28
fadd f4, f2, f1
fsub f5, f0, f4
fsel f0, f5, f0, f4
fsub f1, f2, f1
addi r2, r2, -1
fsub f2, f1, f3
fsel f3, f2, f3, f1
cmpwi cr0, r2, -1
fmr f16, f0
fmr f17, f3
bgt .LBB_main_19 ; no_exit.0.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16764 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-06 09:53:04 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::MULLI, 2, TmpReg2).addReg(TmpReg1)
|
|
|
|
.addSImm(CI->getRawValue());
|
|
|
|
} else {
|
|
|
|
unsigned Op1Reg = getReg(Op1, MBB, IP);
|
|
|
|
BuildMI(*MBB, IP, PPC::MULLW, 2, TmpReg2).addReg(TmpReg1).addReg(Op1Reg);
|
|
|
|
}
|
|
|
|
BuildMI(*MBB, IP, PPC::SUBF, 2, ResultReg).addReg(TmpReg2).addReg(Op0Reg);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Shift instructions: 'shl', 'sar', 'shr' - Some special cases here
|
|
|
|
/// for constant immediate shift values, and for constant immediate
|
|
|
|
/// shift values equal to 1. Even the general case is sort of special,
|
|
|
|
/// because the shift amount has to be in CL, not just any old register.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitShiftInst(ShiftInst &I) {
|
2004-10-24 10:33:30 +00:00
|
|
|
if (std::find(SkipList.begin(), SkipList.end(), &I) != SkipList.end())
|
|
|
|
return;
|
|
|
|
|
2004-07-23 16:08:20 +00:00
|
|
|
MachineBasicBlock::iterator IP = BB->end();
|
|
|
|
emitShiftOperation(BB, IP, I.getOperand(0), I.getOperand(1),
|
|
|
|
I.getOpcode() == Instruction::Shl, I.getType(),
|
2004-10-26 03:48:25 +00:00
|
|
|
&I, getReg(I));
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// emitShiftOperation - Common code shared between visitShiftInst and
|
|
|
|
/// constant expression support.
|
2004-06-21 20:22:03 +00:00
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::emitShiftOperation(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
Value *Op, Value *ShiftAmount,
|
2004-10-26 03:48:25 +00:00
|
|
|
bool isLeftShift, const Type *ResultTy,
|
|
|
|
ShiftInst *SI, unsigned DestReg) {
|
2004-06-21 16:55:25 +00:00
|
|
|
bool isSigned = ResultTy->isSigned ();
|
|
|
|
unsigned Class = getClass (ResultTy);
|
|
|
|
|
|
|
|
// Longs, as usual, are handled specially...
|
|
|
|
if (Class == cLong) {
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
unsigned SrcReg = getReg (Op, MBB, IP);
|
2004-06-21 16:55:25 +00:00
|
|
|
// If we have a constant shift, we can generate much more efficient code
|
2004-10-16 20:43:38 +00:00
|
|
|
// than for a variable shift by using the rlwimi instruction.
|
2004-06-21 16:55:25 +00:00
|
|
|
if (ConstantUInt *CUI = dyn_cast<ConstantUInt>(ShiftAmount)) {
|
|
|
|
unsigned Amount = CUI->getValue();
|
2004-11-30 06:29:10 +00:00
|
|
|
if (Amount == 0) {
|
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
|
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1)
|
|
|
|
.addReg(SrcReg+1).addReg(SrcReg+1);
|
|
|
|
|
|
|
|
} else if (Amount < 32) {
|
2004-10-16 20:43:38 +00:00
|
|
|
unsigned TempReg = makeAnotherReg(ResultTy);
|
2004-06-21 16:55:25 +00:00
|
|
|
if (isLeftShift) {
|
2004-10-16 20:43:38 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, TempReg).addReg(SrcReg)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addImm(Amount).addImm(0).addImm(31-Amount);
|
2004-10-16 20:43:38 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWIMI, 5, DestReg).addReg(TempReg)
|
|
|
|
.addReg(SrcReg+1).addImm(Amount).addImm(32-Amount).addImm(31);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg+1).addReg(SrcReg+1)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addImm(Amount).addImm(0).addImm(31-Amount);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
2004-10-16 20:43:38 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, TempReg).addReg(SrcReg+1)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addImm(32-Amount).addImm(Amount).addImm(31);
|
2004-10-16 20:43:38 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWIMI, 5, DestReg+1).addReg(TempReg)
|
|
|
|
.addReg(SrcReg).addImm(32-Amount).addImm(0).addImm(Amount-1);
|
2005-04-06 22:42:08 +00:00
|
|
|
if (isSigned) {
|
|
|
|
BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg).addReg(SrcReg)
|
|
|
|
.addImm(Amount);
|
|
|
|
} else {
|
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg)
|
|
|
|
.addImm(32-Amount).addImm(Amount).addImm(31);
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
} else { // Shifting more than 32 bits
|
|
|
|
Amount -= 32;
|
|
|
|
if (isLeftShift) {
|
|
|
|
if (Amount != 0) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg+1)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addImm(Amount).addImm(0).addImm(31-Amount);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg+1)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addReg(SrcReg+1);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LI, 1, DestReg+1).addSImm(0);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
|
|
|
if (Amount != 0) {
|
2004-06-21 17:41:12 +00:00
|
|
|
if (isSigned)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg+1).addReg(SrcReg)
|
2004-06-24 22:00:15 +00:00
|
|
|
.addImm(Amount);
|
2004-06-21 17:41:12 +00:00
|
|
|
else
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg+1).addReg(SrcReg)
|
2004-06-24 22:00:15 +00:00
|
|
|
.addImm(32-Amount).addImm(Amount).addImm(31);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addReg(SrcReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
2005-04-06 22:42:08 +00:00
|
|
|
if (isSigned)
|
|
|
|
BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg).addReg(SrcReg)
|
|
|
|
.addImm(31);
|
|
|
|
else
|
|
|
|
BuildMI(*MBB, IP,PPC::LI, 1, DestReg).addSImm(0);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unsigned TmpReg1 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned TmpReg2 = makeAnotherReg(Type::IntTy);
|
2004-06-21 17:41:12 +00:00
|
|
|
unsigned TmpReg3 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned TmpReg4 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned TmpReg5 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned TmpReg6 = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned ShiftAmountReg = getReg (ShiftAmount, MBB, IP);
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
if (isLeftShift) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SUBFIC, 2, TmpReg1).addReg(ShiftAmountReg)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addSImm(32);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg2).addReg(SrcReg)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addReg(ShiftAmountReg);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg3).addReg(SrcReg+1)
|
2004-07-22 15:58:04 +00:00
|
|
|
.addReg(TmpReg1);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2,TmpReg4).addReg(TmpReg2).addReg(TmpReg3);
|
|
|
|
BuildMI(*MBB, IP, PPC::ADDI, 2, TmpReg5).addReg(ShiftAmountReg)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addSImm(-32);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg6).addReg(SrcReg+1)
|
2004-07-22 15:58:04 +00:00
|
|
|
.addReg(TmpReg5);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(TmpReg4)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addReg(TmpReg6);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SLW, 2, DestReg+1).addReg(SrcReg+1)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addReg(ShiftAmountReg);
|
2004-06-21 17:41:12 +00:00
|
|
|
} else {
|
2004-08-29 08:19:32 +00:00
|
|
|
if (isSigned) { // shift right algebraic
|
|
|
|
MachineBasicBlock *TmpMBB =new MachineBasicBlock(BB->getBasicBlock());
|
|
|
|
MachineBasicBlock *PhiMBB =new MachineBasicBlock(BB->getBasicBlock());
|
|
|
|
MachineBasicBlock *OldMBB = BB;
|
|
|
|
ilist<MachineBasicBlock>::iterator It = BB; ++It;
|
|
|
|
F->getBasicBlockList().insert(It, TmpMBB);
|
|
|
|
F->getBasicBlockList().insert(It, PhiMBB);
|
|
|
|
BB->addSuccessor(TmpMBB);
|
|
|
|
BB->addSuccessor(PhiMBB);
|
|
|
|
|
|
|
|
BuildMI(*MBB, IP, PPC::SUBFIC, 2, TmpReg1).addReg(ShiftAmountReg)
|
|
|
|
.addSImm(32);
|
|
|
|
BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg2).addReg(SrcReg+1)
|
|
|
|
.addReg(ShiftAmountReg);
|
|
|
|
BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg3).addReg(SrcReg)
|
|
|
|
.addReg(TmpReg1);
|
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, TmpReg4).addReg(TmpReg2)
|
|
|
|
.addReg(TmpReg3);
|
|
|
|
BuildMI(*MBB, IP, PPC::ADDICo, 2, TmpReg5).addReg(ShiftAmountReg)
|
|
|
|
.addSImm(-32);
|
|
|
|
BuildMI(*MBB, IP, PPC::SRAW, 2, TmpReg6).addReg(SrcReg)
|
|
|
|
.addReg(TmpReg5);
|
|
|
|
BuildMI(*MBB, IP, PPC::SRAW, 2, DestReg).addReg(SrcReg)
|
|
|
|
.addReg(ShiftAmountReg);
|
|
|
|
BuildMI(*MBB, IP, PPC::BLE, 2).addReg(PPC::CR0).addMBB(PhiMBB);
|
|
|
|
|
|
|
|
// OrMBB:
|
|
|
|
// Select correct least significant half if the shift amount > 32
|
|
|
|
BB = TmpMBB;
|
|
|
|
unsigned OrReg = makeAnotherReg(Type::IntTy);
|
2004-11-30 06:40:04 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, OrReg).addReg(TmpReg6).addReg(TmpReg6);
|
2004-08-29 08:19:32 +00:00
|
|
|
TmpMBB->addSuccessor(PhiMBB);
|
|
|
|
|
|
|
|
BB = PhiMBB;
|
|
|
|
BuildMI(BB, PPC::PHI, 4, DestReg+1).addReg(TmpReg4).addMBB(OldMBB)
|
|
|
|
.addReg(OrReg).addMBB(TmpMBB);
|
|
|
|
} else { // shift right logical
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SUBFIC, 2, TmpReg1).addReg(ShiftAmountReg)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addSImm(32);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg2).addReg(SrcReg+1)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addReg(ShiftAmountReg);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg3).addReg(SrcReg)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addReg(TmpReg1);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, TmpReg4).addReg(TmpReg2)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addReg(TmpReg3);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::ADDI, 2, TmpReg5).addReg(ShiftAmountReg)
|
2004-07-21 20:09:08 +00:00
|
|
|
.addSImm(-32);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg6).addReg(SrcReg)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addReg(TmpReg5);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(TmpReg4)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addReg(TmpReg6);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SRW, 2, DestReg).addReg(SrcReg)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addReg(ShiftAmountReg);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ConstantUInt *CUI = dyn_cast<ConstantUInt>(ShiftAmount)) {
|
|
|
|
// The shift amount is constant, guaranteed to be a ubyte. Get its value.
|
|
|
|
assert(CUI->getType() == Type::UByteTy && "Shift amount not a ubyte?");
|
|
|
|
unsigned Amount = CUI->getValue();
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
|
2004-10-24 10:33:30 +00:00
|
|
|
// If this is a shift with one use, and that use is an And instruction,
|
|
|
|
// then attempt to emit a bitfield operation.
|
2004-10-26 03:48:25 +00:00
|
|
|
if (SI && emitBitfieldInsert(SI, DestReg))
|
|
|
|
return;
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
|
|
|
|
unsigned SrcReg = getReg (Op, MBB, IP);
|
2004-11-30 06:36:11 +00:00
|
|
|
if (Amount == 0) {
|
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
|
|
|
|
} else if (isLeftShift) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addImm(Amount).addImm(0).addImm(31-Amount);
|
2004-06-21 17:41:12 +00:00
|
|
|
} else {
|
2004-06-21 20:22:03 +00:00
|
|
|
if (isSigned) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SRAWI,2,DestReg).addReg(SrcReg).addImm(Amount);
|
2004-06-21 20:22:03 +00:00
|
|
|
} else {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addImm(32-Amount).addImm(Amount).addImm(31);
|
|
|
|
}
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
} else { // The shift amount is non-constant.
|
Implement bitfield insert by recognizing the following pattern:
1. optional shift left
2. and x, immX
3. and y, immY
4. or z, x, y
==> rlwimi z, x, y, shift, mask begin, mask end
where immX == ~immY and immX is a run of set bits. This transformation
fires 32 times on voronoi, once on espresso, and probably several
dozen times on external benchmarks such as gcc.
To put this in terms of actual code generated for
struct B { unsigned a : 3; unsigned b : 2; };
void storeA (struct B *b, int v) { b->a = v;}
void storeB (struct B *b, int v) { b->b = v;}
Old:
_storeA:
rlwinm r2, r4, 0, 29, 31
lwz r4, 0(r3)
rlwinm r4, r4, 0, 0, 28
or r2, r4, r2
stw r2, 0(r3)
blr
_storeB:
rlwinm r2, r4, 3, 0, 28
rlwinm r2, r2, 0, 27, 28
lwz r4, 0(r3)
rlwinm r4, r4, 0, 29, 26
or r2, r2, r4
stw r2, 0(r3)
blr
New:
_storeA:
lwz r2, 0(r3)
rlwimi r2, r4, 0, 29, 31
stw r2, 0(r3)
blr
_storeB:
lwz r2, 0(r3)
rlwimi r2, r4, 3, 27, 28
stw r2, 0(r3)
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17078 91177308-0d34-0410-b5e6-96231b3b80d8
2004-10-17 05:19:20 +00:00
|
|
|
unsigned SrcReg = getReg (Op, MBB, IP);
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned ShiftAmountReg = getReg (ShiftAmount, MBB, IP);
|
|
|
|
|
2004-06-21 17:41:12 +00:00
|
|
|
if (isLeftShift) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SLW, 2, DestReg).addReg(SrcReg)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addReg(ShiftAmountReg);
|
2004-06-21 17:41:12 +00:00
|
|
|
} else {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, isSigned ? PPC::SRAW : PPC::SRW, 2, DestReg)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addReg(SrcReg).addReg(ShiftAmountReg);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-22 08:10:15 +00:00
|
|
|
/// LoadNeedsSignExtend - On PowerPC, there is no load byte with sign extend.
|
|
|
|
/// Therefore, if this is a byte load and the destination type is signed, we
|
2004-10-06 11:03:30 +00:00
|
|
|
/// would normally need to also emit a sign extend instruction after the load.
|
2004-08-22 08:10:15 +00:00
|
|
|
/// However, store instructions don't care whether a signed type was sign
|
|
|
|
/// extended across a whole register. Also, a SetCC instruction will emit its
|
|
|
|
/// own sign extension to force the value into the appropriate range, so we
|
|
|
|
/// need not emit it here. Ideally, this kind of thing wouldn't be necessary
|
|
|
|
/// once LLVM's type system is improved.
|
|
|
|
static bool LoadNeedsSignExtend(LoadInst &LI) {
|
|
|
|
if (cByte == getClassB(LI.getType()) && LI.getType()->isSigned()) {
|
|
|
|
bool AllUsesAreStoresOrSetCC = true;
|
2004-10-06 11:03:30 +00:00
|
|
|
for (Value::use_iterator I = LI.use_begin(), E = LI.use_end(); I != E; ++I){
|
2004-10-06 16:28:24 +00:00
|
|
|
if (isa<SetCondInst>(*I))
|
2004-10-06 11:03:30 +00:00
|
|
|
continue;
|
2004-10-06 16:28:24 +00:00
|
|
|
if (StoreInst *SI = dyn_cast<StoreInst>(*I))
|
2004-10-07 22:30:03 +00:00
|
|
|
if (cByte == getClassB(SI->getOperand(0)->getType()))
|
2004-10-06 11:03:30 +00:00
|
|
|
continue;
|
|
|
|
AllUsesAreStoresOrSetCC = false;
|
|
|
|
break;
|
|
|
|
}
|
2004-08-22 08:10:15 +00:00
|
|
|
if (!AllUsesAreStoresOrSetCC)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-07-26 18:13:24 +00:00
|
|
|
/// visitLoadInst - Implement LLVM load instructions. Pretty straightforward
|
|
|
|
/// mapping of LLVM classes to PPC load instructions, with the exception of
|
|
|
|
/// signed byte loads, which need a sign extension following them.
|
2004-06-21 16:55:25 +00:00
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitLoadInst(LoadInst &I) {
|
2004-07-26 18:13:24 +00:00
|
|
|
// Immediate opcodes, for reg+imm addressing
|
|
|
|
static const unsigned ImmOpcodes[] = {
|
2004-08-10 22:47:03 +00:00
|
|
|
PPC::LBZ, PPC::LHZ, PPC::LWZ,
|
|
|
|
PPC::LFS, PPC::LFD, PPC::LWZ
|
2004-07-26 18:13:24 +00:00
|
|
|
};
|
|
|
|
// Indexed opcodes, for reg+reg addressing
|
|
|
|
static const unsigned IdxOpcodes[] = {
|
2004-08-10 22:47:03 +00:00
|
|
|
PPC::LBZX, PPC::LHZX, PPC::LWZX,
|
|
|
|
PPC::LFSX, PPC::LFDX, PPC::LWZX
|
2004-06-21 20:22:03 +00:00
|
|
|
};
|
2004-07-22 15:58:04 +00:00
|
|
|
|
2004-07-26 18:13:24 +00:00
|
|
|
unsigned Class = getClassB(I.getType());
|
|
|
|
unsigned ImmOpcode = ImmOpcodes[Class];
|
|
|
|
unsigned IdxOpcode = IdxOpcodes[Class];
|
|
|
|
unsigned DestReg = getReg(I);
|
|
|
|
Value *SourceAddr = I.getOperand(0);
|
|
|
|
|
2004-08-10 22:47:03 +00:00
|
|
|
if (Class == cShort && I.getType()->isSigned()) ImmOpcode = PPC::LHA;
|
|
|
|
if (Class == cShort && I.getType()->isSigned()) IdxOpcode = PPC::LHAX;
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-11-24 21:53:14 +00:00
|
|
|
// If this is a fixed size alloca, emit a load directly from the stack slot
|
|
|
|
// corresponding to it.
|
2004-07-26 18:13:24 +00:00
|
|
|
if (AllocaInst *AI = dyn_castFixedAlloca(SourceAddr)) {
|
2004-06-21 17:41:12 +00:00
|
|
|
unsigned FI = getFixedSizedAllocaFI(AI);
|
2004-06-21 16:55:25 +00:00
|
|
|
if (Class == cLong) {
|
2004-07-26 18:13:24 +00:00
|
|
|
addFrameReference(BuildMI(BB, ImmOpcode, 2, DestReg), FI);
|
|
|
|
addFrameReference(BuildMI(BB, ImmOpcode, 2, DestReg+1), FI, 4);
|
2004-08-22 08:10:15 +00:00
|
|
|
} else if (LoadNeedsSignExtend(I)) {
|
2004-07-22 15:58:04 +00:00
|
|
|
unsigned TmpReg = makeAnotherReg(I.getType());
|
2004-07-26 18:13:24 +00:00
|
|
|
addFrameReference(BuildMI(BB, ImmOpcode, 2, TmpReg), FI);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
} else {
|
2004-07-26 18:13:24 +00:00
|
|
|
addFrameReference(BuildMI(BB, ImmOpcode, 2, DestReg), FI);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-09-23 05:31:33 +00:00
|
|
|
// If the offset fits in 16 bits, we can emit a reg+imm load, otherwise, we
|
|
|
|
// use the index from the FoldedGEP struct and use reg+reg addressing.
|
2004-07-26 18:13:24 +00:00
|
|
|
if (GetElementPtrInst *GEPI = canFoldGEPIntoLoadOrStore(SourceAddr)) {
|
|
|
|
|
2004-09-23 05:31:33 +00:00
|
|
|
// Generate the code for the GEP and get the components of the folded GEP
|
|
|
|
emitGEPOperation(BB, BB->end(), GEPI, true);
|
|
|
|
unsigned baseReg = GEPMap[GEPI].base;
|
|
|
|
unsigned indexReg = GEPMap[GEPI].index;
|
|
|
|
ConstantSInt *offset = GEPMap[GEPI].offset;
|
|
|
|
|
|
|
|
if (Class != cLong) {
|
2004-11-19 08:01:16 +00:00
|
|
|
unsigned TmpReg = LoadNeedsSignExtend(I) ? makeAnotherReg(I.getType())
|
|
|
|
: DestReg;
|
2004-09-23 05:31:33 +00:00
|
|
|
if (indexReg == 0)
|
2004-07-26 18:13:24 +00:00
|
|
|
BuildMI(BB, ImmOpcode, 2, TmpReg).addSImm(offset->getValue())
|
|
|
|
.addReg(baseReg);
|
2004-09-23 05:31:33 +00:00
|
|
|
else
|
|
|
|
BuildMI(BB, IdxOpcode, 2, TmpReg).addReg(indexReg).addReg(baseReg);
|
|
|
|
if (LoadNeedsSignExtend(I))
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg);
|
2004-09-23 05:31:33 +00:00
|
|
|
} else {
|
|
|
|
indexReg = (indexReg != 0) ? indexReg : getReg(offset);
|
2004-07-26 18:13:24 +00:00
|
|
|
unsigned indexPlus4 = makeAnotherReg(Type::IntTy);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::ADDI, 2, indexPlus4).addReg(indexReg).addSImm(4);
|
2004-07-26 18:13:24 +00:00
|
|
|
BuildMI(BB, IdxOpcode, 2, DestReg).addReg(indexReg).addReg(baseReg);
|
|
|
|
BuildMI(BB, IdxOpcode, 2, DestReg+1).addReg(indexPlus4).addReg(baseReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
2004-07-26 18:13:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The fallback case, where the load was from a source that could not be
|
|
|
|
// folded into the load instruction.
|
|
|
|
unsigned SrcAddrReg = getReg(SourceAddr);
|
|
|
|
|
|
|
|
if (Class == cLong) {
|
|
|
|
BuildMI(BB, ImmOpcode, 2, DestReg).addSImm(0).addReg(SrcAddrReg);
|
|
|
|
BuildMI(BB, ImmOpcode, 2, DestReg+1).addSImm(4).addReg(SrcAddrReg);
|
2004-08-22 08:10:15 +00:00
|
|
|
} else if (LoadNeedsSignExtend(I)) {
|
2004-07-26 18:13:24 +00:00
|
|
|
unsigned TmpReg = makeAnotherReg(I.getType());
|
|
|
|
BuildMI(BB, ImmOpcode, 2, TmpReg).addSImm(0).addReg(SrcAddrReg);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
} else {
|
|
|
|
BuildMI(BB, ImmOpcode, 2, DestReg).addSImm(0).addReg(SrcAddrReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// visitStoreInst - Implement LLVM store instructions
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitStoreInst(StoreInst &I) {
|
2004-07-26 18:13:24 +00:00
|
|
|
// Immediate opcodes, for reg+imm addressing
|
|
|
|
static const unsigned ImmOpcodes[] = {
|
2004-08-10 22:47:03 +00:00
|
|
|
PPC::STB, PPC::STH, PPC::STW,
|
|
|
|
PPC::STFS, PPC::STFD, PPC::STW
|
2004-07-26 18:13:24 +00:00
|
|
|
};
|
|
|
|
// Indexed opcodes, for reg+reg addressing
|
|
|
|
static const unsigned IdxOpcodes[] = {
|
2004-08-10 22:47:03 +00:00
|
|
|
PPC::STBX, PPC::STHX, PPC::STWX,
|
|
|
|
PPC::STFSX, PPC::STFDX, PPC::STWX
|
2004-07-26 18:13:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Value *SourceAddr = I.getOperand(1);
|
|
|
|
const Type *ValTy = I.getOperand(0)->getType();
|
|
|
|
unsigned Class = getClassB(ValTy);
|
|
|
|
unsigned ImmOpcode = ImmOpcodes[Class];
|
|
|
|
unsigned IdxOpcode = IdxOpcodes[Class];
|
|
|
|
unsigned ValReg = getReg(I.getOperand(0));
|
|
|
|
|
2004-11-24 21:53:14 +00:00
|
|
|
// If this is a fixed size alloca, emit a store directly to the stack slot
|
|
|
|
// corresponding to it.
|
|
|
|
if (AllocaInst *AI = dyn_castFixedAlloca(SourceAddr)) {
|
|
|
|
unsigned FI = getFixedSizedAllocaFI(AI);
|
|
|
|
addFrameReference(BuildMI(BB, ImmOpcode, 3).addReg(ValReg), FI);
|
|
|
|
if (Class == cLong)
|
|
|
|
addFrameReference(BuildMI(BB, ImmOpcode, 3).addReg(ValReg+1), FI, 4);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-09-23 05:31:33 +00:00
|
|
|
// If the offset fits in 16 bits, we can emit a reg+imm store, otherwise, we
|
|
|
|
// use the index from the FoldedGEP struct and use reg+reg addressing.
|
2004-07-26 18:13:24 +00:00
|
|
|
if (GetElementPtrInst *GEPI = canFoldGEPIntoLoadOrStore(SourceAddr)) {
|
2004-09-23 05:31:33 +00:00
|
|
|
// Generate the code for the GEP and get the components of the folded GEP
|
|
|
|
emitGEPOperation(BB, BB->end(), GEPI, true);
|
|
|
|
unsigned baseReg = GEPMap[GEPI].base;
|
|
|
|
unsigned indexReg = GEPMap[GEPI].index;
|
|
|
|
ConstantSInt *offset = GEPMap[GEPI].offset;
|
2004-07-26 18:13:24 +00:00
|
|
|
|
2004-09-23 05:31:33 +00:00
|
|
|
if (Class != cLong) {
|
|
|
|
if (indexReg == 0)
|
|
|
|
BuildMI(BB, ImmOpcode, 3).addReg(ValReg).addSImm(offset->getValue())
|
|
|
|
.addReg(baseReg);
|
|
|
|
else
|
|
|
|
BuildMI(BB, IdxOpcode, 3).addReg(ValReg).addReg(indexReg)
|
|
|
|
.addReg(baseReg);
|
|
|
|
} else {
|
|
|
|
indexReg = (indexReg != 0) ? indexReg : getReg(offset);
|
2004-07-26 18:13:24 +00:00
|
|
|
unsigned indexPlus4 = makeAnotherReg(Type::IntTy);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::ADDI, 2, indexPlus4).addReg(indexReg).addSImm(4);
|
2004-07-26 18:13:24 +00:00
|
|
|
BuildMI(BB, IdxOpcode, 3).addReg(ValReg).addReg(indexReg).addReg(baseReg);
|
|
|
|
BuildMI(BB, IdxOpcode, 3).addReg(ValReg+1).addReg(indexPlus4)
|
|
|
|
.addReg(baseReg);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the store address wasn't the only use of a GEP, we fall back to the
|
|
|
|
// standard path: store the ValReg at the value in AddressReg.
|
|
|
|
unsigned AddressReg = getReg(I.getOperand(1));
|
2004-06-21 16:55:25 +00:00
|
|
|
if (Class == cLong) {
|
2004-07-26 18:13:24 +00:00
|
|
|
BuildMI(BB, ImmOpcode, 3).addReg(ValReg).addSImm(0).addReg(AddressReg);
|
|
|
|
BuildMI(BB, ImmOpcode, 3).addReg(ValReg+1).addSImm(4).addReg(AddressReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-07-26 18:13:24 +00:00
|
|
|
BuildMI(BB, ImmOpcode, 3).addReg(ValReg).addSImm(0).addReg(AddressReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// visitCastInst - Here we have various kinds of copying with or without sign
|
|
|
|
/// extension going on.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitCastInst(CastInst &CI) {
|
2004-06-21 16:55:25 +00:00
|
|
|
Value *Op = CI.getOperand(0);
|
|
|
|
|
|
|
|
unsigned SrcClass = getClassB(Op->getType());
|
|
|
|
unsigned DestClass = getClassB(CI.getType());
|
|
|
|
|
2004-11-08 02:25:40 +00:00
|
|
|
// Noop casts are not emitted: getReg will return the source operand as the
|
|
|
|
// register to use for any uses of the noop cast.
|
|
|
|
if (DestClass == SrcClass) return;
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
// If this is a cast from a 32-bit integer to a Long type, and the only uses
|
2004-08-19 08:07:50 +00:00
|
|
|
// of the cast are GEP instructions, then the cast does not need to be
|
2004-06-21 16:55:25 +00:00
|
|
|
// generated explicitly, it will be folded into the GEP.
|
|
|
|
if (DestClass == cLong && SrcClass == cInt) {
|
|
|
|
bool AllUsesAreGEPs = true;
|
|
|
|
for (Value::use_iterator I = CI.use_begin(), E = CI.use_end(); I != E; ++I)
|
|
|
|
if (!isa<GetElementPtrInst>(*I)) {
|
|
|
|
AllUsesAreGEPs = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (AllUsesAreGEPs) return;
|
|
|
|
}
|
2004-08-19 08:07:50 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned DestReg = getReg(CI);
|
|
|
|
MachineBasicBlock::iterator MI = BB->end();
|
2004-08-19 08:07:50 +00:00
|
|
|
|
2004-10-23 00:50:23 +00:00
|
|
|
// If this is a cast from an integer type to a ubyte, with one use where the
|
|
|
|
// use is the shift amount argument of a shift instruction, just emit a move
|
|
|
|
// instead (since the shift instruction will only look at the low 5 bits
|
|
|
|
// regardless of how it is sign extended)
|
|
|
|
if (CI.getType() == Type::UByteTy && SrcClass <= cInt && CI.hasOneUse()) {
|
|
|
|
ShiftInst *SI = dyn_cast<ShiftInst>(*(CI.use_begin()));
|
|
|
|
if (SI && (SI->getOperand(1) == &CI)) {
|
|
|
|
unsigned SrcReg = getReg(Op, BB, MI);
|
|
|
|
BuildMI(*BB, MI, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-19 08:07:50 +00:00
|
|
|
// If this is a cast from an byte, short, or int to an integer type of equal
|
|
|
|
// or lesser width, and all uses of the cast are store instructions then dont
|
|
|
|
// emit them, as the store instruction will implicitly not store the zero or
|
|
|
|
// sign extended bytes.
|
|
|
|
if (SrcClass <= cInt && SrcClass >= DestClass) {
|
2004-11-07 20:23:42 +00:00
|
|
|
bool AllUsesAreStores = true;
|
2004-08-19 08:07:50 +00:00
|
|
|
for (Value::use_iterator I = CI.use_begin(), E = CI.use_end(); I != E; ++I)
|
2004-11-07 20:23:42 +00:00
|
|
|
if (!isa<StoreInst>(*I)) {
|
|
|
|
AllUsesAreStores = false;
|
2004-08-19 08:07:50 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Turn this cast directly into a move instruction, which the register
|
|
|
|
// allocator will deal with.
|
2004-11-07 20:23:42 +00:00
|
|
|
if (AllUsesAreStores) {
|
2004-08-19 08:07:50 +00:00
|
|
|
unsigned SrcReg = getReg(Op, BB, MI);
|
|
|
|
BuildMI(*BB, MI, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
emitCastOperation(BB, MI, Op, CI.getType(), DestReg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// emitCastOperation - Common code shared between visitCastInst and constant
|
|
|
|
/// expression cast support.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::emitCastOperation(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
|
|
|
Value *Src, const Type *DestTy,
|
|
|
|
unsigned DestReg) {
|
2004-06-21 16:55:25 +00:00
|
|
|
const Type *SrcTy = Src->getType();
|
|
|
|
unsigned SrcClass = getClassB(SrcTy);
|
|
|
|
unsigned DestClass = getClassB(DestTy);
|
2004-07-20 00:41:46 +00:00
|
|
|
unsigned SrcReg = getReg(Src, MBB, IP);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-10-20 21:55:41 +00:00
|
|
|
// Implement casts from bool to integer types as a move operation
|
|
|
|
if (SrcTy == Type::BoolTy) {
|
|
|
|
switch (DestClass) {
|
|
|
|
case cByte:
|
|
|
|
case cShort:
|
|
|
|
case cInt:
|
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
|
|
|
|
return;
|
|
|
|
case cLong:
|
|
|
|
BuildMI(*MBB, IP, PPC::LI, 1, DestReg).addImm(0);
|
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg).addReg(SrcReg);
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
// Implement casts to bool by using compare on the operand followed by set if
|
|
|
|
// not zero on the result.
|
|
|
|
if (DestTy == Type::BoolTy) {
|
|
|
|
switch (SrcClass) {
|
|
|
|
case cByte:
|
2004-06-21 17:41:12 +00:00
|
|
|
case cShort:
|
2004-06-21 16:55:25 +00:00
|
|
|
case cInt: {
|
|
|
|
unsigned TmpReg = makeAnotherReg(Type::IntTy);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::ADDIC, 2, TmpReg).addReg(SrcReg).addSImm(-1);
|
|
|
|
BuildMI(*MBB, IP, PPC::SUBFE, 2, DestReg).addReg(TmpReg).addReg(SrcReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case cLong: {
|
|
|
|
unsigned TmpReg = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned SrcReg2 = makeAnotherReg(Type::IntTy);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, SrcReg2).addReg(SrcReg).addReg(SrcReg+1);
|
|
|
|
BuildMI(*MBB, IP, PPC::ADDIC, 2, TmpReg).addReg(SrcReg2).addSImm(-1);
|
|
|
|
BuildMI(*MBB, IP, PPC::SUBFE, 2, DestReg).addReg(TmpReg)
|
2004-07-20 20:43:05 +00:00
|
|
|
.addReg(SrcReg2);
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
}
|
2004-07-20 00:41:46 +00:00
|
|
|
case cFP32:
|
|
|
|
case cFP64:
|
2004-08-29 08:19:32 +00:00
|
|
|
unsigned TmpReg = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned ConstZero = getReg(ConstantFP::get(Type::DoubleTy, 0.0), BB, IP);
|
|
|
|
BuildMI(*MBB, IP, PPC::FCMPU, PPC::CR7).addReg(SrcReg).addReg(ConstZero);
|
|
|
|
BuildMI(*MBB, IP, PPC::MFCR, TmpReg);
|
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, DestReg).addReg(TmpReg).addImm(31)
|
|
|
|
.addImm(31).addImm(31);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-07-20 00:41:46 +00:00
|
|
|
// Handle cast of Float -> Double
|
|
|
|
if (SrcClass == cFP32 && DestClass == cFP64) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::FMR, 1, DestReg).addReg(SrcReg);
|
2004-07-20 00:41:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle cast of Double -> Float
|
|
|
|
if (SrcClass == cFP64 && DestClass == cFP32) {
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::FRSP, 1, DestReg).addReg(SrcReg);
|
2004-07-20 00:41:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
// Handle casts from integer to floating point now...
|
2004-07-20 00:41:46 +00:00
|
|
|
if (DestClass == cFP32 || DestClass == cFP64) {
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-06-21 17:41:12 +00:00
|
|
|
// Emit a library call for long to float conversion
|
|
|
|
if (SrcClass == cLong) {
|
2004-07-20 00:41:46 +00:00
|
|
|
Function *floatFn = (DestClass == cFP32) ? __floatdisfFn : __floatdidfFn;
|
2004-08-29 08:19:32 +00:00
|
|
|
if (SrcTy->isSigned()) {
|
|
|
|
std::vector<ValueRecord> Args;
|
|
|
|
Args.push_back(ValueRecord(SrcReg, SrcTy));
|
|
|
|
MachineInstr *TheCall =
|
|
|
|
BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(floatFn, true);
|
|
|
|
doCall(ValueRecord(DestReg, DestTy), TheCall, Args, false);
|
|
|
|
} else {
|
|
|
|
std::vector<ValueRecord> CmpArgs, ClrArgs, SetArgs;
|
|
|
|
unsigned ZeroLong = getReg(ConstantUInt::get(SrcTy, 0));
|
|
|
|
unsigned CondReg = makeAnotherReg(Type::IntTy);
|
|
|
|
|
|
|
|
// Update machine-CFG edges
|
|
|
|
MachineBasicBlock *ClrMBB = new MachineBasicBlock(BB->getBasicBlock());
|
|
|
|
MachineBasicBlock *SetMBB = new MachineBasicBlock(BB->getBasicBlock());
|
|
|
|
MachineBasicBlock *PhiMBB = new MachineBasicBlock(BB->getBasicBlock());
|
|
|
|
MachineBasicBlock *OldMBB = BB;
|
|
|
|
ilist<MachineBasicBlock>::iterator It = BB; ++It;
|
|
|
|
F->getBasicBlockList().insert(It, ClrMBB);
|
|
|
|
F->getBasicBlockList().insert(It, SetMBB);
|
|
|
|
F->getBasicBlockList().insert(It, PhiMBB);
|
|
|
|
BB->addSuccessor(ClrMBB);
|
|
|
|
BB->addSuccessor(SetMBB);
|
|
|
|
|
|
|
|
CmpArgs.push_back(ValueRecord(SrcReg, SrcTy));
|
|
|
|
CmpArgs.push_back(ValueRecord(ZeroLong, SrcTy));
|
|
|
|
MachineInstr *TheCall =
|
|
|
|
BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(__cmpdi2Fn, true);
|
|
|
|
doCall(ValueRecord(CondReg, Type::IntTy), TheCall, CmpArgs, false);
|
|
|
|
BuildMI(*MBB, IP, PPC::CMPWI, 2, PPC::CR0).addReg(CondReg).addSImm(0);
|
|
|
|
BuildMI(*MBB, IP, PPC::BLE, 2).addReg(PPC::CR0).addMBB(SetMBB);
|
|
|
|
|
|
|
|
// ClrMBB
|
|
|
|
BB = ClrMBB;
|
|
|
|
unsigned ClrReg = makeAnotherReg(DestTy);
|
|
|
|
ClrArgs.push_back(ValueRecord(SrcReg, SrcTy));
|
|
|
|
TheCall = BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(floatFn, true);
|
|
|
|
doCall(ValueRecord(ClrReg, DestTy), TheCall, ClrArgs, false);
|
|
|
|
BuildMI(BB, PPC::B, 1).addMBB(PhiMBB);
|
|
|
|
BB->addSuccessor(PhiMBB);
|
|
|
|
|
|
|
|
// SetMBB
|
|
|
|
BB = SetMBB;
|
|
|
|
unsigned SetReg = makeAnotherReg(DestTy);
|
|
|
|
unsigned CallReg = makeAnotherReg(DestTy);
|
|
|
|
unsigned ShiftedReg = makeAnotherReg(SrcTy);
|
|
|
|
ConstantSInt *Const1 = ConstantSInt::get(Type::IntTy, 1);
|
2004-10-26 03:48:25 +00:00
|
|
|
emitShiftOperation(BB, BB->end(), Src, Const1, false, SrcTy, 0,
|
|
|
|
ShiftedReg);
|
2004-08-29 08:19:32 +00:00
|
|
|
SetArgs.push_back(ValueRecord(ShiftedReg, SrcTy));
|
|
|
|
TheCall = BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(floatFn, true);
|
|
|
|
doCall(ValueRecord(CallReg, DestTy), TheCall, SetArgs, false);
|
|
|
|
unsigned SetOpcode = (DestClass == cFP32) ? PPC::FADDS : PPC::FADD;
|
|
|
|
BuildMI(BB, SetOpcode, 2, SetReg).addReg(CallReg).addReg(CallReg);
|
|
|
|
BB->addSuccessor(PhiMBB);
|
|
|
|
|
|
|
|
// PhiMBB
|
|
|
|
BB = PhiMBB;
|
|
|
|
BuildMI(BB, PPC::PHI, 4, DestReg).addReg(ClrReg).addMBB(ClrMBB)
|
|
|
|
.addReg(SetReg).addMBB(SetMBB);
|
|
|
|
}
|
2004-06-21 17:41:12 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-07-20 00:41:46 +00:00
|
|
|
// Make sure we're dealing with a full 32 bits
|
2004-11-19 02:06:40 +00:00
|
|
|
if (SrcClass < cInt) {
|
|
|
|
unsigned TmpReg = makeAnotherReg(Type::IntTy);
|
|
|
|
promote32(TmpReg, ValueRecord(SrcReg, SrcTy));
|
|
|
|
SrcReg = TmpReg;
|
|
|
|
}
|
2004-06-21 17:41:12 +00:00
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
// Spill the integer to memory and reload it from there.
|
2004-06-21 17:41:12 +00:00
|
|
|
// Also spill room for a special conversion constant
|
2004-06-21 16:55:25 +00:00
|
|
|
int ValueFrameIdx =
|
|
|
|
F->getFrameInfo()->CreateStackObject(Type::DoubleTy, TM.getTargetData());
|
|
|
|
|
2004-06-21 17:41:12 +00:00
|
|
|
unsigned constantHi = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned TempF = makeAnotherReg(Type::DoubleTy);
|
|
|
|
|
2004-06-21 16:55:25 +00:00
|
|
|
if (!SrcTy->isSigned()) {
|
2004-08-19 05:20:54 +00:00
|
|
|
ConstantFP *CFP = ConstantFP::get(Type::DoubleTy, 0x1.000000p52);
|
|
|
|
unsigned ConstF = getReg(CFP, BB, IP);
|
2004-08-29 08:19:32 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LIS, 1, constantHi).addSImm(0x4330);
|
|
|
|
addFrameReference(BuildMI(*MBB, IP, PPC::STW, 3).addReg(constantHi),
|
2004-06-21 20:22:03 +00:00
|
|
|
ValueFrameIdx);
|
2004-08-29 08:19:32 +00:00
|
|
|
addFrameReference(BuildMI(*MBB, IP, PPC::STW, 3).addReg(SrcReg),
|
2004-06-21 20:22:03 +00:00
|
|
|
ValueFrameIdx, 4);
|
2004-08-29 08:19:32 +00:00
|
|
|
addFrameReference(BuildMI(*MBB, IP, PPC::LFD, 2, TempF), ValueFrameIdx);
|
|
|
|
BuildMI(*MBB, IP, PPC::FSUB, 2, DestReg).addReg(TempF).addReg(ConstF);
|
2004-06-21 17:41:12 +00:00
|
|
|
} else {
|
2004-08-19 05:20:54 +00:00
|
|
|
ConstantFP *CFP = ConstantFP::get(Type::DoubleTy, 0x1.000008p52);
|
|
|
|
unsigned ConstF = getReg(CFP, BB, IP);
|
2004-06-21 17:41:12 +00:00
|
|
|
unsigned TempLo = makeAnotherReg(Type::IntTy);
|
2004-08-29 08:19:32 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LIS, 1, constantHi).addSImm(0x4330);
|
|
|
|
addFrameReference(BuildMI(*MBB, IP, PPC::STW, 3).addReg(constantHi),
|
2004-06-21 20:22:03 +00:00
|
|
|
ValueFrameIdx);
|
2004-08-29 08:19:32 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::XORIS, 2, TempLo).addReg(SrcReg).addImm(0x8000);
|
|
|
|
addFrameReference(BuildMI(*MBB, IP, PPC::STW, 3).addReg(TempLo),
|
2004-06-21 20:22:03 +00:00
|
|
|
ValueFrameIdx, 4);
|
2004-08-29 08:19:32 +00:00
|
|
|
addFrameReference(BuildMI(*MBB, IP, PPC::LFD, 2, TempF), ValueFrameIdx);
|
|
|
|
BuildMI(*MBB, IP, PPC::FSUB, 2, DestReg).addReg(TempF).addReg(ConstF);
|
2004-06-21 17:41:12 +00:00
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle casts from floating point to integer now...
|
2004-07-20 00:41:46 +00:00
|
|
|
if (SrcClass == cFP32 || SrcClass == cFP64) {
|
2004-08-10 20:42:36 +00:00
|
|
|
static Function* const Funcs[] =
|
|
|
|
{ __fixsfdiFn, __fixdfdiFn, __fixunssfdiFn, __fixunsdfdiFn };
|
2004-06-21 17:41:12 +00:00
|
|
|
// emit library call
|
|
|
|
if (DestClass == cLong) {
|
2004-08-10 20:42:36 +00:00
|
|
|
bool isDouble = SrcClass == cFP64;
|
|
|
|
unsigned nameIndex = 2 * DestTy->isSigned() + isDouble;
|
2004-06-21 17:41:12 +00:00
|
|
|
std::vector<ValueRecord> Args;
|
|
|
|
Args.push_back(ValueRecord(SrcReg, SrcTy));
|
2004-08-10 20:42:36 +00:00
|
|
|
Function *floatFn = Funcs[nameIndex];
|
2004-06-21 20:22:03 +00:00
|
|
|
MachineInstr *TheCall =
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(floatFn, true);
|
2004-07-06 22:51:53 +00:00
|
|
|
doCall(ValueRecord(DestReg, DestTy), TheCall, Args, false);
|
2004-06-21 17:41:12 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
int ValueFrameIdx =
|
2004-08-15 06:42:28 +00:00
|
|
|
F->getFrameInfo()->CreateStackObject(Type::DoubleTy, TM.getTargetData());
|
2004-06-21 16:55:25 +00:00
|
|
|
|
2004-07-20 00:41:46 +00:00
|
|
|
if (DestTy->isSigned()) {
|
2004-07-23 01:11:19 +00:00
|
|
|
unsigned TempReg = makeAnotherReg(Type::DoubleTy);
|
|
|
|
|
|
|
|
// Convert to integer in the FP reg and store it to a stack slot
|
2004-08-29 08:19:32 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::FCTIWZ, 1, TempReg).addReg(SrcReg);
|
|
|
|
addFrameReference(BuildMI(*MBB, IP, PPC::STFD, 3)
|
2004-07-23 01:11:19 +00:00
|
|
|
.addReg(TempReg), ValueFrameIdx);
|
2004-07-26 18:13:24 +00:00
|
|
|
|
|
|
|
// There is no load signed byte opcode, so we must emit a sign extend for
|
|
|
|
// that particular size. Make sure to source the new integer from the
|
|
|
|
// correct offset.
|
2004-07-23 01:11:19 +00:00
|
|
|
if (DestClass == cByte) {
|
|
|
|
unsigned TempReg2 = makeAnotherReg(DestTy);
|
2004-08-29 08:19:32 +00:00
|
|
|
addFrameReference(BuildMI(*MBB, IP, PPC::LBZ, 2, TempReg2),
|
2004-07-26 18:13:24 +00:00
|
|
|
ValueFrameIdx, 7);
|
2004-08-29 08:19:32 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(TempReg2);
|
2004-07-23 01:11:19 +00:00
|
|
|
} else {
|
2004-07-26 18:13:24 +00:00
|
|
|
int offset = (DestClass == cShort) ? 6 : 4;
|
2004-08-10 22:47:03 +00:00
|
|
|
unsigned LoadOp = (DestClass == cShort) ? PPC::LHA : PPC::LWZ;
|
2004-08-29 08:19:32 +00:00
|
|
|
addFrameReference(BuildMI(*MBB, IP, LoadOp, 2, DestReg),
|
2004-07-26 18:13:24 +00:00
|
|
|
ValueFrameIdx, offset);
|
2004-07-23 01:11:19 +00:00
|
|
|
}
|
2004-07-20 00:41:46 +00:00
|
|
|
} else {
|
2004-07-23 20:32:59 +00:00
|
|
|
unsigned Zero = getReg(ConstantFP::get(Type::DoubleTy, 0.0f));
|
|
|
|
double maxInt = (1LL << 32) - 1;
|
|
|
|
unsigned MaxInt = getReg(ConstantFP::get(Type::DoubleTy, maxInt));
|
|
|
|
double border = 1LL << 31;
|
|
|
|
unsigned Border = getReg(ConstantFP::get(Type::DoubleTy, border));
|
|
|
|
unsigned UseZero = makeAnotherReg(Type::DoubleTy);
|
|
|
|
unsigned UseMaxInt = makeAnotherReg(Type::DoubleTy);
|
|
|
|
unsigned UseChoice = makeAnotherReg(Type::DoubleTy);
|
|
|
|
unsigned TmpReg = makeAnotherReg(Type::DoubleTy);
|
|
|
|
unsigned TmpReg2 = makeAnotherReg(Type::DoubleTy);
|
|
|
|
unsigned ConvReg = makeAnotherReg(Type::DoubleTy);
|
|
|
|
unsigned IntTmp = makeAnotherReg(Type::IntTy);
|
|
|
|
unsigned XorReg = makeAnotherReg(Type::IntTy);
|
|
|
|
int FrameIdx =
|
|
|
|
F->getFrameInfo()->CreateStackObject(SrcTy, TM.getTargetData());
|
|
|
|
// 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
|
2004-08-29 08:19:32 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::FSEL, 3, UseZero).addReg(SrcReg).addReg(SrcReg)
|
2004-07-23 20:32:59 +00:00
|
|
|
.addReg(Zero);
|
|
|
|
// Use 2**32 - 1 if incoming value is >= 2**32
|
2004-08-29 08:19:32 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::FSUB, 2, UseMaxInt).addReg(MaxInt).addReg(SrcReg);
|
|
|
|
BuildMI(*MBB, IP, PPC::FSEL, 3, UseChoice).addReg(UseMaxInt)
|
2004-07-23 20:32:59 +00:00
|
|
|
.addReg(UseZero).addReg(MaxInt);
|
|
|
|
// Subtract 2**31
|
2004-08-29 08:19:32 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::FSUB, 2, TmpReg).addReg(UseChoice).addReg(Border);
|
2004-07-23 20:32:59 +00:00
|
|
|
// Use difference if >= 2**31
|
2004-08-29 08:19:32 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::FCMPU, 2, PPC::CR0).addReg(UseChoice)
|
2004-07-23 20:32:59 +00:00
|
|
|
.addReg(Border);
|
2004-08-29 08:19:32 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::FSEL, 3, TmpReg2).addReg(TmpReg).addReg(TmpReg)
|
2004-07-23 20:32:59 +00:00
|
|
|
.addReg(UseChoice);
|
|
|
|
// Convert to integer
|
2004-08-29 08:19:32 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::FCTIWZ, 1, ConvReg).addReg(TmpReg2);
|
|
|
|
addFrameReference(BuildMI(*MBB, IP, PPC::STFD, 3).addReg(ConvReg),
|
2004-07-23 20:32:59 +00:00
|
|
|
FrameIdx);
|
2004-07-26 18:13:24 +00:00
|
|
|
if (DestClass == cByte) {
|
2004-08-29 08:19:32 +00:00
|
|
|
addFrameReference(BuildMI(*MBB, IP, PPC::LBZ, 2, DestReg),
|
2004-07-26 18:13:24 +00:00
|
|
|
FrameIdx, 7);
|
|
|
|
} else if (DestClass == cShort) {
|
2004-08-29 08:19:32 +00:00
|
|
|
addFrameReference(BuildMI(*MBB, IP, PPC::LHZ, 2, DestReg),
|
2004-07-26 18:13:24 +00:00
|
|
|
FrameIdx, 6);
|
|
|
|
} if (DestClass == cInt) {
|
2004-08-29 08:19:32 +00:00
|
|
|
addFrameReference(BuildMI(*MBB, IP, PPC::LWZ, 2, IntTmp),
|
2004-07-26 18:13:24 +00:00
|
|
|
FrameIdx, 4);
|
2004-08-29 08:19:32 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::BLT, 2).addReg(PPC::CR0).addMBB(PhiMBB);
|
|
|
|
BuildMI(*MBB, IP, PPC::B, 1).addMBB(XorMBB);
|
2004-07-26 18:13:24 +00:00
|
|
|
|
|
|
|
// XorMBB:
|
|
|
|
// add 2**31 if input was >= 2**31
|
|
|
|
BB = XorMBB;
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::XORIS, 2, XorReg).addReg(IntTmp).addImm(0x8000);
|
2004-07-26 18:13:24 +00:00
|
|
|
XorMBB->addSuccessor(PhiMBB);
|
|
|
|
|
|
|
|
// PhiMBB:
|
|
|
|
// DestReg = phi [ IntTmp, OldMBB ], [ XorReg, XorMBB ]
|
|
|
|
BB = PhiMBB;
|
2004-08-19 21:00:12 +00:00
|
|
|
BuildMI(BB, PPC::PHI, 4, DestReg).addReg(IntTmp).addMBB(OldMBB)
|
2004-07-26 18:13:24 +00:00
|
|
|
.addReg(XorReg).addMBB(XorMBB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check our invariants
|
|
|
|
assert((SrcClass <= cInt || SrcClass == cLong) &&
|
|
|
|
"Unhandled source class for cast operation!");
|
|
|
|
assert((DestClass <= cInt || DestClass == cLong) &&
|
|
|
|
"Unhandled destination class for cast operation!");
|
|
|
|
|
|
|
|
bool sourceUnsigned = SrcTy->isUnsigned() || SrcTy == Type::BoolTy;
|
|
|
|
bool destUnsigned = DestTy->isUnsigned();
|
|
|
|
|
|
|
|
// Unsigned -> Unsigned, clear if larger,
|
|
|
|
if (sourceUnsigned && destUnsigned) {
|
|
|
|
// handle long dest class now to keep switch clean
|
|
|
|
if (DestClass == cLong) {
|
2004-11-19 02:06:40 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LI, 1, DestReg).addSImm(0);
|
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg)
|
|
|
|
.addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle u{ byte, short, int } x u{ byte, short, int }
|
|
|
|
unsigned clearBits = (SrcClass == cByte || DestClass == cByte) ? 24 : 16;
|
|
|
|
switch (SrcClass) {
|
|
|
|
case cByte:
|
|
|
|
case cShort:
|
2004-11-19 02:06:40 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg)
|
|
|
|
.addImm(0).addImm(clearBits).addImm(31);
|
2004-07-26 18:13:24 +00:00
|
|
|
break;
|
|
|
|
case cLong:
|
|
|
|
++SrcReg;
|
|
|
|
// Fall through
|
|
|
|
case cInt:
|
2004-11-19 02:06:40 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg)
|
|
|
|
.addImm(0).addImm(clearBits).addImm(31);
|
2004-07-26 18:13:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Signed -> Signed
|
|
|
|
if (!sourceUnsigned && !destUnsigned) {
|
|
|
|
// handle long dest class now to keep switch clean
|
|
|
|
if (DestClass == cLong) {
|
2004-11-19 02:06:40 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg).addReg(SrcReg).addImm(31);
|
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg)
|
|
|
|
.addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle { byte, short, int } x { byte, short, int }
|
|
|
|
switch (SrcClass) {
|
|
|
|
case cByte:
|
2004-11-18 04:56:53 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
break;
|
|
|
|
case cShort:
|
|
|
|
if (DestClass == cByte)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
else
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSH, 1, DestReg).addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
break;
|
|
|
|
case cLong:
|
|
|
|
++SrcReg;
|
|
|
|
// Fall through
|
|
|
|
case cInt:
|
|
|
|
if (DestClass == cByte)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
else if (DestClass == cShort)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSH, 1, DestReg).addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
else
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unsigned -> Signed
|
|
|
|
if (sourceUnsigned && !destUnsigned) {
|
|
|
|
// handle long dest class now to keep switch clean
|
|
|
|
if (DestClass == cLong) {
|
2004-11-19 02:06:40 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::LI, 1, DestReg).addSImm(0);
|
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg)
|
|
|
|
.addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle u{ byte, short, int } -> { byte, short, int }
|
|
|
|
switch (SrcClass) {
|
|
|
|
case cByte:
|
2004-11-18 04:56:53 +00:00
|
|
|
// uByte 255 -> signed short/int == 255
|
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg).addImm(0)
|
|
|
|
.addImm(24).addImm(31);
|
2004-07-26 18:13:24 +00:00
|
|
|
break;
|
|
|
|
case cShort:
|
|
|
|
if (DestClass == cByte)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
else
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg).addImm(0)
|
2004-07-26 18:13:24 +00:00
|
|
|
.addImm(16).addImm(31);
|
|
|
|
break;
|
|
|
|
case cLong:
|
|
|
|
++SrcReg;
|
|
|
|
// Fall through
|
|
|
|
case cInt:
|
|
|
|
if (DestClass == cByte)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
else if (DestClass == cShort)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSH, 1, DestReg).addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
else
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Signed -> Unsigned
|
|
|
|
if (!sourceUnsigned && destUnsigned) {
|
|
|
|
// handle long dest class now to keep switch clean
|
|
|
|
if (DestClass == cLong) {
|
2004-11-19 02:06:40 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg).addReg(SrcReg).addImm(31);
|
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg)
|
|
|
|
.addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle { byte, short, int } -> u{ byte, short, int }
|
|
|
|
unsigned clearBits = (DestClass == cByte) ? 24 : 16;
|
|
|
|
switch (SrcClass) {
|
|
|
|
case cByte:
|
2004-11-18 04:56:53 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg);
|
|
|
|
break;
|
2004-07-26 18:13:24 +00:00
|
|
|
case cShort:
|
2004-11-18 04:56:53 +00:00
|
|
|
if (DestClass == cByte)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg)
|
2004-07-26 18:13:24 +00:00
|
|
|
.addImm(0).addImm(clearBits).addImm(31);
|
|
|
|
else
|
2004-11-18 04:56:53 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::EXTSH, 1, DestReg).addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
break;
|
|
|
|
case cLong:
|
|
|
|
++SrcReg;
|
|
|
|
// Fall through
|
|
|
|
case cInt:
|
|
|
|
if (DestClass == cInt)
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
|
2004-07-26 18:13:24 +00:00
|
|
|
else
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg)
|
2004-07-26 18:13:24 +00:00
|
|
|
.addImm(0).addImm(clearBits).addImm(31);
|
|
|
|
break;
|
2004-07-20 00:41:46 +00:00
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Anything we haven't handled already, we can't (yet) handle at all.
|
2004-07-26 18:13:24 +00:00
|
|
|
std::cerr << "Unhandled cast from " << SrcTy->getDescription()
|
|
|
|
<< "to " << DestTy->getDescription() << '\n';
|
2004-06-21 16:55:25 +00:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// visitVANextInst - Implement the va_next instruction...
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitVANextInst(VANextInst &I) {
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned VAList = getReg(I.getOperand(0));
|
|
|
|
unsigned DestReg = getReg(I);
|
|
|
|
|
|
|
|
unsigned Size;
|
2004-06-21 17:25:55 +00:00
|
|
|
switch (I.getArgType()->getTypeID()) {
|
2004-06-21 16:55:25 +00:00
|
|
|
default:
|
|
|
|
std::cerr << I;
|
|
|
|
assert(0 && "Error: bad type for va_next instruction!");
|
|
|
|
return;
|
|
|
|
case Type::PointerTyID:
|
|
|
|
case Type::UIntTyID:
|
|
|
|
case Type::IntTyID:
|
|
|
|
Size = 4;
|
|
|
|
break;
|
|
|
|
case Type::ULongTyID:
|
|
|
|
case Type::LongTyID:
|
|
|
|
case Type::DoubleTyID:
|
|
|
|
Size = 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Increment the VAList pointer...
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::ADDI, 2, DestReg).addReg(VAList).addSImm(Size);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitVAArgInst(VAArgInst &I) {
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned VAList = getReg(I.getOperand(0));
|
|
|
|
unsigned DestReg = getReg(I);
|
|
|
|
|
2004-06-21 17:25:55 +00:00
|
|
|
switch (I.getType()->getTypeID()) {
|
2004-06-21 16:55:25 +00:00
|
|
|
default:
|
|
|
|
std::cerr << I;
|
|
|
|
assert(0 && "Error: bad type for va_next instruction!");
|
|
|
|
return;
|
|
|
|
case Type::PointerTyID:
|
|
|
|
case Type::UIntTyID:
|
|
|
|
case Type::IntTyID:
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::LWZ, 2, DestReg).addSImm(0).addReg(VAList);
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
case Type::ULongTyID:
|
|
|
|
case Type::LongTyID:
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::LWZ, 2, DestReg).addSImm(0).addReg(VAList);
|
|
|
|
BuildMI(BB, PPC::LWZ, 2, DestReg+1).addSImm(4).addReg(VAList);
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
2004-07-26 18:13:24 +00:00
|
|
|
case Type::FloatTyID:
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::LFS, 2, DestReg).addSImm(0).addReg(VAList);
|
2004-07-26 18:13:24 +00:00
|
|
|
break;
|
2004-06-21 16:55:25 +00:00
|
|
|
case Type::DoubleTyID:
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::LFD, 2, DestReg).addSImm(0).addReg(VAList);
|
2004-06-21 16:55:25 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// visitGetElementPtrInst - instruction-select GEP instructions
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitGetElementPtrInst(GetElementPtrInst &I) {
|
2004-07-26 18:13:24 +00:00
|
|
|
if (canFoldGEPIntoLoadOrStore(&I))
|
|
|
|
return;
|
|
|
|
|
2004-09-23 05:31:33 +00:00
|
|
|
emitGEPOperation(BB, BB->end(), &I, false);
|
|
|
|
}
|
|
|
|
|
2004-07-21 20:09:08 +00:00
|
|
|
/// emitGEPOperation - Common code shared between visitGetElementPtrInst and
|
|
|
|
/// constant expression GEP support.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::emitGEPOperation(MachineBasicBlock *MBB,
|
|
|
|
MachineBasicBlock::iterator IP,
|
2004-09-23 05:31:33 +00:00
|
|
|
GetElementPtrInst *GEPI, bool GEPIsFolded) {
|
|
|
|
// If we've already emitted this particular GEP, just return to avoid
|
|
|
|
// multiple definitions of the base register.
|
To go along with sabre's improved InstCombining, improve recognition of
integers that we can use as immediate values in instructions.
Example from yacr2:
- lis r10, -1
- ori r10, r10, 65535
- add r28, r28, r10
+ addi r28, r28, -1
addi r7, r7, 1
addi r9, r9, 1
b .LBB_main_9 ; loopentry.1.i214
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@16566 91177308-0d34-0410-b5e6-96231b3b80d8
2004-09-29 02:35:05 +00:00
|
|
|
if (GEPIsFolded && (GEPMap[GEPI].base != 0))
|
2004-09-23 05:31:33 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
Value *Src = GEPI->getOperand(0);
|
|
|
|
User::op_iterator IdxBegin = GEPI->op_begin()+1;
|
|
|
|
User::op_iterator IdxEnd = GEPI->op_end();
|
2004-07-22 15:58:04 +00:00
|
|
|
const TargetData &TD = TM.getTargetData();
|
|
|
|
const Type *Ty = Src->getType();
|
2005-04-09 19:47:21 +00:00
|
|
|
int32_t constValue = 0;
|
2004-07-23 16:08:20 +00:00
|
|
|
|
|
|
|
// Record the operations to emit the GEP in a vector so that we can emit them
|
|
|
|
// after having analyzed the entire instruction.
|
2004-07-26 18:13:24 +00:00
|
|
|
std::vector<CollapsedGepOp> ops;
|
2004-07-23 16:08:20 +00:00
|
|
|
|
2004-07-21 20:09:08 +00:00
|
|
|
// GEPs have zero or more indices; we must perform a struct access
|
|
|
|
// or array access for each one.
|
|
|
|
for (GetElementPtrInst::op_iterator oi = IdxBegin, oe = IdxEnd; oi != oe;
|
|
|
|
++oi) {
|
|
|
|
Value *idx = *oi;
|
2004-07-22 15:58:04 +00:00
|
|
|
if (const StructType *StTy = dyn_cast<StructType>(Ty)) {
|
2004-07-21 20:09:08 +00:00
|
|
|
// It's a struct access. idx is the index into the structure,
|
|
|
|
// which names the field. Use the TargetData structure to
|
|
|
|
// pick out what the layout of the structure is in memory.
|
|
|
|
// Use the (constant) structure index's value to find the
|
|
|
|
// right byte offset from the StructLayout class's list of
|
|
|
|
// structure member offsets.
|
2004-07-22 15:58:04 +00:00
|
|
|
unsigned fieldIndex = cast<ConstantUInt>(idx)->getValue();
|
2004-07-23 16:08:20 +00:00
|
|
|
|
|
|
|
// StructType member offsets are always constant values. Add it to the
|
|
|
|
// running total.
|
2004-09-23 05:31:33 +00:00
|
|
|
constValue += TD.getStructLayout(StTy)->MemberOffsets[fieldIndex];
|
2004-07-23 16:08:20 +00:00
|
|
|
|
2004-09-23 05:31:33 +00:00
|
|
|
// The next type is the member of the structure selected by the index.
|
2004-07-23 16:08:20 +00:00
|
|
|
Ty = StTy->getElementType (fieldIndex);
|
2004-09-23 05:31:33 +00:00
|
|
|
} else if (const SequentialType *SqTy = dyn_cast<SequentialType>(Ty)) {
|
2004-07-09 15:45:07 +00:00
|
|
|
// Many GEP instructions use a [cast (int/uint) to LongTy] as their
|
|
|
|
// operand. Handle this case directly now...
|
|
|
|
if (CastInst *CI = dyn_cast<CastInst>(idx))
|
|
|
|
if (CI->getOperand(0)->getType() == Type::IntTy ||
|
|
|
|
CI->getOperand(0)->getType() == Type::UIntTy)
|
|
|
|
idx = CI->getOperand(0);
|
2004-07-21 20:09:08 +00:00
|
|
|
|
2004-07-23 16:08:20 +00:00
|
|
|
// It's an array or pointer access: [ArraySize x ElementType].
|
|
|
|
// We want to add basePtrReg to (idxReg * sizeof ElementType). First, we
|
|
|
|
// must find the size of the pointed-to type (Not coincidentally, the next
|
|
|
|
// type is the type of the elements in the array).
|
2004-07-21 20:09:08 +00:00
|
|
|
Ty = SqTy->getElementType();
|
2004-07-22 15:58:04 +00:00
|
|
|
unsigned elementSize = TD.getTypeSize(Ty);
|
2004-07-21 20:09:08 +00:00
|
|
|
|
2004-07-23 16:08:20 +00:00
|
|
|
if (ConstantInt *C = dyn_cast<ConstantInt>(idx)) {
|
|
|
|
if (ConstantSInt *CS = dyn_cast<ConstantSInt>(C))
|
|
|
|
constValue += CS->getValue() * elementSize;
|
|
|
|
else if (ConstantUInt *CU = dyn_cast<ConstantUInt>(C))
|
|
|
|
constValue += CU->getValue() * elementSize;
|
|
|
|
else
|
|
|
|
assert(0 && "Invalid ConstantInt GEP index type!");
|
2004-07-09 15:45:07 +00:00
|
|
|
} else {
|
2004-09-23 05:31:33 +00:00
|
|
|
// Push current gep state to this point as an add and multiply
|
|
|
|
ops.push_back(CollapsedGepOp(
|
|
|
|
ConstantSInt::get(Type::IntTy, constValue),
|
|
|
|
idx, ConstantUInt::get(Type::UIntTy, elementSize)));
|
|
|
|
|
2004-07-23 16:08:20 +00:00
|
|
|
constValue = 0;
|
2004-07-09 15:45:07 +00:00
|
|
|
}
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
2004-07-23 16:08:20 +00:00
|
|
|
}
|
|
|
|
// Emit instructions for all the collapsed ops
|
2004-09-23 05:31:33 +00:00
|
|
|
unsigned indexReg = 0;
|
2004-07-26 18:13:24 +00:00
|
|
|
for(std::vector<CollapsedGepOp>::iterator cgo_i = ops.begin(),
|
2004-07-23 16:08:20 +00:00
|
|
|
cgo_e = ops.end(); cgo_i != cgo_e; ++cgo_i) {
|
2004-07-26 18:13:24 +00:00
|
|
|
CollapsedGepOp& cgo = *cgo_i;
|
2004-07-23 16:08:20 +00:00
|
|
|
|
2004-11-19 02:06:40 +00:00
|
|
|
// Avoid emitting known move instructions here for the register allocator
|
|
|
|
// to deal with later. val * 1 == val. val + 0 == val.
|
|
|
|
unsigned TmpReg1;
|
|
|
|
if (cgo.size->getValue() == 1) {
|
|
|
|
TmpReg1 = getReg(cgo.index, MBB, IP);
|
|
|
|
} else {
|
|
|
|
TmpReg1 = makeAnotherReg(Type::IntTy);
|
|
|
|
doMultiplyConst(MBB, IP, TmpReg1, cgo.index, cgo.size);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned TmpReg2;
|
|
|
|
if (cgo.offset->isNullValue()) {
|
|
|
|
TmpReg2 = TmpReg1;
|
|
|
|
} else {
|
|
|
|
TmpReg2 = makeAnotherReg(Type::IntTy);
|
|
|
|
emitBinaryConstOperation(MBB, IP, TmpReg1, cgo.offset, 0, TmpReg2);
|
|
|
|
}
|
2004-09-23 05:31:33 +00:00
|
|
|
|
|
|
|
if (indexReg == 0)
|
|
|
|
indexReg = TmpReg2;
|
|
|
|
else {
|
|
|
|
unsigned TmpReg3 = makeAnotherReg(Type::IntTy);
|
|
|
|
BuildMI(*MBB, IP, PPC::ADD, 2, TmpReg3).addReg(indexReg).addReg(TmpReg2);
|
|
|
|
indexReg = TmpReg3;
|
|
|
|
}
|
2004-06-21 20:22:03 +00:00
|
|
|
}
|
2004-09-23 05:31:33 +00:00
|
|
|
|
|
|
|
// We now have a base register, an index register, and possibly a constant
|
|
|
|
// remainder. If the GEP is going to be folded, we try to generate the
|
|
|
|
// optimal addressing mode.
|
2004-07-23 16:08:20 +00:00
|
|
|
ConstantSInt *remainder = ConstantSInt::get(Type::IntTy, constValue);
|
|
|
|
|
2004-07-26 18:13:24 +00:00
|
|
|
// If we are emitting this during a fold, copy the current base register to
|
|
|
|
// the target, and save the current constant offset so the folding load or
|
|
|
|
// store can try and use it as an immediate.
|
|
|
|
if (GEPIsFolded) {
|
2004-09-23 05:31:33 +00:00
|
|
|
if (indexReg == 0) {
|
2004-10-07 22:30:03 +00:00
|
|
|
if (!canUseAsImmediateForOpcode(remainder, 0, false)) {
|
2004-09-23 05:31:33 +00:00
|
|
|
indexReg = getReg(remainder, MBB, IP);
|
|
|
|
remainder = 0;
|
2004-08-10 20:42:36 +00:00
|
|
|
}
|
2004-11-19 08:01:16 +00:00
|
|
|
} else if (!remainder->isNullValue()) {
|
2004-09-23 05:31:33 +00:00
|
|
|
unsigned TmpReg = makeAnotherReg(Type::IntTy);
|
2004-10-07 22:30:03 +00:00
|
|
|
emitBinaryConstOperation(MBB, IP, indexReg, remainder, 0, TmpReg);
|
2004-09-23 05:31:33 +00:00
|
|
|
indexReg = TmpReg;
|
|
|
|
remainder = 0;
|
2004-08-10 20:42:36 +00:00
|
|
|
}
|
2004-11-18 07:22:46 +00:00
|
|
|
unsigned basePtrReg = getReg(Src, MBB, IP);
|
|
|
|
GEPMap[GEPI] = FoldedGEP(basePtrReg, indexReg, remainder);
|
2004-07-26 18:13:24 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-08-10 20:42:36 +00:00
|
|
|
|
2004-09-23 05:31:33 +00:00
|
|
|
// We're not folding, so collapse the base, index, and any remainder into the
|
|
|
|
// destination register.
|
2004-11-18 07:22:46 +00:00
|
|
|
unsigned TargetReg = getReg(GEPI, MBB, IP);
|
|
|
|
unsigned basePtrReg = getReg(Src, MBB, IP);
|
2004-11-19 08:01:16 +00:00
|
|
|
|
2004-11-21 05:14:06 +00:00
|
|
|
if ((indexReg == 0) && remainder->isNullValue()) {
|
|
|
|
BuildMI(*MBB, IP, PPC::OR, 2, TargetReg).addReg(basePtrReg)
|
|
|
|
.addReg(basePtrReg);
|
|
|
|
return;
|
|
|
|
}
|
2004-11-19 08:01:16 +00:00
|
|
|
if (!remainder->isNullValue()) {
|
|
|
|
unsigned TmpReg = (indexReg == 0) ? TargetReg : makeAnotherReg(Type::IntTy);
|
|
|
|
emitBinaryConstOperation(MBB, IP, basePtrReg, remainder, 0, TmpReg);
|
2004-08-10 20:42:36 +00:00
|
|
|
basePtrReg = TmpReg;
|
|
|
|
}
|
2004-11-21 05:14:06 +00:00
|
|
|
if (indexReg != 0)
|
2004-11-19 08:01:16 +00:00
|
|
|
BuildMI(*MBB, IP, PPC::ADD, 2, TargetReg).addReg(indexReg)
|
|
|
|
.addReg(basePtrReg);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// visitAllocaInst - If this is a fixed size alloca, allocate space from the
|
|
|
|
/// frame manager, otherwise do it the hard way.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitAllocaInst(AllocaInst &I) {
|
2004-06-21 16:55:25 +00:00
|
|
|
// If this is a fixed size alloca in the entry block for the function, we
|
|
|
|
// statically stack allocate the space, so we don't need to do anything here.
|
|
|
|
//
|
|
|
|
if (dyn_castFixedAlloca(&I)) return;
|
|
|
|
|
|
|
|
// Find the data size of the alloca inst's getAllocatedType.
|
|
|
|
const Type *Ty = I.getAllocatedType();
|
|
|
|
unsigned TySize = TM.getTargetData().getTypeSize(Ty);
|
|
|
|
|
|
|
|
// Create a register to hold the temporary result of multiplying the type size
|
|
|
|
// constant by the variable amount.
|
|
|
|
unsigned TotalSizeReg = makeAnotherReg(Type::UIntTy);
|
|
|
|
|
|
|
|
// TotalSizeReg = mul <numelements>, <TypeSize>
|
|
|
|
MachineBasicBlock::iterator MBBI = BB->end();
|
2004-07-21 20:09:08 +00:00
|
|
|
ConstantUInt *CUI = ConstantUInt::get(Type::UIntTy, TySize);
|
|
|
|
doMultiplyConst(BB, MBBI, TotalSizeReg, I.getArraySize(), CUI);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
// AddedSize = add <TotalSizeReg>, 15
|
|
|
|
unsigned AddedSizeReg = makeAnotherReg(Type::UIntTy);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::ADDI, 2, AddedSizeReg).addReg(TotalSizeReg).addSImm(15);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
// AlignedSize = and <AddedSize>, ~15
|
|
|
|
unsigned AlignedSize = makeAnotherReg(Type::UIntTy);
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::RLWINM, 4, AlignedSize).addReg(AddedSizeReg).addImm(0)
|
2004-06-21 20:22:03 +00:00
|
|
|
.addImm(0).addImm(27);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
// Subtract size from stack pointer, thereby allocating some space.
|
2005-03-28 23:08:54 +00:00
|
|
|
BuildMI(BB, PPC::SUBF, 2, PPC::R1).addReg(AlignedSize).addReg(PPC::R1);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
// Put a pointer to the space into the result register, by copying
|
|
|
|
// the stack pointer.
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(BB, PPC::OR, 2, getReg(I)).addReg(PPC::R1).addReg(PPC::R1);
|
2004-06-21 16:55:25 +00:00
|
|
|
|
|
|
|
// Inform the Frame Information that we have just allocated a variable-sized
|
|
|
|
// object.
|
|
|
|
F->getFrameInfo()->CreateVariableSizedObject();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// visitMallocInst - Malloc instructions are code generated into direct calls
|
|
|
|
/// to the library malloc.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitMallocInst(MallocInst &I) {
|
2004-06-21 16:55:25 +00:00
|
|
|
unsigned AllocSize = TM.getTargetData().getTypeSize(I.getAllocatedType());
|
|
|
|
unsigned Arg;
|
|
|
|
|
|
|
|
if (ConstantUInt *C = dyn_cast<ConstantUInt>(I.getOperand(0))) {
|
|
|
|
Arg = getReg(ConstantUInt::get(Type::UIntTy, C->getValue() * AllocSize));
|
|
|
|
} else {
|
|
|
|
Arg = makeAnotherReg(Type::UIntTy);
|
|
|
|
MachineBasicBlock::iterator MBBI = BB->end();
|
2004-07-21 20:09:08 +00:00
|
|
|
ConstantUInt *CUI = ConstantUInt::get(Type::UIntTy, AllocSize);
|
|
|
|
doMultiplyConst(BB, MBBI, Arg, I.getOperand(0), CUI);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<ValueRecord> Args;
|
|
|
|
Args.push_back(ValueRecord(Arg, Type::UIntTy));
|
2004-06-21 20:22:03 +00:00
|
|
|
MachineInstr *TheCall =
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(mallocFn, true);
|
2004-07-06 22:51:53 +00:00
|
|
|
doCall(ValueRecord(getReg(I), I.getType()), TheCall, Args, false);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// visitFreeInst - Free instructions are code gen'd to call the free libc
|
|
|
|
/// function.
|
|
|
|
///
|
2004-09-21 18:22:19 +00:00
|
|
|
void PPC32ISel::visitFreeInst(FreeInst &I) {
|
2004-06-21 16:55:25 +00:00
|
|
|
std::vector<ValueRecord> Args;
|
|
|
|
Args.push_back(ValueRecord(I.getOperand(0)));
|
2004-06-21 20:22:03 +00:00
|
|
|
MachineInstr *TheCall =
|
2004-08-10 22:47:03 +00:00
|
|
|
BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(freeFn, true);
|
2004-07-06 22:51:53 +00:00
|
|
|
doCall(ValueRecord(0, Type::VoidTy), TheCall, Args, false);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|
|
|
|
|
2004-08-11 00:09:42 +00:00
|
|
|
/// createPPC32ISelSimple - This pass converts an LLVM function into a machine
|
|
|
|
/// code representation is a very simple peep-hole fashion.
|
2004-06-21 16:55:25 +00:00
|
|
|
///
|
2004-08-11 00:09:42 +00:00
|
|
|
FunctionPass *llvm::createPPC32ISelSimple(TargetMachine &TM) {
|
2004-09-21 18:22:19 +00:00
|
|
|
return new PPC32ISel(TM);
|
2004-06-21 16:55:25 +00:00
|
|
|
}
|