blob: 26b51146057e95c4605f91591b5e38ec7b785f18 [file] [log] [blame] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
;###############################################################
;# NaN Tests #
;###############################################################
; minnum(X, qnan) -> X
; maxnum(X, qnan) -> X
; TODO: minnum(X, snan) -> qnan (currently we treat SNaN the same as QNaN)
; TODO: maxnum(X, snan) -> qnan (currently we treat SNaN the same as QNaN)
; minimum(X, nan) -> qnan
; maximum(X, nan) -> qnan
; TODO: minimumnum(X, nan) -> X
; TODO: maximumnum(X, nan) -> X
define void @minmax_qnan_f32(float %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_qnan_f32(
; CHECK-NEXT: store float [[X:%.*]], ptr [[MINNUM_RES:%.*]], align 4
; CHECK-NEXT: store float [[X]], ptr [[MAXNUM_RES:%.*]], align 4
; CHECK-NEXT: store float 0x7FFF000000000000, ptr [[MINIMUM_RES:%.*]], align 4
; CHECK-NEXT: store float 0x7FFF000000000000, ptr [[MAXIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float 0x7FFF000000000000)
; CHECK-NEXT: store float [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float 0x7FFF000000000000)
; CHECK-NEXT: store float [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: ret void
;
%minnum = call float @llvm.minnum.f32(float %x, float 0x7FFF000000000000)
store float %minnum, ptr %minnum_res
%maxnum = call float @llvm.maxnum.f32(float %x, float 0x7FFF000000000000)
store float %maxnum, ptr %maxnum_res
%minimum = call float @llvm.minimum.f32(float %x, float 0x7FFF000000000000)
store float %minimum, ptr %minimum_res
%maximum = call float @llvm.maximum.f32(float %x, float 0x7FFF000000000000)
store float %maximum, ptr %maximum_res
%minimumnum = call float @llvm.minimumnum.f32(float %x, float 0x7FFF000000000000)
store float %minimumnum, ptr %minimumnum_res
%maximumnum = call float @llvm.maximumnum.f32(float %x, float 0x7FFF000000000000)
store float %maximumnum, ptr %maximumnum_res
ret void
}
; TODO currently snan is treated the same as qnan, but maxnum/minnum should really return qnan for these cases, not X
define void @minmax_snan_f32(float %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_snan_f32(
; CHECK-NEXT: store float [[X:%.*]], ptr [[MINNUM_RES:%.*]], align 4
; CHECK-NEXT: store float [[X]], ptr [[MAXNUM_RES:%.*]], align 4
; CHECK-NEXT: store float 0x7FFC000000000000, ptr [[MINIMUM_RES:%.*]], align 4
; CHECK-NEXT: store float 0x7FFC000000000000, ptr [[MAXIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float 0x7FF4000000000000)
; CHECK-NEXT: store float [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float 0x7FF4000000000000)
; CHECK-NEXT: store float [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: ret void
;
%minnum = call float @llvm.minnum.f32(float %x, float 0x7FF4000000000000)
store float %minnum, ptr %minnum_res
%maxnum = call float @llvm.maxnum.f32(float %x, float 0x7FF4000000000000)
store float %maxnum, ptr %maxnum_res
%minimum = call float @llvm.minimum.f32(float %x, float 0x7FF4000000000000)
store float %minimum, ptr %minimum_res
%maximum = call float @llvm.maximum.f32(float %x, float 0x7FF4000000000000)
store float %maximum, ptr %maximum_res
%minimumnum = call float @llvm.minimumnum.f32(float %x, float 0x7FF4000000000000)
store float %minimumnum, ptr %minimumnum_res
%maximumnum = call float @llvm.maximumnum.f32(float %x, float 0x7FF4000000000000)
store float %maximumnum, ptr %maximumnum_res
ret void
}
define void @minmax_qnan_nxv2f64_op0(<vscale x 2 x double> %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_qnan_nxv2f64_op0(
; CHECK-NEXT: store <vscale x 2 x double> [[X:%.*]], ptr [[MINNUM_RES:%.*]], align 16
; CHECK-NEXT: store <vscale x 2 x double> [[X]], ptr [[MAXNUM_RES:%.*]], align 16
; CHECK-NEXT: store <vscale x 2 x double> splat (double 0x7FF8000DEAD00000), ptr [[MINIMUM_RES:%.*]], align 16
; CHECK-NEXT: store <vscale x 2 x double> splat (double 0x7FF8000DEAD00000), ptr [[MAXIMUM_RES:%.*]], align 16
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call <vscale x 2 x double> @llvm.minimumnum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF8000DEAD00000), <vscale x 2 x double> [[X]])
; CHECK-NEXT: store <vscale x 2 x double> [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 16
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call <vscale x 2 x double> @llvm.maximumnum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF8000DEAD00000), <vscale x 2 x double> [[X]])
; CHECK-NEXT: store <vscale x 2 x double> [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 16
; CHECK-NEXT: ret void
;
%minnum = call <vscale x 2 x double> @llvm.minnum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF8000DEAD00000), <vscale x 2 x double> %x)
store <vscale x 2 x double> %minnum, ptr %minnum_res
%maxnum = call <vscale x 2 x double> @llvm.maxnum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF8000DEAD00000), <vscale x 2 x double> %x)
store <vscale x 2 x double> %maxnum, ptr %maxnum_res
%minimum = call <vscale x 2 x double> @llvm.minimum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF8000DEAD00000), <vscale x 2 x double> %x)
store <vscale x 2 x double> %minimum, ptr %minimum_res
%maximum = call <vscale x 2 x double> @llvm.maximum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF8000DEAD00000), <vscale x 2 x double> %x)
store <vscale x 2 x double> %maximum, ptr %maximum_res
%minimumnum = call <vscale x 2 x double> @llvm.minimumnum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF8000DEAD00000), <vscale x 2 x double> %x)
store <vscale x 2 x double> %minimumnum, ptr %minimumnum_res
%maximumnum = call <vscale x 2 x double> @llvm.maximumnum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF8000DEAD00000), <vscale x 2 x double> %x)
store <vscale x 2 x double> %maximumnum, ptr %maximumnum_res
ret void
}
; TODO currently snan is treated the same as qnan, but maxnum/minnum should really return qnan for these cases, not X
define void @minmax_snan_nxv2f64_op1(<vscale x 2 x double> %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_snan_nxv2f64_op1(
; CHECK-NEXT: store <vscale x 2 x double> [[X:%.*]], ptr [[MINNUM_RES:%.*]], align 16
; CHECK-NEXT: store <vscale x 2 x double> [[X]], ptr [[MAXNUM_RES:%.*]], align 16
; CHECK-NEXT: store <vscale x 2 x double> splat (double 0x7FFC00DEAD00DEAD), ptr [[MINIMUM_RES:%.*]], align 16
; CHECK-NEXT: store <vscale x 2 x double> splat (double 0x7FFC00DEAD00DEAD), ptr [[MAXIMUM_RES:%.*]], align 16
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call <vscale x 2 x double> @llvm.minimumnum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF400DEAD00DEAD), <vscale x 2 x double> [[X]])
; CHECK-NEXT: store <vscale x 2 x double> [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 16
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call <vscale x 2 x double> @llvm.maximumnum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF400DEAD00DEAD), <vscale x 2 x double> [[X]])
; CHECK-NEXT: store <vscale x 2 x double> [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 16
; CHECK-NEXT: ret void
;
%minnum = call <vscale x 2 x double> @llvm.minnum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF400DEAD00DEAD), <vscale x 2 x double> %x)
store <vscale x 2 x double> %minnum, ptr %minnum_res
%maxnum = call <vscale x 2 x double> @llvm.maxnum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF400DEAD00DEAD), <vscale x 2 x double> %x)
store <vscale x 2 x double> %maxnum, ptr %maxnum_res
%minimum = call <vscale x 2 x double> @llvm.minimum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF400DEAD00DEAD), <vscale x 2 x double> %x)
store <vscale x 2 x double> %minimum, ptr %minimum_res
%maximum = call <vscale x 2 x double> @llvm.maximum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF400DEAD00DEAD), <vscale x 2 x double> %x)
store <vscale x 2 x double> %maximum, ptr %maximum_res
%minimumnum = call <vscale x 2 x double> @llvm.minimumnum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF400DEAD00DEAD), <vscale x 2 x double> %x)
store <vscale x 2 x double> %minimumnum, ptr %minimumnum_res
%maximumnum = call <vscale x 2 x double> @llvm.maximumnum.nxv2f64(<vscale x 2 x double> splat (double 0x7FF400DEAD00DEAD), <vscale x 2 x double> %x)
store <vscale x 2 x double> %maximumnum, ptr %maximumnum_res
ret void
}
; TODO Currently, we treat SNaN and QNaN the same. However, for maxnum and minnum, we should not optimize this, as we should return <%x0, QNaN> instead of <%x0, %x1>
define void @minmax_mixed_snan_qnan_v2f64(<2 x double> %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_mixed_snan_qnan_v2f64(
; CHECK-NEXT: store <2 x double> [[X:%.*]], ptr [[MINNUM_RES:%.*]], align 16
; CHECK-NEXT: store <2 x double> [[X]], ptr [[MAXNUM_RES:%.*]], align 16
; CHECK-NEXT: store <2 x double> <double 0x7FFC00DEAD00DEAD, double 0x7FF8000FEED00000>, ptr [[MINIMUM_RES:%.*]], align 16
; CHECK-NEXT: store <2 x double> <double 0x7FFC00DEAD00DEAD, double 0x7FF8000FEED00000>, ptr [[MAXIMUM_RES:%.*]], align 16
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> <double 0x7FF400DEAD00DEAD, double 0x7FF8000FEED00000>, <2 x double> [[X]])
; CHECK-NEXT: store <2 x double> [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 16
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> <double 0x7FF400DEAD00DEAD, double 0x7FF8000FEED00000>, <2 x double> [[X]])
; CHECK-NEXT: store <2 x double> [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 16
; CHECK-NEXT: ret void
;
%minnum = call <2 x double> @llvm.minnum.v2f64(<2 x double> <double 0x7FF400DEAD00DEAD, double 0x7FF8000FEED00000>, <2 x double> %x)
store <2 x double> %minnum, ptr %minnum_res
%maxnum = call <2 x double> @llvm.maxnum.v2f64(<2 x double> <double 0x7FF400DEAD00DEAD, double 0x7FF8000FEED00000>, <2 x double> %x)
store <2 x double> %maxnum, ptr %maxnum_res
%minimum = call <2 x double> @llvm.minimum.v2f64(<2 x double> <double 0x7FF400DEAD00DEAD, double 0x7FF8000FEED00000>, <2 x double> %x)
store <2 x double> %minimum, ptr %minimum_res
%maximum = call <2 x double> @llvm.maximum.v2f64(<2 x double> <double 0x7FF400DEAD00DEAD, double 0x7FF8000FEED00000>, <2 x double> %x)
store <2 x double> %maximum, ptr %maximum_res
%minimumnum = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> <double 0x7FF400DEAD00DEAD, double 0x7FF8000FEED00000>, <2 x double> %x)
store <2 x double> %minimumnum, ptr %minimumnum_res
%maximumnum = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> <double 0x7FF400DEAD00DEAD, double 0x7FF8000FEED00000>, <2 x double> %x)
store <2 x double> %maximumnum, ptr %maximumnum_res
ret void
}
; Test with vector variants (v2f64) with NaN and poison
; Use the poison element for flexibility to choose to return either the constant arg or the other arg X
define void @minmax_mixed_qnan_poison_v2f64(<2 x double> %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_mixed_qnan_poison_v2f64(
; CHECK-NEXT: store <2 x double> [[X:%.*]], ptr [[MINNUM_RES:%.*]], align 16
; CHECK-NEXT: store <2 x double> [[X]], ptr [[MAXNUM_RES:%.*]], align 16
; CHECK-NEXT: store <2 x double> <double poison, double 0x7FF8000DEAD00000>, ptr [[MINIMUM_RES:%.*]], align 16
; CHECK-NEXT: store <2 x double> <double poison, double 0x7FF8000DEAD00000>, ptr [[MAXIMUM_RES:%.*]], align 16
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> <double poison, double 0x7FF8000DEAD00000>, <2 x double> [[X]])
; CHECK-NEXT: store <2 x double> [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 16
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> <double poison, double 0x7FF8000DEAD00000>, <2 x double> [[X]])
; CHECK-NEXT: store <2 x double> [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 16
; CHECK-NEXT: ret void
;
%minnum = call <2 x double> @llvm.minnum.v2f64(<2 x double> <double poison, double 0x7FF8000DEAD00000>, <2 x double> %x)
store <2 x double> %minnum, ptr %minnum_res
%maxnum = call <2 x double> @llvm.maxnum.v2f64(<2 x double> <double poison, double 0x7FF8000DEAD00000>, <2 x double> %x)
store <2 x double> %maxnum, ptr %maxnum_res
%minimum = call <2 x double> @llvm.minimum.v2f64(<2 x double> <double poison, double 0x7FF8000DEAD00000>, <2 x double> %x)
store <2 x double> %minimum, ptr %minimum_res
%maximum = call <2 x double> @llvm.maximum.v2f64(<2 x double> <double poison, double 0x7FF8000DEAD00000>, <2 x double> %x)
store <2 x double> %maximum, ptr %maximum_res
%minimumnum = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> <double poison, double 0x7FF8000DEAD00000>, <2 x double> %x)
store <2 x double> %minimumnum, ptr %minimumnum_res
%maximumnum = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> <double poison, double 0x7FF8000DEAD00000>, <2 x double> %x)
store <2 x double> %maximumnum, ptr %maximumnum_res
ret void
}
;###############################################################
;# Poison Tests #
;###############################################################
define void @minmax_poison_op0_f16(half %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_poison_op0_f16(
; CHECK-NEXT: store half [[X:%.*]], ptr [[MINNUM_RES:%.*]], align 2
; CHECK-NEXT: store half [[X]], ptr [[MAXNUM_RES:%.*]], align 2
; CHECK-NEXT: store half [[X]], ptr [[MINIMUM_RES:%.*]], align 2
; CHECK-NEXT: store half [[X]], ptr [[MAXIMUM_RES:%.*]], align 2
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call half @llvm.minimumnum.f16(half poison, half [[X]])
; CHECK-NEXT: store half [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 2
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call half @llvm.maximumnum.f16(half poison, half [[X]])
; CHECK-NEXT: store half [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 2
; CHECK-NEXT: ret void
;
%minnum = call half @llvm.minnum.f16(half poison, half %x)
store half %minnum, ptr %minnum_res
%maxnum = call half @llvm.maxnum.f16(half poison, half %x)
store half %maxnum, ptr %maxnum_res
%minimum = call half @llvm.minimum.f16(half poison, half %x)
store half %minimum, ptr %minimum_res
%maximum = call half @llvm.maximum.f16(half poison, half %x)
store half %maximum, ptr %maximum_res
%minimumnum = call half @llvm.minimumnum.f16(half poison, half %x)
store half %minimumnum, ptr %minimumnum_res
%maximumnum = call half @llvm.maximumnum.f16(half poison, half %x)
store half %maximumnum, ptr %maximumnum_res
ret void
}
define void @minmax_poison_op1_nxv2f64(<vscale x 2 x double> %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_poison_op1_nxv2f64(
; CHECK-NEXT: store <vscale x 2 x double> [[X:%.*]], ptr [[MINNUM_RES:%.*]], align 16
; CHECK-NEXT: store <vscale x 2 x double> [[X]], ptr [[MAXNUM_RES:%.*]], align 16
; CHECK-NEXT: store <vscale x 2 x double> [[X]], ptr [[MINIMUM_RES:%.*]], align 16
; CHECK-NEXT: store <vscale x 2 x double> [[X]], ptr [[MAXIMUM_RES:%.*]], align 16
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call nnan <vscale x 2 x double> @llvm.minimumnum.nxv2f64(<vscale x 2 x double> [[X]], <vscale x 2 x double> poison)
; CHECK-NEXT: store <vscale x 2 x double> [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 16
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call nnan <vscale x 2 x double> @llvm.maximumnum.nxv2f64(<vscale x 2 x double> [[X]], <vscale x 2 x double> poison)
; CHECK-NEXT: store <vscale x 2 x double> [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 16
; CHECK-NEXT: ret void
;
%minnum = call nnan <vscale x 2 x double> @llvm.minnum.nxv2f64(<vscale x 2 x double> %x, <vscale x 2 x double> poison)
store <vscale x 2 x double> %minnum, ptr %minnum_res
%maxnum = call nnan <vscale x 2 x double> @llvm.maxnum.nxv2f64(<vscale x 2 x double> %x, <vscale x 2 x double> poison)
store <vscale x 2 x double> %maxnum, ptr %maxnum_res
%minimum = call nnan <vscale x 2 x double> @llvm.minimum.nxv2f64(<vscale x 2 x double> %x, <vscale x 2 x double> poison)
store <vscale x 2 x double> %minimum, ptr %minimum_res
%maximum = call nnan <vscale x 2 x double> @llvm.maximum.nxv2f64(<vscale x 2 x double> %x, <vscale x 2 x double> poison)
store <vscale x 2 x double> %maximum, ptr %maximum_res
%minimumnum = call nnan <vscale x 2 x double> @llvm.minimumnum.nxv2f64(<vscale x 2 x double> %x, <vscale x 2 x double> poison)
store <vscale x 2 x double> %minimumnum, ptr %minimumnum_res
%maximumnum = call nnan <vscale x 2 x double> @llvm.maximumnum.nxv2f64(<vscale x 2 x double> %x, <vscale x 2 x double> poison)
store <vscale x 2 x double> %maximumnum, ptr %maximumnum_res
ret void
}
;###############################################################
;# Positive Infinity Tests #
;###############################################################
; maxnum(X, +inf) -> +inf (ignoring SNaN -> QNaN propagation)
; minnum(X, +inf) -> X if nnan (ignoring NaN quieting)
; maximum(X, +inf) -> +inf if nnan
; minimum(X, +inf) -> X (ignoring NaN quieting)
; TODO: maximumnum(X, +inf) -> +inf
; TODO: minimumnum(X, +inf) -> X if nnan (ignoring NaN quieting)
; Can only optimize maxnum and minimum without the nnan flag
define void @minmax_pos_inf_f32(float %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_pos_inf_f32(
; CHECK-NEXT: [[MINNUM:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 0x7FF0000000000000)
; CHECK-NEXT: store float [[MINNUM]], ptr [[MINNUM_RES:%.*]], align 4
; CHECK-NEXT: store float 0x7FF0000000000000, ptr [[MAXNUM_RES:%.*]], align 4
; CHECK-NEXT: store float [[X]], ptr [[MINIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUM:%.*]] = call float @llvm.maximum.f32(float [[X]], float 0x7FF0000000000000)
; CHECK-NEXT: store float [[MAXIMUM]], ptr [[MAXIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float 0x7FF0000000000000)
; CHECK-NEXT: store float [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float 0x7FF0000000000000)
; CHECK-NEXT: store float [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: ret void
;
%minnum = call float @llvm.minnum.f32(float %x, float 0x7FF0000000000000)
store float %minnum, ptr %minnum_res
%maxnum = call float @llvm.maxnum.f32(float %x, float 0x7FF0000000000000)
store float %maxnum, ptr %maxnum_res
%minimum = call float @llvm.minimum.f32(float %x, float 0x7FF0000000000000)
store float %minimum, ptr %minimum_res
%maximum = call float @llvm.maximum.f32(float %x, float 0x7FF0000000000000)
store float %maximum, ptr %maximum_res
%minimumnum = call float @llvm.minimumnum.f32(float %x, float 0x7FF0000000000000)
store float %minimumnum, ptr %minimumnum_res
%maximumnum = call float @llvm.maximumnum.f32(float %x, float 0x7FF0000000000000)
store float %maximumnum, ptr %maximumnum_res
ret void
}
; Can optimize all minmax variants if the nnan flag is set
; TODO maximumnum/minimumnum
define void @minmax_pos_inf_nnan_v2f32(<2 x float> %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_pos_inf_nnan_v2f32(
; CHECK-NEXT: store <2 x float> [[X:%.*]], ptr [[MINNUM_RES:%.*]], align 8
; CHECK-NEXT: store <2 x float> splat (float 0x7FF0000000000000), ptr [[MAXNUM_RES:%.*]], align 8
; CHECK-NEXT: store <2 x float> [[X]], ptr [[MINIMUM_RES:%.*]], align 8
; CHECK-NEXT: store <2 x float> splat (float 0x7FF0000000000000), ptr [[MAXIMUM_RES:%.*]], align 8
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call nnan <2 x float> @llvm.minimumnum.v2f32(<2 x float> splat (float 0x7FF0000000000000), <2 x float> [[X]])
; CHECK-NEXT: store <2 x float> [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 8
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call nnan <2 x float> @llvm.maximumnum.v2f32(<2 x float> splat (float 0x7FF0000000000000), <2 x float> [[X]])
; CHECK-NEXT: store <2 x float> [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 8
; CHECK-NEXT: ret void
;
%minnum = call nnan <2 x float> @llvm.minnum.v2f32(<2 x float> splat (float 0x7FF0000000000000), <2 x float> %x)
store <2 x float> %minnum, ptr %minnum_res
%maxnum = call nnan <2 x float> @llvm.maxnum.v2f32(<2 x float> splat (float 0x7FF0000000000000), <2 x float> %x)
store <2 x float> %maxnum, ptr %maxnum_res
%minimum = call nnan <2 x float> @llvm.minimum.v2f32(<2 x float> splat (float 0x7FF0000000000000), <2 x float> %x)
store <2 x float> %minimum, ptr %minimum_res
%maximum = call nnan <2 x float> @llvm.maximum.v2f32(<2 x float> splat (float 0x7FF0000000000000), <2 x float> %x)
store <2 x float> %maximum, ptr %maximum_res
%minimumnum = call nnan <2 x float> @llvm.minimumnum.v2f32(<2 x float> splat (float 0x7FF0000000000000), <2 x float> %x)
store <2 x float> %minimumnum, ptr %minimumnum_res
%maximumnum = call nnan <2 x float> @llvm.maximumnum.v2f32(<2 x float> splat (float 0x7FF0000000000000), <2 x float> %x)
store <2 x float> %maximumnum, ptr %maximumnum_res
ret void
}
;###############################################################
;# Negative Infinity Tests #
;###############################################################
; minnum(X, -inf) -> -inf (Ignoring SNaN -> QNaN propagation)
; maxnum(X, -inf) -> X if nnan
; minimum(X, -inf) -> -inf if nnan
; maximum(X, -inf) -> X (Ignoring NaN quieting)
; TODO: minimumnum(X, -inf) -> -inf
; TODO: maximumnum(X, -inf) -> X if nnan
; Can only optimize minnum and maximum without the nnan flag
define void @minmax_neg_inf_f32(float %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_neg_inf_f32(
; CHECK-NEXT: store float 0xFFF0000000000000, ptr [[MINNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXNUM:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float 0xFFF0000000000000)
; CHECK-NEXT: store float [[MAXNUM]], ptr [[MAXNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUM:%.*]] = call float @llvm.minimum.f32(float [[X]], float 0xFFF0000000000000)
; CHECK-NEXT: store float [[MINIMUM]], ptr [[MINIMUM_RES:%.*]], align 4
; CHECK-NEXT: store float [[X]], ptr [[MAXIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float 0xFFF0000000000000)
; CHECK-NEXT: store float [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float 0xFFF0000000000000)
; CHECK-NEXT: store float [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: ret void
;
%minnum = call float @llvm.minnum.f32(float %x, float 0xFFF0000000000000)
store float %minnum, ptr %minnum_res
%maxnum = call float @llvm.maxnum.f32(float %x, float 0xFFF0000000000000)
store float %maxnum, ptr %maxnum_res
%minimum = call float @llvm.minimum.f32(float %x, float 0xFFF0000000000000)
store float %minimum, ptr %minimum_res
%maximum = call float @llvm.maximum.f32(float %x, float 0xFFF0000000000000)
store float %maximum, ptr %maximum_res
%minimumnum = call float @llvm.minimumnum.f32(float %x, float 0xFFF0000000000000)
store float %minimumnum, ptr %minimumnum_res
%maximumnum = call float @llvm.maximumnum.f32(float %x, float 0xFFF0000000000000)
store float %maximumnum, ptr %maximumnum_res
ret void
}
; Can optimize all minmax variants if the nnan flag is set
; TODO maximumnum/minimumnum
define void @minmax_neg_inf_nnan_v2f64(<2 x double> %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_neg_inf_nnan_v2f64(
; CHECK-NEXT: store <2 x double> splat (double 0xFFF0000000000000), ptr [[MINNUM_RES:%.*]], align 16
; CHECK-NEXT: store <2 x double> [[X:%.*]], ptr [[MAXNUM_RES:%.*]], align 16
; CHECK-NEXT: store <2 x double> splat (double 0xFFF0000000000000), ptr [[MINIMUM_RES:%.*]], align 16
; CHECK-NEXT: store <2 x double> [[X]], ptr [[MAXIMUM_RES:%.*]], align 16
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call nnan <2 x double> @llvm.minimumnum.v2f64(<2 x double> [[X]], <2 x double> splat (double 0xFFF0000000000000))
; CHECK-NEXT: store <2 x double> [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 16
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call nnan <2 x double> @llvm.maximumnum.v2f64(<2 x double> [[X]], <2 x double> splat (double 0xFFF0000000000000))
; CHECK-NEXT: store <2 x double> [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 16
; CHECK-NEXT: ret void
;
%minnum = call nnan <2 x double> @llvm.minnum.v2f64(<2 x double> %x, <2 x double> splat (double 0xFFF0000000000000))
store <2 x double> %minnum, ptr %minnum_res
%maxnum = call nnan <2 x double> @llvm.maxnum.v2f64(<2 x double> %x, <2 x double> splat (double 0xFFF0000000000000))
store <2 x double> %maxnum, ptr %maxnum_res
%minimum = call nnan <2 x double> @llvm.minimum.v2f64(<2 x double> %x, <2 x double> splat (double 0xFFF0000000000000))
store <2 x double> %minimum, ptr %minimum_res
%maximum = call nnan <2 x double> @llvm.maximum.v2f64(<2 x double> %x, <2 x double> splat (double 0xFFF0000000000000))
store <2 x double> %maximum, ptr %maximum_res
%minimumnum = call nnan <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> splat (double 0xFFF0000000000000))
store <2 x double> %minimumnum, ptr %minimumnum_res
%maximumnum = call nnan <2 x double> @llvm.maximumnum.v2f64(<2 x double> %x, <2 x double> splat (double 0xFFF0000000000000))
store <2 x double> %maximumnum, ptr %maximumnum_res
ret void
}
;###############################################################
;# Largest Positive Float Constant Tests #
;###############################################################
; maxnum(X, +largest) -> +largest if ninf (ignoring SNaN -> QNaN propagation)
; minnum(X, +largest) -> X if ninf && nnan
; maximum(X, +largest) -> +largest if ninf && nnan
; minimum(X, +largest) -> X if ninf (ignoring quieting of sNaNs)
; TODO: maximumnum(X, +largest) -> +largest if ninf && nnan
; TODO: minimumnum(X, +largest) -> X if ninf && nnan
; None of these should be optimized away without the nnan/ninf flags
define void @minmax_largest_f32(float %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_largest_f32(
; CHECK-NEXT: [[MINNUM:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000)
; CHECK-NEXT: store float [[MINNUM]], ptr [[MINNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXNUM:%.*]] = call float @llvm.maxnum.f32(float [[X]], float 0x47EFFFFFE0000000)
; CHECK-NEXT: store float [[MAXNUM]], ptr [[MAXNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUM:%.*]] = call float @llvm.minimum.f32(float [[X]], float 0x47EFFFFFE0000000)
; CHECK-NEXT: store float [[MINIMUM]], ptr [[MINIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUM:%.*]] = call float @llvm.maximum.f32(float [[X]], float 0x47EFFFFFE0000000)
; CHECK-NEXT: store float [[MAXIMUM]], ptr [[MAXIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float 0x47EFFFFFE0000000)
; CHECK-NEXT: store float [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float 0x47EFFFFFE0000000)
; CHECK-NEXT: store float [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: ret void
;
%minnum = call float @llvm.minnum.f32(float %x, float 0x47EFFFFFE0000000)
store float %minnum, ptr %minnum_res
%maxnum = call float @llvm.maxnum.f32(float %x, float 0x47EFFFFFE0000000)
store float %maxnum, ptr %maxnum_res
%minimum = call float @llvm.minimum.f32(float %x, float 0x47EFFFFFE0000000)
store float %minimum, ptr %minimum_res
%maximum = call float @llvm.maximum.f32(float %x, float 0x47EFFFFFE0000000)
store float %maximum, ptr %maximum_res
%minimumnum = call float @llvm.minimumnum.f32(float %x, float 0x47EFFFFFE0000000)
store float %minimumnum, ptr %minimumnum_res
%maximumnum = call float @llvm.maximumnum.f32(float %x, float 0x47EFFFFFE0000000)
store float %maximumnum, ptr %maximumnum_res
ret void
}
; We can optimize maxnum and minimum if we know ninf is set
define void @minmax_largest_f32_ninf(float %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_largest_f32_ninf(
; CHECK-NEXT: [[MINNUM:%.*]] = call ninf float @llvm.minnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000)
; CHECK-NEXT: store float [[MINNUM]], ptr [[MINNUM_RES:%.*]], align 4
; CHECK-NEXT: store float 0x47EFFFFFE0000000, ptr [[MAXNUM_RES:%.*]], align 4
; CHECK-NEXT: store float [[X]], ptr [[MINIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUM:%.*]] = call ninf float @llvm.maximum.f32(float [[X]], float 0x47EFFFFFE0000000)
; CHECK-NEXT: store float [[MAXIMUM]], ptr [[MAXIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call ninf float @llvm.minimumnum.f32(float [[X]], float 0x47EFFFFFE0000000)
; CHECK-NEXT: store float [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call ninf float @llvm.maximumnum.f32(float [[X]], float 0x47EFFFFFE0000000)
; CHECK-NEXT: store float [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: ret void
;
%minnum = call ninf float @llvm.minnum.f32(float %x, float 0x47EFFFFFE0000000)
store float %minnum, ptr %minnum_res
%maxnum = call ninf float @llvm.maxnum.f32(float %x, float 0x47EFFFFFE0000000)
store float %maxnum, ptr %maxnum_res
%minimum = call ninf float @llvm.minimum.f32(float %x, float 0x47EFFFFFE0000000)
store float %minimum, ptr %minimum_res
%maximum = call ninf float @llvm.maximum.f32(float %x, float 0x47EFFFFFE0000000)
store float %maximum, ptr %maximum_res
%minimumnum = call ninf float @llvm.minimumnum.f32(float %x, float 0x47EFFFFFE0000000)
store float %minimumnum, ptr %minimumnum_res
%maximumnum = call ninf float @llvm.maximumnum.f32(float %x, float 0x47EFFFFFE0000000)
store float %maximumnum, ptr %maximumnum_res
ret void
}
; All can be optimized if both the ninf and nnan flags are set (ignoring SNaN propagation in minnum/maxnum)
; TODO maximumnum/minimumnum
define void @minmax_largest_v2f32_ninf_nnan(<2 x float> %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_largest_v2f32_ninf_nnan(
; CHECK-NEXT: store <2 x float> [[X:%.*]], ptr [[MINNUM_RES:%.*]], align 8
; CHECK-NEXT: store <2 x float> splat (float 0x47EFFFFFE0000000), ptr [[MAXNUM_RES:%.*]], align 8
; CHECK-NEXT: store <2 x float> [[X]], ptr [[MINIMUM_RES:%.*]], align 8
; CHECK-NEXT: store <2 x float> splat (float 0x47EFFFFFE0000000), ptr [[MAXIMUM_RES:%.*]], align 8
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call nnan ninf <2 x float> @llvm.minimumnum.v2f32(<2 x float> [[X]], <2 x float> splat (float 0x47EFFFFFE0000000))
; CHECK-NEXT: store <2 x float> [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 8
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call nnan ninf <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X]], <2 x float> splat (float 0x47EFFFFFE0000000))
; CHECK-NEXT: store <2 x float> [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 8
; CHECK-NEXT: ret void
;
%minnum = call ninf nnan <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> splat (float 0x47EFFFFFE0000000))
store <2 x float> %minnum, ptr %minnum_res
%maxnum = call ninf nnan <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> splat (float 0x47EFFFFFE0000000))
store <2 x float> %maxnum, ptr %maxnum_res
%minimum = call ninf nnan <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> splat (float 0x47EFFFFFE0000000))
store <2 x float> %minimum, ptr %minimum_res
%maximum = call ninf nnan <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> splat (float 0x47EFFFFFE0000000))
store <2 x float> %maximum, ptr %maximum_res
%minimumnum = call ninf nnan <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> splat (float 0x47EFFFFFE0000000))
store <2 x float> %minimumnum, ptr %minimumnum_res
%maximumnum = call ninf nnan <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> splat (float 0x47EFFFFFE0000000))
store <2 x float> %maximumnum, ptr %maximumnum_res
ret void
}
;###############################################################
;# Largest Negative Float Constant Tests #
;###############################################################
; maxnum(X, -largest) -> X if ninf && nnan
; minnum(X, -largest) -> -largest if ninf (ignoring SNaN -> QNaN propagation)
; maximum(X, -largest) -> X if ninf (ignoring quieting of sNaNs)
; minimum(X, -largest) -> -largest if ninf && nnan
; TODO: maximumnum(X, -largest) -> X if ninf && nnan
; TODO: minimumnum(X, -largest) -> -largest if ninf
; None of these should be optimized away without the nnan/ninf flags
define void @minmax_neg_largest_f32(float %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_neg_largest_f32(
; CHECK-NEXT: [[MINNUM:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 0xC7EFFFFFE0000000)
; CHECK-NEXT: store float [[MINNUM]], ptr [[MINNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXNUM:%.*]] = call float @llvm.maxnum.f32(float [[X]], float 0xC7EFFFFFE0000000)
; CHECK-NEXT: store float [[MAXNUM]], ptr [[MAXNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUM:%.*]] = call float @llvm.minimum.f32(float [[X]], float 0xC7EFFFFFE0000000)
; CHECK-NEXT: store float [[MINIMUM]], ptr [[MINIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUM:%.*]] = call float @llvm.maximum.f32(float [[X]], float 0xC7EFFFFFE0000000)
; CHECK-NEXT: store float [[MAXIMUM]], ptr [[MAXIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float 0xC7EFFFFFE0000000)
; CHECK-NEXT: store float [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float 0xC7EFFFFFE0000000)
; CHECK-NEXT: store float [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: ret void
;
%minnum = call float @llvm.minnum.f32(float %x, float 0xC7EFFFFFE0000000)
store float %minnum, ptr %minnum_res
%maxnum = call float @llvm.maxnum.f32(float %x, float 0xC7EFFFFFE0000000)
store float %maxnum, ptr %maxnum_res
%minimum = call float @llvm.minimum.f32(float %x, float 0xC7EFFFFFE0000000)
store float %minimum, ptr %minimum_res
%maximum = call float @llvm.maximum.f32(float %x, float 0xC7EFFFFFE0000000)
store float %maximum, ptr %maximum_res
%minimumnum = call float @llvm.minimumnum.f32(float %x, float 0xC7EFFFFFE0000000)
store float %minimumnum, ptr %minimumnum_res
%maximumnum = call float @llvm.maximumnum.f32(float %x, float 0xC7EFFFFFE0000000)
store float %maximumnum, ptr %maximumnum_res
ret void
}
; We can optimize minnum and maximum if we know ninf is set
define void @minmax_neg_largest_f32_ninf(float %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_neg_largest_f32_ninf(
; CHECK-NEXT: store float 0xC7EFFFFFE0000000, ptr [[MINNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXNUM:%.*]] = call ninf float @llvm.maxnum.f32(float [[X:%.*]], float 0xC7EFFFFFE0000000)
; CHECK-NEXT: store float [[MAXNUM]], ptr [[MAXNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUM:%.*]] = call ninf float @llvm.minimum.f32(float [[X]], float 0xC7EFFFFFE0000000)
; CHECK-NEXT: store float [[MINIMUM]], ptr [[MINIMUM_RES:%.*]], align 4
; CHECK-NEXT: store float [[X]], ptr [[MAXIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call ninf float @llvm.minimumnum.f32(float [[X]], float 0xC7EFFFFFE0000000)
; CHECK-NEXT: store float [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call ninf float @llvm.maximumnum.f32(float [[X]], float 0xC7EFFFFFE0000000)
; CHECK-NEXT: store float [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: ret void
;
%minnum = call ninf float @llvm.minnum.f32(float %x, float 0xC7EFFFFFE0000000)
store float %minnum, ptr %minnum_res
%maxnum = call ninf float @llvm.maxnum.f32(float %x, float 0xC7EFFFFFE0000000)
store float %maxnum, ptr %maxnum_res
%minimum = call ninf float @llvm.minimum.f32(float %x, float 0xC7EFFFFFE0000000)
store float %minimum, ptr %minimum_res
%maximum = call ninf float @llvm.maximum.f32(float %x, float 0xC7EFFFFFE0000000)
store float %maximum, ptr %maximum_res
%minimumnum = call ninf float @llvm.minimumnum.f32(float %x, float 0xC7EFFFFFE0000000)
store float %minimumnum, ptr %minimumnum_res
%maximumnum = call ninf float @llvm.maximumnum.f32(float %x, float 0xC7EFFFFFE0000000)
store float %maximumnum, ptr %maximumnum_res
ret void
}
; All can be optimized if both the ninf and nnan flags are set (ignoring SNaN propagation in minnum/maxnum)
; TODO maximumnum/minimumnum
define void @minmax_neg_largest_nxv2f32_nnan_ninf(<vscale x 2 x float> %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_neg_largest_nxv2f32_nnan_ninf(
; CHECK-NEXT: store <vscale x 2 x float> splat (float 0xC7EFFFFFE0000000), ptr [[MINNUM_RES:%.*]], align 8
; CHECK-NEXT: store <vscale x 2 x float> [[X:%.*]], ptr [[MAXNUM_RES:%.*]], align 8
; CHECK-NEXT: store <vscale x 2 x float> splat (float 0xC7EFFFFFE0000000), ptr [[MINIMUM_RES:%.*]], align 8
; CHECK-NEXT: store <vscale x 2 x float> [[X]], ptr [[MAXIMUM_RES:%.*]], align 8
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call nnan ninf <vscale x 2 x float> @llvm.minimumnum.nxv2f32(<vscale x 2 x float> [[X]], <vscale x 2 x float> splat (float 0xC7EFFFFFE0000000))
; CHECK-NEXT: store <vscale x 2 x float> [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 8
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call nnan ninf <vscale x 2 x float> @llvm.maximumnum.nxv2f32(<vscale x 2 x float> [[X]], <vscale x 2 x float> splat (float 0xC7EFFFFFE0000000))
; CHECK-NEXT: store <vscale x 2 x float> [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 8
; CHECK-NEXT: ret void
;
%minnum = call nnan ninf <vscale x 2 x float> @llvm.minnum.nxv2f32(<vscale x 2 x float> %x, <vscale x 2 x float> splat (float 0xC7EFFFFFE0000000))
store <vscale x 2 x float> %minnum, ptr %minnum_res
%maxnum = call nnan ninf <vscale x 2 x float> @llvm.maxnum.nxv2f32(<vscale x 2 x float> %x, <vscale x 2 x float> splat (float 0xC7EFFFFFE0000000))
store <vscale x 2 x float> %maxnum, ptr %maxnum_res
%minimum = call nnan ninf <vscale x 2 x float> @llvm.minimum.nxv2f32(<vscale x 2 x float> %x, <vscale x 2 x float> splat (float 0xC7EFFFFFE0000000))
store <vscale x 2 x float> %minimum, ptr %minimum_res
%maximum = call nnan ninf <vscale x 2 x float> @llvm.maximum.nxv2f32(<vscale x 2 x float> %x, <vscale x 2 x float> splat (float 0xC7EFFFFFE0000000))
store <vscale x 2 x float> %maximum, ptr %maximum_res
%minimumnum = call nnan ninf <vscale x 2 x float> @llvm.minimumnum.nxv2f32(<vscale x 2 x float> %x, <vscale x 2 x float> splat (float 0xC7EFFFFFE0000000))
store <vscale x 2 x float> %minimumnum, ptr %minimumnum_res
%maximumnum = call nnan ninf <vscale x 2 x float> @llvm.maximumnum.nxv2f32(<vscale x 2 x float> %x, <vscale x 2 x float> splat (float 0xC7EFFFFFE0000000))
store <vscale x 2 x float> %maximumnum, ptr %maximumnum_res
ret void
}
;###############################################################
;# Min(x, x) / Max(x, x) #
;###############################################################
; min(x, x) -> x and max(x, x) -> x for all variants (ignoring SNaN quieting)
define void @minmax_same_args(float %x, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_same_args(
; CHECK-NEXT: store float [[X:%.*]], ptr [[MINNUM_RES:%.*]], align 4
; CHECK-NEXT: store float [[X]], ptr [[MAXNUM_RES:%.*]], align 4
; CHECK-NEXT: store float [[X]], ptr [[MINIMUM_RES:%.*]], align 4
; CHECK-NEXT: store float [[X]], ptr [[MAXIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUMNUM:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float [[X]])
; CHECK-NEXT: store float [[MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUMNUM:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float [[X]])
; CHECK-NEXT: store float [[MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: ret void
;
%minnum = call float @llvm.minnum.f32(float %x, float %x)
store float %minnum, ptr %minnum_res
%maxnum = call float @llvm.maxnum.f32(float %x, float %x)
store float %maxnum, ptr %maxnum_res
%minimum = call float @llvm.minimum.f32(float %x, float %x)
store float %minimum, ptr %minimum_res
%maximum = call float @llvm.maximum.f32(float %x, float %x)
store float %maximum, ptr %maximum_res
%minimumnum = call float @llvm.minimumnum.f32(float %x, float %x)
store float %minimumnum, ptr %minimumnum_res
%maximumnum = call float @llvm.maximumnum.f32(float %x, float %x)
store float %maximumnum, ptr %maximumnum_res
ret void
}
;###############################################################
;# Nested calls: M(x, M(x, y)) -> M(x, y) #
;###############################################################
define void @minmax_x_minmax_xy(<2 x float> %x, <2 x float> %y, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_x_minmax_xy(
; CHECK-NEXT: [[MINNUM_XY:%.*]] = call <2 x float> @llvm.minnum.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]])
; CHECK-NEXT: store <2 x float> [[MINNUM_XY]], ptr [[MINNUM_RES:%.*]], align 8
; CHECK-NEXT: [[MAXNUM_XY:%.*]] = call <2 x float> @llvm.maxnum.v2f32(<2 x float> [[X]], <2 x float> [[Y]])
; CHECK-NEXT: store <2 x float> [[MAXNUM_XY]], ptr [[MAXNUM_RES:%.*]], align 8
; CHECK-NEXT: [[MINIMUM_XY:%.*]] = call <2 x float> @llvm.minimum.v2f32(<2 x float> [[X]], <2 x float> [[Y]])
; CHECK-NEXT: store <2 x float> [[MINIMUM_XY]], ptr [[MINIMUM_RES:%.*]], align 8
; CHECK-NEXT: [[MAXIMUM_XY:%.*]] = call <2 x float> @llvm.maximum.v2f32(<2 x float> [[X]], <2 x float> [[Y]])
; CHECK-NEXT: store <2 x float> [[MAXIMUM_XY]], ptr [[MAXIMUM_RES:%.*]], align 8
; CHECK-NEXT: [[MINIMUMNUM_XY:%.*]] = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> [[X]], <2 x float> [[Y]])
; CHECK-NEXT: [[MINIMUMNUM_NESTED:%.*]] = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> [[X]], <2 x float> [[MINIMUMNUM_XY]])
; CHECK-NEXT: store <2 x float> [[MINIMUMNUM_NESTED]], ptr [[MINIMUMNUM_RES:%.*]], align 8
; CHECK-NEXT: [[MAXIMUMNUM_XY:%.*]] = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X]], <2 x float> [[Y]])
; CHECK-NEXT: [[MAXIMUMNUM_NESTED:%.*]] = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X]], <2 x float> [[MAXIMUMNUM_XY]])
; CHECK-NEXT: store <2 x float> [[MAXIMUMNUM_NESTED]], ptr [[MAXIMUMNUM_RES:%.*]], align 8
; CHECK-NEXT: ret void
;
%minnum_xy = call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> %y)
%minnum_nested = call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> %minnum_xy)
store <2 x float> %minnum_nested, ptr %minnum_res
%maxnum_xy = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> %y)
%maxnum_nested = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> %maxnum_xy)
store <2 x float> %maxnum_nested, ptr %maxnum_res
%minimum_xy = call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> %y)
%minimum_nested = call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> %minimum_xy)
store <2 x float> %minimum_nested, ptr %minimum_res
%maximum_xy = call <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> %y)
%maximum_nested = call <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> %maximum_xy)
store <2 x float> %maximum_nested, ptr %maximum_res
%minimumnum_xy = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> %y)
%minimumnum_nested = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> %minimumnum_xy)
store <2 x float> %minimumnum_nested, ptr %minimumnum_res
%maximumnum_xy = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> %y)
%maximumnum_nested = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> %maximumnum_xy)
store <2 x float> %maximumnum_nested, ptr %maximumnum_res
ret void
}
; Negative test: m(Z, m(X,Y)) cannot be optimized to m(x, y)
define void @minmax_z_minmax_xy(float %x, float %y, float %z, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_z_minmax_xy(
; CHECK-NEXT: [[MINNUM_XY:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float [[Y:%.*]])
; CHECK-NEXT: [[MINNUM_NESTED:%.*]] = call float @llvm.minnum.f32(float [[Z:%.*]], float [[MINNUM_XY]])
; CHECK-NEXT: store float [[MINNUM_NESTED]], ptr [[MINNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXNUM_XY:%.*]] = call float @llvm.maxnum.f32(float [[X]], float [[Y]])
; CHECK-NEXT: [[MAXNUM_NESTED:%.*]] = call float @llvm.maxnum.f32(float [[Z]], float [[MAXNUM_XY]])
; CHECK-NEXT: store float [[MAXNUM_NESTED]], ptr [[MAXNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUM_XY:%.*]] = call float @llvm.minimum.f32(float [[X]], float [[Y]])
; CHECK-NEXT: [[MINIMUM_NESTED:%.*]] = call float @llvm.minimum.f32(float [[Z]], float [[MINIMUM_XY]])
; CHECK-NEXT: store float [[MINIMUM_NESTED]], ptr [[MINIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUM_XY:%.*]] = call float @llvm.maximum.f32(float [[X]], float [[Y]])
; CHECK-NEXT: [[MAXIMUM_NESTED:%.*]] = call float @llvm.maximum.f32(float [[Z]], float [[MAXIMUM_XY]])
; CHECK-NEXT: store float [[MAXIMUM_NESTED]], ptr [[MAXIMUM_RES:%.*]], align 4
; CHECK-NEXT: [[MINIMUMNUM_XY:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float [[Y]])
; CHECK-NEXT: [[MINIMUMNUM_NESTED:%.*]] = call float @llvm.minimumnum.f32(float [[Z]], float [[MINIMUMNUM_XY]])
; CHECK-NEXT: store float [[MINIMUMNUM_NESTED]], ptr [[MINIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: [[MAXIMUMNUM_XY:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float [[Y]])
; CHECK-NEXT: [[MAXIMUMNUM_NESTED:%.*]] = call float @llvm.maximumnum.f32(float [[Z]], float [[MAXIMUMNUM_XY]])
; CHECK-NEXT: store float [[MAXIMUMNUM_NESTED]], ptr [[MAXIMUMNUM_RES:%.*]], align 4
; CHECK-NEXT: ret void
;
%minnum_xy = call float @llvm.minnum.f32(float %x, float %y)
%minnum_nested = call float @llvm.minnum.f32(float %z, float %minnum_xy)
store float %minnum_nested, ptr %minnum_res
%maxnum_xy = call float @llvm.maxnum.f32(float %x, float %y)
%maxnum_nested = call float @llvm.maxnum.f32(float %z, float %maxnum_xy)
store float %maxnum_nested, ptr %maxnum_res
%minimum_xy = call float @llvm.minimum.f32(float %x, float %y)
%minimum_nested = call float @llvm.minimum.f32(float %z, float %minimum_xy)
store float %minimum_nested, ptr %minimum_res
%maximum_xy = call float @llvm.maximum.f32(float %x, float %y)
%maximum_nested = call float @llvm.maximum.f32(float %z, float %maximum_xy)
store float %maximum_nested, ptr %maximum_res
%minimumnum_xy = call float @llvm.minimumnum.f32(float %x, float %y)
%minimumnum_nested = call float @llvm.minimumnum.f32(float %z, float %minimumnum_xy)
store float %minimumnum_nested, ptr %minimumnum_res
%maximumnum_xy = call float @llvm.maximumnum.f32(float %x, float %y)
%maximumnum_nested = call float @llvm.maximumnum.f32(float %z, float %maximumnum_xy)
store float %maximumnum_nested, ptr %maximumnum_res
ret void
}
;###############################################################
;# Nested calls: M(M(x, y), M'(x, y)) -> M(x, y) #
;###############################################################
; m(m(X,Y), m'(Y,X)) -> m(X, Y)
; Test where m' is the same op as m
define void @minmax_minmax_xy_minmax_yx(half %x, half %y, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_minmax_xy_minmax_yx(
; CHECK-NEXT: [[MINNUM_XY:%.*]] = call half @llvm.minnum.f16(half [[X:%.*]], half [[Y:%.*]])
; CHECK-NEXT: store half [[MINNUM_XY]], ptr [[MINNUM_RES:%.*]], align 2
; CHECK-NEXT: [[MAXNUM_XY:%.*]] = call half @llvm.maxnum.f16(half [[X]], half [[Y]])
; CHECK-NEXT: store half [[MAXNUM_XY]], ptr [[MAXNUM_RES:%.*]], align 2
; CHECK-NEXT: [[MINIMUM_XY:%.*]] = call half @llvm.minimum.f16(half [[X]], half [[Y]])
; CHECK-NEXT: store half [[MINIMUM_XY]], ptr [[MINIMUM_RES:%.*]], align 2
; CHECK-NEXT: [[MAXIMUM_XY:%.*]] = call half @llvm.maximum.f16(half [[X]], half [[Y]])
; CHECK-NEXT: store half [[MAXIMUM_XY]], ptr [[MAXIMUM_RES:%.*]], align 2
; CHECK-NEXT: [[MINIMUMNUM_XY:%.*]] = call half @llvm.minimumnum.f16(half [[X]], half [[Y]])
; CHECK-NEXT: [[MINIMUMNUM_YX:%.*]] = call half @llvm.minimumnum.f16(half [[Y]], half [[X]])
; CHECK-NEXT: [[FINAL_MINIMUMNUM:%.*]] = call half @llvm.minimumnum.f16(half [[MINIMUMNUM_XY]], half [[MINIMUMNUM_YX]])
; CHECK-NEXT: store half [[FINAL_MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 2
; CHECK-NEXT: [[MAXIMUMNUM_XY:%.*]] = call half @llvm.maximumnum.f16(half [[X]], half [[Y]])
; CHECK-NEXT: [[MAXIMUMNUM_YX:%.*]] = call half @llvm.maximumnum.f16(half [[Y]], half [[X]])
; CHECK-NEXT: [[FINAL_MAXIMUMNUM:%.*]] = call half @llvm.maximumnum.f16(half [[MAXIMUMNUM_XY]], half [[MAXIMUMNUM_YX]])
; CHECK-NEXT: store half [[FINAL_MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 2
; CHECK-NEXT: ret void
;
%minnum_xy = call half @llvm.minnum.f16(half %x, half %y)
%minnum_yx = call half @llvm.minnum.f16(half %y, half %x)
%final_minnum = call half @llvm.minnum.f16(half %minnum_xy, half %minnum_yx)
store half %final_minnum, ptr %minnum_res
%maxnum_xy = call half @llvm.maxnum.f16(half %x, half %y)
%maxnum_yx = call half @llvm.maxnum.f16(half %y, half %x)
%final_maxnum = call half @llvm.maxnum.f16(half %maxnum_xy, half %maxnum_yx)
store half %final_maxnum, ptr %maxnum_res
%minimum_xy = call half @llvm.minimum.f16(half %x, half %y)
%minimum_yx = call half @llvm.minimum.f16(half %y, half %x)
%final_minimum = call half @llvm.minimum.f16(half %minimum_xy, half %minimum_yx)
store half %final_minimum, ptr %minimum_res
%maximum_xy = call half @llvm.maximum.f16(half %x, half %y)
%maximum_yx = call half @llvm.maximum.f16(half %y, half %x)
%final_maximum = call half @llvm.maximum.f16(half %maximum_xy, half %maximum_yx)
store half %final_maximum, ptr %maximum_res
%minimumnum_xy = call half @llvm.minimumnum.f16(half %x, half %y)
%minimumnum_yx = call half @llvm.minimumnum.f16(half %y, half %x)
%final_minimumnum = call half @llvm.minimumnum.f16(half %minimumnum_xy, half %minimumnum_yx)
store half %final_minimumnum, ptr %minimumnum_res
%maximumnum_xy = call half @llvm.maximumnum.f16(half %x, half %y)
%maximumnum_yx = call half @llvm.maximumnum.f16(half %y, half %x)
%final_maximumnum = call half @llvm.maximumnum.f16(half %maximumnum_xy, half %maximumnum_yx)
store half %final_maximumnum, ptr %maximumnum_res
ret void
}
; m(m(X,Y), m'(Y,X)) -> m(X, Y)
; Test where m' is the opposite op from m
define void @minmax_minmax_xy_maxmin_yx(double %x, double %y, ptr %minnum_res, ptr %maxnum_res, ptr %minimum_res, ptr %maximum_res, ptr %minimumnum_res, ptr %maximumnum_res) {
; CHECK-LABEL: @minmax_minmax_xy_maxmin_yx(
; CHECK-NEXT: [[MINNUM_XY:%.*]] = call double @llvm.minnum.f64(double [[Y:%.*]], double [[X:%.*]])
; CHECK-NEXT: store double [[MINNUM_XY]], ptr [[MINNUM_RES:%.*]], align 8
; CHECK-NEXT: [[MAXNUM_XY:%.*]] = call double @llvm.maxnum.f64(double [[Y]], double [[X]])
; CHECK-NEXT: store double [[MAXNUM_XY]], ptr [[MAXNUM_RES:%.*]], align 8
; CHECK-NEXT: [[MINIMUM_XY:%.*]] = call double @llvm.minimum.f64(double [[Y]], double [[X]])
; CHECK-NEXT: store double [[MINIMUM_XY]], ptr [[MINIMUM_RES:%.*]], align 8
; CHECK-NEXT: [[MAXIMUM_XY:%.*]] = call double @llvm.maximum.f64(double [[Y]], double [[X]])
; CHECK-NEXT: store double [[MAXIMUM_XY]], ptr [[MAXIMUM_RES:%.*]], align 8
; CHECK-NEXT: [[MINIMUMNUM_XY:%.*]] = call double @llvm.minimumnum.f64(double [[Y]], double [[X]])
; CHECK-NEXT: [[MAXIMUMNUM_XY:%.*]] = call double @llvm.maximumnum.f64(double [[X]], double [[Y]])
; CHECK-NEXT: [[FINAL_MINIMUMNUM:%.*]] = call double @llvm.minimumnum.f64(double [[MINIMUMNUM_XY]], double [[MAXIMUMNUM_XY]])
; CHECK-NEXT: store double [[FINAL_MINIMUMNUM]], ptr [[MINIMUMNUM_RES:%.*]], align 8
; CHECK-NEXT: [[MAXIMUMNUM_XY1:%.*]] = call double @llvm.maximumnum.f64(double [[Y]], double [[X]])
; CHECK-NEXT: [[MINIMUMNUM_YX:%.*]] = call double @llvm.minimumnum.f64(double [[X]], double [[Y]])
; CHECK-NEXT: [[FINAL_MAXIMUMNUM:%.*]] = call double @llvm.maximumnum.f64(double [[MAXIMUMNUM_XY1]], double [[MINIMUMNUM_YX]])
; CHECK-NEXT: store double [[FINAL_MAXIMUMNUM]], ptr [[MAXIMUMNUM_RES:%.*]], align 8
; CHECK-NEXT: ret void
;
%minnum_xy = call double @llvm.minnum.f64(double %x, double %y)
%maxnum_yx = call double @llvm.maxnum.f64(double %y, double %x)
%final_minnum = call double @llvm.minnum.f64(double %minnum_xy, double %maxnum_yx)
store double %final_minnum, ptr %minnum_res
%maxnum_xy = call double @llvm.maxnum.f64(double %x, double %y)
%minnum_yx = call double @llvm.minnum.f64(double %y, double %x)
%final_maxnum = call double @llvm.maxnum.f64(double %maxnum_xy, double %minnum_yx)
store double %final_maxnum, ptr %maxnum_res
%minimum_xy = call double @llvm.minimum.f64(double %x, double %y)
%maximum_yx = call double @llvm.maximum.f64(double %y, double %x)
%final_minimum = call double @llvm.minimum.f64(double %minimum_xy, double %maximum_yx)
store double %final_minimum, ptr %minimum_res
%maximum_xy = call double @llvm.maximum.f64(double %x, double %y)
%minimum_yx = call double @llvm.minimum.f64(double %y, double %x)
%final_maximum = call double @llvm.maximum.f64(double %maximum_xy, double %minimum_yx)
store double %final_maximum, ptr %maximum_res
%minimumnum_xy = call double @llvm.minimumnum.f64(double %x, double %y)
%maximumnum_yx = call double @llvm.maximumnum.f64(double %y, double %x)
%final_minimumnum = call double @llvm.minimumnum.f64(double %minimumnum_xy, double %maximumnum_yx)
store double %final_minimumnum, ptr %minimumnum_res
%maximumnum_xy = call double @llvm.maximumnum.f64(double %x, double %y)
%minimumnum_yx = call double @llvm.minimumnum.f64(double %y, double %x)
%final_maximumnum = call double @llvm.maximumnum.f64(double %maximumnum_xy, double %minimumnum_yx)
store double %final_maximumnum, ptr %maximumnum_res
ret void
}