[llvm] [AArch64] Range-check the ext byte index (PR #214468)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 6 05:30:09 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: Zane Hambly (Zaneham)

<details>
<summary>Changes</summary>

`llvm-mc` asserts on an `ext` byte index given as a symbol:

```asm
ext v0.8b, v1.8b, v2.8b, f0
```
```
Assertion failed: MO.isImm() && "did not expect relocated expression",
AArch64MCCodeEmitter.cpp:239
```

`BaseSIMDBitwiseExtract` takes the index as a bare `i32imm`, so nothing requires it to be a constant and it goes straight to the generic encoder. Unlike the FPCLASS comment printer, this one does affect the encoding. With assertions off `getImm()` returns whatever occupies the `MCOperand` union, which for an expression operand is the `MCExpr *`, so the four-bit field ends up holding pointer bits rather than the zero the issue describes.

The same missing constraint silently truncates out-of-range literals, which I don't think has been reported. Before this patch:

```
ext v0.8b,  v1.8b,  v2.8b,  #<!-- -->12   encoding: [0x20,0x20,0x02,0x2e]
ext v0.8b,  v1.8b,  v2.8b,  #<!-- -->4    encoding: [0x20,0x20,0x02,0x2e]
ext v0.16b, v1.16b, v2.16b, #<!-- -->20   encoding: [0x20,0x20,0x02,0x6e]
ext v0.16b, v1.16b, v2.16b, #<!-- -->4    encoding: [0x20,0x20,0x02,0x6e]
```

Index 12 assembles as index 4 on the 64-bit form because the class forces `imm{3}` to 0, and 20 becomes 4 on the 128-bit form. No diagnostic in either case.

Both forms now take a constrained operand, `imm32_0_7` and `imm32_0_15`, which already exist with the parser match classes this wants. The operand stays i32 so the selection pattern is untouched. Symbolic and out-of-range indices both get the usual range diagnostic, and valid indices assemble exactly as before.

`let imm{3} = 0;` on the 64-bit form is redundant now that the operand cannot exceed 7. I left it to keep the diff small, but happy to drop it if you'd rather.

This also covers the `ext` part of #<!-- -->185358, including the Apple `ext.8b v0, v1, v2` syntax. The `scvtf`/`ucvtf` half of that one asserts elsewhere and I'll send it separately.

Fixes #<!-- -->185361


---
Full diff: https://github.com/llvm/llvm-project/pull/214468.diff


3 Files Affected:

- (modified) llvm/lib/Target/AArch64/AArch64InstrFormats.td (+4-4) 
- (modified) llvm/test/MC/AArch64/neon-diagnostics.s (+30) 
- (modified) llvm/test/MC/AArch64/neon-extract.s (+13) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 58fc5ec063c15..cbe57d033e178 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -7684,8 +7684,8 @@ multiclass SIMDWideThreeVectorBHS<bit U, bits<4> opc, string asm,
 //----------------------------------------------------------------------------
 
 class BaseSIMDBitwiseExtract<bit size, RegisterOperand regtype, ValueType vty,
-                             string asm, string kind>
-  : I<(outs regtype:$Rd), (ins regtype:$Rn, regtype:$Rm, i32imm:$imm), asm,
+                             Operand immtype, string asm, string kind>
+  : I<(outs regtype:$Rd), (ins regtype:$Rn, regtype:$Rm, immtype:$imm), asm,
       "{\t$Rd" # kind # ", $Rn" # kind # ", $Rm" # kind # ", $imm" #
       "|" # kind # "\t$Rd, $Rn, $Rm, $imm}", "",
       [(set (vty regtype:$Rd),
@@ -7708,10 +7708,10 @@ class BaseSIMDBitwiseExtract<bit size, RegisterOperand regtype, ValueType vty,
 
 
 multiclass SIMDBitwiseExtract<string asm> {
-  def v8i8  : BaseSIMDBitwiseExtract<0, V64, v8i8, asm, ".8b"> {
+  def v8i8  : BaseSIMDBitwiseExtract<0, V64, v8i8, imm32_0_7, asm, ".8b"> {
     let imm{3} = 0;
   }
-  def v16i8 : BaseSIMDBitwiseExtract<1, V128, v16i8, asm, ".16b">;
+  def v16i8 : BaseSIMDBitwiseExtract<1, V128, v16i8, imm32_0_15, asm, ".16b">;
 }
 
 //----------------------------------------------------------------------------
diff --git a/llvm/test/MC/AArch64/neon-diagnostics.s b/llvm/test/MC/AArch64/neon-diagnostics.s
index 2610f4acf383b..3f9073b792646 100644
--- a/llvm/test/MC/AArch64/neon-diagnostics.s
+++ b/llvm/test/MC/AArch64/neon-diagnostics.s
@@ -7151,3 +7151,33 @@
 // CHECK-ERROR: error: invalid operand for instruction
 // CHECK-ERROR:        fabd d29, s24, d20
 // CHECK-ERROR:                  ^
+
+//----------------------------------------------------------------------
+// Vector Bitwise Extract
+//----------------------------------------------------------------------
+
+    ext v0.8b, v1.8b, v2.8b, #8
+    ext v0.8b, v1.8b, v2.8b, #12
+    ext v0.16b, v1.16b, v2.16b, #16
+    ext v0.16b, v1.16b, v2.16b, #20
+    ext v0.8b, v1.8b, v2.8b, sym
+    ext v0.16b, v1.16b, v2.16b, sym
+
+// CHECK-ERROR: error: immediate must be an integer in range [0, 7].
+// CHECK-ERROR:        ext v0.8b, v1.8b, v2.8b, #8
+// CHECK-ERROR:                                 ^
+// CHECK-ERROR: error: immediate must be an integer in range [0, 7].
+// CHECK-ERROR:        ext v0.8b, v1.8b, v2.8b, #12
+// CHECK-ERROR:                                 ^
+// CHECK-ERROR: error: immediate must be an integer in range [0, 15].
+// CHECK-ERROR:        ext v0.16b, v1.16b, v2.16b, #16
+// CHECK-ERROR:                                    ^
+// CHECK-ERROR: error: immediate must be an integer in range [0, 15].
+// CHECK-ERROR:        ext v0.16b, v1.16b, v2.16b, #20
+// CHECK-ERROR:                                    ^
+// CHECK-ERROR: error: immediate must be an integer in range [0, 7].
+// CHECK-ERROR:        ext v0.8b, v1.8b, v2.8b, sym
+// CHECK-ERROR:                                 ^
+// CHECK-ERROR: error: immediate must be an integer in range [0, 15].
+// CHECK-ERROR:        ext v0.16b, v1.16b, v2.16b, sym
+// CHECK-ERROR:                                    ^
diff --git a/llvm/test/MC/AArch64/neon-extract.s b/llvm/test/MC/AArch64/neon-extract.s
index 1daa46d096eee..c92b98f43da26 100644
--- a/llvm/test/MC/AArch64/neon-extract.s
+++ b/llvm/test/MC/AArch64/neon-extract.s
@@ -11,3 +11,16 @@
 
 // CHECK: ext	v0.8b, v1.8b, v2.8b, #{{0x3|3}}  // encoding: [0x20,0x18,0x02,0x2e]
 // CHECK: ext	v0.16b, v1.16b, v2.16b, #{{0x3|3}} // encoding: [0x20,0x18,0x02,0x6e]
+
+// The index is four bits wide, but only three of them are available on the
+// 64-bit form. Check both ends of each range.
+
+        ext v0.8b, v1.8b, v2.8b, #0
+        ext v0.8b, v1.8b, v2.8b, #7
+        ext v0.16b, v1.16b, v2.16b, #0
+        ext v0.16b, v1.16b, v2.16b, #15
+
+// CHECK: ext	v0.8b, v1.8b, v2.8b, #{{0x0|0}}  // encoding: [0x20,0x00,0x02,0x2e]
+// CHECK: ext	v0.8b, v1.8b, v2.8b, #{{0x7|7}}  // encoding: [0x20,0x38,0x02,0x2e]
+// CHECK: ext	v0.16b, v1.16b, v2.16b, #{{0x0|0}} // encoding: [0x20,0x00,0x02,0x6e]
+// CHECK: ext	v0.16b, v1.16b, v2.16b, #{{0xf|15}} // encoding: [0x20,0x78,0x02,0x6e]

``````````

</details>


https://github.com/llvm/llvm-project/pull/214468


More information about the llvm-commits mailing list