mirror of
https://github.com/RPCS3/llvm.git
synced 2025-01-30 07:14:53 +00:00
Fix ARMFastISel::ARMEmitIntExt shift emission
My patch 'r183551 - ARM FastISel integer sext/zext improvements' was incorrect when emitting ARM register-immediate ASR, LSL, LSR instructions: they are pseudo-instructions in ARMInstrInfo.td and I should have used MOVsi instead. This is not an issue when code is generated through a .s file, but is an issue when generated straight to a .o (-filetype=obj). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@186489 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
8d7435e9b1
commit
d055c59544
@ -42,7 +42,6 @@
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/GetElementPtrTypeIterator.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetLowering.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
@ -2631,34 +2630,46 @@ unsigned ARMFastISel::ARMEmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT,
|
||||
};
|
||||
|
||||
// Table governing the instruction(s) to be emitted.
|
||||
static const struct {
|
||||
// First entry for each of the following is sext, second zext.
|
||||
uint16_t Opc[2];
|
||||
uint8_t Imm[2]; // All instructions have either a shift or a mask.
|
||||
uint8_t hasS[2]; // Some instructions have an S bit, always set it to 0.
|
||||
} OpcTbl[2][2][3] = {
|
||||
static const struct InstructionTable {
|
||||
uint32_t Opc : 16;
|
||||
uint32_t hasS : 1; // Some instructions have an S bit, always set it to 0.
|
||||
uint32_t Shift : 7; // For shift operand addressing mode, used by MOVsi.
|
||||
uint32_t Imm : 8; // All instructions have either a shift or a mask.
|
||||
} IT[2][2][3][2] = {
|
||||
{ // Two instructions (first is left shift, second is in this table).
|
||||
{ // ARM
|
||||
/* 1 */ { { ARM::ASRi, ARM::LSRi }, { 31, 31 }, { 1, 1 } },
|
||||
/* 8 */ { { ARM::ASRi, ARM::LSRi }, { 24, 24 }, { 1, 1 } },
|
||||
/* 16 */ { { ARM::ASRi, ARM::LSRi }, { 16, 16 }, { 1, 1 } }
|
||||
{ // ARM Opc S Shift Imm
|
||||
/* 1 bit sext */ { { ARM::MOVsi , 1, ARM_AM::asr , 31 },
|
||||
/* 1 bit zext */ { ARM::MOVsi , 1, ARM_AM::lsr , 31 } },
|
||||
/* 8 bit sext */ { { ARM::MOVsi , 1, ARM_AM::asr , 24 },
|
||||
/* 8 bit zext */ { ARM::MOVsi , 1, ARM_AM::lsr , 24 } },
|
||||
/* 16 bit sext */ { { ARM::MOVsi , 1, ARM_AM::asr , 16 },
|
||||
/* 16 bit zext */ { ARM::MOVsi , 1, ARM_AM::lsr , 16 } }
|
||||
},
|
||||
{ // Thumb
|
||||
/* 1 */ { { ARM::tASRri, ARM::tLSRri }, { 31, 31 }, { 0, 0 } },
|
||||
/* 8 */ { { ARM::tASRri, ARM::tLSRri }, { 24, 24 }, { 0, 0 } },
|
||||
/* 16 */ { { ARM::tASRri, ARM::tLSRri }, { 16, 16 }, { 0, 0 } }
|
||||
{ // Thumb Opc S Shift Imm
|
||||
/* 1 bit sext */ { { ARM::tASRri , 0, ARM_AM::no_shift, 31 },
|
||||
/* 1 bit zext */ { ARM::tLSRri , 0, ARM_AM::no_shift, 31 } },
|
||||
/* 8 bit sext */ { { ARM::tASRri , 0, ARM_AM::no_shift, 24 },
|
||||
/* 8 bit zext */ { ARM::tLSRri , 0, ARM_AM::no_shift, 24 } },
|
||||
/* 16 bit sext */ { { ARM::tASRri , 0, ARM_AM::no_shift, 16 },
|
||||
/* 16 bit zext */ { ARM::tLSRri , 0, ARM_AM::no_shift, 16 } }
|
||||
}
|
||||
},
|
||||
{ // Single instruction.
|
||||
{ // ARM
|
||||
/* 1 */ { { ARM::KILL, ARM::ANDri }, { 0, 1 }, { 0, 1 } },
|
||||
/* 8 */ { { ARM::SXTB, ARM::ANDri }, { 0, 255 }, { 0, 1 } },
|
||||
/* 16 */ { { ARM::SXTH, ARM::UXTH }, { 0, 0 }, { 0, 0 } }
|
||||
{ // ARM Opc S Shift Imm
|
||||
/* 1 bit sext */ { { ARM::KILL , 0, ARM_AM::no_shift, 0 },
|
||||
/* 1 bit zext */ { ARM::ANDri , 1, ARM_AM::no_shift, 1 } },
|
||||
/* 8 bit sext */ { { ARM::SXTB , 0, ARM_AM::no_shift, 0 },
|
||||
/* 8 bit zext */ { ARM::ANDri , 1, ARM_AM::no_shift, 255 } },
|
||||
/* 16 bit sext */ { { ARM::SXTH , 0, ARM_AM::no_shift, 0 },
|
||||
/* 16 bit zext */ { ARM::UXTH , 0, ARM_AM::no_shift, 0 } }
|
||||
},
|
||||
{ // Thumb
|
||||
/* 1 */ { { ARM::KILL, ARM::t2ANDri }, { 0, 1 }, { 0, 1 } },
|
||||
/* 8 */ { { ARM::t2SXTB, ARM::t2ANDri }, { 0, 255 }, { 0, 1 } },
|
||||
/* 16 */ { { ARM::t2SXTH, ARM::t2UXTH }, { 0, 0 }, { 0, 0 } }
|
||||
{ // Thumb Opc S Shift Imm
|
||||
/* 1 bit sext */ { { ARM::KILL , 0, ARM_AM::no_shift, 0 },
|
||||
/* 1 bit zext */ { ARM::t2ANDri, 1, ARM_AM::no_shift, 1 } },
|
||||
/* 8 bit sext */ { { ARM::t2SXTB , 0, ARM_AM::no_shift, 0 },
|
||||
/* 8 bit zext */ { ARM::t2ANDri, 1, ARM_AM::no_shift, 255 } },
|
||||
/* 16 bit sext */ { { ARM::t2SXTH , 0, ARM_AM::no_shift, 0 },
|
||||
/* 16 bit zext */ { ARM::t2UXTH , 0, ARM_AM::no_shift, 0 } }
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -2673,20 +2684,28 @@ unsigned ARMFastISel::ARMEmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT,
|
||||
"other sizes unimplemented");
|
||||
|
||||
bool hasV6Ops = Subtarget->hasV6Ops();
|
||||
unsigned Bitness = countTrailingZeros(SrcBits) >> 1; // {1,8,16}=>{0,1,2}
|
||||
unsigned Bitness = SrcBits / 8; // {1,8,16}=>{0,1,2}
|
||||
assert((Bitness < 3) && "sanity-check table bounds");
|
||||
|
||||
bool isSingleInstr = isSingleInstrTbl[Bitness][isThumb2][hasV6Ops][isZExt];
|
||||
const TargetRegisterClass *RC = RCTbl[isThumb2][isSingleInstr];
|
||||
unsigned Opc = OpcTbl[isSingleInstr][isThumb2][Bitness].Opc[isZExt];
|
||||
const InstructionTable *ITP = &IT[isSingleInstr][isThumb2][Bitness][isZExt];
|
||||
unsigned Opc = ITP->Opc;
|
||||
assert(ARM::KILL != Opc && "Invalid table entry");
|
||||
unsigned Imm = OpcTbl[isSingleInstr][isThumb2][Bitness].Imm[isZExt];
|
||||
unsigned hasS = OpcTbl[isSingleInstr][isThumb2][Bitness].hasS[isZExt];
|
||||
unsigned hasS = ITP->hasS;
|
||||
ARM_AM::ShiftOpc Shift = (ARM_AM::ShiftOpc) ITP->Shift;
|
||||
assert(((Shift == ARM_AM::no_shift) == (Opc != ARM::MOVsi)) &&
|
||||
"only MOVsi has shift operand addressing mode");
|
||||
unsigned Imm = ITP->Imm;
|
||||
|
||||
// 16-bit Thumb instructions always set CPSR (unless they're in an IT block).
|
||||
bool setsCPSR = &ARM::tGPRRegClass == RC;
|
||||
unsigned LSLOpc = isThumb2 ? ARM::tLSLri : ARM::LSLi;
|
||||
unsigned LSLOpc = isThumb2 ? ARM::tLSLri : ARM::MOVsi;
|
||||
unsigned ResultReg;
|
||||
// MOVsi encodes shift and immediate in shift operand addressing mode.
|
||||
// The following condition has the same value when emitting two
|
||||
// instruction sequences: both are shifts.
|
||||
bool ImmIsSO = (Shift != ARM_AM::no_shift);
|
||||
|
||||
// Either one or two instructions are emitted.
|
||||
// They're always of the form:
|
||||
@ -2699,13 +2718,16 @@ unsigned ARMFastISel::ARMEmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT,
|
||||
unsigned NumInstrsEmitted = isSingleInstr ? 1 : 2;
|
||||
for (unsigned Instr = 0; Instr != NumInstrsEmitted; ++Instr) {
|
||||
ResultReg = createResultReg(RC);
|
||||
unsigned Opcode = ((0 == Instr) && !isSingleInstr) ? LSLOpc : Opc;
|
||||
bool isLsl = (0 == Instr) && !isSingleInstr;
|
||||
unsigned Opcode = isLsl ? LSLOpc : Opc;
|
||||
ARM_AM::ShiftOpc ShiftAM = isLsl ? ARM_AM::lsl : Shift;
|
||||
unsigned ImmEnc = ImmIsSO ? ARM_AM::getSORegOpc(ShiftAM, Imm) : Imm;
|
||||
bool isKill = 1 == Instr;
|
||||
MachineInstrBuilder MIB = BuildMI(
|
||||
*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opcode), ResultReg);
|
||||
if (setsCPSR)
|
||||
MIB.addReg(ARM::CPSR, RegState::Define);
|
||||
AddDefaultPred(MIB.addReg(SrcReg, isKill * RegState::Kill).addImm(Imm));
|
||||
AddDefaultPred(MIB.addReg(SrcReg, isKill * RegState::Kill).addImm(ImmEnc));
|
||||
if (hasS)
|
||||
AddDefaultCC(MIB);
|
||||
// Second instruction consumes the first's result.
|
||||
|
Loading…
x
Reference in New Issue
Block a user