forked from OSchip/llvm-project
The MC code couldn't handle ARM LDR instructions with negative offsets:
vldr.64 d1, [r0, #-32] The problem was with how the addressing mode 5 encodes the offsets. This change makes sure that the way offsets are handled in addressing mode 5 is consistent throughout the MC code. It involves re-refactoring the "getAddrModeImmOpValue" method into an "Imm12" and "addressing mode 5" version. But not to worry! The majority of the duplicated code has been unified. llvm-svn: 118144
This commit is contained in:
parent
68fb004616
commit
e84eb99cbb
|
@ -177,25 +177,44 @@ namespace {
|
|||
const { return 0; }
|
||||
unsigned getBitfieldInvertedMaskOpValue(const MachineInstr &MI,
|
||||
unsigned Op) const { return 0; }
|
||||
uint32_t getAddrModeImmOpValue(const MachineInstr &MI, unsigned Op) const {
|
||||
// {20-17} = reg
|
||||
// {16} = (U)nsigned (add == '1', sub == '0')
|
||||
// {15-0} = imm
|
||||
|
||||
unsigned getAddrModeImm12OpValue(const MachineInstr &MI, unsigned Op)
|
||||
const {
|
||||
// {17-13} = reg
|
||||
// {12} = (U)nsigned (add == '1', sub == '0')
|
||||
// {11-0} = imm12
|
||||
const MachineOperand &MO = MI.getOperand(Op);
|
||||
const MachineOperand &MO1 = MI.getOperand(Op + 1);
|
||||
if (!MO.isReg()) {
|
||||
emitConstPoolAddress(MO.getIndex(), ARM::reloc_arm_cp_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned Reg = getARMRegisterNumbering(MO.getReg());
|
||||
int32_t Imm = MO1.getImm();
|
||||
int32_t Imm12 = MO1.getImm();
|
||||
uint32_t Binary;
|
||||
Binary = Imm & 0xffff;
|
||||
if (Imm >= 0)
|
||||
Binary |= (1 << 16);
|
||||
|
||||
Binary |= (Reg << 17);
|
||||
Binary = Imm12 & 0xfff;
|
||||
if (Imm12 >= 0)
|
||||
Binary |= (1 << 12);
|
||||
Binary |= (Reg << 13);
|
||||
return Binary;
|
||||
}
|
||||
uint32_t getAddrMode5OpValue(const MachineInstr &MI, unsigned Op) const {
|
||||
// {12-9} = reg
|
||||
// {8} = (U)nsigned (add == '1', sub == '0')
|
||||
// {7-0} = imm12
|
||||
const MachineOperand &MO = MI.getOperand(Op);
|
||||
const MachineOperand &MO1 = MI.getOperand(Op + 1);
|
||||
if (!MO.isReg()) {
|
||||
emitConstPoolAddress(MO.getIndex(), ARM::reloc_arm_cp_entry);
|
||||
return 0;
|
||||
}
|
||||
unsigned Reg = getARMRegisterNumbering(MO.getReg());
|
||||
int32_t Imm8 = MO1.getImm();
|
||||
uint32_t Binary;
|
||||
Binary = Imm8 & 0xff;
|
||||
if (Imm8 >= 0)
|
||||
Binary |= (1 << 8);
|
||||
Binary |= (Reg << 9);
|
||||
return Binary;
|
||||
}
|
||||
unsigned getNEONVcvtImm32OpValue(const MachineInstr &MI, unsigned Op)
|
||||
|
|
|
@ -398,7 +398,7 @@ def addrmode_imm12 : Operand<i32>,
|
|||
// #0 and #-0 differently. We flag #-0 as the magic value INT32_MIN. All other
|
||||
// immediate values are as normal.
|
||||
|
||||
string EncoderMethod = "getAddrModeImmOpValue";
|
||||
string EncoderMethod = "getAddrModeImm12OpValue";
|
||||
let PrintMethod = "printAddrModeImm12Operand";
|
||||
let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
|
||||
}
|
||||
|
@ -462,7 +462,7 @@ def addrmode5 : Operand<i32>,
|
|||
let PrintMethod = "printAddrMode5Operand";
|
||||
let MIOperandInfo = (ops GPR:$base, i32imm);
|
||||
let ParserMatchClass = ARMMemMode5AsmOperand;
|
||||
string EncoderMethod = "getAddrModeImmOpValue";
|
||||
string EncoderMethod = "getAddrMode5OpValue";
|
||||
}
|
||||
|
||||
// addrmode6 := reg with optional writeback
|
||||
|
@ -828,20 +828,20 @@ multiclass AI_ldr1<bit opc22, string opc, InstrItinClass iii,
|
|||
def i12 : AIldst1<0b010, opc22, 1, (outs GPR:$Rt), (ins addrmode_imm12:$addr),
|
||||
AddrMode_i12, LdFrm, iii, opc, "\t$Rt, $addr",
|
||||
[(set GPR:$Rt, (opnode addrmode_imm12:$addr))]> {
|
||||
bits<4> Rt;
|
||||
bits<32> addr;
|
||||
let Inst{23} = addr{16}; // U (add = ('U' == 1))
|
||||
let Inst{19-16} = addr{20-17}; // Rn
|
||||
bits<4> Rt;
|
||||
bits<17> addr;
|
||||
let Inst{23} = addr{12}; // U (add = ('U' == 1))
|
||||
let Inst{19-16} = addr{16-13}; // Rn
|
||||
let Inst{15-12} = Rt;
|
||||
let Inst{11-0} = addr{11-0}; // imm12
|
||||
}
|
||||
def rs : AIldst1<0b011, opc22, 1, (outs GPR:$Rt), (ins ldst_so_reg:$shift),
|
||||
AddrModeNone, LdFrm, iir, opc, "\t$Rt, $shift",
|
||||
[(set GPR:$Rt, (opnode ldst_so_reg:$shift))]> {
|
||||
bits<4> Rt;
|
||||
bits<32> shift;
|
||||
let Inst{23} = shift{16}; // U (add = ('U' == 1))
|
||||
let Inst{19-16} = shift{20-17}; // Rn
|
||||
bits<4> Rt;
|
||||
bits<17> shift;
|
||||
let Inst{23} = shift{12}; // U (add = ('U' == 1))
|
||||
let Inst{19-16} = shift{16-13}; // Rn
|
||||
let Inst{11-0} = shift{11-0};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,25 +51,38 @@ def vfp_f64imm : Operand<f64>,
|
|||
//
|
||||
|
||||
let canFoldAsLoad = 1, isReMaterializable = 1 in {
|
||||
|
||||
def VLDRD : ADI5<0b1101, 0b01, (outs DPR:$Dd), (ins addrmode5:$addr),
|
||||
IIC_fpLoad64, "vldr", ".64\t$Dd, $addr",
|
||||
[(set DPR:$Dd, (f64 (load addrmode5:$addr)))]> {
|
||||
// Instruction operands.
|
||||
bits<5> Dd;
|
||||
bits<32> addr;
|
||||
bits<5> Dd;
|
||||
bits<13> addr;
|
||||
|
||||
// Encode instruction operands.
|
||||
let Inst{23} = addr{16}; // U (add = (U == '1'))
|
||||
let Inst{23} = addr{8}; // U (add = (U == '1'))
|
||||
let Inst{22} = Dd{4};
|
||||
let Inst{19-16} = addr{20-17}; // Rn
|
||||
let Inst{19-16} = addr{12-9}; // Rn
|
||||
let Inst{15-12} = Dd{3-0};
|
||||
let Inst{7-0} = addr{7-0}; // imm8
|
||||
}
|
||||
|
||||
def VLDRS : ASI5<0b1101, 0b01, (outs SPR:$dst), (ins addrmode5:$addr),
|
||||
IIC_fpLoad32, "vldr", ".32\t$dst, $addr",
|
||||
[(set SPR:$dst, (load addrmode5:$addr))]>;
|
||||
} // canFoldAsLoad
|
||||
def VLDRS : ASI5<0b1101, 0b01, (outs SPR:$Sd), (ins addrmode5:$addr),
|
||||
IIC_fpLoad32, "vldr", ".32\t$Sd, $addr",
|
||||
[(set SPR:$Sd, (load addrmode5:$addr))]> {
|
||||
// Instruction operands.
|
||||
bits<5> Sd;
|
||||
bits<13> addr;
|
||||
|
||||
// Encode instruction operands.
|
||||
let Inst{23} = addr{8}; // U (add = (U == '1'))
|
||||
let Inst{22} = Sd{0};
|
||||
let Inst{19-16} = addr{12-9}; // Rn
|
||||
let Inst{15-12} = Sd{4-1};
|
||||
let Inst{7-0} = addr{7-0}; // imm8
|
||||
}
|
||||
|
||||
} // End of 'let canFoldAsLoad = 1, isReMaterializable = 1 in'
|
||||
|
||||
def VSTRD : ADI5<0b1101, 0b00, (outs), (ins DPR:$src, addrmode5:$addr),
|
||||
IIC_fpStore64, "vstr", ".64\t$src, $addr",
|
||||
|
|
|
@ -49,8 +49,15 @@ public:
|
|||
/// operand requires relocation, record the relocation and return zero.
|
||||
unsigned getMachineOpValue(const MCInst &MI,const MCOperand &MO) const;
|
||||
|
||||
/// getAddrModeImmOpValue - Return encoding info for 'reg +/- imm' operand.
|
||||
uint32_t getAddrModeImmOpValue(const MCInst &MI, unsigned Op) const;
|
||||
bool EncodeAddrModeOpValues(const MCInst &MI, unsigned OpIdx,
|
||||
unsigned &Reg, unsigned &Imm) const;
|
||||
|
||||
/// getAddrModeImm12OpValue - Return encoding info for 'reg +/- imm12'
|
||||
/// operand.
|
||||
uint32_t getAddrModeImm12OpValue(const MCInst &MI, unsigned OpIdx) const;
|
||||
|
||||
/// getAddrMode5OpValue - Return encoding info for 'reg +/- imm8' operand.
|
||||
uint32_t getAddrMode5OpValue(const MCInst &MI, unsigned OpIdx) const;
|
||||
|
||||
/// getCCOutOpValue - Return encoding of the 's' bit.
|
||||
unsigned getCCOutOpValue(const MCInst &MI, unsigned Op) const {
|
||||
|
@ -170,37 +177,76 @@ unsigned ARMMCCodeEmitter::getMachineOpValue(const MCInst &MI,
|
|||
}
|
||||
|
||||
/// getAddrModeImmOpValue - Return encoding info for 'reg +/- imm' operand.
|
||||
uint32_t ARMMCCodeEmitter::getAddrModeImmOpValue(const MCInst &MI,
|
||||
unsigned OpIdx) const {
|
||||
// {20-17} = reg
|
||||
// {16} = (U)nsigned (add == '1', sub == '0')
|
||||
// {15-0} = imm
|
||||
bool ARMMCCodeEmitter::EncodeAddrModeOpValues(const MCInst &MI, unsigned OpIdx,
|
||||
unsigned &Reg,
|
||||
unsigned &Imm) const {
|
||||
const MCOperand &MO = MI.getOperand(OpIdx);
|
||||
const MCOperand &MO1 = MI.getOperand(OpIdx + 1);
|
||||
uint32_t Binary = 0;
|
||||
|
||||
// If The first operand isn't a register, we have a label reference.
|
||||
if (!MO.isReg()) {
|
||||
Binary |= ARM::PC << 17; // Rn is PC.
|
||||
Reg = ARM::PC; // Rn is PC.
|
||||
Imm = 0;
|
||||
// FIXME: Add a fixup referencing the label.
|
||||
return Binary;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned Reg = getARMRegisterNumbering(MO.getReg());
|
||||
int32_t Imm = MO1.getImm();
|
||||
bool isAdd = Imm >= 0;
|
||||
Reg = getARMRegisterNumbering(MO.getReg());
|
||||
|
||||
int32_t SImm = MO1.getImm();
|
||||
bool isAdd = true;
|
||||
|
||||
// Special value for #-0
|
||||
if (Imm == INT32_MIN)
|
||||
Imm = 0;
|
||||
if (SImm == INT32_MIN)
|
||||
SImm = 0;
|
||||
|
||||
// Immediate is always encoded as positive. The 'U' bit controls add vs sub.
|
||||
if (Imm < 0) Imm = -Imm;
|
||||
if (SImm < 0) {
|
||||
SImm = -SImm;
|
||||
isAdd = false;
|
||||
}
|
||||
|
||||
Binary = Imm & 0xffff;
|
||||
Imm = SImm;
|
||||
return isAdd;
|
||||
}
|
||||
|
||||
/// getAddrModeImm12OpValue - Return encoding info for 'reg +/- imm12' operand.
|
||||
uint32_t ARMMCCodeEmitter::getAddrModeImm12OpValue(const MCInst &MI,
|
||||
unsigned OpIdx) const {
|
||||
// {17-13} = reg
|
||||
// {12} = (U)nsigned (add == '1', sub == '0')
|
||||
// {11-0} = imm12
|
||||
unsigned Reg, Imm12;
|
||||
bool isAdd = EncodeAddrModeOpValues(MI, OpIdx, Reg, Imm12);
|
||||
|
||||
if (Reg == ARM::PC)
|
||||
return ARM::PC << 13; // Rn is PC;
|
||||
|
||||
uint32_t Binary = Imm12 & 0xfff;
|
||||
// Immediate is always encoded as positive. The 'U' bit controls add vs sub.
|
||||
if (isAdd)
|
||||
Binary |= (1 << 16);
|
||||
Binary |= (Reg << 17);
|
||||
Binary |= (1 << 12);
|
||||
Binary |= (Reg << 13);
|
||||
return Binary;
|
||||
}
|
||||
|
||||
/// getAddrMode5OpValue - Return encoding info for 'reg +/- imm12' operand.
|
||||
uint32_t ARMMCCodeEmitter::getAddrMode5OpValue(const MCInst &MI,
|
||||
unsigned OpIdx) const {
|
||||
// {12-9} = reg
|
||||
// {8} = (U)nsigned (add == '1', sub == '0')
|
||||
// {7-0} = imm8
|
||||
unsigned Reg, Imm8;
|
||||
EncodeAddrModeOpValues(MI, OpIdx, Reg, Imm8);
|
||||
|
||||
if (Reg == ARM::PC)
|
||||
return ARM::PC << 13; // Rn is PC;
|
||||
|
||||
uint32_t Binary = ARM_AM::getAM5Offset(Imm8);
|
||||
// Immediate is always encoded as positive. The 'U' bit controls add vs sub.
|
||||
if (ARM_AM::getAM5Op(Imm8) == ARM_AM::add)
|
||||
Binary |= (1 << 8);
|
||||
Binary |= (Reg << 9);
|
||||
return Binary;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ARM.h"
|
||||
#include "ARMAddressingModes.h"
|
||||
#include "ARMSubtarget.h"
|
||||
#include "llvm/MC/MCParser/MCAsmLexer.h"
|
||||
#include "llvm/MC/MCParser/MCAsmParser.h"
|
||||
|
@ -260,16 +261,25 @@ public:
|
|||
|
||||
Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum));
|
||||
assert(!Mem.OffsetIsReg && "invalid mode 5 operand");
|
||||
|
||||
// FIXME: #-0 is encoded differently than #0. Does the parser preserve
|
||||
// the difference?
|
||||
if (Mem.Offset) {
|
||||
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.Offset);
|
||||
assert(CE && "non-constant mode 5 offset operand!");
|
||||
assert(CE && "Non-constant mode 5 offset operand!");
|
||||
|
||||
// The MCInst offset operand doesn't include the low two bits (like
|
||||
// the instruction encoding).
|
||||
Inst.addOperand(MCOperand::CreateImm(CE->getValue() / 4));
|
||||
} else
|
||||
int64_t Offset = CE->getValue() / 4;
|
||||
if (Offset >= 0)
|
||||
Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(ARM_AM::add,
|
||||
Offset)));
|
||||
else
|
||||
Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(ARM_AM::sub,
|
||||
-Offset)));
|
||||
} else {
|
||||
Inst.addOperand(MCOperand::CreateImm(0));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void dump(raw_ostream &OS) const;
|
||||
|
|
|
@ -310,7 +310,7 @@ void ARMInstPrinter::printAddrMode5Operand(const MCInst *MI, unsigned OpNum,
|
|||
if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) {
|
||||
O << ", #"
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm()))
|
||||
<< ImmOffs*4;
|
||||
<< ImmOffs * 4;
|
||||
}
|
||||
O << "]";
|
||||
}
|
||||
|
|
|
@ -162,8 +162,9 @@
|
|||
vldr.64 d17, [r0]
|
||||
|
||||
@ CHECK: vldr.64 d1, [r2, #32] @ encoding: [0x08,0x1b,0x92,0xed]
|
||||
@ CHECK: vldr.64 d1, [r2, #-32] @ encoding: [0x08,0x1b,0x12,0xed]
|
||||
vldr.64 d1, [r2, #32]
|
||||
|
||||
vldr.64 d1, [r2, #-32]
|
||||
|
||||
@ CHECK: vldr.64 d2, [r3] @ encoding: [0x00,0x2b,0x93,0xed]
|
||||
vldr.64 d2, [r3]
|
||||
|
@ -174,3 +175,21 @@
|
|||
vldr.64 d3, [pc]
|
||||
vldr.64 d3, [pc,#0]
|
||||
vldr.64 d3, [pc,#-0]
|
||||
|
||||
@ CHECK: vldr.32 s13, [r0] @ encoding: [0x00,0x6a,0xd0,0xed]
|
||||
vldr.32 s13, [r0]
|
||||
|
||||
@ CHECK: vldr.32 s1, [r2, #32] @ encoding: [0x08,0x0a,0xd2,0xed]
|
||||
@ CHECK: vldr.32 s1, [r2, #-32] @ encoding: [0x08,0x0a,0x52,0xed]
|
||||
vldr.32 s1, [r2, #32]
|
||||
vldr.32 s1, [r2, #-32]
|
||||
|
||||
@ CHECK: vldr.32 s2, [r3] @ encoding: [0x00,0x1a,0x93,0xed]
|
||||
vldr.32 s2, [r3]
|
||||
|
||||
@ CHECK: vldr.32 s5, [pc] @ encoding: [0x00,0x2a,0xdf,0xed]
|
||||
@ CHECK: vldr.32 s5, [pc] @ encoding: [0x00,0x2a,0xdf,0xed]
|
||||
@ CHECK: vldr.32 s5, [pc] @ encoding: [0x00,0x2a,0xdf,0xed]
|
||||
vldr.32 s5, [pc]
|
||||
vldr.32 s5, [pc,#0]
|
||||
vldr.32 s5, [pc,#-0]
|
||||
|
|
Loading…
Reference in New Issue