[llvm] [AMDGPU] Fold constants in 2-elt vector canonicalization (PR #214384)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 8 10:50:39 PDT 2026
https://github.com/LU-JOHN updated https://github.com/llvm/llvm-project/pull/214384
>From 7405d932b784ba2b1b6a7cc11a8398e6a5799441 Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Wed, 5 Aug 2026 20:37:10 -0500
Subject: [PATCH 1/7] Fold constants in v2bf16 canonicalization
Signed-off-by: John Lu <John.Lu at amd.com>
---
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 5 +-
.../test/CodeGen/AMDGPU/fcanonicalize.bf16.ll | 88 ++++++++++++-------
2 files changed, 58 insertions(+), 35 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 72774c7ea97b0..be134704b31af 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -16392,8 +16392,9 @@ SITargetLowering::performFCanonicalizeCombine(SDNode *N,
// TODO: This could be better with wider vectors that will be split to v2f16,
// and to consider uses since there aren't that many packed operations.
- if (N0.getOpcode() == ISD::BUILD_VECTOR && VT == MVT::v2f16 &&
- isTypeLegal(MVT::v2f16)) {
+ if (N0.getOpcode() == ISD::BUILD_VECTOR &&
+ (VT == MVT::v2f16 || VT == MVT::v2bf16) &&
+ isTypeLegal(VT)) {
SDLoc SL(N);
SDValue NewElts[2];
SDValue Lo = N0.getOperand(0);
diff --git a/llvm/test/CodeGen/AMDGPU/fcanonicalize.bf16.ll b/llvm/test/CodeGen/AMDGPU/fcanonicalize.bf16.ll
index 93893346c0604..d10c840993aa9 100644
--- a/llvm/test/CodeGen/AMDGPU/fcanonicalize.bf16.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcanonicalize.bf16.ll
@@ -1087,12 +1087,22 @@ define amdgpu_kernel void @s_test_canonicalize_undef_v2bf16(ptr addrspace(1) %ou
}
define <2 x bfloat> @v_test_canonicalize_reg_undef_v2bf16(bfloat %val) #1 {
-; GFX1250-LABEL: v_test_canonicalize_reg_undef_v2bf16:
-; GFX1250: ; %bb.0:
-; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0
-; GFX1250-NEXT: s_wait_kmcnt 0x0
-; GFX1250-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
-; GFX1250-NEXT: s_set_pc_i64 s[30:31]
+; FAKE16-LABEL: v_test_canonicalize_reg_undef_v2bf16:
+; FAKE16: ; %bb.0:
+; FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
+; FAKE16-NEXT: s_wait_kmcnt 0x0
+; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; FAKE16-NEXT: v_perm_b32 v0, 0, v0, 0x5040100
+; FAKE16-NEXT: s_set_pc_i64 s[30:31]
+;
+; REAL16-LABEL: v_test_canonicalize_reg_undef_v2bf16:
+; REAL16: ; %bb.0:
+; REAL16-NEXT: s_wait_loadcnt_dscnt 0x0
+; REAL16-NEXT: s_wait_kmcnt 0x0
+; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; REAL16-NEXT: v_mov_b16_e32 v0.h, 0
+; REAL16-NEXT: s_set_pc_i64 s[30:31]
%vec = insertelement <2 x bfloat> poison, bfloat %val, i32 0
%canonicalized = call <2 x bfloat> @llvm.canonicalize.v2bf16(<2 x bfloat> %vec)
ret <2 x bfloat> %canonicalized
@@ -1103,18 +1113,19 @@ define <2 x bfloat> @v_test_canonicalize_undef_reg_v2bf16(bfloat %val) #1 {
; FAKE16: ; %bb.0:
; FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
; FAKE16-NEXT: s_wait_kmcnt 0x0
-; FAKE16-NEXT: v_lshlrev_b32_e32 v0, 16, v0
-; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1)
; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; FAKE16-NEXT: v_perm_b32 v0, v0, 0, 0x5040100
; FAKE16-NEXT: s_set_pc_i64 s[30:31]
;
; REAL16-LABEL: v_test_canonicalize_undef_reg_v2bf16:
; REAL16: ; %bb.0:
; REAL16-NEXT: s_wait_loadcnt_dscnt 0x0
; REAL16-NEXT: s_wait_kmcnt 0x0
-; REAL16-NEXT: v_mov_b16_e32 v0.h, v0.l
-; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_1)
-; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; REAL16-NEXT: v_pk_mul_bf16 v1, 1.0, v0 op_sel_hi:[0,1]
+; REAL16-NEXT: v_mov_b16_e32 v0.l, 0
+; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_2)
+; REAL16-NEXT: v_mov_b16_e32 v0.h, v1.l
; REAL16-NEXT: s_set_pc_i64 s[30:31]
%vec = insertelement <2 x bfloat> poison, bfloat %val, i32 1
%canonicalized = call <2 x bfloat> @llvm.canonicalize.v2bf16(<2 x bfloat> %vec)
@@ -1174,20 +1185,18 @@ define <2 x bfloat> @v_test_canonicalize_reg_k_v2bf16(bfloat %val) #1 {
; FAKE16: ; %bb.0:
; FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
; FAKE16-NEXT: s_wait_kmcnt 0x0
+; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
; FAKE16-NEXT: s_movk_i32 s0, 0x4000
-; FAKE16-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instid1(SALU_CYCLE_1)
; FAKE16-NEXT: v_perm_b32 v0, s0, v0, 0x5040100
-; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
; FAKE16-NEXT: s_set_pc_i64 s[30:31]
;
; REAL16-LABEL: v_test_canonicalize_reg_k_v2bf16:
; REAL16: ; %bb.0:
; REAL16-NEXT: s_wait_loadcnt_dscnt 0x0
; REAL16-NEXT: s_wait_kmcnt 0x0
-; REAL16-NEXT: v_mov_b16_e32 v1.h, 0x4000
-; REAL16-NEXT: v_mov_b16_e32 v1.l, v0.l
-; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_1)
-; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v1 op_sel_hi:[0,1]
+; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; REAL16-NEXT: v_mov_b16_e32 v0.h, 0x4000
; REAL16-NEXT: s_set_pc_i64 s[30:31]
%vec0 = insertelement <2 x bfloat> poison, bfloat %val, i32 0
%vec1 = insertelement <2 x bfloat> %vec0, bfloat 2.0, i32 1
@@ -1200,20 +1209,20 @@ define <2 x bfloat> @v_test_canonicalize_k_reg_v2bf16(bfloat %val) #1 {
; FAKE16: ; %bb.0:
; FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
; FAKE16-NEXT: s_wait_kmcnt 0x0
+; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
; FAKE16-NEXT: s_movk_i32 s0, 0x4000
-; FAKE16-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instid1(SALU_CYCLE_1)
; FAKE16-NEXT: v_perm_b32 v0, v0, s0, 0x5040100
-; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
; FAKE16-NEXT: s_set_pc_i64 s[30:31]
;
; REAL16-LABEL: v_test_canonicalize_k_reg_v2bf16:
; REAL16: ; %bb.0:
; REAL16-NEXT: s_wait_loadcnt_dscnt 0x0
; REAL16-NEXT: s_wait_kmcnt 0x0
-; REAL16-NEXT: v_mov_b16_e32 v1.l, 0x4000
-; REAL16-NEXT: v_mov_b16_e32 v1.h, v0.l
-; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_1)
-; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v1 op_sel_hi:[0,1]
+; REAL16-NEXT: v_pk_mul_bf16 v1, 1.0, v0 op_sel_hi:[0,1]
+; REAL16-NEXT: v_mov_b16_e32 v0.l, 0x4000
+; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_2)
+; REAL16-NEXT: v_mov_b16_e32 v0.h, v1.l
; REAL16-NEXT: s_set_pc_i64 s[30:31]
%vec0 = insertelement <2 x bfloat> poison, bfloat 2.0, i32 0
%vec1 = insertelement <2 x bfloat> %vec0, bfloat %val, i32 1
@@ -1240,13 +1249,24 @@ define amdgpu_kernel void @s_test_canonicalize_undef_v4bf16(ptr addrspace(1) %ou
}
define <4 x bfloat> @v_test_canonicalize_reg_undef_undef_undef_v4bf16(bfloat %val) #1 {
-; GFX1250-LABEL: v_test_canonicalize_reg_undef_undef_undef_v4bf16:
-; GFX1250: ; %bb.0:
-; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0
-; GFX1250-NEXT: s_wait_kmcnt 0x0
-; GFX1250-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
-; GFX1250-NEXT: v_mov_b32_e32 v1, 0x7fc07fc0
-; GFX1250-NEXT: s_set_pc_i64 s[30:31]
+; FAKE16-LABEL: v_test_canonicalize_reg_undef_undef_undef_v4bf16:
+; FAKE16: ; %bb.0:
+; FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
+; FAKE16-NEXT: s_wait_kmcnt 0x0
+; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; FAKE16-NEXT: v_mov_b32_e32 v1, 0x7fc07fc0
+; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2)
+; FAKE16-NEXT: v_perm_b32 v0, 0, v0, 0x5040100
+; FAKE16-NEXT: s_set_pc_i64 s[30:31]
+;
+; REAL16-LABEL: v_test_canonicalize_reg_undef_undef_undef_v4bf16:
+; REAL16: ; %bb.0:
+; REAL16-NEXT: s_wait_loadcnt_dscnt 0x0
+; REAL16-NEXT: s_wait_kmcnt 0x0
+; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; REAL16-NEXT: v_mov_b16_e32 v0.h, 0
+; REAL16-NEXT: v_mov_b32_e32 v1, 0x7fc07fc0
+; REAL16-NEXT: s_set_pc_i64 s[30:31]
%vec = insertelement <4 x bfloat> poison, bfloat %val, i32 0
%canonicalized = call <4 x bfloat> @llvm.canonicalize.v4bf16(<4 x bfloat> %vec)
ret <4 x bfloat> %canonicalized
@@ -1283,9 +1303,10 @@ define <4 x bfloat> @v_test_canonicalize_reg_undef_reg_reg_v4bf16(bfloat %val0,
; FAKE16: ; %bb.0:
; FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
; FAKE16-NEXT: s_wait_kmcnt 0x0
-; FAKE16-NEXT: v_perm_b32 v1, v2, v1, 0x5040100
; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
-; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2)
+; FAKE16-NEXT: v_perm_b32 v1, v2, v1, 0x5040100
+; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; FAKE16-NEXT: v_perm_b32 v0, 0, v0, 0x5040100
; FAKE16-NEXT: v_pk_mul_bf16 v1, 1.0, v1 op_sel_hi:[0,1]
; FAKE16-NEXT: s_set_pc_i64 s[30:31]
;
@@ -1295,7 +1316,8 @@ define <4 x bfloat> @v_test_canonicalize_reg_undef_reg_reg_v4bf16(bfloat %val0,
; REAL16-NEXT: s_wait_kmcnt 0x0
; REAL16-NEXT: v_mov_b16_e32 v1.h, v2.l
; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
-; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_2)
+; REAL16-NEXT: v_mov_b16_e32 v0.h, 0
+; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_3)
; REAL16-NEXT: v_pk_mul_bf16 v1, 1.0, v1 op_sel_hi:[0,1]
; REAL16-NEXT: s_set_pc_i64 s[30:31]
%vec0 = insertelement <4 x bfloat> poison, bfloat %val0, i32 0
>From 821bfd1f4b242a6bbf1c05e1b47f079433998f70 Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Wed, 5 Aug 2026 21:31:35 -0500
Subject: [PATCH 2/7] Fix formatting
Signed-off-by: John Lu <John.Lu at amd.com>
---
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index be134704b31af..016278779b2fe 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -16393,8 +16393,7 @@ SITargetLowering::performFCanonicalizeCombine(SDNode *N,
// TODO: This could be better with wider vectors that will be split to v2f16,
// and to consider uses since there aren't that many packed operations.
if (N0.getOpcode() == ISD::BUILD_VECTOR &&
- (VT == MVT::v2f16 || VT == MVT::v2bf16) &&
- isTypeLegal(VT)) {
+ (VT == MVT::v2f16 || VT == MVT::v2bf16) && isTypeLegal(VT)) {
SDLoc SL(N);
SDValue NewElts[2];
SDValue Lo = N0.getOperand(0);
>From bf54b78d8856bee554335062057d091977f22ce5 Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Fri, 7 Aug 2026 20:10:57 -0500
Subject: [PATCH 3/7] Only convert if scalar canonicalization insn exists
Signed-off-by: John Lu <John.Lu at amd.com>
---
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 8 +-
.../test/CodeGen/AMDGPU/fcanonicalize.bf16.ll | 88 +++++++------------
2 files changed, 40 insertions(+), 56 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 016278779b2fe..017e0f5ebc83e 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -16393,13 +16393,19 @@ SITargetLowering::performFCanonicalizeCombine(SDNode *N,
// TODO: This could be better with wider vectors that will be split to v2f16,
// and to consider uses since there aren't that many packed operations.
if (N0.getOpcode() == ISD::BUILD_VECTOR &&
- (VT == MVT::v2f16 || VT == MVT::v2bf16) && isTypeLegal(VT)) {
+ VT.getVectorNumElements() == 2 && isTypeLegal(VT)) {
SDLoc SL(N);
SDValue NewElts[2];
SDValue Lo = N0.getOperand(0);
SDValue Hi = N0.getOperand(1);
EVT EltVT = Lo.getValueType();
+ // Only apply this optimization if scalar canonicalize is legal for the
+ // element type. Otherwise, scalarizing may require widening the scalar back
+ // to a vector, adding overhead (e.g., bf16 has no scalar instructions).
+ if (getOperationAction(ISD::FCANONICALIZE, EltVT) != Legal)
+ return SDValue();
+
if (vectorEltWillFoldAway(Lo) || vectorEltWillFoldAway(Hi)) {
for (unsigned I = 0; I != 2; ++I) {
SDValue Op = N0.getOperand(I);
diff --git a/llvm/test/CodeGen/AMDGPU/fcanonicalize.bf16.ll b/llvm/test/CodeGen/AMDGPU/fcanonicalize.bf16.ll
index d10c840993aa9..93893346c0604 100644
--- a/llvm/test/CodeGen/AMDGPU/fcanonicalize.bf16.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcanonicalize.bf16.ll
@@ -1087,22 +1087,12 @@ define amdgpu_kernel void @s_test_canonicalize_undef_v2bf16(ptr addrspace(1) %ou
}
define <2 x bfloat> @v_test_canonicalize_reg_undef_v2bf16(bfloat %val) #1 {
-; FAKE16-LABEL: v_test_canonicalize_reg_undef_v2bf16:
-; FAKE16: ; %bb.0:
-; FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
-; FAKE16-NEXT: s_wait_kmcnt 0x0
-; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
-; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1)
-; FAKE16-NEXT: v_perm_b32 v0, 0, v0, 0x5040100
-; FAKE16-NEXT: s_set_pc_i64 s[30:31]
-;
-; REAL16-LABEL: v_test_canonicalize_reg_undef_v2bf16:
-; REAL16: ; %bb.0:
-; REAL16-NEXT: s_wait_loadcnt_dscnt 0x0
-; REAL16-NEXT: s_wait_kmcnt 0x0
-; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
-; REAL16-NEXT: v_mov_b16_e32 v0.h, 0
-; REAL16-NEXT: s_set_pc_i64 s[30:31]
+; GFX1250-LABEL: v_test_canonicalize_reg_undef_v2bf16:
+; GFX1250: ; %bb.0:
+; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX1250-NEXT: s_wait_kmcnt 0x0
+; GFX1250-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; GFX1250-NEXT: s_set_pc_i64 s[30:31]
%vec = insertelement <2 x bfloat> poison, bfloat %val, i32 0
%canonicalized = call <2 x bfloat> @llvm.canonicalize.v2bf16(<2 x bfloat> %vec)
ret <2 x bfloat> %canonicalized
@@ -1113,19 +1103,18 @@ define <2 x bfloat> @v_test_canonicalize_undef_reg_v2bf16(bfloat %val) #1 {
; FAKE16: ; %bb.0:
; FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
; FAKE16-NEXT: s_wait_kmcnt 0x0
-; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; FAKE16-NEXT: v_lshlrev_b32_e32 v0, 16, v0
; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1)
-; FAKE16-NEXT: v_perm_b32 v0, v0, 0, 0x5040100
+; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
; FAKE16-NEXT: s_set_pc_i64 s[30:31]
;
; REAL16-LABEL: v_test_canonicalize_undef_reg_v2bf16:
; REAL16: ; %bb.0:
; REAL16-NEXT: s_wait_loadcnt_dscnt 0x0
; REAL16-NEXT: s_wait_kmcnt 0x0
-; REAL16-NEXT: v_pk_mul_bf16 v1, 1.0, v0 op_sel_hi:[0,1]
-; REAL16-NEXT: v_mov_b16_e32 v0.l, 0
-; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_2)
-; REAL16-NEXT: v_mov_b16_e32 v0.h, v1.l
+; REAL16-NEXT: v_mov_b16_e32 v0.h, v0.l
+; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
; REAL16-NEXT: s_set_pc_i64 s[30:31]
%vec = insertelement <2 x bfloat> poison, bfloat %val, i32 1
%canonicalized = call <2 x bfloat> @llvm.canonicalize.v2bf16(<2 x bfloat> %vec)
@@ -1185,18 +1174,20 @@ define <2 x bfloat> @v_test_canonicalize_reg_k_v2bf16(bfloat %val) #1 {
; FAKE16: ; %bb.0:
; FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
; FAKE16-NEXT: s_wait_kmcnt 0x0
-; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
; FAKE16-NEXT: s_movk_i32 s0, 0x4000
-; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instid1(SALU_CYCLE_1)
+; FAKE16-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(VALU_DEP_1)
; FAKE16-NEXT: v_perm_b32 v0, s0, v0, 0x5040100
+; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
; FAKE16-NEXT: s_set_pc_i64 s[30:31]
;
; REAL16-LABEL: v_test_canonicalize_reg_k_v2bf16:
; REAL16: ; %bb.0:
; REAL16-NEXT: s_wait_loadcnt_dscnt 0x0
; REAL16-NEXT: s_wait_kmcnt 0x0
-; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
-; REAL16-NEXT: v_mov_b16_e32 v0.h, 0x4000
+; REAL16-NEXT: v_mov_b16_e32 v1.h, 0x4000
+; REAL16-NEXT: v_mov_b16_e32 v1.l, v0.l
+; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v1 op_sel_hi:[0,1]
; REAL16-NEXT: s_set_pc_i64 s[30:31]
%vec0 = insertelement <2 x bfloat> poison, bfloat %val, i32 0
%vec1 = insertelement <2 x bfloat> %vec0, bfloat 2.0, i32 1
@@ -1209,20 +1200,20 @@ define <2 x bfloat> @v_test_canonicalize_k_reg_v2bf16(bfloat %val) #1 {
; FAKE16: ; %bb.0:
; FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
; FAKE16-NEXT: s_wait_kmcnt 0x0
-; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
; FAKE16-NEXT: s_movk_i32 s0, 0x4000
-; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instid1(SALU_CYCLE_1)
+; FAKE16-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(VALU_DEP_1)
; FAKE16-NEXT: v_perm_b32 v0, v0, s0, 0x5040100
+; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
; FAKE16-NEXT: s_set_pc_i64 s[30:31]
;
; REAL16-LABEL: v_test_canonicalize_k_reg_v2bf16:
; REAL16: ; %bb.0:
; REAL16-NEXT: s_wait_loadcnt_dscnt 0x0
; REAL16-NEXT: s_wait_kmcnt 0x0
-; REAL16-NEXT: v_pk_mul_bf16 v1, 1.0, v0 op_sel_hi:[0,1]
-; REAL16-NEXT: v_mov_b16_e32 v0.l, 0x4000
-; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_2)
-; REAL16-NEXT: v_mov_b16_e32 v0.h, v1.l
+; REAL16-NEXT: v_mov_b16_e32 v1.l, 0x4000
+; REAL16-NEXT: v_mov_b16_e32 v1.h, v0.l
+; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v1 op_sel_hi:[0,1]
; REAL16-NEXT: s_set_pc_i64 s[30:31]
%vec0 = insertelement <2 x bfloat> poison, bfloat 2.0, i32 0
%vec1 = insertelement <2 x bfloat> %vec0, bfloat %val, i32 1
@@ -1249,24 +1240,13 @@ define amdgpu_kernel void @s_test_canonicalize_undef_v4bf16(ptr addrspace(1) %ou
}
define <4 x bfloat> @v_test_canonicalize_reg_undef_undef_undef_v4bf16(bfloat %val) #1 {
-; FAKE16-LABEL: v_test_canonicalize_reg_undef_undef_undef_v4bf16:
-; FAKE16: ; %bb.0:
-; FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
-; FAKE16-NEXT: s_wait_kmcnt 0x0
-; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
-; FAKE16-NEXT: v_mov_b32_e32 v1, 0x7fc07fc0
-; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2)
-; FAKE16-NEXT: v_perm_b32 v0, 0, v0, 0x5040100
-; FAKE16-NEXT: s_set_pc_i64 s[30:31]
-;
-; REAL16-LABEL: v_test_canonicalize_reg_undef_undef_undef_v4bf16:
-; REAL16: ; %bb.0:
-; REAL16-NEXT: s_wait_loadcnt_dscnt 0x0
-; REAL16-NEXT: s_wait_kmcnt 0x0
-; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
-; REAL16-NEXT: v_mov_b16_e32 v0.h, 0
-; REAL16-NEXT: v_mov_b32_e32 v1, 0x7fc07fc0
-; REAL16-NEXT: s_set_pc_i64 s[30:31]
+; GFX1250-LABEL: v_test_canonicalize_reg_undef_undef_undef_v4bf16:
+; GFX1250: ; %bb.0:
+; GFX1250-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX1250-NEXT: s_wait_kmcnt 0x0
+; GFX1250-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; GFX1250-NEXT: v_mov_b32_e32 v1, 0x7fc07fc0
+; GFX1250-NEXT: s_set_pc_i64 s[30:31]
%vec = insertelement <4 x bfloat> poison, bfloat %val, i32 0
%canonicalized = call <4 x bfloat> @llvm.canonicalize.v4bf16(<4 x bfloat> %vec)
ret <4 x bfloat> %canonicalized
@@ -1303,10 +1283,9 @@ define <4 x bfloat> @v_test_canonicalize_reg_undef_reg_reg_v4bf16(bfloat %val0,
; FAKE16: ; %bb.0:
; FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
; FAKE16-NEXT: s_wait_kmcnt 0x0
-; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
; FAKE16-NEXT: v_perm_b32 v1, v2, v1, 0x5040100
-; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
-; FAKE16-NEXT: v_perm_b32 v0, 0, v0, 0x5040100
+; FAKE16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
+; FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2)
; FAKE16-NEXT: v_pk_mul_bf16 v1, 1.0, v1 op_sel_hi:[0,1]
; FAKE16-NEXT: s_set_pc_i64 s[30:31]
;
@@ -1316,8 +1295,7 @@ define <4 x bfloat> @v_test_canonicalize_reg_undef_reg_reg_v4bf16(bfloat %val0,
; REAL16-NEXT: s_wait_kmcnt 0x0
; REAL16-NEXT: v_mov_b16_e32 v1.h, v2.l
; REAL16-NEXT: v_pk_mul_bf16 v0, 1.0, v0 op_sel_hi:[0,1]
-; REAL16-NEXT: v_mov_b16_e32 v0.h, 0
-; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_3)
+; REAL16-NEXT: s_delay_alu instid0(VALU_DEP_2)
; REAL16-NEXT: v_pk_mul_bf16 v1, 1.0, v1 op_sel_hi:[0,1]
; REAL16-NEXT: s_set_pc_i64 s[30:31]
%vec0 = insertelement <4 x bfloat> poison, bfloat %val0, i32 0
>From 801dd61172b9757cb27287263d14c14461ef5fa4 Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Fri, 7 Aug 2026 20:47:59 -0500
Subject: [PATCH 4/7] Add test case
Signed-off-by: John Lu <John.Lu at amd.com>
---
.../CodeGen/AMDGPU/fcanonicalize-v2-undef.ll | 217 ++++++++++++++++++
1 file changed, 217 insertions(+)
create mode 100644 llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-undef.ll
diff --git a/llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-undef.ll b/llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-undef.ll
new file mode 100644
index 0000000000000..784c8b2e46d9c
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-undef.ll
@@ -0,0 +1,217 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=amdgpu9.00 < %s | FileCheck -check-prefixes=GFX9 %s
+; RUN: llc -mtriple=amdgpu11.00 -mattr=+real-true16 < %s | FileCheck -check-prefixes=GFX11-TRUE16 %s
+
+; Test fcanonicalize optimization that scalarizes when building vectors with
+; undef or constant elements. This optimization only applies when scalar
+; fcanonicalize is legal for the element type (f16, f32, f64 - not bf16).
+
+declare <2 x half> @llvm.canonicalize.v2f16(<2 x half>)
+declare <2 x float> @llvm.canonicalize.v2f32(<2 x float>)
+declare <2 x double> @llvm.canonicalize.v2f64(<2 x double>)
+
+; Test v2f16 with register in low lane, undef in high lane
+define <2 x half> @test_canonicalize_v2f16_reg_undef(half %val) {
+; GFX9-LABEL: test_canonicalize_v2f16_reg_undef:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_max_f16_e32 v0, v0, v0
+; GFX9-NEXT: v_pack_b32_f16 v0, v0, 0
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f16_reg_undef:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_max_f16_e32 v0.l, v0.l, v0.l
+; GFX11-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-TRUE16-NEXT: v_cvt_u32_u16_e32 v0, v0.l
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+ %vec = insertelement <2 x half> poison, half %val, i32 0
+ %canonicalized = call <2 x half> @llvm.canonicalize.v2f16(<2 x half> %vec)
+ ret <2 x half> %canonicalized
+}
+
+; Test v2f16 with undef in low lane, register in high lane
+define <2 x half> @test_canonicalize_v2f16_undef_reg(half %val) {
+; GFX9-LABEL: test_canonicalize_v2f16_undef_reg:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_max_f16_e32 v0, v0, v0
+; GFX9-NEXT: v_pack_b32_f16 v0, 0, v0
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f16_undef_reg:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_max_f16_e32 v0.h, v0.l, v0.l
+; GFX11-TRUE16-NEXT: v_mov_b16_e32 v0.l, 0
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+ %vec = insertelement <2 x half> poison, half %val, i32 1
+ %canonicalized = call <2 x half> @llvm.canonicalize.v2f16(<2 x half> %vec)
+ ret <2 x half> %canonicalized
+}
+
+; Test v2f16 with register in low lane, constant in high lane
+define <2 x half> @test_canonicalize_v2f16_reg_const(half %val) {
+; GFX9-LABEL: test_canonicalize_v2f16_reg_const:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_max_f16_e32 v0, v0, v0
+; GFX9-NEXT: v_pack_b32_f16 v0, v0, 2.0
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f16_reg_const:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_max_f16_e32 v0.l, v0.l, v0.l
+; GFX11-TRUE16-NEXT: v_mov_b16_e32 v0.h, 0x4000
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+ %vec0 = insertelement <2 x half> poison, half %val, i32 0
+ %vec1 = insertelement <2 x half> %vec0, half 2.0, i32 1
+ %canonicalized = call <2 x half> @llvm.canonicalize.v2f16(<2 x half> %vec1)
+ ret <2 x half> %canonicalized
+}
+
+; Test v2f16 with constant in low lane, register in high lane
+define <2 x half> @test_canonicalize_v2f16_const_reg(half %val) {
+; GFX9-LABEL: test_canonicalize_v2f16_const_reg:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_max_f16_e32 v0, v0, v0
+; GFX9-NEXT: s_movk_i32 s4, 0x4200
+; GFX9-NEXT: v_pack_b32_f16 v0, s4, v0
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f16_const_reg:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_max_f16_e32 v0.h, v0.l, v0.l
+; GFX11-TRUE16-NEXT: v_mov_b16_e32 v0.l, 0x4200
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+ %vec0 = insertelement <2 x half> poison, half 3.0, i32 0
+ %vec1 = insertelement <2 x half> %vec0, half %val, i32 1
+ %canonicalized = call <2 x half> @llvm.canonicalize.v2f16(<2 x half> %vec1)
+ ret <2 x half> %canonicalized
+}
+
+; Test v2f32 with register in low lane, undef in high lane
+define <2 x float> @test_canonicalize_v2f32_reg_undef(float %val) {
+; GFX9-LABEL: test_canonicalize_v2f32_reg_undef:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_max_f32_e32 v0, v0, v0
+; GFX9-NEXT: v_mov_b32_e32 v1, 0
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f32_reg_undef:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_dual_max_f32 v0, v0, v0 :: v_dual_mov_b32 v1, 0
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+ %vec = insertelement <2 x float> poison, float %val, i32 0
+ %canonicalized = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %vec)
+ ret <2 x float> %canonicalized
+}
+
+; Test v2f32 with undef in low lane, register in high lane
+define <2 x float> @test_canonicalize_v2f32_undef_reg(float %val) {
+; GFX9-LABEL: test_canonicalize_v2f32_undef_reg:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_max_f32_e32 v1, v0, v0
+; GFX9-NEXT: v_mov_b32_e32 v0, 0
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f32_undef_reg:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_dual_max_f32 v1, v0, v0 :: v_dual_mov_b32 v0, 0
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+ %vec = insertelement <2 x float> poison, float %val, i32 1
+ %canonicalized = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %vec)
+ ret <2 x float> %canonicalized
+}
+
+; Test v2f32 with register and constant
+define <2 x float> @test_canonicalize_v2f32_reg_const(float %val) {
+; GFX9-LABEL: test_canonicalize_v2f32_reg_const:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_max_f32_e32 v0, v0, v0
+; GFX9-NEXT: v_mov_b32_e32 v1, 4.0
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f32_reg_const:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_dual_max_f32 v0, v0, v0 :: v_dual_mov_b32 v1, 4.0
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+ %vec0 = insertelement <2 x float> poison, float %val, i32 0
+ %vec1 = insertelement <2 x float> %vec0, float 4.0, i32 1
+ %canonicalized = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %vec1)
+ ret <2 x float> %canonicalized
+}
+
+; Test v2f64 with register in low lane, undef in high lane
+define <2 x double> @test_canonicalize_v2f64_reg_undef(double %val) {
+; GFX9-LABEL: test_canonicalize_v2f64_reg_undef:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_max_f64 v[0:1], v[0:1], v[0:1]
+; GFX9-NEXT: v_mov_b32_e32 v2, 0
+; GFX9-NEXT: v_mov_b32_e32 v3, 0
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f64_reg_undef:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_max_f64 v[0:1], v[0:1], v[0:1]
+; GFX11-TRUE16-NEXT: v_dual_mov_b32 v2, 0 :: v_dual_mov_b32 v3, 0
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+ %vec = insertelement <2 x double> poison, double %val, i32 0
+ %canonicalized = call <2 x double> @llvm.canonicalize.v2f64(<2 x double> %vec)
+ ret <2 x double> %canonicalized
+}
+
+; Test v2f64 with undef in low lane, register in high lane
+define <2 x double> @test_canonicalize_v2f64_undef_reg(double %val) {
+; GFX9-LABEL: test_canonicalize_v2f64_undef_reg:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_max_f64 v[2:3], v[0:1], v[0:1]
+; GFX9-NEXT: v_mov_b32_e32 v0, 0
+; GFX9-NEXT: v_mov_b32_e32 v1, 0
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f64_undef_reg:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_max_f64 v[2:3], v[0:1], v[0:1]
+; GFX11-TRUE16-NEXT: v_dual_mov_b32 v0, 0 :: v_dual_mov_b32 v1, 0
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+ %vec = insertelement <2 x double> poison, double %val, i32 1
+ %canonicalized = call <2 x double> @llvm.canonicalize.v2f64(<2 x double> %vec)
+ ret <2 x double> %canonicalized
+}
+
+; Test v2f64 with register and constant
+define <2 x double> @test_canonicalize_v2f64_reg_const(double %val) {
+; GFX9-LABEL: test_canonicalize_v2f64_reg_const:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_max_f64 v[0:1], v[0:1], v[0:1]
+; GFX9-NEXT: v_mov_b32_e32 v2, 0
+; GFX9-NEXT: v_mov_b32_e32 v3, 0x40140000
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f64_reg_const:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_max_f64 v[0:1], v[0:1], v[0:1]
+; GFX11-TRUE16-NEXT: v_dual_mov_b32 v2, 0 :: v_dual_mov_b32 v3, 0x40140000
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+ %vec0 = insertelement <2 x double> poison, double %val, i32 0
+ %vec1 = insertelement <2 x double> %vec0, double 5.0, i32 1
+ %canonicalized = call <2 x double> @llvm.canonicalize.v2f64(<2 x double> %vec1)
+ ret <2 x double> %canonicalized
+}
>From 93797c52fb82de848dc7bd845baf13fafc7f9e16 Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Fri, 7 Aug 2026 21:20:05 -0500
Subject: [PATCH 5/7] Use poison instead of undef
Signed-off-by: John Lu <John.Lu at amd.com>
---
...v2-undef.ll => fcanonicalize-v2-poison.ll} | 50 +++++++++----------
1 file changed, 25 insertions(+), 25 deletions(-)
rename llvm/test/CodeGen/AMDGPU/{fcanonicalize-v2-undef.ll => fcanonicalize-v2-poison.ll} (84%)
diff --git a/llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-undef.ll b/llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-poison.ll
similarity index 84%
rename from llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-undef.ll
rename to llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-poison.ll
index 784c8b2e46d9c..d7fe6b444d6af 100644
--- a/llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-undef.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-poison.ll
@@ -3,23 +3,23 @@
; RUN: llc -mtriple=amdgpu11.00 -mattr=+real-true16 < %s | FileCheck -check-prefixes=GFX11-TRUE16 %s
; Test fcanonicalize optimization that scalarizes when building vectors with
-; undef or constant elements. This optimization only applies when scalar
+; poison or constant elements. This optimization only applies when scalar
; fcanonicalize is legal for the element type (f16, f32, f64 - not bf16).
declare <2 x half> @llvm.canonicalize.v2f16(<2 x half>)
declare <2 x float> @llvm.canonicalize.v2f32(<2 x float>)
declare <2 x double> @llvm.canonicalize.v2f64(<2 x double>)
-; Test v2f16 with register in low lane, undef in high lane
-define <2 x half> @test_canonicalize_v2f16_reg_undef(half %val) {
-; GFX9-LABEL: test_canonicalize_v2f16_reg_undef:
+; Test v2f16 with register in low lane, poison in high lane
+define <2 x half> @test_canonicalize_v2f16_reg_poison(half %val) {
+; GFX9-LABEL: test_canonicalize_v2f16_reg_poison:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX9-NEXT: v_max_f16_e32 v0, v0, v0
; GFX9-NEXT: v_pack_b32_f16 v0, v0, 0
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
-; GFX11-TRUE16-LABEL: test_canonicalize_v2f16_reg_undef:
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f16_reg_poison:
; GFX11-TRUE16: ; %bb.0:
; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-TRUE16-NEXT: v_max_f16_e32 v0.l, v0.l, v0.l
@@ -31,16 +31,16 @@ define <2 x half> @test_canonicalize_v2f16_reg_undef(half %val) {
ret <2 x half> %canonicalized
}
-; Test v2f16 with undef in low lane, register in high lane
-define <2 x half> @test_canonicalize_v2f16_undef_reg(half %val) {
-; GFX9-LABEL: test_canonicalize_v2f16_undef_reg:
+; Test v2f16 with poison in low lane, register in high lane
+define <2 x half> @test_canonicalize_v2f16_poison_reg(half %val) {
+; GFX9-LABEL: test_canonicalize_v2f16_poison_reg:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX9-NEXT: v_max_f16_e32 v0, v0, v0
; GFX9-NEXT: v_pack_b32_f16 v0, 0, v0
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
-; GFX11-TRUE16-LABEL: test_canonicalize_v2f16_undef_reg:
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f16_poison_reg:
; GFX11-TRUE16: ; %bb.0:
; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-TRUE16-NEXT: v_max_f16_e32 v0.h, v0.l, v0.l
@@ -94,16 +94,16 @@ define <2 x half> @test_canonicalize_v2f16_const_reg(half %val) {
ret <2 x half> %canonicalized
}
-; Test v2f32 with register in low lane, undef in high lane
-define <2 x float> @test_canonicalize_v2f32_reg_undef(float %val) {
-; GFX9-LABEL: test_canonicalize_v2f32_reg_undef:
+; Test v2f32 with register in low lane, poison in high lane
+define <2 x float> @test_canonicalize_v2f32_reg_poison(float %val) {
+; GFX9-LABEL: test_canonicalize_v2f32_reg_poison:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX9-NEXT: v_max_f32_e32 v0, v0, v0
; GFX9-NEXT: v_mov_b32_e32 v1, 0
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
-; GFX11-TRUE16-LABEL: test_canonicalize_v2f32_reg_undef:
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f32_reg_poison:
; GFX11-TRUE16: ; %bb.0:
; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-TRUE16-NEXT: v_dual_max_f32 v0, v0, v0 :: v_dual_mov_b32 v1, 0
@@ -113,16 +113,16 @@ define <2 x float> @test_canonicalize_v2f32_reg_undef(float %val) {
ret <2 x float> %canonicalized
}
-; Test v2f32 with undef in low lane, register in high lane
-define <2 x float> @test_canonicalize_v2f32_undef_reg(float %val) {
-; GFX9-LABEL: test_canonicalize_v2f32_undef_reg:
+; Test v2f32 with poison in low lane, register in high lane
+define <2 x float> @test_canonicalize_v2f32_poison_reg(float %val) {
+; GFX9-LABEL: test_canonicalize_v2f32_poison_reg:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX9-NEXT: v_max_f32_e32 v1, v0, v0
; GFX9-NEXT: v_mov_b32_e32 v0, 0
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
-; GFX11-TRUE16-LABEL: test_canonicalize_v2f32_undef_reg:
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f32_poison_reg:
; GFX11-TRUE16: ; %bb.0:
; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-TRUE16-NEXT: v_dual_max_f32 v1, v0, v0 :: v_dual_mov_b32 v0, 0
@@ -152,9 +152,9 @@ define <2 x float> @test_canonicalize_v2f32_reg_const(float %val) {
ret <2 x float> %canonicalized
}
-; Test v2f64 with register in low lane, undef in high lane
-define <2 x double> @test_canonicalize_v2f64_reg_undef(double %val) {
-; GFX9-LABEL: test_canonicalize_v2f64_reg_undef:
+; Test v2f64 with register in low lane, poison in high lane
+define <2 x double> @test_canonicalize_v2f64_reg_poison(double %val) {
+; GFX9-LABEL: test_canonicalize_v2f64_reg_poison:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX9-NEXT: v_max_f64 v[0:1], v[0:1], v[0:1]
@@ -162,7 +162,7 @@ define <2 x double> @test_canonicalize_v2f64_reg_undef(double %val) {
; GFX9-NEXT: v_mov_b32_e32 v3, 0
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
-; GFX11-TRUE16-LABEL: test_canonicalize_v2f64_reg_undef:
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f64_reg_poison:
; GFX11-TRUE16: ; %bb.0:
; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-TRUE16-NEXT: v_max_f64 v[0:1], v[0:1], v[0:1]
@@ -173,9 +173,9 @@ define <2 x double> @test_canonicalize_v2f64_reg_undef(double %val) {
ret <2 x double> %canonicalized
}
-; Test v2f64 with undef in low lane, register in high lane
-define <2 x double> @test_canonicalize_v2f64_undef_reg(double %val) {
-; GFX9-LABEL: test_canonicalize_v2f64_undef_reg:
+; Test v2f64 with poison in low lane, register in high lane
+define <2 x double> @test_canonicalize_v2f64_poison_reg(double %val) {
+; GFX9-LABEL: test_canonicalize_v2f64_poison_reg:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX9-NEXT: v_max_f64 v[2:3], v[0:1], v[0:1]
@@ -183,7 +183,7 @@ define <2 x double> @test_canonicalize_v2f64_undef_reg(double %val) {
; GFX9-NEXT: v_mov_b32_e32 v1, 0
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
-; GFX11-TRUE16-LABEL: test_canonicalize_v2f64_undef_reg:
+; GFX11-TRUE16-LABEL: test_canonicalize_v2f64_poison_reg:
; GFX11-TRUE16: ; %bb.0:
; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-TRUE16-NEXT: v_max_f64 v[2:3], v[0:1], v[0:1]
>From 664ecb34bef9e8ac022e846985817b50ca81128b Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Fri, 7 Aug 2026 21:29:24 -0500
Subject: [PATCH 6/7] Fix formatting
Signed-off-by: John Lu <John.Lu at amd.com>
---
llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 017e0f5ebc83e..c3709e432b191 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -16392,8 +16392,8 @@ SITargetLowering::performFCanonicalizeCombine(SDNode *N,
// TODO: This could be better with wider vectors that will be split to v2f16,
// and to consider uses since there aren't that many packed operations.
- if (N0.getOpcode() == ISD::BUILD_VECTOR &&
- VT.getVectorNumElements() == 2 && isTypeLegal(VT)) {
+ if (N0.getOpcode() == ISD::BUILD_VECTOR && VT.getVectorNumElements() == 2 &&
+ isTypeLegal(VT)) {
SDLoc SL(N);
SDValue NewElts[2];
SDValue Lo = N0.getOperand(0);
>From a1b7ea72901dbddb8a9704f0905aa72fed3481ae Mon Sep 17 00:00:00 2001
From: John Lu <John.Lu at amd.com>
Date: Sat, 8 Aug 2026 12:50:20 -0500
Subject: [PATCH 7/7] Remove unnecessary declarations
Signed-off-by: John Lu <John.Lu at amd.com>
---
llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-poison.ll | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-poison.ll b/llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-poison.ll
index d7fe6b444d6af..925f647f35470 100644
--- a/llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-poison.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcanonicalize-v2-poison.ll
@@ -2,14 +2,10 @@
; RUN: llc -mtriple=amdgpu9.00 < %s | FileCheck -check-prefixes=GFX9 %s
; RUN: llc -mtriple=amdgpu11.00 -mattr=+real-true16 < %s | FileCheck -check-prefixes=GFX11-TRUE16 %s
-; Test fcanonicalize optimization that scalarizes when building vectors with
-; poison or constant elements. This optimization only applies when scalar
+; Test fcanonicalize optimization that scalarizes when building 2-element vectors
+; with poison or constant elements. This optimization only applies when scalar
; fcanonicalize is legal for the element type (f16, f32, f64 - not bf16).
-declare <2 x half> @llvm.canonicalize.v2f16(<2 x half>)
-declare <2 x float> @llvm.canonicalize.v2f32(<2 x float>)
-declare <2 x double> @llvm.canonicalize.v2f64(<2 x double>)
-
; Test v2f16 with register in low lane, poison in high lane
define <2 x half> @test_canonicalize_v2f16_reg_poison(half %val) {
; GFX9-LABEL: test_canonicalize_v2f16_reg_poison:
More information about the llvm-commits
mailing list