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:
JF Bastien 2013-07-17 05:46:46 +00:00
parent 8d7435e9b1
commit d055c59544

View File

@ -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.