[llvm] [NVPTX] Add mix precision arith intrinsics (PR #136657)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 21 23:20:05 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-nvptx
Author: Rajat Bajpai (rajatbajpai)
<details>
<summary>Changes</summary>
This change adds "add" and "sub" mix precision operations.
---
Patch is 22.49 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/136657.diff
3 Files Affected:
- (modified) llvm/include/llvm/IR/IntrinsicsNVVM.td (+42)
- (modified) llvm/lib/Target/NVPTX/NVPTXIntrinsics.td (+45)
- (added) llvm/test/CodeGen/NVPTX/arith-mix-precision.ll (+515)
``````````diff
diff --git a/llvm/include/llvm/IR/IntrinsicsNVVM.td b/llvm/include/llvm/IR/IntrinsicsNVVM.td
index d09e1da457249..d3076b1ecf29a 100644
--- a/llvm/include/llvm/IR/IntrinsicsNVVM.td
+++ b/llvm/include/llvm/IR/IntrinsicsNVVM.td
@@ -1306,6 +1306,48 @@ let TargetPrefix = "nvvm" in {
DefaultAttrsIntrinsic<[llvm_double_ty], [llvm_double_ty, llvm_double_ty],
[IntrNoMem, IntrSpeculatable, Commutative]>;
+ // Mixed-precision add intrinsics for half and bfloat16 to float
+ foreach rnd = ["rn", "rz", "rm", "rp"] in {
+ foreach sat = ["", "_sat"] in {
+ // Half-precision to float
+ def int_nvvm_add_#rnd#sat#_h_f
+ : ClangBuiltin<"__nvvm_add_"#rnd#sat#"_h_f">,
+ DefaultAttrsIntrinsic<[llvm_float_ty],
+ [llvm_half_ty, llvm_float_ty],
+ [IntrNoMem, IntrSpeculatable]>;
+
+ // BFloat16 to float
+ def int_nvvm_add_#rnd#sat#_bf_f
+ : ClangBuiltin<"__nvvm_add_"#rnd#sat#"_bf_f">,
+ DefaultAttrsIntrinsic<[llvm_float_ty],
+ [llvm_bfloat_ty, llvm_float_ty],
+ [IntrNoMem, IntrSpeculatable]>;
+ }
+ }
+
+ //
+ // Sub
+ //
+
+ // Mixed-precision subtraction intrinsics for half and bfloat16 to float
+ foreach rnd = ["rn", "rz", "rm", "rp"] in {
+ foreach sat = ["", "_sat"] in {
+ // Half-precision to float
+ def int_nvvm_sub_#rnd#sat#_h_f
+ : ClangBuiltin<"__nvvm_sub_"#rnd#sat#"_h_f">,
+ DefaultAttrsIntrinsic<[llvm_float_ty],
+ [llvm_half_ty, llvm_float_ty],
+ [IntrNoMem, IntrSpeculatable]>;
+
+ // BFloat16 to float
+ def int_nvvm_sub_#rnd#sat#_bf_f
+ : ClangBuiltin<"__nvvm_sub_"#rnd#sat#"_bf_f">,
+ DefaultAttrsIntrinsic<[llvm_float_ty],
+ [llvm_bfloat_ty, llvm_float_ty],
+ [IntrNoMem, IntrSpeculatable]>;
+ }
+ }
+
//
// Dot Product
//
diff --git a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
index 4ba3e6f06bb5f..abb94e2ec0b70 100644
--- a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
+++ b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
@@ -1656,6 +1656,51 @@ def INT_NVVM_ADD_RM_D : F_MATH_2<"add.rm.f64 \t$dst, $src0, $src1;",
def INT_NVVM_ADD_RP_D : F_MATH_2<"add.rp.f64 \t$dst, $src0, $src1;",
Float64Regs, Float64Regs, Float64Regs, int_nvvm_add_rp_d>;
+// Define mixed-precision add instructions for half and bfloat16 to float
+foreach rnd = ["rn", "rz", "rm", "rp"] in {
+ foreach sat = ["", "_sat"] in {
+ // Half-precision to float
+ def INT_NVVM_ADD_#!toupper(rnd#sat)#_H_F
+ : F_MATH_2<"add."#rnd#!subst("_", ".",
+ sat)#".f32.f16 \t$dst, $src0, $src1;",
+ Float32Regs, Int16Regs, Float32Regs,
+ !cast<Intrinsic>("int_nvvm_add_"#rnd#sat#"_h_f"),
+ [hasPTX<86>, hasSM<100>]>;
+
+ // BFloat16 to float
+ def INT_NVVM_ADD_#!toupper(rnd#sat)#_BF_F
+ : F_MATH_2<"add."#rnd#!subst("_", ".",
+ sat)#".f32.bf16 \t$dst, $src0, $src1;",
+ Float32Regs, Int16Regs, Float32Regs,
+ !cast<Intrinsic>("int_nvvm_add_"#rnd#sat#"_bf_f"),
+ [hasPTX<86>, hasSM<100>]>;
+ }
+}
+
+//
+// Sub
+//
+// Define mixed-precision sub instructions for half and bfloat16 to float
+foreach rnd = ["rn", "rz", "rm", "rp"] in {
+ foreach sat = ["", "_sat"] in {
+ // Half-precision to float
+ def INT_NVVM_SUB_#!toupper(rnd#sat)#_H_F
+ : F_MATH_2<"sub."#rnd#!subst("_", ".",
+ sat)#".f32.f16 \t$dst, $src0, $src1;",
+ Float32Regs, Int16Regs, Float32Regs,
+ !cast<Intrinsic>("int_nvvm_sub_"#rnd#sat#"_h_f"),
+ [hasPTX<86>, hasSM<100>]>;
+
+ // BFloat16 to float
+ def INT_NVVM_SUB_#!toupper(rnd#sat)#_BF_F
+ : F_MATH_2<"sub."#rnd#!subst("_", ".",
+ sat)#".f32.bf16 \t$dst, $src0, $src1;",
+ Float32Regs, Int16Regs, Float32Regs,
+ !cast<Intrinsic>("int_nvvm_sub_"#rnd#sat#"_bf_f"),
+ [hasPTX<86>, hasSM<100>]>;
+ }
+}
+
//
// BFIND
//
diff --git a/llvm/test/CodeGen/NVPTX/arith-mix-precision.ll b/llvm/test/CodeGen/NVPTX/arith-mix-precision.ll
new file mode 100644
index 0000000000000..444300dd40ec3
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/arith-mix-precision.ll
@@ -0,0 +1,515 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -march=nvptx64 -mcpu=sm_100 -mattr=+ptx86 | FileCheck %s
+
+define float @test_add_rn_h_f(half %a, float %b) {
+; CHECK-LABEL: test_add_rn_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rn_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rn_h_f_param_1];
+; CHECK-NEXT: add.rn.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rn.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rn_sat_h_f(half %a, float %b) {
+; CHECK-LABEL: test_add_rn_sat_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rn_sat_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rn_sat_h_f_param_1];
+; CHECK-NEXT: add.rn.sat.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rn.sat.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rz_h_f(half %a, float %b) {
+; CHECK-LABEL: test_add_rz_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rz_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rz_h_f_param_1];
+; CHECK-NEXT: add.rz.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rz.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rz_sat_h_f(half %a, float %b) {
+; CHECK-LABEL: test_add_rz_sat_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rz_sat_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rz_sat_h_f_param_1];
+; CHECK-NEXT: add.rz.sat.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rz.sat.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rm_h_f(half %a, float %b) {
+; CHECK-LABEL: test_add_rm_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rm_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rm_h_f_param_1];
+; CHECK-NEXT: add.rm.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rm.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rm_sat_h_f(half %a, float %b) {
+; CHECK-LABEL: test_add_rm_sat_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rm_sat_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rm_sat_h_f_param_1];
+; CHECK-NEXT: add.rm.sat.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rm.sat.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rp_h_f(half %a, float %b) {
+; CHECK-LABEL: test_add_rp_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rp_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rp_h_f_param_1];
+; CHECK-NEXT: add.rp.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rp.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rp_sat_h_f(half %a, float %b) {
+; CHECK-LABEL: test_add_rp_sat_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rp_sat_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rp_sat_h_f_param_1];
+; CHECK-NEXT: add.rp.sat.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rp.sat.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rn_bf_f(bfloat %a, float %b) {
+; CHECK-LABEL: test_add_rn_bf_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rn_bf_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rn_bf_f_param_1];
+; CHECK-NEXT: add.rn.f32.bf16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rn.bf.f(bfloat %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rn_sat_bf_f(bfloat %a, float %b) {
+; CHECK-LABEL: test_add_rn_sat_bf_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rn_sat_bf_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rn_sat_bf_f_param_1];
+; CHECK-NEXT: add.rn.sat.f32.bf16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rn.sat.bf.f(bfloat %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rz_bf_f(bfloat %a, float %b) {
+; CHECK-LABEL: test_add_rz_bf_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rz_bf_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rz_bf_f_param_1];
+; CHECK-NEXT: add.rz.f32.bf16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rz.bf.f(bfloat %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rz_sat_bf_f(bfloat %a, float %b) {
+; CHECK-LABEL: test_add_rz_sat_bf_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rz_sat_bf_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rz_sat_bf_f_param_1];
+; CHECK-NEXT: add.rz.sat.f32.bf16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rz.sat.bf.f(bfloat %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rm_bf_f(bfloat %a, float %b) {
+; CHECK-LABEL: test_add_rm_bf_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rm_bf_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rm_bf_f_param_1];
+; CHECK-NEXT: add.rm.f32.bf16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rm.bf.f(bfloat %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rm_sat_bf_f(bfloat %a, float %b) {
+; CHECK-LABEL: test_add_rm_sat_bf_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rm_sat_bf_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rm_sat_bf_f_param_1];
+; CHECK-NEXT: add.rm.sat.f32.bf16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rm.sat.bf.f(bfloat %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rp_bf_f(bfloat %a, float %b) {
+; CHECK-LABEL: test_add_rp_bf_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rp_bf_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rp_bf_f_param_1];
+; CHECK-NEXT: add.rp.f32.bf16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rp.bf.f(bfloat %a, float %b)
+ ret float %res
+}
+
+define float @test_add_rp_sat_bf_f(bfloat %a, float %b) {
+; CHECK-LABEL: test_add_rp_sat_bf_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_add_rp_sat_bf_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_add_rp_sat_bf_f_param_1];
+; CHECK-NEXT: add.rp.sat.f32.bf16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.add.rp.sat.bf.f(bfloat %a, float %b)
+ ret float %res
+}
+
+; Sub
+define float @test_sub_rn_h_f(half %a, float %b) {
+; CHECK-LABEL: test_sub_rn_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_sub_rn_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_sub_rn_h_f_param_1];
+; CHECK-NEXT: sub.rn.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.sub.rn.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_sub_rn_sat_h_f(half %a, float %b) {
+; CHECK-LABEL: test_sub_rn_sat_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_sub_rn_sat_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_sub_rn_sat_h_f_param_1];
+; CHECK-NEXT: sub.rn.sat.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.sub.rn.sat.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_sub_rz_h_f(half %a, float %b) {
+; CHECK-LABEL: test_sub_rz_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_sub_rz_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_sub_rz_h_f_param_1];
+; CHECK-NEXT: sub.rz.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.sub.rz.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_sub_rz_sat_h_f(half %a, float %b) {
+; CHECK-LABEL: test_sub_rz_sat_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_sub_rz_sat_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_sub_rz_sat_h_f_param_1];
+; CHECK-NEXT: sub.rz.sat.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.sub.rz.sat.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_sub_rm_h_f(half %a, float %b) {
+; CHECK-LABEL: test_sub_rm_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_sub_rm_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_sub_rm_h_f_param_1];
+; CHECK-NEXT: sub.rm.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.sub.rm.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_sub_rm_sat_h_f(half %a, float %b) {
+; CHECK-LABEL: test_sub_rm_sat_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_sub_rm_sat_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_sub_rm_sat_h_f_param_1];
+; CHECK-NEXT: sub.rm.sat.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.sub.rm.sat.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_sub_rp_h_f(half %a, float %b) {
+; CHECK-LABEL: test_sub_rp_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_sub_rp_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_sub_rp_h_f_param_1];
+; CHECK-NEXT: sub.rp.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.sub.rp.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_sub_rp_sat_h_f(half %a, float %b) {
+; CHECK-LABEL: test_sub_rp_sat_h_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_sub_rp_sat_h_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_sub_rp_sat_h_f_param_1];
+; CHECK-NEXT: sub.rp.sat.f32.f16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.sub.rp.sat.h.f(half %a, float %b)
+ ret float %res
+}
+
+define float @test_sub_rn_bf_f(bfloat %a, float %b) {
+; CHECK-LABEL: test_sub_rn_bf_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_sub_rn_bf_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_sub_rn_bf_f_param_1];
+; CHECK-NEXT: sub.rn.f32.bf16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.sub.rn.bf.f(bfloat %a, float %b)
+ ret float %res
+}
+
+define float @test_sub_rn_sat_bf_f(bfloat %a, float %b) {
+; CHECK-LABEL: test_sub_rn_sat_bf_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_sub_rn_sat_bf_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_sub_rn_sat_bf_f_param_1];
+; CHECK-NEXT: sub.rn.sat.f32.bf16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.sub.rn.sat.bf.f(bfloat %a, float %b)
+ ret float %res
+}
+
+define float @test_sub_rz_bf_f(bfloat %a, float %b) {
+; CHECK-LABEL: test_sub_rz_bf_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_sub_rz_bf_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1, [test_sub_rz_bf_f_param_1];
+; CHECK-NEXT: sub.rz.f32.bf16 %f2, %rs1, %f1;
+; CHECK-NEXT: st.param.f32 [func_retval0], %f2;
+; CHECK-NEXT: ret;
+ %res = call float @llvm.nvvm.sub.rz.bf.f(bfloat %a, float %b)
+ ret float %res
+}
+
+define float @test_sub_rz_sat_bf_f(bfloat %a, float %b) {
+; CHECK-LABEL: test_sub_rz_sat_bf_f(
+; CHECK: {
+; CHECK-NEXT: .reg .b16 %rs<2>;
+; CHECK-NEXT: .reg .f32 %f<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT: // %bb.0:
+; CHECK-NEXT: ld.param.b16 %rs1, [test_sub_rz_sat_bf_f_param_0];
+; CHECK-NEXT: ld.param.f32 %f1...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/136657
More information about the llvm-commits
mailing list