[llvm] 1e204ac - [THUMB2] add .w suffixes for ldr/str (immediate) T4

Nick Desaulniers via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 23 09:26:07 PST 2021


Author: Nick Desaulniers
Date: 2021-02-23T09:25:40-08:00
New Revision: 1e204ac78952cf7e4fcf335423e80007388d3979

URL: https://github.com/llvm/llvm-project/commit/1e204ac78952cf7e4fcf335423e80007388d3979
DIFF: https://github.com/llvm/llvm-project/commit/1e204ac78952cf7e4fcf335423e80007388d3979.diff

LOG: [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 at agner.ch>
Reported-by: Arnd Bergmann <arnd at kernel.org>
Signed-off-by: Nick Desaulniers <ndesaulniers at google.com>

Reviewed By: DavidSpickett

Differential Revision: https://reviews.llvm.org/D96632

Added: 
    llvm/test/MC/ARM/thumb2-ldr.w-str.w.s

Modified: 
    llvm/lib/Target/ARM/ARMInstrThumb2.td
    llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td
index b70d66869b06..23758fa18ab5 100644
--- a/llvm/lib/Target/ARM/ARMInstrThumb2.td
+++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td
@@ -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, at earlyclobber $Rn_wb" on POST or
+// "$addr.base = $Rn_wb, at 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

diff  --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 52577d75ddf5..b64637cfb37b 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -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 
diff erent 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.

diff  --git a/llvm/test/MC/ARM/thumb2-ldr.w-str.w.s b/llvm/test/MC/ARM/thumb2-ldr.w-str.w.s
new file mode 100644
index 000000000000..437d28fb278f
--- /dev/null
+++ b/llvm/test/MC/ARM/thumb2-ldr.w-str.w.s
@@ -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]


        


More information about the llvm-commits mailing list