Skip to content

Commit c005f73

Browse files
Fix "Cannot select" crash on bitcast between f64 and int vector types (#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
1 parent f357a47 commit c005f73

2 files changed

Lines changed: 70 additions & 2 deletions

File tree

llvm/lib/Target/Hexagon/HexagonPatterns.td

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,17 +530,22 @@ def: Pat<(i64 (bitconvert F64:$v)), (I64:$v)>;
530530
def: Pat<(f64 (bitconvert I64:$v)), (F64:$v)>;
531531

532532
// Bit convert 32- and 64-bit types.
533-
// All of these are bitcastable to one another: i32, v2i16, v4i8.
533+
// All of these are bitcastable to one another: i32, f32, v2i16, v4i8.
534534
defm: NopCast_pat<i32, v2i16, IntRegs>;
535535
defm: NopCast_pat<i32, v4i8, IntRegs>;
536536
defm: NopCast_pat<v2i16, v4i8, IntRegs>;
537-
// All of these are bitcastable to one another: i64, v2i32, v4i16, v8i8.
537+
defm: NopCast_pat<f32, v2i16, IntRegs>;
538+
defm: NopCast_pat<f32, v4i8, IntRegs>;
539+
// All of these are bitcastable to one another: i64, f64, v2i32, v4i16, v8i8.
538540
defm: NopCast_pat<i64, v2i32, DoubleRegs>;
539541
defm: NopCast_pat<i64, v4i16, DoubleRegs>;
540542
defm: NopCast_pat<i64, v8i8, DoubleRegs>;
541543
defm: NopCast_pat<v2i32, v4i16, DoubleRegs>;
542544
defm: NopCast_pat<v2i32, v8i8, DoubleRegs>;
543545
defm: NopCast_pat<v4i16, v8i8, DoubleRegs>;
546+
defm: NopCast_pat<f64, v2i32, DoubleRegs>;
547+
defm: NopCast_pat<f64, v4i16, DoubleRegs>;
548+
defm: NopCast_pat<f64, v8i8, DoubleRegs>;
544549

545550

546551
// --(3) Extend/truncate/saturate ----------------------------------------
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
; RUN: llc -mtriple=hexagon -mcpu=hexagonv68 -O3 < %s | FileCheck %s
2+
3+
; Verify that bitcasts between f64 and the integer vector types that share the
4+
; DoubleRegs register class (v2i32, v4i16, v8i8) are treated as no-ops by the
5+
; instruction selector and do not cause a "Cannot select" crash.
6+
;
7+
; All of i64, f64, v2i32, v4i16, v8i8 live in DoubleRegs (64-bit register
8+
; pairs). A bitcast between any two of them is a pure reinterpretation of the
9+
; same 64 bits. Therefore no instruction is emitted.
10+
;
11+
; Regression test for: llvm.org/PR195495
12+
; llc -mtriple=hexagon -mcpu=hexagonv68 -O3 crashed with
13+
; "Cannot select: f64 = bitcast v2i32" when compiling Eigen's packetmath.
14+
15+
; CHECK-LABEL: test_v2i32_to_f64:
16+
; CHECK: dfcmp
17+
; CHECK: jumpr r31
18+
define i1 @test_v2i32_to_f64(<2 x i32> %a) {
19+
%bc = bitcast <2 x i32> %a to double
20+
%cmp = fcmp une double %bc, 0.0
21+
ret i1 %cmp
22+
}
23+
24+
; f64->v2i32 is a no-op: the argument is already in a DoubleReg pair.
25+
; CHECK-LABEL: test_f64_to_v2i32:
26+
; CHECK-NOT: combine
27+
; CHECK: jumpr r31
28+
define <2 x i32> @test_f64_to_v2i32(double %a) {
29+
%bc = bitcast double %a to <2 x i32>
30+
ret <2 x i32> %bc
31+
}
32+
33+
; CHECK-LABEL: test_v4i16_to_f64:
34+
; CHECK: dfcmp
35+
; CHECK: jumpr r31
36+
define i1 @test_v4i16_to_f64(<4 x i16> %a) {
37+
%bc = bitcast <4 x i16> %a to double
38+
%cmp = fcmp une double %bc, 0.0
39+
ret i1 %cmp
40+
}
41+
42+
; CHECK-LABEL: test_v8i8_to_f64:
43+
; CHECK: dfcmp
44+
; CHECK: jumpr r31
45+
define i1 @test_v8i8_to_f64(<8 x i8> %a) {
46+
%bc = bitcast <8 x i8> %a to double
47+
%cmp = fcmp une double %bc, 0.0
48+
ret i1 %cmp
49+
}
50+
51+
; Regression test: the original crash.
52+
; <4 x i32> is passed in two v2i32 DoubleReg pairs; after type-legalizing
53+
; <2 x f64> setcc into two scalar f64 setcc ops, each f64 operand is produced
54+
; by a "f64 = bitcast v2i32" node that previously had no matching pattern.
55+
; CHECK-LABEL: test_packetmath_reduced:
56+
; CHECK: dfcmp
57+
; CHECK: jumpr r31
58+
define <2 x i1> @test_packetmath_reduced(<4 x i32> %arg) {
59+
entry:
60+
%bc = bitcast <4 x i32> %arg to <2 x double>
61+
%cmp = fcmp une <2 x double> %bc, zeroinitializer
62+
ret <2 x i1> %cmp
63+
}

0 commit comments

Comments
 (0)