[llvm] [InstCombine] Add folds for `(fp_binop ({s|u}itofp x), ({s|u}itofp y))` (PR #82555)

via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 29 10:19:11 PST 2024


https://github.com/goldsteinn updated https://github.com/llvm/llvm-project/pull/82555

>From b14ab1e0e1387fb620f9f6c65007fd4c2f078dd6 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Wed, 21 Feb 2024 16:05:20 -0600
Subject: [PATCH 1/3] [InstCombine] Add tests for folding `(fp_binop
 ({s|u}itofp x), ({s|u}itofp y))`; NFC

---
 .../Transforms/InstCombine/binop-itofp.ll     | 1024 +++++++++++++++++
 1 file changed, 1024 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/binop-itofp.ll

diff --git a/llvm/test/Transforms/InstCombine/binop-itofp.ll b/llvm/test/Transforms/InstCombine/binop-itofp.ll
new file mode 100644
index 000000000000000..6354be7d723b646
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/binop-itofp.ll
@@ -0,0 +1,1024 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define half @test_ui_ui_i8_add(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i8_add(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 127
+; CHECK-NEXT:    [[Y:%.*]] = and i8 [[Y_IN:%.*]], 127
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 127
+  %y = and i8 %y_in, 127
+  %xf = uitofp i8 %x to half
+  %yf = uitofp i8 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i8_add_fail_overflow(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i8_add_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 127
+; CHECK-NEXT:    [[Y:%.*]] = and i8 [[Y_IN:%.*]], -127
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 127
+  %y = and i8 %y_in, 129
+  %xf = uitofp i8 %x to half
+  %yf = uitofp i8 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i8_add_C(i8 noundef %x_in) {
+; CHECK-LABEL: @test_ui_ui_i8_add_C(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 127
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xH5800
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 127
+  %xf = uitofp i8 %x to half
+  %r = fadd half %xf, 128.0
+  ret half %r
+}
+
+define half @test_ui_ui_i8_add_C_fail_no_repr(i8 noundef %x_in) {
+; CHECK-LABEL: @test_ui_ui_i8_add_C_fail_no_repr(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 127
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xH57F8
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 127
+  %xf = uitofp i8 %x to half
+  %r = fadd half %xf, 127.5
+  ret half %r
+}
+
+define half @test_ui_ui_i8_add_C_fail_overflow(i8 noundef %x_in) {
+; CHECK-LABEL: @test_ui_ui_i8_add_C_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 127
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xH5808
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 127
+  %xf = uitofp i8 %x to half
+  %r = fadd half %xf, 129.0
+  ret half %r
+}
+
+define half @test_si_si_i8_add(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i8_add(
+; CHECK-NEXT:    [[X:%.*]] = or i8 [[X_IN:%.*]], -64
+; CHECK-NEXT:    [[Y:%.*]] = or i8 [[Y_IN:%.*]], -64
+; CHECK-NEXT:    [[ADDCONV:%.*]] = add nsw i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i8 [[ADDCONV]] to half
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i8 %x_in, -64
+  %y = or i8 %y_in, -64
+  %xf = sitofp i8 %x to half
+  %yf = sitofp i8 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i8_add_fail_overflow(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i8_add_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = or i8 [[X_IN:%.*]], -64
+; CHECK-NEXT:    [[Y:%.*]] = or i8 [[Y_IN:%.*]], -65
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i8 %x_in, -64
+  %y = or i8 %y_in, -65
+  %xf = sitofp i8 %x to half
+  %yf = sitofp i8 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_si_i8_add(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_ui_si_i8_add(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 63
+; CHECK-NEXT:    [[Y:%.*]] = and i8 [[Y_IN:%.*]], 63
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 63
+  %y = and i8 %y_in, 63
+  %xf = sitofp i8 %x to half
+  %yf = uitofp i8 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_si_i8_add_overflow(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_ui_si_i8_add_overflow(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 63
+; CHECK-NEXT:    [[Y:%.*]] = and i8 [[Y_IN:%.*]], 65
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 63
+  %y = and i8 %y_in, 65
+  %xf = sitofp i8 %x to half
+  %yf = uitofp i8 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i8_sub_C(i8 noundef %x_in) {
+; CHECK-LABEL: @test_ui_ui_i8_sub_C(
+; CHECK-NEXT:    [[X:%.*]] = or i8 [[X_IN:%.*]], -128
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xHD800
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i8 %x_in, 128
+  %xf = uitofp i8 %x to half
+  %r = fsub half %xf, 128.0
+  ret half %r
+}
+
+define half @test_ui_ui_i8_sub_C_fail_overflow(i8 noundef %x_in) {
+; CHECK-LABEL: @test_ui_ui_i8_sub_C_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 127
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xHD800
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 127
+  %xf = uitofp i8 %x to half
+  %r = fsub half %xf, 128.0
+  ret half %r
+}
+
+define half @test_si_si_i8_sub(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i8_sub(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 63
+; CHECK-NEXT:    [[Y:%.*]] = or i8 [[Y_IN:%.*]], -64
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 63
+  %y = or i8 %y_in, -64
+  %xf = sitofp i8 %x to half
+  %yf = sitofp i8 %y to half
+  %r = fsub half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i8_sub_fail_overflow(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i8_sub_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 63
+; CHECK-NEXT:    [[Y:%.*]] = or i8 [[Y_IN:%.*]], -65
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 63
+  %y = or i8 %y_in, -65
+  %xf = sitofp i8 %x to half
+  %yf = sitofp i8 %y to half
+  %r = fsub half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i8_sub_C(i8 noundef %x_in) {
+; CHECK-LABEL: @test_si_si_i8_sub_C(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 63
+; CHECK-NEXT:    [[ADDCONV:%.*]] = or disjoint i8 [[X]], 64
+; CHECK-NEXT:    [[R:%.*]] = sitofp i8 [[ADDCONV]] to half
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 63
+  %xf = sitofp i8 %x to half
+  %r = fsub half %xf, -64.0
+  ret half %r
+}
+
+define half @test_si_si_i8_sub_C_fail_overflow(i8 noundef %x_in) {
+; CHECK-LABEL: @test_si_si_i8_sub_C_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 65
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xH5400
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 65
+  %xf = sitofp i8 %x to half
+  %r = fsub half %xf, -64.0
+  ret half %r
+}
+
+define half @test_ui_si_i8_sub(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_ui_si_i8_sub(
+; CHECK-NEXT:    [[X:%.*]] = or i8 [[X_IN:%.*]], 64
+; CHECK-NEXT:    [[Y:%.*]] = and i8 [[Y_IN:%.*]], 63
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i8 %x_in, 64
+  %y = and i8 %y_in, 63
+  %xf = sitofp i8 %x to half
+  %yf = uitofp i8 %y to half
+  %r = fsub half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_si_i8_sub_fail_maybe_sign(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_ui_si_i8_sub_fail_maybe_sign(
+; CHECK-NEXT:    [[X:%.*]] = or i8 [[X_IN:%.*]], 64
+; CHECK-NEXT:    [[Y:%.*]] = and i8 [[Y_IN:%.*]], 63
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i8 %x_in, 64
+  %y = and i8 %y_in, 63
+  %xf = uitofp i8 %x to half
+  %yf = sitofp i8 %y to half
+  %r = fsub half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i8_mul(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i8_mul(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 15
+; CHECK-NEXT:    [[Y:%.*]] = and i8 [[Y_IN:%.*]], 15
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 15
+  %y = and i8 %y_in, 15
+  %xf = uitofp i8 %x to half
+  %yf = uitofp i8 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i8_mul_C(i8 noundef %x_in) {
+; CHECK-LABEL: @test_ui_ui_i8_mul_C(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 15
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], 0xH4C00
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 15
+  %xf = uitofp i8 %x to half
+  %r = fmul half %xf, 16.0
+  ret half %r
+}
+
+define half @test_ui_ui_i8_mul_C_fail_overlow(i8 noundef %x_in) {
+; CHECK-LABEL: @test_ui_ui_i8_mul_C_fail_overlow(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 14
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], 0xH4CC0
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 14
+  %xf = uitofp i8 %x to half
+  %r = fmul half %xf, 19.0
+  ret half %r
+}
+
+define half @test_si_si_i8_mul(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i8_mul(
+; CHECK-NEXT:    [[XX:%.*]] = and i8 [[X_IN:%.*]], 6
+; CHECK-NEXT:    [[X:%.*]] = or disjoint i8 [[XX]], 1
+; CHECK-NEXT:    [[Y:%.*]] = or i8 [[Y_IN:%.*]], -8
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i8 %x_in, 6
+  %x = add nsw nuw i8 %xx, 1
+  %y = or i8 %y_in, -8
+  %xf = sitofp i8 %x to half
+  %yf = sitofp i8 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i8_mul_fail_maybe_zero(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i8_mul_fail_maybe_zero(
+; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 7
+; CHECK-NEXT:    [[Y:%.*]] = or i8 [[Y_IN:%.*]], -8
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i8 %x_in, 7
+  %y = or i8 %y_in, -8
+  %xf = sitofp i8 %x to half
+  %yf = sitofp i8 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i8_mul_C_fail_no_repr(i8 noundef %x_in) {
+; CHECK-LABEL: @test_si_si_i8_mul_C_fail_no_repr(
+; CHECK-NEXT:    [[XX:%.*]] = and i8 [[X_IN:%.*]], 6
+; CHECK-NEXT:    [[X:%.*]] = or disjoint i8 [[XX]], 1
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], 0xHC780
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i8 %x_in, 6
+  %x = add nsw nuw i8 %xx, 1
+  %xf = sitofp i8 %x to half
+  %r = fmul half %xf, -7.5
+  ret half %r
+}
+
+define half @test_si_si_i8_mul_C_fail_overflow(i8 noundef %x_in) {
+; CHECK-LABEL: @test_si_si_i8_mul_C_fail_overflow(
+; CHECK-NEXT:    [[XX:%.*]] = and i8 [[X_IN:%.*]], 6
+; CHECK-NEXT:    [[X:%.*]] = or disjoint i8 [[XX]], 1
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], 0xHCCC0
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i8 %x_in, 6
+  %x = add nsw nuw i8 %xx, 1
+  %xf = sitofp i8 %x to half
+  %r = fmul half %xf, -19.0
+  ret half %r
+}
+
+define half @test_ui_si_i8_mul(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_ui_si_i8_mul(
+; CHECK-NEXT:    [[XX:%.*]] = and i8 [[X_IN:%.*]], 6
+; CHECK-NEXT:    [[X:%.*]] = or disjoint i8 [[XX]], 1
+; CHECK-NEXT:    [[YY:%.*]] = and i8 [[Y_IN:%.*]], 7
+; CHECK-NEXT:    [[Y:%.*]] = add nuw nsw i8 [[YY]], 1
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i8 %x_in, 6
+  %x = add i8 %xx, 1
+  %yy = and i8 %y_in, 7
+  %y = add i8 %yy, 1
+  %xf = sitofp i8 %x to half
+  %yf = uitofp i8 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_si_i8_mul_fail_maybe_zero(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_ui_si_i8_mul_fail_maybe_zero(
+; CHECK-NEXT:    [[XX:%.*]] = and i8 [[X_IN:%.*]], 7
+; CHECK-NEXT:    [[X:%.*]] = add nuw nsw i8 [[XX]], 1
+; CHECK-NEXT:    [[Y:%.*]] = and i8 [[Y_IN:%.*]], 7
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i8 %x_in, 7
+  %x = add i8 %xx, 1
+  %y = and i8 %y_in, 7
+  %xf = sitofp i8 %x to half
+  %yf = uitofp i8 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_si_i8_mul_fail_signed(i8 noundef %x_in, i8 noundef %y_in) {
+; CHECK-LABEL: @test_ui_si_i8_mul_fail_signed(
+; CHECK-NEXT:    [[XX:%.*]] = and i8 [[X_IN:%.*]], 7
+; CHECK-NEXT:    [[X:%.*]] = add nuw nsw i8 [[XX]], 1
+; CHECK-NEXT:    [[Y:%.*]] = or i8 [[Y_IN:%.*]], -4
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i8 %x_in, 7
+  %x = add i8 %xx, 1
+  %y = or i8 %y_in, -4
+  %xf = sitofp i8 %x to half
+  %yf = uitofp i8 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i16_add(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i16_add(
+; CHECK-NEXT:    [[X:%.*]] = and i16 [[X_IN:%.*]], 2047
+; CHECK-NEXT:    [[Y:%.*]] = and i16 [[Y_IN:%.*]], 2047
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i16 %x_in, 2047
+  %y = and i16 %y_in, 2047
+  %xf = uitofp i16 %x to half
+  %yf = uitofp i16 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i16_add_fail_not_promotable(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i16_add_fail_not_promotable(
+; CHECK-NEXT:    [[X:%.*]] = and i16 [[X_IN:%.*]], 2049
+; CHECK-NEXT:    [[Y:%.*]] = and i16 [[Y_IN:%.*]], 2047
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i16 %x_in, 2049
+  %y = and i16 %y_in, 2047
+  %xf = uitofp i16 %x to half
+  %yf = uitofp i16 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i16_add_C(i16 noundef %x_in) {
+; CHECK-LABEL: @test_ui_ui_i16_add_C(
+; CHECK-NEXT:    [[X:%.*]] = and i16 [[X_IN:%.*]], 2047
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i16 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xH7BC0
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i16 %x_in, 2047
+  %xf = uitofp i16 %x to half
+  %r = fadd half %xf, 63488.0
+  ret half %r
+}
+
+define half @test_ui_ui_i16_add_C_fail_overflow(i16 noundef %x_in) {
+; CHECK-LABEL: @test_ui_ui_i16_add_C_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = and i16 [[X_IN:%.*]], 2047
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i16 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xH7BD0
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i16 %x_in, 2047
+  %xf = uitofp i16 %x to half
+  %r = fadd half %xf, 64000.0
+  ret half %r
+}
+
+define half @test_si_si_i16_add(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i16_add(
+; CHECK-NEXT:    [[X:%.*]] = or i16 [[X_IN:%.*]], -2048
+; CHECK-NEXT:    [[Y:%.*]] = or i16 [[Y_IN:%.*]], -2048
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i16 %x_in, -2048
+  %y = or i16 %y_in, -2048
+  %xf = sitofp i16 %x to half
+  %yf = sitofp i16 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i16_add_fail_no_promotion(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i16_add_fail_no_promotion(
+; CHECK-NEXT:    [[XX:%.*]] = or i16 [[X_IN:%.*]], -2048
+; CHECK-NEXT:    [[X:%.*]] = add nsw i16 [[XX]], -1
+; CHECK-NEXT:    [[Y:%.*]] = or i16 [[Y_IN:%.*]], -2048
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = or i16 %x_in, -2048
+  %x = sub i16 %xx, 1
+  %y = or i16 %y_in, -2048
+  %xf = sitofp i16 %x to half
+  %yf = sitofp i16 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i16_add_C_overflow(i16 noundef %x_in) {
+; CHECK-LABEL: @test_si_si_i16_add_C_overflow(
+; CHECK-NEXT:    [[X:%.*]] = or i16 [[X_IN:%.*]], -2048
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xH7840
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i16 %x_in, -2048
+  %xf = sitofp i16 %x to half
+  %r = fadd half %xf, 0xH7840
+  ret half %r
+}
+
+define half @test_si_si_i16_sub(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i16_sub(
+; CHECK-NEXT:    [[X:%.*]] = or i16 [[X_IN:%.*]], -2048
+; CHECK-NEXT:    [[Y:%.*]] = and i16 [[Y_IN:%.*]], 2047
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i16 %x_in, -2048
+  %y = and i16 %y_in, 2047
+  %xf = sitofp i16 %x to half
+  %yf = sitofp i16 %y to half
+  %r = fsub half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i16_sub_fail_no_promotion(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i16_sub_fail_no_promotion(
+; CHECK-NEXT:    [[X:%.*]] = and i16 [[X_IN:%.*]], 2047
+; CHECK-NEXT:    [[Y:%.*]] = or i16 [[Y_IN:%.*]], -2049
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i16 %x_in, 2047
+  %y = or i16 %y_in, -2049
+  %xf = sitofp i16 %x to half
+  %yf = sitofp i16 %y to half
+  %r = fsub half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_si_i16_sub(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_ui_si_i16_sub(
+; CHECK-NEXT:    [[X:%.*]] = and i16 [[X_IN:%.*]], 2047
+; CHECK-NEXT:    [[Y:%.*]] = and i16 [[Y_IN:%.*]], 2047
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i16 %x_in, 2047
+  %y = and i16 %y_in, 2047
+  %xf = uitofp i16 %x to half
+  %yf = sitofp i16 %y to half
+  %r = fsub half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_si_i16_sub_fail_maybe_signed(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_ui_si_i16_sub_fail_maybe_signed(
+; CHECK-NEXT:    [[X:%.*]] = or i16 [[X_IN:%.*]], -2048
+; CHECK-NEXT:    [[Y:%.*]] = and i16 [[Y_IN:%.*]], 2047
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i16 %x_in, -2048
+  %y = and i16 %y_in, 2047
+  %xf = uitofp i16 %x to half
+  %yf = sitofp i16 %y to half
+  %r = fsub half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i16_mul(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i16_mul(
+; CHECK-NEXT:    [[X:%.*]] = and i16 [[X_IN:%.*]], 255
+; CHECK-NEXT:    [[Y:%.*]] = and i16 [[Y_IN:%.*]], 255
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i16 %x_in, 255
+  %y = and i16 %y_in, 255
+  %xf = uitofp i16 %x to half
+  %yf = uitofp i16 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i16_mul_fail_no_promotion(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i16_mul_fail_no_promotion(
+; CHECK-NEXT:    [[X:%.*]] = and i16 [[X_IN:%.*]], 4095
+; CHECK-NEXT:    [[Y:%.*]] = and i16 [[Y_IN:%.*]], 3
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i16 %x_in, 4095
+  %y = and i16 %y_in, 3
+  %xf = uitofp i16 %x to half
+  %yf = uitofp i16 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i16_mul(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i16_mul(
+; CHECK-NEXT:    [[XX:%.*]] = and i16 [[X_IN:%.*]], 126
+; CHECK-NEXT:    [[X:%.*]] = or disjoint i16 [[XX]], 1
+; CHECK-NEXT:    [[Y:%.*]] = or i16 [[Y_IN:%.*]], -255
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i16 %x_in, 126
+  %x = add nsw nuw i16 %xx, 1
+  %y = or i16 %y_in, -255
+  %xf = sitofp i16 %x to half
+  %yf = sitofp i16 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i16_mul_fail_overflow(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i16_mul_fail_overflow(
+; CHECK-NEXT:    [[XX:%.*]] = and i16 [[X_IN:%.*]], 126
+; CHECK-NEXT:    [[X:%.*]] = or disjoint i16 [[XX]], 1
+; CHECK-NEXT:    [[Y:%.*]] = or i16 [[Y_IN:%.*]], -257
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i16 %x_in, 126
+  %x = add nsw nuw i16 %xx, 1
+  %y = or i16 %y_in, -257
+  %xf = sitofp i16 %x to half
+  %yf = sitofp i16 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i16_mul_C_fail_overflow(i16 noundef %x_in) {
+; CHECK-LABEL: @test_si_si_i16_mul_C_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = or i16 [[X_IN:%.*]], -129
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], 0xH5800
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i16 %x_in, -129
+  %xf = sitofp i16 %x to half
+  %r = fmul half %xf, 128.0
+  ret half %r
+}
+
+define half @test_si_si_i16_mul_C_fail_no_promotion(i16 noundef %x_in) {
+; CHECK-LABEL: @test_si_si_i16_mul_C_fail_no_promotion(
+; CHECK-NEXT:    [[X:%.*]] = or i16 [[X_IN:%.*]], -4097
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], 0xH4500
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i16 %x_in, -4097
+  %xf = sitofp i16 %x to half
+  %r = fmul half %xf, 5.0
+  ret half %r
+}
+
+define half @test_ui_si_i16_mul(i16 noundef %x_in, i16 noundef %y_in) {
+; CHECK-LABEL: @test_ui_si_i16_mul(
+; CHECK-NEXT:    [[XX:%.*]] = and i16 [[X_IN:%.*]], 126
+; CHECK-NEXT:    [[X:%.*]] = or disjoint i16 [[XX]], 1
+; CHECK-NEXT:    [[YY:%.*]] = and i16 [[Y_IN:%.*]], 126
+; CHECK-NEXT:    [[Y:%.*]] = or disjoint i16 [[YY]], 1
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i16 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i16 %x_in, 126
+  %x = add i16 %xx, 1
+  %yy = and i16 %y_in, 126
+  %y = add i16 %yy, 1
+  %xf = sitofp i16 %x to half
+  %yf = uitofp i16 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i12_add(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i12_add(
+; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 2047
+; CHECK-NEXT:    [[Y:%.*]] = and i12 [[Y_IN:%.*]], 2047
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i12 %x_in, 2047
+  %y = and i12 %y_in, 2047
+  %xf = uitofp i12 %x to half
+  %yf = uitofp i12 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i12_add_fail_overflow(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i12_add_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 2047
+; CHECK-NEXT:    [[Y:%.*]] = and i12 [[Y_IN:%.*]], -2047
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i12 %x_in, 2047
+  %y = and i12 %y_in, 2049
+  %xf = uitofp i12 %x to half
+  %yf = uitofp i12 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+
+define half @test_si_si_i12_add(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i12_add(
+; CHECK-NEXT:    [[X:%.*]] = or i12 [[X_IN:%.*]], -1024
+; CHECK-NEXT:    [[Y:%.*]] = or i12 [[Y_IN:%.*]], -1024
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i12 %x_in, -1024
+  %y = or i12 %y_in, -1024
+  %xf = sitofp i12 %x to half
+  %yf = sitofp i12 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i12_add_fail_overflow(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i12_add_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = or i12 [[X_IN:%.*]], -1025
+; CHECK-NEXT:    [[Y:%.*]] = or i12 [[Y_IN:%.*]], -1025
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i12 %x_in, -1025
+  %y = or i12 %y_in, -1025
+  %xf = sitofp i12 %x to half
+  %yf = sitofp i12 %y to half
+  %r = fadd half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i12_add_C_fail_overflow(i12 noundef %x_in) {
+; CHECK-LABEL: @test_si_si_i12_add_C_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = or i12 [[X_IN:%.*]], -2048
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xHBC00
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i12 %x_in, -2048
+  %xf = sitofp i12 %x to half
+  %r = fadd half %xf, -1.0
+  ret half %r
+}
+
+define half @test_ui_ui_i12_sub(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i12_sub(
+; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 1023
+; CHECK-NEXT:    [[Y:%.*]] = and i12 [[Y_IN:%.*]], 1023
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i12 %x_in, 1023
+  %y = and i12 %y_in, 1023
+  %xf = uitofp i12 %x to half
+  %yf = uitofp i12 %y to half
+  %r = fsub half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i12_sub_fail_overflow(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i12_sub_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 1023
+; CHECK-NEXT:    [[Y:%.*]] = and i12 [[Y_IN:%.*]], 2047
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i12 %x_in, 1023
+  %y = and i12 %y_in, 2047
+  %xf = uitofp i12 %x to half
+  %yf = uitofp i12 %y to half
+  %r = fsub half %xf, %yf
+  ret half %r
+}
+
+
+define half @test_si_si_i12_sub(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i12_sub(
+; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 1023
+; CHECK-NEXT:    [[Y:%.*]] = or i12 [[Y_IN:%.*]], -1024
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i12 %x_in, 1023
+  %y = or i12 %y_in, -1024
+  %xf = sitofp i12 %x to half
+  %yf = sitofp i12 %y to half
+  %r = fsub half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i12_sub_fail_overflow(i12 noundef %x, i12 noundef %y) {
+; CHECK-LABEL: @test_si_si_i12_sub_fail_overflow(
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X:%.*]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i12 [[Y:%.*]] to half
+; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xf = sitofp i12 %x to half
+  %yf = sitofp i12 %y to half
+  %r = fsub half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i12_mul(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i12_mul(
+; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 31
+; CHECK-NEXT:    [[Y:%.*]] = and i12 [[Y_IN:%.*]], 63
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i12 %x_in, 31
+  %y = and i12 %y_in, 63
+  %xf = uitofp i12 %x to half
+  %yf = uitofp i12 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i12_mul_fail_overflow(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_ui_ui_i12_mul_fail_overflow(
+; CHECK-NEXT:    [[XX:%.*]] = and i12 [[X_IN:%.*]], 31
+; CHECK-NEXT:    [[X:%.*]] = add nuw nsw i12 [[XX]], 1
+; CHECK-NEXT:    [[Y:%.*]] = and i12 [[Y_IN:%.*]], 63
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = uitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i12 %x_in, 31
+  %x = add i12 %xx, 1
+  %y = and i12 %y_in, 63
+  %xf = uitofp i12 %x to half
+  %yf = uitofp i12 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_ui_ui_i12_mul_C(i12 noundef %x_in) {
+; CHECK-LABEL: @test_ui_ui_i12_mul_C(
+; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 31
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], 0xH5400
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i12 %x_in, 31
+  %xf = uitofp i12 %x to half
+  %r = fmul half %xf, 64.0
+  ret half %r
+}
+
+define half @test_si_si_i12_mul(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i12_mul(
+; CHECK-NEXT:    [[XX:%.*]] = and i12 [[X_IN:%.*]], 30
+; CHECK-NEXT:    [[X:%.*]] = or disjoint i12 [[XX]], 1
+; CHECK-NEXT:    [[Y:%.*]] = or i12 [[Y_IN:%.*]], -64
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i12 %x_in, 30
+  %x = add nsw nuw i12 %xx, 1
+  %y = or i12 %y_in, -64
+  %xf = sitofp i12 %x to half
+  %yf = sitofp i12 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i12_mul_fail_overflow(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i12_mul_fail_overflow(
+; CHECK-NEXT:    [[XX:%.*]] = and i12 [[X_IN:%.*]], 30
+; CHECK-NEXT:    [[X:%.*]] = or disjoint i12 [[XX]], 1
+; CHECK-NEXT:    [[Y:%.*]] = or i12 [[Y_IN:%.*]], -128
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i12 %x_in, 30
+  %x = add nsw nuw i12 %xx, 1
+  %y = or i12 %y_in, -128
+  %xf = sitofp i12 %x to half
+  %yf = sitofp i12 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i12_mul_fail_maybe_non_zero(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_si_si_i12_mul_fail_maybe_non_zero(
+; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 30
+; CHECK-NEXT:    [[Y:%.*]] = or i12 [[Y_IN:%.*]], -128
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = and i12 %x_in, 30
+  %y = or i12 %y_in, -128
+  %xf = sitofp i12 %x to half
+  %yf = sitofp i12 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}
+
+define half @test_si_si_i12_mul_C(i12 noundef %x_in) {
+; CHECK-LABEL: @test_si_si_i12_mul_C(
+; CHECK-NEXT:    [[X:%.*]] = or i12 [[X_IN:%.*]], -64
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], 0xHCC00
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i12 %x_in, -64
+  %xf = sitofp i12 %x to half
+  %r = fmul half %xf, -16.0
+  ret half %r
+}
+
+define half @test_si_si_i12_mul_C_fail_overflow(i12 noundef %x_in) {
+; CHECK-LABEL: @test_si_si_i12_mul_C_fail_overflow(
+; CHECK-NEXT:    [[X:%.*]] = or i12 [[X_IN:%.*]], -64
+; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], 0xHD400
+; CHECK-NEXT:    ret half [[R]]
+;
+  %x = or i12 %x_in, -64
+  %xf = sitofp i12 %x to half
+  %r = fmul half %xf, -64.0
+  ret half %r
+}
+
+define half @test_ui_si_i12_mul_nsw(i12 noundef %x_in, i12 noundef %y_in) {
+; CHECK-LABEL: @test_ui_si_i12_mul_nsw(
+; CHECK-NEXT:    [[XX:%.*]] = and i12 [[X_IN:%.*]], 31
+; CHECK-NEXT:    [[X:%.*]] = add nuw nsw i12 [[XX]], 1
+; CHECK-NEXT:    [[YY:%.*]] = and i12 [[Y_IN:%.*]], 30
+; CHECK-NEXT:    [[Y:%.*]] = or disjoint i12 [[YY]], 1
+; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
+; CHECK-NEXT:    [[YF:%.*]] = sitofp i12 [[Y]] to half
+; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    ret half [[R]]
+;
+  %xx = and i12 %x_in, 31
+  %x = add i12 %xx, 1
+  %yy = and i12 %y_in, 30
+  %y = add i12 %yy, 1
+  %xf = uitofp i12 %x to half
+  %yf = sitofp i12 %y to half
+  %r = fmul half %xf, %yf
+  ret half %r
+}

>From 82888cd4b7fcca405e3ec29126baf31e1935c3a6 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Wed, 21 Feb 2024 16:13:01 -0600
Subject: [PATCH 2/3] [InstCombine] Move folding `(add (sitofp x), (sitofp y))`
 impl to InstructionCombiner; NFC

---
 .../InstCombine/InstCombineAddSub.cpp         | 60 +---------------
 .../InstCombine/InstCombineInternal.h         |  1 +
 .../InstCombine/InstructionCombining.cpp      | 68 +++++++++++++++++++
 .../test/Transforms/InstCombine/add-sitofp.ll | 16 ++---
 .../Transforms/InstCombine/binop-itofp.ll     |  8 +--
 5 files changed, 84 insertions(+), 69 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 36a5faa5f6743a0..770df1093df034b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1867,64 +1867,10 @@ Instruction *InstCombinerImpl::visitFAdd(BinaryOperator &I) {
 
   // Check for (fadd double (sitofp x), y), see if we can merge this into an
   // integer add followed by a promotion.
-  Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
-  if (SIToFPInst *LHSConv = dyn_cast<SIToFPInst>(LHS)) {
-    Value *LHSIntVal = LHSConv->getOperand(0);
-    Type *FPType = LHSConv->getType();
-
-    // TODO: This check is overly conservative. In many cases known bits
-    // analysis can tell us that the result of the addition has less significant
-    // bits than the integer type can hold.
-    auto IsValidPromotion = [](Type *FTy, Type *ITy) {
-      Type *FScalarTy = FTy->getScalarType();
-      Type *IScalarTy = ITy->getScalarType();
-
-      // Do we have enough bits in the significand to represent the result of
-      // the integer addition?
-      unsigned MaxRepresentableBits =
-          APFloat::semanticsPrecision(FScalarTy->getFltSemantics());
-      return IScalarTy->getIntegerBitWidth() <= MaxRepresentableBits;
-    };
-
-    // (fadd double (sitofp x), fpcst) --> (sitofp (add int x, intcst))
-    // ... if the constant fits in the integer value.  This is useful for things
-    // like (double)(x & 1234) + 4.0 -> (double)((X & 1234)+4) which no longer
-    // requires a constant pool load, and generally allows the add to be better
-    // instcombined.
-    if (ConstantFP *CFP = dyn_cast<ConstantFP>(RHS))
-      if (IsValidPromotion(FPType, LHSIntVal->getType())) {
-        Constant *CI = ConstantFoldCastOperand(Instruction::FPToSI, CFP,
-                                               LHSIntVal->getType(), DL);
-        if (LHSConv->hasOneUse() &&
-            ConstantFoldCastOperand(Instruction::SIToFP, CI, I.getType(), DL) ==
-                CFP &&
-            willNotOverflowSignedAdd(LHSIntVal, CI, I)) {
-          // Insert the new integer add.
-          Value *NewAdd = Builder.CreateNSWAdd(LHSIntVal, CI, "addconv");
-          return new SIToFPInst(NewAdd, I.getType());
-        }
-      }
-
-    // (fadd double (sitofp x), (sitofp y)) --> (sitofp (add int x, y))
-    if (SIToFPInst *RHSConv = dyn_cast<SIToFPInst>(RHS)) {
-      Value *RHSIntVal = RHSConv->getOperand(0);
-      // It's enough to check LHS types only because we require int types to
-      // be the same for this transform.
-      if (IsValidPromotion(FPType, LHSIntVal->getType())) {
-        // Only do this if x/y have the same type, if at least one of them has a
-        // single use (so we don't increase the number of int->fp conversions),
-        // and if the integer add will not overflow.
-        if (LHSIntVal->getType() == RHSIntVal->getType() &&
-            (LHSConv->hasOneUse() || RHSConv->hasOneUse()) &&
-            willNotOverflowSignedAdd(LHSIntVal, RHSIntVal, I)) {
-          // Insert the new integer add.
-          Value *NewAdd = Builder.CreateNSWAdd(LHSIntVal, RHSIntVal, "addconv");
-          return new SIToFPInst(NewAdd, I.getType());
-        }
-      }
-    }
-  }
+  if (Instruction *R = foldFBinOpOfIntCasts(I))
+    return R;
 
+  Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
   // Handle specials cases for FAdd with selects feeding the operation
   if (Value *V = SimplifySelectsFeedingBinaryOp(I, LHS, RHS))
     return replaceInstUsesWith(I, V);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 0b4283bc37650ae..57148d719d9b613 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -379,6 +379,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
   Instruction *scalarizePHI(ExtractElementInst &EI, PHINode *PN);
   Instruction *foldBitcastExtElt(ExtractElementInst &ExtElt);
   Instruction *foldCastedBitwiseLogic(BinaryOperator &I);
+  Instruction *foldFBinOpOfIntCasts(BinaryOperator &I);
   Instruction *foldBinopOfSextBoolToSelect(BinaryOperator &I);
   Instruction *narrowBinOp(TruncInst &Trunc);
   Instruction *narrowMaskedBinOp(BinaryOperator &And);
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 87c8dca7efed897..9db528fc5de6217 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -1401,6 +1401,74 @@ Value *InstCombinerImpl::dyn_castNegVal(Value *V) const {
   return nullptr;
 }
 
+// Try to fold:
+//    1) (add (sitofp x), (sitofp y))
+//          -> (sitofp (add x, y))
+//    2) (add (sitofp x), FpC)
+//          -> (sitofp (add x, (fptosi FpC)))
+Instruction *InstCombinerImpl::foldFBinOpOfIntCasts(BinaryOperator &BO) {
+  // Check for (fadd double (sitofp x), y), see if we can merge this into an
+  // integer add followed by a promotion.
+  Value *LHS = BO.getOperand(0), *RHS = BO.getOperand(1);
+  if (SIToFPInst *LHSConv = dyn_cast<SIToFPInst>(LHS)) {
+    Value *LHSIntVal = LHSConv->getOperand(0);
+    Type *FPType = LHSConv->getType();
+
+    // TODO: This check is overly conservative. In many cases known bits
+    // analysis can tell us that the result of the addition has less significant
+    // bits than the integer type can hold.
+    auto IsValidPromotion = [](Type *FTy, Type *ITy) {
+      Type *FScalarTy = FTy->getScalarType();
+      Type *IScalarTy = ITy->getScalarType();
+
+      // Do we have enough bits in the significand to represent the result of
+      // the integer addition?
+      unsigned MaxRepresentableBits =
+          APFloat::semanticsPrecision(FScalarTy->getFltSemantics());
+      return IScalarTy->getIntegerBitWidth() <= MaxRepresentableBits;
+    };
+
+    // (fadd double (sitofp x), fpcst) --> (sitofp (add int x, intcst))
+    // ... if the constant fits in the integer value.  This is useful for things
+    // like (double)(x & 1234) + 4.0 -> (double)((X & 1234)+4) which no longer
+    // requires a constant pool load, and generally allows the add to be better
+    // instcombined.
+    if (ConstantFP *CFP = dyn_cast<ConstantFP>(RHS))
+      if (IsValidPromotion(FPType, LHSIntVal->getType())) {
+        Constant *CI = ConstantFoldCastOperand(Instruction::FPToSI, CFP,
+                                               LHSIntVal->getType(), DL);
+        if (LHSConv->hasOneUse() &&
+            ConstantFoldCastOperand(Instruction::SIToFP, CI, BO.getType(),
+                                    DL) == CFP &&
+            willNotOverflowSignedAdd(LHSIntVal, CI, BO)) {
+          // Insert the new integer add.
+          Value *NewAdd = Builder.CreateNSWAdd(LHSIntVal, CI);
+          return new SIToFPInst(NewAdd, BO.getType());
+        }
+      }
+
+    // (fadd double (sitofp x), (sitofp y)) --> (sitofp (add int x, y))
+    if (SIToFPInst *RHSConv = dyn_cast<SIToFPInst>(RHS)) {
+      Value *RHSIntVal = RHSConv->getOperand(0);
+      // It's enough to check LHS types only because we require int types to
+      // be the same for this transform.
+      if (IsValidPromotion(FPType, LHSIntVal->getType())) {
+        // Only do this if x/y have the same type, if at least one of them has a
+        // single use (so we don't increase the number of int->fp conversions),
+        // and if the integer add will not overflow.
+        if (LHSIntVal->getType() == RHSIntVal->getType() &&
+            (LHSConv->hasOneUse() || RHSConv->hasOneUse()) &&
+            willNotOverflowSignedAdd(LHSIntVal, RHSIntVal, BO)) {
+          // Insert the new integer add.
+          Value *NewAdd = Builder.CreateNSWAdd(LHSIntVal, RHSIntVal);
+          return new SIToFPInst(NewAdd, BO.getType());
+        }
+      }
+    }
+  }
+  return nullptr;
+}
+
 /// A binop with a constant operand and a sign-extended boolean operand may be
 /// converted into a select of constants by applying the binary operation to
 /// the constant with the two possible values of the extended boolean (0 or -1).
diff --git a/llvm/test/Transforms/InstCombine/add-sitofp.ll b/llvm/test/Transforms/InstCombine/add-sitofp.ll
index db44b806593b642..206c0a7ebd26265 100644
--- a/llvm/test/Transforms/InstCombine/add-sitofp.ll
+++ b/llvm/test/Transforms/InstCombine/add-sitofp.ll
@@ -5,8 +5,8 @@ define double @x(i32 %a, i32 %b) {
 ; CHECK-LABEL: @x(
 ; CHECK-NEXT:    [[M:%.*]] = lshr i32 [[A:%.*]], 24
 ; CHECK-NEXT:    [[N:%.*]] = and i32 [[M]], [[B:%.*]]
-; CHECK-NEXT:    [[ADDCONV:%.*]] = add nuw nsw i32 [[N]], 1
-; CHECK-NEXT:    [[P:%.*]] = sitofp i32 [[ADDCONV]] to double
+; CHECK-NEXT:    [[TMP1:%.*]] = add nuw nsw i32 [[N]], 1
+; CHECK-NEXT:    [[P:%.*]] = sitofp i32 [[TMP1]] to double
 ; CHECK-NEXT:    ret double [[P]]
 ;
   %m = lshr i32 %a, 24
@@ -19,8 +19,8 @@ define double @x(i32 %a, i32 %b) {
 define double @test(i32 %a) {
 ; CHECK-LABEL: @test(
 ; CHECK-NEXT:    [[A_AND:%.*]] = and i32 [[A:%.*]], 1073741823
-; CHECK-NEXT:    [[ADDCONV:%.*]] = add nuw nsw i32 [[A_AND]], 1
-; CHECK-NEXT:    [[RES:%.*]] = sitofp i32 [[ADDCONV]] to double
+; CHECK-NEXT:    [[TMP1:%.*]] = add nuw nsw i32 [[A_AND]], 1
+; CHECK-NEXT:    [[RES:%.*]] = sitofp i32 [[TMP1]] to double
 ; CHECK-NEXT:    ret double [[RES]]
 ;
   ; Drop two highest bits to guarantee that %a + 1 doesn't overflow
@@ -48,8 +48,8 @@ define double @test_2(i32 %a, i32 %b) {
 ; CHECK-LABEL: @test_2(
 ; CHECK-NEXT:    [[A_AND:%.*]] = and i32 [[A:%.*]], 1073741823
 ; CHECK-NEXT:    [[B_AND:%.*]] = and i32 [[B:%.*]], 1073741823
-; CHECK-NEXT:    [[ADDCONV:%.*]] = add nuw nsw i32 [[A_AND]], [[B_AND]]
-; CHECK-NEXT:    [[RES:%.*]] = sitofp i32 [[ADDCONV]] to double
+; CHECK-NEXT:    [[TMP1:%.*]] = add nuw nsw i32 [[A_AND]], [[B_AND]]
+; CHECK-NEXT:    [[RES:%.*]] = sitofp i32 [[TMP1]] to double
 ; CHECK-NEXT:    ret double [[RES]]
 ;
   ; Drop two highest bits to guarantee that %a + %b doesn't overflow
@@ -105,8 +105,8 @@ define <4 x double> @test_4(<4 x i32> %a, <4 x i32> %b) {
 ; CHECK-LABEL: @test_4(
 ; CHECK-NEXT:    [[A_AND:%.*]] = and <4 x i32> [[A:%.*]], <i32 1073741823, i32 1073741823, i32 1073741823, i32 1073741823>
 ; CHECK-NEXT:    [[B_AND:%.*]] = and <4 x i32> [[B:%.*]], <i32 1073741823, i32 1073741823, i32 1073741823, i32 1073741823>
-; CHECK-NEXT:    [[ADDCONV:%.*]] = add nuw nsw <4 x i32> [[A_AND]], [[B_AND]]
-; CHECK-NEXT:    [[RES:%.*]] = sitofp <4 x i32> [[ADDCONV]] to <4 x double>
+; CHECK-NEXT:    [[TMP1:%.*]] = add nuw nsw <4 x i32> [[A_AND]], [[B_AND]]
+; CHECK-NEXT:    [[RES:%.*]] = sitofp <4 x i32> [[TMP1]] to <4 x double>
 ; CHECK-NEXT:    ret <4 x double> [[RES]]
 ;
   ; Drop two highest bits to guarantee that %a + %b doesn't overflow
diff --git a/llvm/test/Transforms/InstCombine/binop-itofp.ll b/llvm/test/Transforms/InstCombine/binop-itofp.ll
index 6354be7d723b646..ea1ad9f8d881b94 100644
--- a/llvm/test/Transforms/InstCombine/binop-itofp.ll
+++ b/llvm/test/Transforms/InstCombine/binop-itofp.ll
@@ -78,8 +78,8 @@ define half @test_si_si_i8_add(i8 noundef %x_in, i8 noundef %y_in) {
 ; CHECK-LABEL: @test_si_si_i8_add(
 ; CHECK-NEXT:    [[X:%.*]] = or i8 [[X_IN:%.*]], -64
 ; CHECK-NEXT:    [[Y:%.*]] = or i8 [[Y_IN:%.*]], -64
-; CHECK-NEXT:    [[ADDCONV:%.*]] = add nsw i8 [[X]], [[Y]]
-; CHECK-NEXT:    [[R:%.*]] = sitofp i8 [[ADDCONV]] to half
+; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i8 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = or i8 %x_in, -64
@@ -204,8 +204,8 @@ define half @test_si_si_i8_sub_fail_overflow(i8 noundef %x_in, i8 noundef %y_in)
 define half @test_si_si_i8_sub_C(i8 noundef %x_in) {
 ; CHECK-LABEL: @test_si_si_i8_sub_C(
 ; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 63
-; CHECK-NEXT:    [[ADDCONV:%.*]] = or disjoint i8 [[X]], 64
-; CHECK-NEXT:    [[R:%.*]] = sitofp i8 [[ADDCONV]] to half
+; CHECK-NEXT:    [[TMP1:%.*]] = or disjoint i8 [[X]], 64
+; CHECK-NEXT:    [[R:%.*]] = sitofp i8 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i8 %x_in, 63

>From 498f112f622f0494aa5051417e297f4ca1705971 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Wed, 21 Feb 2024 16:05:30 -0600
Subject: [PATCH 3/3] [InstCombine] Add folds for `(fp_binop ({s|u}itofp x),
 ({s|u}itofp y))`

The full fold is one of the following:
1) `(fp_binop ({s|u}itofp x), ({s|u}itofp y))`
    -> `({s|u}itofp (int_binop x, y))`
2) `(fp_binop ({s|u}itofp x), FpC)`
    -> `({s|u}itofp (int_binop x, (fpto{s|u}i FpC)))`

And support the following binops:
    `fmul` -> `mul`
    `fadd` -> `add`
    `fsub` -> `sub`

Proofs: https://alive2.llvm.org/ce/z/zuacA8

The proofs timeout, so they must be reproduced locally.
---
 .../InstCombine/InstCombineAddSub.cpp         |   3 +
 .../InstCombine/InstCombineMulDivRem.cpp      |   3 +
 .../InstCombine/InstructionCombining.cpp      | 225 +++++++++++++-----
 .../test/Transforms/InstCombine/add-sitofp.ll |   8 +-
 .../Transforms/InstCombine/binop-itofp.ll     | 140 +++++------
 llvm/test/Transforms/InstCombine/pr33453.ll   |   4 +-
 6 files changed, 232 insertions(+), 151 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 770df1093df034b..aaf7184a5562cdf 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2793,6 +2793,9 @@ Instruction *InstCombinerImpl::visitFSub(BinaryOperator &I) {
   if (Instruction *X = foldFNegIntoConstant(I, DL))
     return X;
 
+  if (Instruction *R = foldFBinOpOfIntCasts(I))
+    return R;
+
   Value *X, *Y;
   Constant *C;
 
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 0bd4b6d1a835af5..3ebf6b3d9bf7f72 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -769,6 +769,9 @@ Instruction *InstCombinerImpl::visitFMul(BinaryOperator &I) {
   if (Instruction *R = foldFPSignBitOps(I))
     return R;
 
+  if (Instruction *R = foldFBinOpOfIntCasts(I))
+    return R;
+
   // X * -1.0 --> -X
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
   if (match(Op1, m_SpecificFP(-1.0)))
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 9db528fc5de6217..0e77f0811077b16 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -1402,71 +1402,176 @@ Value *InstCombinerImpl::dyn_castNegVal(Value *V) const {
 }
 
 // Try to fold:
-//    1) (add (sitofp x), (sitofp y))
-//          -> (sitofp (add x, y))
-//    2) (add (sitofp x), FpC)
-//          -> (sitofp (add x, (fptosi FpC)))
+//    1) (fp_binop ({s|u}itofp x), ({s|u}itofp y))
+//        -> ({s|u}itofp (int_binop x, y))
+//    2) (fp_binop ({s|u}itofp x), FpC)
+//        -> ({s|u}itofp (int_binop x, (fpto{s|u}i FpC)))
 Instruction *InstCombinerImpl::foldFBinOpOfIntCasts(BinaryOperator &BO) {
-  // Check for (fadd double (sitofp x), y), see if we can merge this into an
-  // integer add followed by a promotion.
-  Value *LHS = BO.getOperand(0), *RHS = BO.getOperand(1);
-  if (SIToFPInst *LHSConv = dyn_cast<SIToFPInst>(LHS)) {
-    Value *LHSIntVal = LHSConv->getOperand(0);
-    Type *FPType = LHSConv->getType();
-
-    // TODO: This check is overly conservative. In many cases known bits
-    // analysis can tell us that the result of the addition has less significant
-    // bits than the integer type can hold.
-    auto IsValidPromotion = [](Type *FTy, Type *ITy) {
-      Type *FScalarTy = FTy->getScalarType();
-      Type *IScalarTy = ITy->getScalarType();
-
-      // Do we have enough bits in the significand to represent the result of
-      // the integer addition?
-      unsigned MaxRepresentableBits =
-          APFloat::semanticsPrecision(FScalarTy->getFltSemantics());
-      return IScalarTy->getIntegerBitWidth() <= MaxRepresentableBits;
-    };
+  Value *IntOps[2] = {nullptr, nullptr};
+  Constant *Op1FpC = nullptr;
+
+  // Check for:
+  //    1) (binop ({s|u}itofp x), ({s|u}itofp y))
+  //    2) (binop ({s|u}itofp x), FpC)
+  if (!match(BO.getOperand(0), m_SIToFP(m_Value(IntOps[0]))) &&
+      !match(BO.getOperand(0), m_UIToFP(m_Value(IntOps[0]))))
+    return nullptr;
 
-    // (fadd double (sitofp x), fpcst) --> (sitofp (add int x, intcst))
-    // ... if the constant fits in the integer value.  This is useful for things
-    // like (double)(x & 1234) + 4.0 -> (double)((X & 1234)+4) which no longer
-    // requires a constant pool load, and generally allows the add to be better
-    // instcombined.
-    if (ConstantFP *CFP = dyn_cast<ConstantFP>(RHS))
-      if (IsValidPromotion(FPType, LHSIntVal->getType())) {
-        Constant *CI = ConstantFoldCastOperand(Instruction::FPToSI, CFP,
-                                               LHSIntVal->getType(), DL);
-        if (LHSConv->hasOneUse() &&
-            ConstantFoldCastOperand(Instruction::SIToFP, CI, BO.getType(),
-                                    DL) == CFP &&
-            willNotOverflowSignedAdd(LHSIntVal, CI, BO)) {
-          // Insert the new integer add.
-          Value *NewAdd = Builder.CreateNSWAdd(LHSIntVal, CI);
-          return new SIToFPInst(NewAdd, BO.getType());
-        }
-      }
+  if (!match(BO.getOperand(1), m_Constant(Op1FpC)) &&
+      !match(BO.getOperand(1), m_SIToFP(m_Value(IntOps[1]))) &&
+      !match(BO.getOperand(1), m_UIToFP(m_Value(IntOps[1]))))
+    return nullptr;
 
-    // (fadd double (sitofp x), (sitofp y)) --> (sitofp (add int x, y))
-    if (SIToFPInst *RHSConv = dyn_cast<SIToFPInst>(RHS)) {
-      Value *RHSIntVal = RHSConv->getOperand(0);
-      // It's enough to check LHS types only because we require int types to
-      // be the same for this transform.
-      if (IsValidPromotion(FPType, LHSIntVal->getType())) {
-        // Only do this if x/y have the same type, if at least one of them has a
-        // single use (so we don't increase the number of int->fp conversions),
-        // and if the integer add will not overflow.
-        if (LHSIntVal->getType() == RHSIntVal->getType() &&
-            (LHSConv->hasOneUse() || RHSConv->hasOneUse()) &&
-            willNotOverflowSignedAdd(LHSIntVal, RHSIntVal, BO)) {
-          // Insert the new integer add.
-          Value *NewAdd = Builder.CreateNSWAdd(LHSIntVal, RHSIntVal);
-          return new SIToFPInst(NewAdd, BO.getType());
-        }
-      }
+  Type *FPTy = BO.getType();
+  Type *IntTy = IntOps[0]->getType();
+
+  // Do we have signed casts?
+  bool OpsFromSigned = isa<SIToFPInst>(BO.getOperand(0));
+
+  unsigned IntSz = IntTy->getScalarSizeInBits();
+  // This is the maximum number of inuse bits by the integer where the int -> fp
+  // casts are exact.
+  unsigned MaxRepresentableBits =
+      APFloat::semanticsPrecision(FPTy->getScalarType()->getFltSemantics());
+
+  // Cache KnownBits a bit to potentially save some analysis.
+  WithCache<const Value *> OpsKnown[2] = {IntOps[0], IntOps[1]};
+
+  // Preserve known number of leading bits. This can allow us to trivial nsw/nuw
+  // checks later on.
+  unsigned NumUsedLeadingBits[2] = {IntSz, IntSz};
+
+  auto IsNonZero = [&](unsigned OpNo) -> bool {
+    if (OpsKnown[OpNo].hasKnownBits() &&
+        OpsKnown[OpNo].getKnownBits(SQ).isNonZero())
+      return true;
+    return isKnownNonZero(IntOps[OpNo], SQ.DL);
+  };
+
+  auto IsNonNeg = [&](unsigned OpNo) -> bool {
+    if (OpsKnown[OpNo].hasKnownBits() &&
+        OpsKnown[OpNo].getKnownBits(SQ).isNonNegative())
+      return true;
+    return isKnownNonNegative(IntOps[OpNo], SQ);
+  };
+
+  // Check if we know for certain that ({s|u}itofp op) is exact.
+  auto IsValidPromotion = [&](unsigned OpNo) -> bool {
+    // If fp precision >= bitwidth(op) then its exact.
+    // NB: This is slightly conservative for `sitofp`. For signed conversion, we
+    // can handle `MaxRepresentableBits == IntSz - 1` as the sign bit will be
+    // handled specially. We can't, however, increase the bound arbitrarily for
+    // `sitofp` as for larger sizes, it won't sign extend.
+    if (MaxRepresentableBits >= IntSz)
+      ;
+    // Otherwise if its signed cast check that fp precisions >= bitwidth(op) -
+    // numSignBits(op).
+    // TODO: If we add support for `WithCache` in `ComputeNumSignBits`, change
+    // `IntOps[OpNo]` arguments to `KnownOps[OpNo]`.
+    else if (OpsFromSigned)
+      NumUsedLeadingBits[OpNo] = IntSz - ComputeNumSignBits(IntOps[OpNo]);
+    // Finally for unsigned check that fp precision >= bitwidth(op) -
+    // numLeadingZeros(op).
+    else {
+      NumUsedLeadingBits[OpNo] =
+          IntSz - OpsKnown[OpNo].getKnownBits(SQ).countMinLeadingZeros();
+    }
+    // NB: We could also check if op is known to be a power of 2 or zero (which
+    // will always be representable). Its unlikely, however, that is we are
+    // unable to bound op in any way we will be able to pass the overflow checks
+    // later on.
+
+    if (MaxRepresentableBits < NumUsedLeadingBits[OpNo])
+      return false;
+    // Signed + Mul also requires that op is non-zero to avoid -0 cases.
+    return !OpsFromSigned || BO.getOpcode() != Instruction::FMul ||
+           IsNonZero(OpNo);
+  };
+
+  // If we have a constant rhs, see if we can losslessly convert it to an int.
+  if (Op1FpC != nullptr) {
+    Constant *Op1IntC = ConstantFoldCastOperand(
+        OpsFromSigned ? Instruction::FPToSI : Instruction::FPToUI, Op1FpC,
+        IntTy, DL);
+    if (Op1IntC == nullptr)
+      return nullptr;
+    if (ConstantFoldCastOperand(OpsFromSigned ? Instruction::SIToFP
+                                              : Instruction::UIToFP,
+                                Op1IntC, FPTy, DL) != Op1FpC)
+      return nullptr;
+
+    // First try to keep sign of cast the same.
+    IntOps[1] = Op1IntC;
+  }
+
+  // Ensure lhs/rhs integer types match.
+  if (IntTy != IntOps[1]->getType())
+    return nullptr;
+
+  if (Op1FpC == nullptr) {
+    if (OpsFromSigned != isa<SIToFPInst>(BO.getOperand(1))) {
+      // If we have a signed + unsigned, see if we can treat both as signed
+      // (uitofp nneg x) == (sitofp nneg x).
+      if (OpsFromSigned ? !IsNonNeg(1) : !IsNonNeg(0))
+        return nullptr;
+      OpsFromSigned = true;
     }
+    if (!IsValidPromotion(1))
+      return nullptr;
   }
-  return nullptr;
+  if (!IsValidPromotion(0))
+    return nullptr;
+
+  // Final we check if the integer version of the binop will not overflow.
+  BinaryOperator::BinaryOps IntOpc;
+  // Because of the precision check, we can often rule out overflows.
+  bool NeedsOverflowCheck = true;
+  // Try to conservatively rule out overflow based on the already done precision
+  // checks.
+  unsigned OverflowMaxOutputBits = OpsFromSigned ? 2 : 1;
+  unsigned OverflowMaxCurBits =
+      std::max(NumUsedLeadingBits[0], NumUsedLeadingBits[1]);
+  bool OutputSigned = OpsFromSigned;
+  switch (BO.getOpcode()) {
+  case Instruction::FAdd:
+    IntOpc = Instruction::Add;
+    OverflowMaxOutputBits += OverflowMaxCurBits;
+    break;
+  case Instruction::FSub:
+    IntOpc = Instruction::Sub;
+    OverflowMaxOutputBits += OverflowMaxCurBits;
+    break;
+  case Instruction::FMul:
+    IntOpc = Instruction::Mul;
+    OverflowMaxOutputBits += OverflowMaxCurBits * 2;
+    break;
+  default:
+    llvm_unreachable("Unsupported binop");
+  }
+  // The precision check may have already ruled out overflow.
+  if (OverflowMaxOutputBits < IntSz) {
+    NeedsOverflowCheck = false;
+    // We can bound unsigned overflow from sub to in range signed value (this is
+    // what allows us to avoid the overflow check for sub).
+    if (IntOpc == Instruction::Sub)
+      OutputSigned = true;
+  }
+
+  // Precision check did not rule out overflow, so need to check.
+  // TODO: If we add support for `WithCache` in `willNotOverflow`, change
+  // `IntOps[...]` arguments to `KnownOps[...]`.
+  if (NeedsOverflowCheck &&
+      !willNotOverflow(IntOpc, IntOps[0], IntOps[1], BO, OutputSigned))
+    return nullptr;
+
+  Value *IntBinOp = Builder.CreateBinOp(IntOpc, IntOps[0], IntOps[1]);
+  if (auto *IntBO = dyn_cast<BinaryOperator>(IntBinOp)) {
+    IntBO->setHasNoSignedWrap(OutputSigned);
+    IntBO->setHasNoUnsignedWrap(!OutputSigned);
+  }
+  if (OutputSigned)
+    return new SIToFPInst(IntBinOp, FPTy);
+  return new UIToFPInst(IntBinOp, FPTy);
 }
 
 /// A binop with a constant operand and a sign-extended boolean operand may be
diff --git a/llvm/test/Transforms/InstCombine/add-sitofp.ll b/llvm/test/Transforms/InstCombine/add-sitofp.ll
index 206c0a7ebd26265..049db8c84a522dd 100644
--- a/llvm/test/Transforms/InstCombine/add-sitofp.ll
+++ b/llvm/test/Transforms/InstCombine/add-sitofp.ll
@@ -83,15 +83,13 @@ define float @test_2_neg(i32 %a, i32 %b) {
   ret float %res
 }
 
-; This test demonstrates overly conservative legality check. The float addition
-; can be replaced with the integer addition because the result of the operation
-; can be represented in float, but we don't do that now.
+; can be represented in float.
 define float @test_3(i32 %a, i32 %b) {
 ; CHECK-LABEL: @test_3(
 ; CHECK-NEXT:    [[M:%.*]] = lshr i32 [[A:%.*]], 24
 ; CHECK-NEXT:    [[N:%.*]] = and i32 [[M]], [[B:%.*]]
-; CHECK-NEXT:    [[O:%.*]] = sitofp i32 [[N]] to float
-; CHECK-NEXT:    [[P:%.*]] = fadd float [[O]], 1.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = add nuw nsw i32 [[N]], 1
+; CHECK-NEXT:    [[P:%.*]] = sitofp i32 [[TMP1]] to float
 ; CHECK-NEXT:    ret float [[P]]
 ;
   %m = lshr i32 %a, 24
diff --git a/llvm/test/Transforms/InstCombine/binop-itofp.ll b/llvm/test/Transforms/InstCombine/binop-itofp.ll
index ea1ad9f8d881b94..ffa893745791458 100644
--- a/llvm/test/Transforms/InstCombine/binop-itofp.ll
+++ b/llvm/test/Transforms/InstCombine/binop-itofp.ll
@@ -5,9 +5,8 @@ define half @test_ui_ui_i8_add(i8 noundef %x_in, i8 noundef %y_in) {
 ; CHECK-LABEL: @test_ui_ui_i8_add(
 ; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 127
 ; CHECK-NEXT:    [[Y:%.*]] = and i8 [[Y_IN:%.*]], 127
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add nuw i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = uitofp i8 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i8 %x_in, 127
@@ -37,9 +36,8 @@ define half @test_ui_ui_i8_add_fail_overflow(i8 noundef %x_in, i8 noundef %y_in)
 
 define half @test_ui_ui_i8_add_C(i8 noundef %x_in) {
 ; CHECK-LABEL: @test_ui_ui_i8_add_C(
-; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 127
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
-; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xH5800
+; CHECK-NEXT:    [[TMP1:%.*]] = or i8 [[X_IN:%.*]], -128
+; CHECK-NEXT:    [[R:%.*]] = uitofp i8 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i8 %x_in, 127
@@ -111,9 +109,8 @@ define half @test_ui_si_i8_add(i8 noundef %x_in, i8 noundef %y_in) {
 ; CHECK-LABEL: @test_ui_si_i8_add(
 ; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 63
 ; CHECK-NEXT:    [[Y:%.*]] = and i8 [[Y_IN:%.*]], 63
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add nuw nsw i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i8 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i8 %x_in, 63
@@ -143,9 +140,8 @@ define half @test_ui_si_i8_add_overflow(i8 noundef %x_in, i8 noundef %y_in) {
 
 define half @test_ui_ui_i8_sub_C(i8 noundef %x_in) {
 ; CHECK-LABEL: @test_ui_ui_i8_sub_C(
-; CHECK-NEXT:    [[X:%.*]] = or i8 [[X_IN:%.*]], -128
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
-; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xHD800
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[X_IN:%.*]], 127
+; CHECK-NEXT:    [[R:%.*]] = uitofp i8 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = or i8 %x_in, 128
@@ -171,9 +167,8 @@ define half @test_si_si_i8_sub(i8 noundef %x_in, i8 noundef %y_in) {
 ; CHECK-LABEL: @test_si_si_i8_sub(
 ; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 63
 ; CHECK-NEXT:    [[Y:%.*]] = or i8 [[Y_IN:%.*]], -64
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = sitofp i8 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = sub nsw i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i8 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i8 %x_in, 63
@@ -231,9 +226,8 @@ define half @test_ui_si_i8_sub(i8 noundef %x_in, i8 noundef %y_in) {
 ; CHECK-LABEL: @test_ui_si_i8_sub(
 ; CHECK-NEXT:    [[X:%.*]] = or i8 [[X_IN:%.*]], 64
 ; CHECK-NEXT:    [[Y:%.*]] = and i8 [[Y_IN:%.*]], 63
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = sub nuw nsw i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i8 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = or i8 %x_in, 64
@@ -265,9 +259,8 @@ define half @test_ui_ui_i8_mul(i8 noundef %x_in, i8 noundef %y_in) {
 ; CHECK-LABEL: @test_ui_ui_i8_mul(
 ; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 15
 ; CHECK-NEXT:    [[Y:%.*]] = and i8 [[Y_IN:%.*]], 15
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nuw i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = uitofp i8 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i8 %x_in, 15
@@ -280,9 +273,8 @@ define half @test_ui_ui_i8_mul(i8 noundef %x_in, i8 noundef %y_in) {
 
 define half @test_ui_ui_i8_mul_C(i8 noundef %x_in) {
 ; CHECK-LABEL: @test_ui_ui_i8_mul_C(
-; CHECK-NEXT:    [[X:%.*]] = and i8 [[X_IN:%.*]], 15
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i8 [[X]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], 0xH4C00
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i8 [[X_IN:%.*]], 4
+; CHECK-NEXT:    [[R:%.*]] = uitofp i8 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i8 %x_in, 15
@@ -309,9 +301,8 @@ define half @test_si_si_i8_mul(i8 noundef %x_in, i8 noundef %y_in) {
 ; CHECK-NEXT:    [[XX:%.*]] = and i8 [[X_IN:%.*]], 6
 ; CHECK-NEXT:    [[X:%.*]] = or disjoint i8 [[XX]], 1
 ; CHECK-NEXT:    [[Y:%.*]] = or i8 [[Y_IN:%.*]], -8
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = sitofp i8 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nsw i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i8 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %xx = and i8 %x_in, 6
@@ -376,9 +367,8 @@ define half @test_ui_si_i8_mul(i8 noundef %x_in, i8 noundef %y_in) {
 ; CHECK-NEXT:    [[X:%.*]] = or disjoint i8 [[XX]], 1
 ; CHECK-NEXT:    [[YY:%.*]] = and i8 [[Y_IN:%.*]], 7
 ; CHECK-NEXT:    [[Y:%.*]] = add nuw nsw i8 [[YY]], 1
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i8 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = uitofp i8 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nuw nsw i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i8 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %xx = and i8 %x_in, 6
@@ -433,9 +423,8 @@ define half @test_ui_ui_i16_add(i16 noundef %x_in, i16 noundef %y_in) {
 ; CHECK-LABEL: @test_ui_ui_i16_add(
 ; CHECK-NEXT:    [[X:%.*]] = and i16 [[X_IN:%.*]], 2047
 ; CHECK-NEXT:    [[Y:%.*]] = and i16 [[Y_IN:%.*]], 2047
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i16 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = uitofp i16 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add nuw nsw i16 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = uitofp i16 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i16 %x_in, 2047
@@ -465,9 +454,8 @@ define half @test_ui_ui_i16_add_fail_not_promotable(i16 noundef %x_in, i16 nound
 
 define half @test_ui_ui_i16_add_C(i16 noundef %x_in) {
 ; CHECK-LABEL: @test_ui_ui_i16_add_C(
-; CHECK-NEXT:    [[X:%.*]] = and i16 [[X_IN:%.*]], 2047
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i16 [[X]] to half
-; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], 0xH7BC0
+; CHECK-NEXT:    [[TMP1:%.*]] = or i16 [[X_IN:%.*]], -2048
+; CHECK-NEXT:    [[R:%.*]] = uitofp i16 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i16 %x_in, 2047
@@ -493,9 +481,8 @@ define half @test_si_si_i16_add(i16 noundef %x_in, i16 noundef %y_in) {
 ; CHECK-LABEL: @test_si_si_i16_add(
 ; CHECK-NEXT:    [[X:%.*]] = or i16 [[X_IN:%.*]], -2048
 ; CHECK-NEXT:    [[Y:%.*]] = or i16 [[Y_IN:%.*]], -2048
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = sitofp i16 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i16 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i16 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = or i16 %x_in, -2048
@@ -542,9 +529,8 @@ define half @test_si_si_i16_sub(i16 noundef %x_in, i16 noundef %y_in) {
 ; CHECK-LABEL: @test_si_si_i16_sub(
 ; CHECK-NEXT:    [[X:%.*]] = or i16 [[X_IN:%.*]], -2048
 ; CHECK-NEXT:    [[Y:%.*]] = and i16 [[Y_IN:%.*]], 2047
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = sitofp i16 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = sub nuw nsw i16 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i16 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = or i16 %x_in, -2048
@@ -576,9 +562,8 @@ define half @test_ui_si_i16_sub(i16 noundef %x_in, i16 noundef %y_in) {
 ; CHECK-LABEL: @test_ui_si_i16_sub(
 ; CHECK-NEXT:    [[X:%.*]] = and i16 [[X_IN:%.*]], 2047
 ; CHECK-NEXT:    [[Y:%.*]] = and i16 [[Y_IN:%.*]], 2047
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i16 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = sitofp i16 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = sub nsw i16 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i16 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i16 %x_in, 2047
@@ -610,9 +595,8 @@ define half @test_ui_ui_i16_mul(i16 noundef %x_in, i16 noundef %y_in) {
 ; CHECK-LABEL: @test_ui_ui_i16_mul(
 ; CHECK-NEXT:    [[X:%.*]] = and i16 [[X_IN:%.*]], 255
 ; CHECK-NEXT:    [[Y:%.*]] = and i16 [[Y_IN:%.*]], 255
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i16 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = uitofp i16 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nuw i16 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = uitofp i16 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i16 %x_in, 255
@@ -645,9 +629,8 @@ define half @test_si_si_i16_mul(i16 noundef %x_in, i16 noundef %y_in) {
 ; CHECK-NEXT:    [[XX:%.*]] = and i16 [[X_IN:%.*]], 126
 ; CHECK-NEXT:    [[X:%.*]] = or disjoint i16 [[XX]], 1
 ; CHECK-NEXT:    [[Y:%.*]] = or i16 [[Y_IN:%.*]], -255
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = sitofp i16 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nsw i16 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i16 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %xx = and i16 %x_in, 126
@@ -710,9 +693,8 @@ define half @test_ui_si_i16_mul(i16 noundef %x_in, i16 noundef %y_in) {
 ; CHECK-NEXT:    [[X:%.*]] = or disjoint i16 [[XX]], 1
 ; CHECK-NEXT:    [[YY:%.*]] = and i16 [[Y_IN:%.*]], 126
 ; CHECK-NEXT:    [[Y:%.*]] = or disjoint i16 [[YY]], 1
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i16 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = uitofp i16 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nuw nsw i16 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i16 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %xx = and i16 %x_in, 126
@@ -729,9 +711,8 @@ define half @test_ui_ui_i12_add(i12 noundef %x_in, i12 noundef %y_in) {
 ; CHECK-LABEL: @test_ui_ui_i12_add(
 ; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 2047
 ; CHECK-NEXT:    [[Y:%.*]] = and i12 [[Y_IN:%.*]], 2047
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = uitofp i12 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add nuw i12 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = uitofp i12 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i12 %x_in, 2047
@@ -764,9 +745,8 @@ define half @test_si_si_i12_add(i12 noundef %x_in, i12 noundef %y_in) {
 ; CHECK-LABEL: @test_si_si_i12_add(
 ; CHECK-NEXT:    [[X:%.*]] = or i12 [[X_IN:%.*]], -1024
 ; CHECK-NEXT:    [[Y:%.*]] = or i12 [[Y_IN:%.*]], -1024
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = sitofp i12 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i12 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i12 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = or i12 %x_in, -1024
@@ -811,9 +791,8 @@ define half @test_ui_ui_i12_sub(i12 noundef %x_in, i12 noundef %y_in) {
 ; CHECK-LABEL: @test_ui_ui_i12_sub(
 ; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 1023
 ; CHECK-NEXT:    [[Y:%.*]] = and i12 [[Y_IN:%.*]], 1023
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = uitofp i12 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = sub nsw i12 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i12 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i12 %x_in, 1023
@@ -846,9 +825,8 @@ define half @test_si_si_i12_sub(i12 noundef %x_in, i12 noundef %y_in) {
 ; CHECK-LABEL: @test_si_si_i12_sub(
 ; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 1023
 ; CHECK-NEXT:    [[Y:%.*]] = or i12 [[Y_IN:%.*]], -1024
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = sitofp i12 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = sub nsw i12 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i12 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i12 %x_in, 1023
@@ -876,9 +854,8 @@ define half @test_ui_ui_i12_mul(i12 noundef %x_in, i12 noundef %y_in) {
 ; CHECK-LABEL: @test_ui_ui_i12_mul(
 ; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 31
 ; CHECK-NEXT:    [[Y:%.*]] = and i12 [[Y_IN:%.*]], 63
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = uitofp i12 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nuw nsw i12 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = uitofp i12 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i12 %x_in, 31
@@ -894,9 +871,8 @@ define half @test_ui_ui_i12_mul_fail_overflow(i12 noundef %x_in, i12 noundef %y_
 ; CHECK-NEXT:    [[XX:%.*]] = and i12 [[X_IN:%.*]], 31
 ; CHECK-NEXT:    [[X:%.*]] = add nuw nsw i12 [[XX]], 1
 ; CHECK-NEXT:    [[Y:%.*]] = and i12 [[Y_IN:%.*]], 63
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = uitofp i12 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nuw i12 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = uitofp i12 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %xx = and i12 %x_in, 31
@@ -910,9 +886,9 @@ define half @test_ui_ui_i12_mul_fail_overflow(i12 noundef %x_in, i12 noundef %y_
 
 define half @test_ui_ui_i12_mul_C(i12 noundef %x_in) {
 ; CHECK-LABEL: @test_ui_ui_i12_mul_C(
-; CHECK-NEXT:    [[X:%.*]] = and i12 [[X_IN:%.*]], 31
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], 0xH5400
+; CHECK-NEXT:    [[X:%.*]] = shl i12 [[X_IN:%.*]], 6
+; CHECK-NEXT:    [[TMP1:%.*]] = and i12 [[X]], 1984
+; CHECK-NEXT:    [[R:%.*]] = uitofp i12 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = and i12 %x_in, 31
@@ -926,9 +902,8 @@ define half @test_si_si_i12_mul(i12 noundef %x_in, i12 noundef %y_in) {
 ; CHECK-NEXT:    [[XX:%.*]] = and i12 [[X_IN:%.*]], 30
 ; CHECK-NEXT:    [[X:%.*]] = or disjoint i12 [[XX]], 1
 ; CHECK-NEXT:    [[Y:%.*]] = or i12 [[Y_IN:%.*]], -64
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = sitofp i12 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nsw i12 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i12 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %xx = and i12 %x_in, 30
@@ -979,8 +954,8 @@ define half @test_si_si_i12_mul_fail_maybe_non_zero(i12 noundef %x_in, i12 nound
 define half @test_si_si_i12_mul_C(i12 noundef %x_in) {
 ; CHECK-LABEL: @test_si_si_i12_mul_C(
 ; CHECK-NEXT:    [[X:%.*]] = or i12 [[X_IN:%.*]], -64
-; CHECK-NEXT:    [[XF:%.*]] = sitofp i12 [[X]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], 0xHCC00
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nsw i12 [[X]], -16
+; CHECK-NEXT:    [[R:%.*]] = sitofp i12 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %x = or i12 %x_in, -64
@@ -1008,9 +983,8 @@ define half @test_ui_si_i12_mul_nsw(i12 noundef %x_in, i12 noundef %y_in) {
 ; CHECK-NEXT:    [[X:%.*]] = add nuw nsw i12 [[XX]], 1
 ; CHECK-NEXT:    [[YY:%.*]] = and i12 [[Y_IN:%.*]], 30
 ; CHECK-NEXT:    [[Y:%.*]] = or disjoint i12 [[YY]], 1
-; CHECK-NEXT:    [[XF:%.*]] = uitofp i12 [[X]] to half
-; CHECK-NEXT:    [[YF:%.*]] = sitofp i12 [[Y]] to half
-; CHECK-NEXT:    [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nuw nsw i12 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sitofp i12 [[TMP1]] to half
 ; CHECK-NEXT:    ret half [[R]]
 ;
   %xx = and i12 %x_in, 31
diff --git a/llvm/test/Transforms/InstCombine/pr33453.ll b/llvm/test/Transforms/InstCombine/pr33453.ll
index 09f1569bc95e61b..45f87b75300601b 100644
--- a/llvm/test/Transforms/InstCombine/pr33453.ll
+++ b/llvm/test/Transforms/InstCombine/pr33453.ll
@@ -6,9 +6,7 @@
 
 define float @patatino() {
 ; CHECK-LABEL: @patatino(
-; CHECK-NEXT:    [[UITOFP1:%.*]] = uitofp i1 icmp eq (ptr getelementptr inbounds (i16, ptr @g2, i64 1), ptr @g1) to float
-; CHECK-NEXT:    [[UITOFP2:%.*]] = uitofp i1 icmp eq (ptr getelementptr inbounds (i16, ptr @g2, i64 1), ptr @g1) to float
-; CHECK-NEXT:    [[FMUL:%.*]] = fmul float [[UITOFP1]], [[UITOFP2]]
+; CHECK-NEXT:    [[FMUL:%.*]] = uitofp i1 mul (i1 icmp eq (ptr getelementptr inbounds (i16, ptr @g2, i64 1), ptr @g1), i1 icmp eq (ptr getelementptr inbounds (i16, ptr @g2, i64 1), ptr @g1)) to float
 ; CHECK-NEXT:    ret float [[FMUL]]
 ;
   %uitofp1 = uitofp i1 icmp eq (ptr getelementptr inbounds (i16, ptr @g2, i64 1), ptr @g1) to float



More information about the llvm-commits mailing list