[llvm] [AMDGPU][InstCombine] Add dot zero/constant folding tests. NFC (PR #225001)
Harrison Hao via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 07:11:01 PDT 2026
https://github.com/harrisonGPU updated https://github.com/llvm/llvm-project/pull/225001
>From 4c284b69f7756e45e5d04cc0d352ef1d23d6e136 Mon Sep 17 00:00:00 2001
From: Harrison Hao <tsworld1314 at gmail.com>
Date: Mon, 21 Sep 2026 13:06:34 +0800
Subject: [PATCH 1/3] [AMDGPU][InstCombine] Add dot zero/constant folding
tests. NFC
---
.../InstCombine/AMDGPU/llvm.amdgcn.dot.ll | 616 ++++++++++++++++++
1 file changed, 616 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll
diff --git a/llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll b/llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll
new file mode 100644
index 00000000000000..bf97c14c7fe786
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll
@@ -0,0 +1,616 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=instcombine -mtriple=amdgpu12.00 %s | FileCheck %s
+
+define i32 @sdot2_add(<2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: define i32 @sdot2_add(
+; CHECK-SAME: <2 x i16> [[A:%.*]], <2 x i16> [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot2(<2 x i16> [[A]], <2 x i16> [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot2(<2 x i16> %a, <2 x i16> %b, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot2_sub(<2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: define i32 @sdot2_sub(
+; CHECK-SAME: <2 x i16> [[A:%.*]], <2 x i16> [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot2(<2 x i16> [[A]], <2 x i16> [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], -1
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot2(<2 x i16> %a, <2 x i16> %b, i32 7, i1 false)
+ %r = sub i32 %dot, 1
+ ret i32 %r
+}
+
+define i32 @sdot2_a_zero(<2 x i16> %b) {
+; CHECK-LABEL: define i32 @sdot2_a_zero(
+; CHECK-SAME: <2 x i16> [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot2(<2 x i16> zeroinitializer, <2 x i16> [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot2(<2 x i16> zeroinitializer, <2 x i16> %b, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot2_const_lhs(<2 x i16> %b, i32 %acc) {
+; CHECK-LABEL: define i32 @sdot2_const_lhs(
+; CHECK-SAME: <2 x i16> [[B:%.*]], i32 [[ACC:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot2(<2 x i16> zeroinitializer, <2 x i16> [[B]], i32 [[ACC]], i1 false)
+; CHECK-NEXT: ret i32 [[DOT]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot2(<2 x i16> zeroinitializer, <2 x i16> %b, i32 %acc, i1 false)
+ ret i32 %dot
+}
+
+define i32 @sdot2_b_zero(<2 x i16> %a) {
+; CHECK-LABEL: define i32 @sdot2_b_zero(
+; CHECK-SAME: <2 x i16> [[A:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot2(<2 x i16> [[A]], <2 x i16> zeroinitializer, i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot2(<2 x i16> %a, <2 x i16> zeroinitializer, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot2_const_nonzero(<2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: define i32 @sdot2_const_nonzero(
+; CHECK-SAME: <2 x i16> [[A:%.*]], <2 x i16> [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot2(<2 x i16> splat (i16 1), <2 x i16> splat (i16 2), i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot2(<2 x i16> <i16 1, i16 1>, <2 x i16> <i16 2, i16 2>, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot2_clamp(<2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: define i32 @sdot2_clamp(
+; CHECK-SAME: <2 x i16> [[A:%.*]], <2 x i16> [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot2(<2 x i16> [[A]], <2 x i16> [[B]], i32 7, i1 true)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot2(<2 x i16> %a, <2 x i16> %b, i32 7, i1 true)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot2_sub_from_const(<2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: define i32 @sdot2_sub_from_const(
+; CHECK-SAME: <2 x i16> [[A:%.*]], <2 x i16> [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot2(<2 x i16> [[A]], <2 x i16> [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = sub i32 9, [[DOT]]
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot2(<2 x i16> %a, <2 x i16> %b, i32 7, i1 false)
+ %r = sub i32 9, %dot
+ ret i32 %r
+}
+
+define i32 @sdot2_multi_use(<2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: define i32 @sdot2_multi_use(
+; CHECK-SAME: <2 x i16> [[A:%.*]], <2 x i16> [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot2(<2 x i16> [[A]], <2 x i16> [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: [[R:%.*]] = mul i32 [[ADD]], [[DOT]]
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot2(<2 x i16> %a, <2 x i16> %b, i32 7, i1 false)
+ %add = add i32 %dot, 9
+ %r = mul i32 %add, %dot
+ ret i32 %r
+}
+
+define i32 @udot2_add(<2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: define i32 @udot2_add(
+; CHECK-SAME: <2 x i16> [[A:%.*]], <2 x i16> [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot2(<2 x i16> [[A]], <2 x i16> [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot2(<2 x i16> %a, <2 x i16> %b, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot2_sub(<2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: define i32 @udot2_sub(
+; CHECK-SAME: <2 x i16> [[A:%.*]], <2 x i16> [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot2(<2 x i16> [[A]], <2 x i16> [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], -1
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot2(<2 x i16> %a, <2 x i16> %b, i32 7, i1 false)
+ %r = sub i32 %dot, 1
+ ret i32 %r
+}
+
+define i32 @udot2_a_zero(<2 x i16> %b) {
+; CHECK-LABEL: define i32 @udot2_a_zero(
+; CHECK-SAME: <2 x i16> [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot2(<2 x i16> zeroinitializer, <2 x i16> [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot2(<2 x i16> zeroinitializer, <2 x i16> %b, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot2_const_lhs(<2 x i16> %b, i32 %acc) {
+; CHECK-LABEL: define i32 @udot2_const_lhs(
+; CHECK-SAME: <2 x i16> [[B:%.*]], i32 [[ACC:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot2(<2 x i16> zeroinitializer, <2 x i16> [[B]], i32 [[ACC]], i1 false)
+; CHECK-NEXT: ret i32 [[DOT]]
+;
+ %dot = call i32 @llvm.amdgcn.udot2(<2 x i16> zeroinitializer, <2 x i16> %b, i32 %acc, i1 false)
+ ret i32 %dot
+}
+
+define i32 @udot2_b_zero(<2 x i16> %a) {
+; CHECK-LABEL: define i32 @udot2_b_zero(
+; CHECK-SAME: <2 x i16> [[A:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot2(<2 x i16> [[A]], <2 x i16> zeroinitializer, i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot2(<2 x i16> %a, <2 x i16> zeroinitializer, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot2_const_nonzero(<2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: define i32 @udot2_const_nonzero(
+; CHECK-SAME: <2 x i16> [[A:%.*]], <2 x i16> [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot2(<2 x i16> splat (i16 1), <2 x i16> splat (i16 2), i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot2(<2 x i16> <i16 1, i16 1>, <2 x i16> <i16 2, i16 2>, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot2_clamp(<2 x i16> %a, <2 x i16> %b) {
+; CHECK-LABEL: define i32 @udot2_clamp(
+; CHECK-SAME: <2 x i16> [[A:%.*]], <2 x i16> [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot2(<2 x i16> [[A]], <2 x i16> [[B]], i32 7, i1 true)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot2(<2 x i16> %a, <2 x i16> %b, i32 7, i1 true)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot4_add(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot4_add(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 %a, i32 %b, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot4_add_commuted(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot4_add_commuted(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 %a, i32 %b, i32 7, i1 false)
+ %r = add i32 9, %dot
+ ret i32 %r
+}
+
+define i32 @sdot4_sub(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot4_sub(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], -1
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 %a, i32 %b, i32 7, i1 false)
+ %r = sub i32 %dot, 1
+ ret i32 %r
+}
+
+define i32 @sdot4_a_zero(i32 %b) {
+; CHECK-LABEL: define i32 @sdot4_a_zero(
+; CHECK-SAME: i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 0, i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 0, i32 %b, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot4_const_lhs(i32 %b, i32 %acc) {
+; CHECK-LABEL: define i32 @sdot4_const_lhs(
+; CHECK-SAME: i32 [[B:%.*]], i32 [[ACC:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 16843009, i32 [[B]], i32 [[ACC]], i1 false)
+; CHECK-NEXT: ret i32 [[DOT]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 16843009, i32 %b, i32 %acc, i1 false)
+ ret i32 %dot
+}
+
+define i32 @sdot4_b_zero(i32 %a) {
+; CHECK-LABEL: define i32 @sdot4_b_zero(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 [[A]], i32 0, i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 %a, i32 0, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot4_sub_to_zero(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot4_sub_to_zero(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 [[A]], i32 [[B]], i32 9, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], -9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 %a, i32 %b, i32 9, i1 false)
+ %r = sub i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot4_add_chain(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot4_add_chain(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 6
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 %a, i32 %b, i32 7, i1 false)
+ %add = add i32 %dot, 9
+ %r = sub i32 %add, 3
+ ret i32 %r
+}
+
+define i32 @sdot4_const_nonzero(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot4_const_nonzero(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 1, i32 2, i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 1, i32 2, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot4_clamp(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot4_clamp(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 [[A]], i32 [[B]], i32 7, i1 true)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 %a, i32 %b, i32 7, i1 true)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot4_sub_from_const(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot4_sub_from_const(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = sub i32 9, [[DOT]]
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 %a, i32 %b, i32 7, i1 false)
+ %r = sub i32 9, %dot
+ ret i32 %r
+}
+
+define i32 @sdot4_multi_use(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot4_multi_use(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: [[R:%.*]] = mul i32 [[ADD]], [[DOT]]
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 %a, i32 %b, i32 7, i1 false)
+ %add = add i32 %dot, 9
+ %r = mul i32 %add, %dot
+ ret i32 %r
+}
+
+define i32 @sdot4_acc_not_const(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: define i32 @sdot4_acc_not_const(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 [[A]], i32 [[B]], i32 [[C]], i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 %a, i32 %b, i32 %c, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot4_add_x(i32 %a, i32 %b, i32 %x) {
+; CHECK-LABEL: define i32 @sdot4_add_x(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i32 [[X:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot4(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], [[X]]
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot4(i32 %a, i32 %b, i32 7, i1 false)
+ %r = add i32 %dot, %x
+ ret i32 %r
+}
+
+define i32 @udot4_add(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @udot4_add(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot4(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot4(i32 %a, i32 %b, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot4_sub(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @udot4_sub(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot4(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], -1
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot4(i32 %a, i32 %b, i32 7, i1 false)
+ %r = sub i32 %dot, 1
+ ret i32 %r
+}
+
+define i32 @udot4_a_zero(i32 %b) {
+; CHECK-LABEL: define i32 @udot4_a_zero(
+; CHECK-SAME: i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot4(i32 0, i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot4(i32 0, i32 %b, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot4_const_lhs(i32 %b, i32 %acc) {
+; CHECK-LABEL: define i32 @udot4_const_lhs(
+; CHECK-SAME: i32 [[B:%.*]], i32 [[ACC:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot4(i32 6, i32 [[B]], i32 [[ACC]], i1 false)
+; CHECK-NEXT: ret i32 [[DOT]]
+;
+ %dot = call i32 @llvm.amdgcn.udot4(i32 6, i32 %b, i32 %acc, i1 false)
+ ret i32 %dot
+}
+
+define i32 @udot4_b_zero(i32 %a) {
+; CHECK-LABEL: define i32 @udot4_b_zero(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot4(i32 [[A]], i32 0, i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot4(i32 %a, i32 0, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot4_const_nonzero(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @udot4_const_nonzero(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot4(i32 1, i32 2, i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot4(i32 1, i32 2, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot4_clamp(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @udot4_clamp(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot4(i32 [[A]], i32 [[B]], i32 7, i1 true)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot4(i32 %a, i32 %b, i32 7, i1 true)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot8_add(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot8_add(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot8(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot8(i32 %a, i32 %b, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot8_sub(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot8_sub(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot8(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], -1
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot8(i32 %a, i32 %b, i32 7, i1 false)
+ %r = sub i32 %dot, 1
+ ret i32 %r
+}
+
+define i32 @sdot8_a_zero(i32 %b) {
+; CHECK-LABEL: define i32 @sdot8_a_zero(
+; CHECK-SAME: i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot8(i32 0, i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot8(i32 0, i32 %b, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot8_const_lhs(i32 %b, i32 %acc) {
+; CHECK-LABEL: define i32 @sdot8_const_lhs(
+; CHECK-SAME: i32 [[B:%.*]], i32 [[ACC:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot8(i32 16843009, i32 [[B]], i32 [[ACC]], i1 false)
+; CHECK-NEXT: ret i32 [[DOT]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot8(i32 16843009, i32 %b, i32 %acc, i1 false)
+ ret i32 %dot
+}
+
+define i32 @sdot8_b_zero(i32 %a) {
+; CHECK-LABEL: define i32 @sdot8_b_zero(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot8(i32 [[A]], i32 0, i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot8(i32 %a, i32 0, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot8_const_nonzero(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot8_const_nonzero(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot8(i32 1, i32 2, i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot8(i32 1, i32 2, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @sdot8_clamp(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @sdot8_clamp(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.sdot8(i32 [[A]], i32 [[B]], i32 7, i1 true)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.sdot8(i32 %a, i32 %b, i32 7, i1 true)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot8_add(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @udot8_add(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot8(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot8(i32 %a, i32 %b, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot8_sub(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @udot8_sub(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot8(i32 [[A]], i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], -1
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot8(i32 %a, i32 %b, i32 7, i1 false)
+ %r = sub i32 %dot, 1
+ ret i32 %r
+}
+
+define i32 @udot8_a_zero(i32 %b) {
+; CHECK-LABEL: define i32 @udot8_a_zero(
+; CHECK-SAME: i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot8(i32 0, i32 [[B]], i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot8(i32 0, i32 %b, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot8_const_lhs(i32 %b, i32 %acc) {
+; CHECK-LABEL: define i32 @udot8_const_lhs(
+; CHECK-SAME: i32 [[B:%.*]], i32 [[ACC:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot8(i32 0, i32 [[B]], i32 [[ACC]], i1 false)
+; CHECK-NEXT: ret i32 [[DOT]]
+;
+ %dot = call i32 @llvm.amdgcn.udot8(i32 0, i32 %b, i32 %acc, i1 false)
+ ret i32 %dot
+}
+
+define i32 @udot8_b_zero(i32 %a) {
+; CHECK-LABEL: define i32 @udot8_b_zero(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot8(i32 [[A]], i32 0, i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot8(i32 %a, i32 0, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot8_const_nonzero(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @udot8_const_nonzero(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot8(i32 1, i32 2, i32 7, i1 false)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot8(i32 1, i32 2, i32 7, i1 false)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+define i32 @udot8_clamp(i32 %a, i32 %b) {
+; CHECK-LABEL: define i32 @udot8_clamp(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: [[DOT:%.*]] = call i32 @llvm.amdgcn.udot8(i32 [[A]], i32 [[B]], i32 7, i1 true)
+; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %dot = call i32 @llvm.amdgcn.udot8(i32 %a, i32 %b, i32 7, i1 true)
+ %r = add i32 %dot, 9
+ ret i32 %r
+}
+
+declare i32 @llvm.amdgcn.sdot2(<2 x i16>, <2 x i16>, i32, i1 immarg) #0
+declare i32 @llvm.amdgcn.udot2(<2 x i16>, <2 x i16>, i32, i1 immarg) #0
+declare i32 @llvm.amdgcn.sdot4(i32, i32, i32, i1 immarg) #0
+declare i32 @llvm.amdgcn.udot4(i32, i32, i32, i1 immarg) #0
+declare i32 @llvm.amdgcn.sdot8(i32, i32, i32, i1 immarg) #0
+declare i32 @llvm.amdgcn.udot8(i32, i32, i32, i1 immarg) #0
+
+attributes #0 = { nounwind readnone speculatable }
>From 6993e679b0759a105d1ba02deae636e95b0306d3 Mon Sep 17 00:00:00 2001
From: Harrison Hao <tsworld1314 at gmail.com>
Date: Mon, 21 Sep 2026 21:41:56 +0800
Subject: [PATCH 2/3] Use splat
---
llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll b/llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll
index bf97c14c7fe786..68ba966ea3b95c 100644
--- a/llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll
+++ b/llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll
@@ -66,7 +66,7 @@ define i32 @sdot2_const_nonzero(<2 x i16> %a, <2 x i16> %b) {
; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
; CHECK-NEXT: ret i32 [[R]]
;
- %dot = call i32 @llvm.amdgcn.sdot2(<2 x i16> <i16 1, i16 1>, <2 x i16> <i16 2, i16 2>, i32 7, i1 false)
+ %dot = call i32 @llvm.amdgcn.sdot2(<2 x i16> splat (i16 1), <2 x i16> splat (i16 2), i32 7, i1 false)
%r = add i32 %dot, 9
ret i32 %r
}
@@ -174,7 +174,7 @@ define i32 @udot2_const_nonzero(<2 x i16> %a, <2 x i16> %b) {
; CHECK-NEXT: [[R:%.*]] = add i32 [[DOT]], 9
; CHECK-NEXT: ret i32 [[R]]
;
- %dot = call i32 @llvm.amdgcn.udot2(<2 x i16> <i16 1, i16 1>, <2 x i16> <i16 2, i16 2>, i32 7, i1 false)
+ %dot = call i32 @llvm.amdgcn.udot2(<2 x i16> splat (i16 1), <2 x i16> splat (i16 2), i32 7, i1 false)
%r = add i32 %dot, 9
ret i32 %r
}
>From fc1947728021bdc702e5833d4c9f17d0cb430446 Mon Sep 17 00:00:00 2001
From: Harrison Hao <tsworld1314 at gmail.com>
Date: Mon, 21 Sep 2026 22:09:57 +0800
Subject: [PATCH 3/3] Add no use test
---
.../Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll b/llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll
index 68ba966ea3b95c..cf2ee80bd288f1 100644
--- a/llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll
+++ b/llvm/test/Transforms/InstCombine/AMDGPU/llvm.amdgcn.dot.ll
@@ -360,6 +360,15 @@ define i32 @sdot4_add_x(i32 %a, i32 %b, i32 %x) {
ret i32 %r
}
+define void @sdot4_no_use(i32 %a, i32 %b) {
+; CHECK-LABEL: define void @sdot4_no_use(
+; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
+; CHECK-NEXT: ret void
+;
+ call i32 @llvm.amdgcn.sdot4(i32 %a, i32 %b, i32 7, i1 false)
+ ret void
+}
+
define i32 @udot4_add(i32 %a, i32 %b) {
; CHECK-LABEL: define i32 @udot4_add(
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
More information about the llvm-commits
mailing list