Skip to content

Fix "Cannot select" crash on bitcast between f64 and int vector types#201509

Merged
quic-asaravan merged 1 commit into
llvm:mainfrom
quic-asaravan:Bitcastv2i32-f32
Jun 4, 2026
Merged

Fix "Cannot select" crash on bitcast between f64 and int vector types#201509
quic-asaravan merged 1 commit into
llvm:mainfrom
quic-asaravan:Bitcastv2i32-f32

Conversation

@quic-asaravan

@quic-asaravan quic-asaravan commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

All of i64, f64, v2i32, v4i16, v8i8 are assigned to the DoubleRegs register class (64-bit register pairs). A bitcast between any two of these types is a machine-level no-op (ie. the same physical register is reinterpreted with a different type).

HexagonPatterns.td had NopCast_pat entries for all int-to-int bitcasts within DoubleRegs, and explicit patterns for f64 <-> i64, but was missing patterns for f64 <-> v2i32, f64 <-> v4i16, and f64 <-> v8i8. The same gap existed in IntRegs for f32 <-> v2i16 and f32 <-> v4i8.

Without a tableGen pattern for "f64 = bitcast v2i32" node, the instruction selector crashed with:

LLVM ERROR: Cannot select: t26: f64 = bitcast t6
t6: v2i32,ch = CopyFromReg t0, Register:v2i32 %2

Fix by adding the five missing NopCast_pat entries.

Fixes: #195495

…ypes

All of i64, f64, v2i32, v4i16, v8i8 are assigned to the DoubleRegs
register class (64-bit register pairs). A bitcast between any two of
these types is a machine-level no-op (ie. the same physical register is
reinterpreted with a different type).

HexagonPatterns.td had NopCast_pat entries for all int-to-int bitcasts
within DoubleRegs, and explicit patterns for f64 <-> i64, but
was missing patterns for f64 <-> v2i32, f64 <-> v4i16, and
f64 <-> v8i8. The same gap existed in IntRegs for f32 <-> v2i16 and
f32 <-> v4i8.

Without a tableGen pattern for "f64 = bitcast v2i32" node, the
instruction selector crashed with:

  LLVM ERROR: Cannot select: t26: f64 = bitcast t6
    t6: v2i32,ch = CopyFromReg t0, Register:v2i32 %2

Fix by adding the five missing NopCast_pat entries.

Fixes: llvm#195495
@quic-asaravan quic-asaravan changed the title Fix "Cannot select" crash on bitcast between f64 and integer vector t… Fix "Cannot select" crash on bitcast between f64 and int vector types Jun 4, 2026
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

🪟 Windows x64 Test Results

  • 135393 tests passed
  • 3361 tests skipped

✅ The build succeeded and all tests passed.

@quic-asaravan quic-asaravan marked this pull request as ready for review June 4, 2026 08:19
@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-backend-hexagon

Author: Abinaya Saravanan (quic-asaravan)

Changes

All of i64, f64, v2i32, v4i16, v8i8 are assigned to the DoubleRegs register class (64-bit register pairs). A bitcast between any two of these types is a machine-level no-op (ie. the same physical register is reinterpreted with a different type).

HexagonPatterns.td had NopCast_pat entries for all int-to-int bitcasts within DoubleRegs, and explicit patterns for f64 <-> i64, but was missing patterns for f64 <-> v2i32, f64 <-> v4i16, and f64 <-> v8i8. The same gap existed in IntRegs for f32 <-> v2i16 and f32 <-> v4i8.

Without a tableGen pattern for "f64 = bitcast v2i32" node, the instruction selector crashed with:

LLVM ERROR: Cannot select: t26: f64 = bitcast t6
t6: v2i32,ch = CopyFromReg t0, Register:v2i32 %2

Fix by adding the five missing NopCast_pat entries.

Fixes: #195495


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

2 Files Affected:

  • (modified) llvm/lib/Target/Hexagon/HexagonPatterns.td (+7-2)
  • (added) llvm/test/CodeGen/Hexagon/bitcast-f64-vector.ll (+63)
diff --git a/llvm/lib/Target/Hexagon/HexagonPatterns.td b/llvm/lib/Target/Hexagon/HexagonPatterns.td
index a152b905ad39c..63e94b302c117 100644
--- a/llvm/lib/Target/Hexagon/HexagonPatterns.td
+++ b/llvm/lib/Target/Hexagon/HexagonPatterns.td
@@ -530,17 +530,22 @@ def: Pat<(i64 (bitconvert F64:$v)), (I64:$v)>;
 def: Pat<(f64 (bitconvert I64:$v)), (F64:$v)>;
 
 // Bit convert 32- and 64-bit types.
-// All of these are bitcastable to one another: i32, v2i16, v4i8.
+// All of these are bitcastable to one another: i32, f32, v2i16, v4i8.
 defm: NopCast_pat<i32,   v2i16, IntRegs>;
 defm: NopCast_pat<i32,    v4i8, IntRegs>;
 defm: NopCast_pat<v2i16,  v4i8, IntRegs>;
-// All of these are bitcastable to one another: i64, v2i32, v4i16, v8i8.
+defm: NopCast_pat<f32,   v2i16, IntRegs>;
+defm: NopCast_pat<f32,    v4i8, IntRegs>;
+// All of these are bitcastable to one another: i64, f64, v2i32, v4i16, v8i8.
 defm: NopCast_pat<i64,   v2i32, DoubleRegs>;
 defm: NopCast_pat<i64,   v4i16, DoubleRegs>;
 defm: NopCast_pat<i64,    v8i8, DoubleRegs>;
 defm: NopCast_pat<v2i32, v4i16, DoubleRegs>;
 defm: NopCast_pat<v2i32,  v8i8, DoubleRegs>;
 defm: NopCast_pat<v4i16,  v8i8, DoubleRegs>;
+defm: NopCast_pat<f64,   v2i32, DoubleRegs>;
+defm: NopCast_pat<f64,   v4i16, DoubleRegs>;
+defm: NopCast_pat<f64,    v8i8, DoubleRegs>;
 
 
 // --(3) Extend/truncate/saturate ----------------------------------------
diff --git a/llvm/test/CodeGen/Hexagon/bitcast-f64-vector.ll b/llvm/test/CodeGen/Hexagon/bitcast-f64-vector.ll
new file mode 100644
index 0000000000000..172a3ab32e616
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/bitcast-f64-vector.ll
@@ -0,0 +1,63 @@
+; RUN: llc -mtriple=hexagon -mcpu=hexagonv68 -O3 < %s | FileCheck %s
+
+; Verify that bitcasts between f64 and the integer vector types that share the
+; DoubleRegs register class (v2i32, v4i16, v8i8) are treated as no-ops by the
+; instruction selector and do not cause a "Cannot select" crash.
+;
+; All of i64, f64, v2i32, v4i16, v8i8 live in DoubleRegs (64-bit register
+; pairs). A bitcast between any two of them is a pure reinterpretation of the
+; same 64 bits. Therefore no instruction is emitted.
+;
+; Regression test for: llvm.org/PR195495
+;   llc -mtriple=hexagon -mcpu=hexagonv68 -O3 crashed with
+;   "Cannot select: f64 = bitcast v2i32" when compiling Eigen's packetmath.
+
+; CHECK-LABEL: test_v2i32_to_f64:
+; CHECK: dfcmp
+; CHECK: jumpr r31
+define i1 @test_v2i32_to_f64(<2 x i32> %a) {
+  %bc = bitcast <2 x i32> %a to double
+  %cmp = fcmp une double %bc, 0.0
+  ret i1 %cmp
+}
+
+; f64->v2i32 is a no-op: the argument is already in a DoubleReg pair.
+; CHECK-LABEL: test_f64_to_v2i32:
+; CHECK-NOT: combine
+; CHECK: jumpr r31
+define <2 x i32> @test_f64_to_v2i32(double %a) {
+  %bc = bitcast double %a to <2 x i32>
+  ret <2 x i32> %bc
+}
+
+; CHECK-LABEL: test_v4i16_to_f64:
+; CHECK: dfcmp
+; CHECK: jumpr r31
+define i1 @test_v4i16_to_f64(<4 x i16> %a) {
+  %bc = bitcast <4 x i16> %a to double
+  %cmp = fcmp une double %bc, 0.0
+  ret i1 %cmp
+}
+
+; CHECK-LABEL: test_v8i8_to_f64:
+; CHECK: dfcmp
+; CHECK: jumpr r31
+define i1 @test_v8i8_to_f64(<8 x i8> %a) {
+  %bc = bitcast <8 x i8> %a to double
+  %cmp = fcmp une double %bc, 0.0
+  ret i1 %cmp
+}
+
+; Regression test: the original crash.
+; <4 x i32> is passed in two v2i32 DoubleReg pairs; after type-legalizing
+; <2 x f64> setcc into two scalar f64 setcc ops, each f64 operand is produced
+; by a "f64 = bitcast v2i32" node that previously had no matching pattern.
+; CHECK-LABEL: test_packetmath_reduced:
+; CHECK: dfcmp
+; CHECK: jumpr r31
+define <2 x i1> @test_packetmath_reduced(<4 x i32> %arg) {
+entry:
+  %bc = bitcast <4 x i32> %arg to <2 x double>
+  %cmp = fcmp une <2 x double> %bc, zeroinitializer
+  ret <2 x i1> %cmp
+}

@quic-asaravan quic-asaravan merged commit c005f73 into llvm:main Jun 4, 2026
17 of 18 checks passed
dyung pushed a commit that referenced this pull request Jun 8, 2026
…#201509)

All of i64, f64, v2i32, v4i16, v8i8 are assigned to the DoubleRegs
register class (64-bit register pairs). A bitcast between any two of
these types is a machine-level no-op (ie. the same physical register is
reinterpreted with a different type).

HexagonPatterns.td had NopCast_pat entries for all int-to-int bitcasts
within DoubleRegs, and explicit patterns for f64 <-> i64, but was
missing patterns for f64 <-> v2i32, f64 <-> v4i16, and f64 <-> v8i8. The
same gap existed in IntRegs for f32 <-> v2i16 and f32 <-> v4i8.

Without a tableGen pattern for "f64 = bitcast v2i32" node, the
instruction selector crashed with:

  LLVM ERROR: Cannot select: t26: f64 = bitcast t6
    t6: v2i32,ch = CopyFromReg t0, Register:v2i32 %2

Fix by adding the five missing NopCast_pat entries.

Fixes: #195495
(cherry picked from commit c005f73)
carlobertolli pushed a commit to carlobertolli/llvm-project that referenced this pull request Jun 11, 2026
…llvm#201509)

All of i64, f64, v2i32, v4i16, v8i8 are assigned to the DoubleRegs
register class (64-bit register pairs). A bitcast between any two of
these types is a machine-level no-op (ie. the same physical register is
reinterpreted with a different type).

HexagonPatterns.td had NopCast_pat entries for all int-to-int bitcasts
within DoubleRegs, and explicit patterns for f64 <-> i64, but was
missing patterns for f64 <-> v2i32, f64 <-> v4i16, and f64 <-> v8i8. The
same gap existed in IntRegs for f32 <-> v2i16 and f32 <-> v4i8.

Without a tableGen pattern for "f64 = bitcast v2i32" node, the
instruction selector crashed with:

  LLVM ERROR: Cannot select: t26: f64 = bitcast t6
    t6: v2i32,ch = CopyFromReg t0, Register:v2i32 %2

Fix by adding the five missing NopCast_pat entries.

Fixes: llvm#195495
daunabomba pushed a commit to daunabomba/llvm-project that referenced this pull request Jun 17, 2026
…llvm#201509)

All of i64, f64, v2i32, v4i16, v8i8 are assigned to the DoubleRegs
register class (64-bit register pairs). A bitcast between any two of
these types is a machine-level no-op (ie. the same physical register is
reinterpreted with a different type).

HexagonPatterns.td had NopCast_pat entries for all int-to-int bitcasts
within DoubleRegs, and explicit patterns for f64 <-> i64, but was
missing patterns for f64 <-> v2i32, f64 <-> v4i16, and f64 <-> v8i8. The
same gap existed in IntRegs for f32 <-> v2i16 and f32 <-> v4i8.

Without a tableGen pattern for "f64 = bitcast v2i32" node, the
instruction selector crashed with:

  LLVM ERROR: Cannot select: t26: f64 = bitcast t6
    t6: v2i32,ch = CopyFromReg t0, Register:v2i32 %2

Fix by adding the five missing NopCast_pat entries.

Fixes: llvm#195495
(cherry picked from commit c005f73)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[hexagon] Cannot select: f64 = bitcast v2i32, Eigen packetmath

3 participants