forked from OSchip/llvm-project
[THUMB2] add .w suffixes for ldr/str (immediate) T4
The Linux kernel when built with CONFIG_THUMB2_KERNEL makes use of these instructions with immediate operands and wide encodings. These are the T4 variants of the follow sections from the Arm ARM. F5.1.72 LDR (immediate) F5.1.229 STR (immediate) I wasn't able to represent these simple aliases using t2InstAlias due to the Constraints on the non-suffixed existing instructions, which results in some manual parsing logic needing to be added. F1.2 Standard assembler syntax fields describes the use of the .w (wide) vs .n (narrow) encoding suffix. Link: https://bugs.llvm.org/show_bug.cgi?id=49118 Link: https://github.com/ClangBuiltLinux/linux/issues/1296 Reported-by: Stefan Agner <stefan@agner.ch> Reported-by: Arnd Bergmann <arnd@kernel.org> Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> Reviewed By: DavidSpickett Differential Revision: https://reviews.llvm.org/D96632
This commit is contained in:
parent
956c90d347
commit
1e204ac789
|
@ -1563,6 +1563,14 @@ def t2LDRSH_POST : T2Ipostldst<1, 0b01, 1, 0, (outs GPR:$Rt, GPR:$Rn_wb),
|
|||
Sched<[WriteLd]>;
|
||||
} // mayLoad = 1, hasSideEffects = 0
|
||||
|
||||
// F5.1.72 LDR (immediate) T4
|
||||
// .w suffixes; Constraints can't be used on t2InstAlias to describe
|
||||
// "$Rn = $Rn_wb" on POST or "$addr.base = $Rn_wb" on PRE.
|
||||
def t2LDR_PRE_imm : t2AsmPseudo<"ldr${p}.w $Rt, $addr!",
|
||||
(ins GPR:$Rt, t2addrmode_imm8_pre:$addr, pred:$p)>;
|
||||
def t2LDR_POST_imm : t2AsmPseudo<"ldr${p}.w $Rt, $Rn, $imm",
|
||||
(ins GPR:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$imm, pred:$p)>;
|
||||
|
||||
// LDRT, LDRBT, LDRHT, LDRSBT, LDRSHT all have offset mode (PUW=0b110).
|
||||
// Ref: A8.6.57 LDR (immediate, Thumb) Encoding T4
|
||||
class T2IldT<bit signed, bits<2> type, string opc, InstrItinClass ii>
|
||||
|
@ -1720,6 +1728,15 @@ def t2STRH_preidx: t2PseudoInst<(outs GPRnopc:$Rn_wb),
|
|||
Sched<[WriteST]>;
|
||||
}
|
||||
|
||||
// F5.1.229 STR (immediate) T4
|
||||
// .w suffixes; Constraints can't be used on t2InstAlias to describe
|
||||
// "$Rn = $Rn_wb,@earlyclobber $Rn_wb" on POST or
|
||||
// "$addr.base = $Rn_wb,@earlyclobber $Rn_wb" on PRE.
|
||||
def t2STR_PRE_imm : t2AsmPseudo<"str${p}.w $Rt, $addr!",
|
||||
(ins GPR:$Rt, t2addrmode_imm8_pre:$addr, pred:$p)>;
|
||||
def t2STR_POST_imm : t2AsmPseudo<"str${p}.w $Rt, $Rn, $imm",
|
||||
(ins GPR:$Rt, addr_offset_none:$Rn, t2am_imm8_offset:$imm, pred:$p)>;
|
||||
|
||||
// STRT, STRBT, STRHT all have offset mode (PUW=0b110) and are for disassembly
|
||||
// only.
|
||||
// Ref: A8.6.193 STR (immediate, Thumb) Encoding T4
|
||||
|
|
|
@ -7658,6 +7658,33 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
|
|||
"source register and base register can't be identical");
|
||||
return false;
|
||||
}
|
||||
case ARM::t2LDR_PRE_imm:
|
||||
case ARM::t2LDR_POST_imm:
|
||||
case ARM::t2STR_PRE_imm:
|
||||
case ARM::t2STR_POST_imm: {
|
||||
// Rt must be different from Rn.
|
||||
const unsigned Rt = MRI->getEncodingValue(Inst.getOperand(0).getReg());
|
||||
const unsigned Rn = MRI->getEncodingValue(Inst.getOperand(1).getReg());
|
||||
|
||||
if (Rt == Rn)
|
||||
return Error(Operands[3]->getStartLoc(),
|
||||
"destination register and base register can't be identical");
|
||||
if (Inst.getOpcode() == ARM::t2LDR_POST_imm ||
|
||||
Inst.getOpcode() == ARM::t2STR_POST_imm) {
|
||||
int Imm = Inst.getOperand(2).getImm();
|
||||
if (Imm > 255 || Imm < -255)
|
||||
return Error(Operands[5]->getStartLoc(),
|
||||
"operand must be in range [-255, 255]");
|
||||
}
|
||||
if (Inst.getOpcode() == ARM::t2STR_PRE_imm ||
|
||||
Inst.getOpcode() == ARM::t2STR_POST_imm) {
|
||||
if (Inst.getOperand(0).getReg() == ARM::PC) {
|
||||
return Error(Operands[3]->getStartLoc(),
|
||||
"operand must be a register in range [r0, r14]");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case ARM::LDR_PRE_IMM:
|
||||
case ARM::LDR_PRE_REG:
|
||||
case ARM::t2LDR_PRE:
|
||||
|
@ -8625,6 +8652,34 @@ bool ARMAsmParser::processInstruction(MCInst &Inst,
|
|||
Inst = TmpInst;
|
||||
return true;
|
||||
}
|
||||
// Aliases for imm syntax of LDR instructions.
|
||||
case ARM::t2LDR_PRE_imm:
|
||||
case ARM::t2LDR_POST_imm: {
|
||||
MCInst TmpInst;
|
||||
TmpInst.setOpcode(Inst.getOpcode() == ARM::t2LDR_PRE_imm ? ARM::t2LDR_PRE
|
||||
: ARM::t2LDR_POST);
|
||||
TmpInst.addOperand(Inst.getOperand(0)); // Rt
|
||||
TmpInst.addOperand(Inst.getOperand(4)); // Rt_wb
|
||||
TmpInst.addOperand(Inst.getOperand(1)); // Rn
|
||||
TmpInst.addOperand(Inst.getOperand(2)); // imm
|
||||
TmpInst.addOperand(Inst.getOperand(3)); // CondCode
|
||||
Inst = TmpInst;
|
||||
return true;
|
||||
}
|
||||
// Aliases for imm syntax of STR instructions.
|
||||
case ARM::t2STR_PRE_imm:
|
||||
case ARM::t2STR_POST_imm: {
|
||||
MCInst TmpInst;
|
||||
TmpInst.setOpcode(Inst.getOpcode() == ARM::t2STR_PRE_imm ? ARM::t2STR_PRE
|
||||
: ARM::t2STR_POST);
|
||||
TmpInst.addOperand(Inst.getOperand(4)); // Rt_wb
|
||||
TmpInst.addOperand(Inst.getOperand(0)); // Rt
|
||||
TmpInst.addOperand(Inst.getOperand(1)); // Rn
|
||||
TmpInst.addOperand(Inst.getOperand(2)); // imm
|
||||
TmpInst.addOperand(Inst.getOperand(3)); // CondCode
|
||||
Inst = TmpInst;
|
||||
return true;
|
||||
}
|
||||
// Aliases for alternate PC+imm syntax of LDR instructions.
|
||||
case ARM::t2LDRpcrel:
|
||||
// Select the narrow version if the immediate will fit.
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
@ RUN: not llvm-mc -triple=thumbv7-unknown-linux-gnueabi -arm-implicit-it=thumb -show-encoding < %s 2>&1 | FileCheck %s
|
||||
.syntax unified
|
||||
|
||||
@ Note: The error stream for XFAIL needs to get checked first.
|
||||
|
||||
ldr.w r1, [r1, #-4]!
|
||||
ldr.w r1, [r0, #256]!
|
||||
ldr.w r1, [r0, #-256]!
|
||||
ldr.w r1, [pc, #-4]!
|
||||
ldr.w r1, [r1], #4
|
||||
ldr.w r0, [r0], #4
|
||||
ldr.w r0, [r1], #256
|
||||
ldr.w r0, [r1], #-256
|
||||
str.w r0, [r0, #-4]!
|
||||
str.w pc, [r0, #-4]!
|
||||
str.w r1, [pc, #-4]!
|
||||
str.w r1, [r2, #256]!
|
||||
str.w r1, [r2, #-256]!
|
||||
str.w r0, [r0], #4
|
||||
str.w pc, [r0], #4
|
||||
str.w r1, [r0], #256
|
||||
str.w r1, [r0], #-256
|
||||
|
||||
@@ XFAIL
|
||||
|
||||
@ CHECK: error: destination register and base register can't be identical
|
||||
@ CHECK-NEXT: ldr.w r1, [r1, #-4]!
|
||||
@ CHECK: error: invalid instruction, any one of the following would fix this:
|
||||
@ CHECK-NEXT: ldr.w r1, [r0, #256]!
|
||||
@ CHECK: note: invalid operand for instruction
|
||||
@ CHECK: note: too many operands for instruction
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK-NEXT: ldr.w r1, [r0, #-256]!
|
||||
@ CHECK: error: invalid instruction, any one of the following would fix this:
|
||||
@ CHECK-NEXT: ldr.w r1, [pc, #-4]!
|
||||
@ CHECK: note: invalid operand for instruction
|
||||
@ CHECK: note: too many operands for instruction
|
||||
@ CHECK: error: destination register and base register can't be identical
|
||||
@ CHECK-NEXT: ldr.w r1, [r1], #4
|
||||
@ CHECK: error: destination register and base register can't be identical
|
||||
@ CHECK-NEXT: ldr.w r0, [r0], #4
|
||||
@ CHECK: error: operand must be in range [-255, 255]
|
||||
@ CHECK-NEXT: ldr.w r0, [r1], #256
|
||||
@ CHECK: error: operand must be in range [-255, 255]
|
||||
@ CHECK-NEXT: ldr.w r0, [r1], #-256
|
||||
@ CHECK: error: destination register and base register can't be identical
|
||||
@ CHECK-NEXT: str.w r0, [r0, #-4]!
|
||||
@ CHECK: error: operand must be a register in range [r0, r14]
|
||||
@ CHECK-NEXT: str.w pc, [r0, #-4]!
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK-NEXT: str.w r1, [pc, #-4]!
|
||||
@ CHECK: error: invalid instruction, any one of the following would fix this:
|
||||
@ CHECK-NEXT: str.w r1, [r2, #256]!
|
||||
@ CHECK: note: invalid operand for instruction
|
||||
@ CHECK: note: too many operands for instruction
|
||||
@ CHECK: error: invalid operand for instruction
|
||||
@ CHECK-NEXT: str.w r1, [r2, #-256]!
|
||||
@ CHECK: error: destination register and base register can't be identical
|
||||
@ CHECK-NEXT: str.w r0, [r0], #4
|
||||
@ CHECK: error: operand must be a register in range [r0, r14]
|
||||
@ CHECK-NEXT: str.w pc, [r0], #4
|
||||
@ CHECK: error: operand must be in range [-255, 255]
|
||||
@ CHECK-NEXT: str.w r1, [r0], #256
|
||||
@ CHECK: error: operand must be in range [-255, 255]
|
||||
@ CHECK-NEXT: str.w r1, [r0], #-256
|
||||
|
||||
@@ XPASS
|
||||
|
||||
@ Simple checks that we get the same encoding w/ and w/o the .w suffix.
|
||||
ldr r3, [r1], #4
|
||||
ldr.w r3, [r1], #4
|
||||
|
||||
str r3, [r0], #4
|
||||
str.w r3, [r0], #4
|
||||
|
||||
ldr r3, [r1, #-4]!
|
||||
ldr.w r3, [r1, #-4]!
|
||||
|
||||
str r3, [r0, #-4]!
|
||||
str.w r3, [r0, #-4]!
|
||||
|
||||
@ CHECK: ldr r3, [r1], #4 @ encoding: [0x51,0xf8,0x04,0x3b]
|
||||
@ CHECK: ldr r3, [r1], #4 @ encoding: [0x51,0xf8,0x04,0x3b]
|
||||
@ CHECK: str r3, [r0], #4 @ encoding: [0x40,0xf8,0x04,0x3b]
|
||||
@ CHECK: str r3, [r0], #4 @ encoding: [0x40,0xf8,0x04,0x3b]
|
||||
@ CHECK: ldr r3, [r1, #-4]! @ encoding: [0x51,0xf8,0x04,0x3d]
|
||||
@ CHECK: ldr r3, [r1, #-4]! @ encoding: [0x51,0xf8,0x04,0x3d]
|
||||
@ CHECK: str r3, [r0, #-4]! @ encoding: [0x40,0xf8,0x04,0x3d]
|
||||
@ CHECK: str r3, [r0, #-4]! @ encoding: [0x40,0xf8,0x04,0x3d]
|
||||
|
||||
@@ LDR pre-increment w/ writeback
|
||||
@ Vary Rt.
|
||||
ldr.w r0, [r1, #-4]!
|
||||
ldr.w sp, [r1, #-4]! @ TODO: GAS warns for this
|
||||
ldr.w pc, [r1, #-4]!
|
||||
@ Vary Rn.
|
||||
ldr.w r1, [r0, #-4]!
|
||||
ldr.w r1, [sp, #-4]!
|
||||
@ Vary imm.
|
||||
ldr.w r1, [r0, #255]!
|
||||
ldr.w r1, [r0, #-255]!
|
||||
ldr.w r1, [r0, #0]!
|
||||
@ Condition codes.
|
||||
ldreq.w r1, [r0, #255]!
|
||||
ldrle.w r1, [r0, #255]!
|
||||
|
||||
@ CHECK: ldr r0, [r1, #-4]! @ encoding: [0x51,0xf8,0x04,0x0d]
|
||||
@ CHECK: ldr sp, [r1, #-4]! @ encoding: [0x51,0xf8,0x04,0xdd]
|
||||
@ CHECK: ldr pc, [r1, #-4]! @ encoding: [0x51,0xf8,0x04,0xfd]
|
||||
@ CHECK: ldr r1, [r0, #-4]! @ encoding: [0x50,0xf8,0x04,0x1d]
|
||||
@ CHECK: ldr r1, [sp, #-4]! @ encoding: [0x5d,0xf8,0x04,0x1d]
|
||||
@ CHECK: ldr r1, [r0, #255]! @ encoding: [0x50,0xf8,0xff,0x1f]
|
||||
@ CHECK: ldr r1, [r0, #-255]! @ encoding: [0x50,0xf8,0xff,0x1d]
|
||||
@ CHECK: ldr r1, [r0, #0]! @ encoding: [0x50,0xf8,0x00,0x1f]
|
||||
@ CHECK: it eq @ encoding: [0x08,0xbf]
|
||||
@ CHECK: ldreq r1, [r0, #255]! @ encoding: [0x50,0xf8,0xff,0x1f]
|
||||
@ CHECK: it le @ encoding: [0xd8,0xbf]
|
||||
@ CHECK: ldrle r1, [r0, #255]! @ encoding: [0x50,0xf8,0xff,0x1f]
|
||||
|
||||
@@ LDR post-increment
|
||||
@ Vary Rt.
|
||||
ldr.w r0, [r1], #4
|
||||
ldr.w sp, [r1], #4 @ TODO: GAS warns for this
|
||||
ldr.w pc, [r1], #4
|
||||
@ Vary Rn.
|
||||
ldr.w r0, [r1], #4
|
||||
ldr.w r0, [sp], #4
|
||||
ldr.w r0, [pc], #4 @ TODO: GAS warns for this
|
||||
@ Vary imm.
|
||||
ldr.w r0, [r1], #255
|
||||
ldr.w r0, [r1], #0
|
||||
ldr.w r0, [r1], #-255
|
||||
@ Condition codes.
|
||||
ldreq.w r0, [r1], #255
|
||||
ldrle.w r0, [r1], #255
|
||||
|
||||
@ CHECK: ldr r0, [r1], #4 @ encoding: [0x51,0xf8,0x04,0x0b]
|
||||
@ CHECK: ldr sp, [r1], #4 @ encoding: [0x51,0xf8,0x04,0xdb]
|
||||
@ CHECK: ldr pc, [r1], #4 @ encoding: [0x51,0xf8,0x04,0xfb]
|
||||
@ CHECK: ldr r0, [r1], #4 @ encoding: [0x51,0xf8,0x04,0x0b]
|
||||
@ CHECK: ldr r0, [sp], #4 @ encoding: [0x5d,0xf8,0x04,0x0b]
|
||||
@ CHECK: ldr r0, [pc], #4 @ encoding: [0x5f,0xf8,0x04,0x0b]
|
||||
@ CHECK: ldr r0, [r1], #255 @ encoding: [0x51,0xf8,0xff,0x0b]
|
||||
@ CHECK: ldr r0, [r1], #0 @ encoding: [0x51,0xf8,0x00,0x0b]
|
||||
@ CHECK: ldr r0, [r1], #-255 @ encoding: [0x51,0xf8,0xff,0x09]
|
||||
@ CHECK: it eq @ encoding: [0x08,0xbf]
|
||||
@ CHECK: ldreq r0, [r1], #255 @ encoding: [0x51,0xf8,0xff,0x0b]
|
||||
@ CHECK: it le @ encoding: [0xd8,0xbf]
|
||||
@ CHECK: ldrle r0, [r1], #255 @ encoding: [0x51,0xf8,0xff,0x0b]
|
||||
|
||||
@@ STR pre-increment w/ writeback
|
||||
@ Vary Rt.
|
||||
str.w r1, [r0, #-4]!
|
||||
str.w sp, [r0, #-4]!
|
||||
@ Vary Rn.
|
||||
str.w r1, [r2, #-4]!
|
||||
str.w r1, [sp, #-4]!
|
||||
@ Vary imm.
|
||||
str.w r1, [r2, #255]!
|
||||
str.w r1, [r2, #0]!
|
||||
str.w r1, [r2, #-255]!
|
||||
@ Condition codes.
|
||||
streq.w r1, [r2, #255]!
|
||||
strle.w r1, [r2, #255]!
|
||||
|
||||
@ CHECK: str r1, [r0, #-4]! @ encoding: [0x40,0xf8,0x04,0x1d]
|
||||
@ CHECK: str sp, [r0, #-4]! @ encoding: [0x40,0xf8,0x04,0xdd]
|
||||
@ CHECK: str r1, [r2, #-4]! @ encoding: [0x42,0xf8,0x04,0x1d]
|
||||
@ CHECK: str r1, [sp, #-4]! @ encoding: [0x4d,0xf8,0x04,0x1d]
|
||||
@ CHECK: str r1, [r2, #255]! @ encoding: [0x42,0xf8,0xff,0x1f]
|
||||
@ CHECK: str r1, [r2, #0]! @ encoding: [0x42,0xf8,0x00,0x1f]
|
||||
@ CHECK: str r1, [r2, #-255]! @ encoding: [0x42,0xf8,0xff,0x1d]
|
||||
@ CHECK: it eq @ encoding: [0x08,0xbf]
|
||||
@ CHECK: streq r1, [r2, #255]! @ encoding: [0x42,0xf8,0xff,0x1f]
|
||||
@ CHECK: it le @ encoding: [0xd8,0xbf]
|
||||
@ CHECK: strle r1, [r2, #255]! @ encoding: [0x42,0xf8,0xff,0x1f]
|
||||
|
||||
@@ STR post-increment
|
||||
@ Vary Rt.
|
||||
str.w r1, [r0], #4
|
||||
str.w sp, [r0], #4
|
||||
@ Vary Rn.
|
||||
str.w r0, [r1], #4
|
||||
str.w r0, [sp], #4
|
||||
str.w r0, [pc], #4 @ TODO: GAS warns for this.
|
||||
@ Vary imm.
|
||||
str.w r1, [r0], #255
|
||||
str.w r1, [r0], #0
|
||||
str.w r1, [r0], #-255
|
||||
@ Condition codes.
|
||||
streq.w r1, [r0], #255
|
||||
strle.w r1, [r0], #255
|
||||
|
||||
@ CHECK: str r1, [r0], #4 @ encoding: [0x40,0xf8,0x04,0x1b]
|
||||
@ CHECK: str sp, [r0], #4 @ encoding: [0x40,0xf8,0x04,0xdb]
|
||||
@ CHECK: str r0, [r1], #4 @ encoding: [0x41,0xf8,0x04,0x0b]
|
||||
@ CHECK: str r0, [sp], #4 @ encoding: [0x4d,0xf8,0x04,0x0b]
|
||||
@ CHECK: str r0, [pc], #4 @ encoding: [0x4f,0xf8,0x04,0x0b]
|
||||
@ CHECK: str r1, [r0], #255 @ encoding: [0x40,0xf8,0xff,0x1b]
|
||||
@ CHECK: str r1, [r0], #0 @ encoding: [0x40,0xf8,0x00,0x1b]
|
||||
@ CHECK: str r1, [r0], #-255 @ encoding: [0x40,0xf8,0xff,0x19]
|
||||
@ CHECK: it eq @ encoding: [0x08,0xbf]
|
||||
@ CHECK: streq r1, [r0], #255 @ encoding: [0x40,0xf8,0xff,0x1b]
|
||||
@ CHECK: it le @ encoding: [0xd8,0xbf]
|
||||
@ CHECK: strle r1, [r0], #255 @ encoding: [0x40,0xf8,0xff,0x1b]
|
Loading…
Reference in New Issue