mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-17 21:29:20 +00:00
Implement more complete and correct codegen for bitfield inserts, as tested
by the recently committed rlwimi.ll test file. Also commit initial code for bitfield extract, although it is turned off until fully debugged. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@17207 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2a40841387
commit
905a29152f
@ -32,8 +32,6 @@
|
|||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
Statistic<> Bitfields("ppc-codegen", "Number of bitfield inserts");
|
|
||||||
|
|
||||||
/// TypeClass - Used by the PowerPC backend to group LLVM types by their basic
|
/// TypeClass - Used by the PowerPC backend to group LLVM types by their basic
|
||||||
/// PPC Representation.
|
/// PPC Representation.
|
||||||
///
|
///
|
||||||
@ -99,19 +97,18 @@ namespace {
|
|||||||
FoldedGEP(unsigned b, unsigned i, ConstantSInt *o) :
|
FoldedGEP(unsigned b, unsigned i, ConstantSInt *o) :
|
||||||
base(b), index(i), offset(o) {}
|
base(b), index(i), offset(o) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// RlwimiRec - This struct is for recording the necessary information to
|
/// RlwimiRec - This struct is for recording the arguments to a PowerPC
|
||||||
/// emit a PowerPC rlwimi instruction for a bitfield insert rather than
|
/// rlwimi instruction to be output for a particular Instruction::Or when
|
||||||
/// a sequence of shifts and ands, followed by an or.
|
/// we recognize the pattern for rlwimi, starting with a shift or and.
|
||||||
struct RlwimiRec {
|
struct RlwimiRec {
|
||||||
unsigned Shift;
|
Value *Target, *Insert;
|
||||||
unsigned MB, ME;
|
unsigned Shift, MB, ME;
|
||||||
Value *Op0, *Op1;
|
RlwimiRec() : Target(0), Insert(0), Shift(0), MB(0), ME(0) {}
|
||||||
RlwimiRec() : Shift(0), MB(0), ME(0), Op0(0), Op1(0) {}
|
RlwimiRec(Value *tgt, Value *ins, unsigned s, unsigned b, unsigned e) :
|
||||||
RlwimiRec(unsigned s, unsigned b, unsigned e, Value *y, Value *z) :
|
Target(tgt), Insert(ins), Shift(s), MB(b), ME(e) {}
|
||||||
Shift(s), MB(b), ME(e), Op0(y), Op1(z) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// External functions used in the Module
|
// External functions used in the Module
|
||||||
Function *fmodfFn, *fmodFn, *__cmpdi2Fn, *__moddi3Fn, *__divdi3Fn,
|
Function *fmodfFn, *fmodFn, *__cmpdi2Fn, *__moddi3Fn, *__divdi3Fn,
|
||||||
*__umoddi3Fn, *__udivdi3Fn, *__fixsfdiFn, *__fixdfdiFn, *__fixunssfdiFn,
|
*__umoddi3Fn, *__udivdi3Fn, *__fixsfdiFn, *__fixdfdiFn, *__fixunssfdiFn,
|
||||||
@ -132,7 +129,11 @@ namespace {
|
|||||||
|
|
||||||
// RlwimiMap - Mapping between BinaryOperand (Or) instructions and info
|
// RlwimiMap - Mapping between BinaryOperand (Or) instructions and info
|
||||||
// needed to properly emit a rlwimi instruction in its place.
|
// needed to properly emit a rlwimi instruction in its place.
|
||||||
std::map<BinaryOperator *, RlwimiRec> RlwimiMap;
|
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.
|
||||||
std::vector<Instruction *> SkipList;
|
std::vector<Instruction *> SkipList;
|
||||||
|
|
||||||
// A Reg to hold the base address used for global loads and stores, and a
|
// A Reg to hold the base address used for global loads and stores, and a
|
||||||
@ -215,8 +216,8 @@ namespace {
|
|||||||
GEPMap.clear();
|
GEPMap.clear();
|
||||||
RegMap.clear();
|
RegMap.clear();
|
||||||
MBBMap.clear();
|
MBBMap.clear();
|
||||||
|
InsertMap.clear();
|
||||||
AllocaMap.clear();
|
AllocaMap.clear();
|
||||||
RlwimiMap.clear();
|
|
||||||
SkipList.clear();
|
SkipList.clear();
|
||||||
F = 0;
|
F = 0;
|
||||||
// We always build a machine code representation for the function
|
// We always build a machine code representation for the function
|
||||||
@ -339,10 +340,18 @@ namespace {
|
|||||||
|
|
||||||
|
|
||||||
/// emitBitfieldInsert - return true if we were able to fold the sequence of
|
/// emitBitfieldInsert - return true if we were able to fold the sequence of
|
||||||
/// instructions starting with AndI into a bitfield insert.
|
/// instructions into a bitfield insert (rlwimi).
|
||||||
bool PPC32ISel::emitBitfieldInsert(BinaryOperator *AndI,
|
bool emitBitfieldInsert(MachineBasicBlock *MBB,
|
||||||
unsigned ShlAmount,
|
MachineBasicBlock::iterator IP,
|
||||||
Value *InsertOp);
|
User *OpUser, unsigned DestReg);
|
||||||
|
|
||||||
|
/// 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,
|
||||||
|
BinaryOperator *AndI, Value *Op,
|
||||||
|
unsigned Amount, bool isLeftShift,
|
||||||
|
unsigned DestReg);
|
||||||
|
|
||||||
/// emitBinaryConstOperation - Used by several functions to emit simple
|
/// emitBinaryConstOperation - Used by several functions to emit simple
|
||||||
/// arithmetic and logical operations with constants on a register rather
|
/// arithmetic and logical operations with constants on a register rather
|
||||||
@ -359,8 +368,7 @@ namespace {
|
|||||||
///
|
///
|
||||||
void emitSimpleBinaryOperation(MachineBasicBlock *BB,
|
void emitSimpleBinaryOperation(MachineBasicBlock *BB,
|
||||||
MachineBasicBlock::iterator IP,
|
MachineBasicBlock::iterator IP,
|
||||||
BinaryOperator *BO,
|
BinaryOperator *BO, Value *Op0, Value *Op1,
|
||||||
Value *Op0, Value *Op1,
|
|
||||||
unsigned OperatorClass, unsigned TargetReg);
|
unsigned OperatorClass, unsigned TargetReg);
|
||||||
|
|
||||||
/// emitBinaryFPOperation - This method handles emission of floating point
|
/// emitBinaryFPOperation - This method handles emission of floating point
|
||||||
@ -2021,23 +2029,23 @@ void PPC32ISel::visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI) {
|
|||||||
/// Xor.
|
/// Xor.
|
||||||
///
|
///
|
||||||
void PPC32ISel::visitSimpleBinary(BinaryOperator &B, unsigned OperatorClass) {
|
void PPC32ISel::visitSimpleBinary(BinaryOperator &B, unsigned OperatorClass) {
|
||||||
unsigned DestReg = getReg(B);
|
|
||||||
MachineBasicBlock::iterator MI = BB->end();
|
|
||||||
Value *Op0 = B.getOperand(0), *Op1 = B.getOperand(1);
|
|
||||||
unsigned Class = getClassB(B.getType());
|
|
||||||
|
|
||||||
if (std::find(SkipList.begin(), SkipList.end(), &B) != SkipList.end())
|
if (std::find(SkipList.begin(), SkipList.end(), &B) != SkipList.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RlwimiRec r = RlwimiMap[&B];
|
unsigned DestReg = getReg(B);
|
||||||
if (0 != r.Op0) {
|
MachineBasicBlock::iterator MI = BB->end();
|
||||||
unsigned Op0Reg = getReg(r.Op0, BB, MI);
|
RlwimiRec RR = InsertMap[&B];
|
||||||
unsigned Op1Reg = getReg(r.Op1, BB, MI);
|
if (RR.Target != 0) {
|
||||||
BuildMI(*BB, MI, PPC::RLWIMI, 5, DestReg).addReg(Op1Reg)
|
unsigned TargetReg = getReg(RR.Target, BB, MI);
|
||||||
.addReg(Op0Reg).addImm(r.Shift).addImm(r.MB).addImm(r.ME);
|
unsigned InsertReg = getReg(RR.Insert, BB, MI);
|
||||||
} else {
|
BuildMI(*BB, MI, PPC::RLWIMI, 5, DestReg).addReg(TargetReg)
|
||||||
emitSimpleBinaryOperation(BB, MI, &B, Op0, Op1, OperatorClass, DestReg);
|
.addReg(InsertReg).addImm(RR.Shift).addImm(RR.MB).addImm(RR.ME);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned Class = getClassB(B.getType());
|
||||||
|
Value *Op0 = B.getOperand(0), *Op1 = B.getOperand(1);
|
||||||
|
emitSimpleBinaryOperation(BB, MI, &B, Op0, Op1, OperatorClass, DestReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// emitBinaryFPOperation - This method handles emission of floating point
|
/// emitBinaryFPOperation - This method handles emission of floating point
|
||||||
@ -2134,52 +2142,189 @@ static bool isRunOfOnes(unsigned Val, unsigned &MB, unsigned &ME) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// emitBitfieldInsert - return true if we were able to fold the sequence of
|
/// isInsertAndHalf - Helper function for emitBitfieldInsert. Returns true if
|
||||||
/// instructions starting with AndI into a bitfield insert.
|
/// OpUser has one use, is used by an or instruction, and is itself an and whose
|
||||||
bool PPC32ISel::emitBitfieldInsert(BinaryOperator *AndI, unsigned ShlAmount,
|
/// second operand is a constant int. Optionally, set OrI to the Or instruction
|
||||||
Value *InsertOp) {
|
/// that is the sole user of OpUser, and Op1User to the other operand of the Or
|
||||||
if (AndI->hasOneUse()) {
|
/// instruction.
|
||||||
ConstantInt *CI_1 = dyn_cast<ConstantInt>(AndI->getOperand(1));
|
static bool isInsertAndHalf(User *OpUser, Instruction **Op1User,
|
||||||
BinaryOperator *OrI = dyn_cast<BinaryOperator>(*(AndI->use_begin()));
|
Instruction **OrI, unsigned &Mask) {
|
||||||
if (CI_1 && OrI && OrI->getOpcode() == Instruction::Or) {
|
// If this instruction doesn't have one use, then return false.
|
||||||
Value *Op0 = OrI->getOperand(0);
|
if (!OpUser->hasOneUse())
|
||||||
Value *Op1 = OrI->getOperand(1);
|
return false;
|
||||||
BinaryOperator *AndI_2 = 0;
|
|
||||||
// Whichever operand our initial And instruction is to the Or instruction,
|
Mask = 0xFFFFFFFF;
|
||||||
// Look at the other operand to determine if it is also an And instruction
|
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(OpUser))
|
||||||
if (AndI == Op0) {
|
if (BO->getOpcode() == Instruction::And) {
|
||||||
AndI_2 = dyn_cast<BinaryOperator>(Op1);
|
Value *AndUse = *(OpUser->use_begin());
|
||||||
} else if (AndI == Op1) {
|
if (BinaryOperator *Or = dyn_cast<BinaryOperator>(AndUse)) {
|
||||||
AndI_2 = dyn_cast<BinaryOperator>(Op0);
|
if (Or->getOpcode() == Instruction::Or) {
|
||||||
std::swap(Op0, Op1);
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(OpUser->getOperand(1))) {
|
||||||
} else {
|
if (OrI) *OrI = Or;
|
||||||
assert(0 && "And instruction not used in Or!");
|
if (Op1User) {
|
||||||
}
|
if (Or->getOperand(0) == OpUser)
|
||||||
// Verify that the second operand to the Or is an And with one use
|
*Op1User = dyn_cast<Instruction>(Or->getOperand(1));
|
||||||
if (AndI_2 && AndI_2->hasOneUse()
|
else
|
||||||
&& AndI_2->getOpcode() == Instruction::And) {
|
*Op1User = dyn_cast<Instruction>(Or->getOperand(0));
|
||||||
// Check to see if this And instruction also has a constant int operand.
|
|
||||||
// If it does, then we can replace this sequence of instructions with an
|
|
||||||
// insert if the sum of the two ConstantInts has all bits set, and
|
|
||||||
// one is a run of ones (which implies the other is as well).
|
|
||||||
ConstantInt *CI_2 = dyn_cast<ConstantInt>(AndI_2->getOperand(1));
|
|
||||||
if (CI_2) {
|
|
||||||
unsigned Imm1 = CI_1->getRawValue();
|
|
||||||
unsigned Imm2 = CI_2->getRawValue();
|
|
||||||
if (Imm1 + Imm2 == 0xFFFFFFFF) {
|
|
||||||
unsigned MB, ME;
|
|
||||||
if (isRunOfOnes(Imm1, MB, ME)) {
|
|
||||||
++Bitfields;
|
|
||||||
SkipList.push_back(AndI);
|
|
||||||
SkipList.push_back(AndI_2);
|
|
||||||
RlwimiMap[OrI] = RlwimiRec(ShlAmount, MB, ME,
|
|
||||||
InsertOp, AndI_2->getOperand(0));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
bool PPC32ISel::emitBitfieldInsert(MachineBasicBlock *MBB,
|
||||||
|
MachineBasicBlock::iterator IP,
|
||||||
|
User *OpUser, unsigned DestReg) {
|
||||||
|
// 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,
|
||||||
|
BinaryOperator *BO, Value *Op,
|
||||||
|
unsigned Amount, bool isLeftShift,
|
||||||
|
unsigned DestReg) {
|
||||||
|
return false;
|
||||||
|
if (BO && BO->getOpcode() == Instruction::And) {
|
||||||
|
// Since the powerpc shift instructions are really rotate left, subtract 32
|
||||||
|
// to simulate a right shift.
|
||||||
|
unsigned Rotate = (isLeftShift) ? Amount : 32 - Amount;
|
||||||
|
|
||||||
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(BO->getOperand(1))) {
|
||||||
|
unsigned Imm = CI->getRawValue(), MB, ME;
|
||||||
|
// In the case of a left shift or unsigned right shift, be sure to clear
|
||||||
|
// any bits that would have been zeroes shifted in from the left or right.
|
||||||
|
// Usually instcombine will do this for us, but there's no guarantee the
|
||||||
|
// optimization has been performed already.
|
||||||
|
//
|
||||||
|
// Also, take this opportunity to check for the algebraic right shift case
|
||||||
|
// where the mask would overlap sign bits shifted in from the left. We do
|
||||||
|
// not want to perform the optimization in that case since we could clear
|
||||||
|
// bits that should be set. Think of int (x >> 17) & 0x0000FFFF;
|
||||||
|
unsigned mask = 0xFFFFFFFF;
|
||||||
|
if (isLeftShift)
|
||||||
|
Imm &= (mask << Amount);
|
||||||
|
else if (!isLeftShift && !Op->getType()->isSigned())
|
||||||
|
Imm &= (mask >> Amount);
|
||||||
|
else if (((mask << Rotate) & Imm) != 0)
|
||||||
|
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);
|
||||||
|
BO->replaceAllUsesWith(Op->use_back());
|
||||||
|
SkipList.push_back(BO);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2322,9 +2467,9 @@ void PPC32ISel::emitSimpleBinaryOperation(MachineBasicBlock *MBB,
|
|||||||
// Special case: op Reg, <const int>
|
// Special case: op Reg, <const int>
|
||||||
if (ConstantInt *CI = dyn_cast<ConstantInt>(Op1))
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(Op1))
|
||||||
if (Class != cLong) {
|
if (Class != cLong) {
|
||||||
if (OperatorClass == 2 && emitBitfieldInsert(BO, 0, Op0))
|
if (emitBitfieldInsert(MBB, IP, BO, DestReg))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unsigned Op0r = getReg(Op0, MBB, IP);
|
unsigned Op0r = getReg(Op0, MBB, IP);
|
||||||
emitBinaryConstOperation(MBB, IP, Op0r, CI, OperatorClass, DestReg);
|
emitBinaryConstOperation(MBB, IP, Op0r, CI, OperatorClass, DestReg);
|
||||||
return;
|
return;
|
||||||
@ -2619,6 +2764,9 @@ void PPC32ISel::emitDivRemOperation(MachineBasicBlock *MBB,
|
|||||||
/// because the shift amount has to be in CL, not just any old register.
|
/// because the shift amount has to be in CL, not just any old register.
|
||||||
///
|
///
|
||||||
void PPC32ISel::visitShiftInst(ShiftInst &I) {
|
void PPC32ISel::visitShiftInst(ShiftInst &I) {
|
||||||
|
if (std::find(SkipList.begin(), SkipList.end(), &I) != SkipList.end())
|
||||||
|
return;
|
||||||
|
|
||||||
MachineBasicBlock::iterator IP = BB->end();
|
MachineBasicBlock::iterator IP = BB->end();
|
||||||
emitShiftOperation(BB, IP, I.getOperand(0), I.getOperand(1),
|
emitShiftOperation(BB, IP, I.getOperand(0), I.getOperand(1),
|
||||||
I.getOpcode() == Instruction::Shl, I.getType(),
|
I.getOpcode() == Instruction::Shl, I.getType(),
|
||||||
@ -2776,17 +2924,16 @@ void PPC32ISel::emitShiftOperation(MachineBasicBlock *MBB,
|
|||||||
assert(CUI->getType() == Type::UByteTy && "Shift amount not a ubyte?");
|
assert(CUI->getType() == Type::UByteTy && "Shift amount not a ubyte?");
|
||||||
unsigned Amount = CUI->getValue();
|
unsigned Amount = CUI->getValue();
|
||||||
|
|
||||||
// If this is a left shift with one use, and that use is an And instruction,
|
// If this is a shift with one use, and that use is an And instruction,
|
||||||
// then attempt to emit a bitfield insert.
|
// then attempt to emit a bitfield operation.
|
||||||
if (isLeftShift) {
|
User *U = Op->use_back();
|
||||||
User *U = Op->use_back();
|
if (U->hasOneUse()) {
|
||||||
if (U->hasOneUse()) {
|
BinaryOperator *BO = dyn_cast<BinaryOperator>(*(U->use_begin()));
|
||||||
Value *V = *(U->use_begin());
|
if (BO) {
|
||||||
BinaryOperator *BO = dyn_cast<BinaryOperator>(V);
|
if (emitBitfieldInsert(MBB, IP, U, DestReg))
|
||||||
if (BO && BO->getOpcode() == Instruction::And) {
|
return;
|
||||||
if (emitBitfieldInsert(BO, Amount, Op))
|
if (emitBitfieldExtract(MBB, IP, BO, Op, Amount, isLeftShift, DestReg))
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user