[llvm] e6e7a6d - Attributor: Add baseline tests for nofpclass

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 14 22:13:22 PDT 2023


Author: Matt Arsenault
Date: 2023-03-15T01:13:08-04:00
New Revision: e6e7a6dd365d62e9baa04cc25e0dbaac6c5a0700

URL: https://github.com/llvm/llvm-project/commit/e6e7a6dd365d62e9baa04cc25e0dbaac6c5a0700
DIFF: https://github.com/llvm/llvm-project/commit/e6e7a6dd365d62e9baa04cc25e0dbaac6c5a0700.diff

LOG: Attributor: Add baseline tests for nofpclass

Added: 
    llvm/test/Transforms/Attributor/nofpclass.ll

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/llvm/test/Transforms/Attributor/nofpclass.ll b/llvm/test/Transforms/Attributor/nofpclass.ll
new file mode 100644
index 0000000000000..a21f60a395c90
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofpclass.ll
@@ -0,0 +1,616 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --version 2
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
+
+declare nofpclass(nan) float @ret_nofpclass_nan()
+declare [2 x [3 x float]] @ret_array()
+declare float @extern()
+declare void @extern.use(float)
+declare void @extern.use.array([2 x [3 x float]])
+declare void @llvm.assume(i1 noundef)
+declare void @unknown()
+declare half @llvm.fabs.f16(half)
+declare void @extern.use.f16(half)
+declare i1 @llvm.is.fpclass.f32(float, i32 immarg)
+
+define float @returned_0() {
+; CHECK-LABEL: define noundef float @returned_0() {
+; CHECK-NEXT:    call void @unknown()
+; CHECK-NEXT:    ret float 0.000000e+00
+;
+  call void @unknown()
+  ret float 0.0
+}
+
+define float @returned_neg0() {
+; CHECK-LABEL: define noundef float @returned_neg0() {
+; CHECK-NEXT:    call void @unknown()
+; CHECK-NEXT:    ret float -0.000000e+00
+;
+  call void @unknown()
+  ret float -0.0
+}
+
+define float @returned_undef() {
+; CHECK-LABEL: define float @returned_undef() {
+; CHECK-NEXT:    call void @unknown()
+; CHECK-NEXT:    ret float undef
+;
+  call void @unknown()
+  ret float undef
+}
+
+define float @returned_poison() {
+; CHECK-LABEL: define float @returned_poison() {
+; CHECK-NEXT:    call void @unknown()
+; CHECK-NEXT:    ret float poison
+;
+  call void @unknown()
+  ret float poison
+}
+
+define double @returned_snan() {
+; CHECK-LABEL: define noundef double @returned_snan() {
+; CHECK-NEXT:    call void @unknown()
+; CHECK-NEXT:    ret double 0x7FF0000000000001
+;
+  call void @unknown()
+  ret double 0x7FF0000000000001
+}
+
+define double @returned_qnan() {
+; CHECK-LABEL: define noundef double @returned_qnan() {
+; CHECK-NEXT:    call void @unknown()
+; CHECK-NEXT:    ret double 0x7FF8000000000000
+;
+  call void @unknown()
+  ret double 0x7FF8000000000000
+}
+
+define <2 x double> @returned_zero_vector() {
+; CHECK-LABEL: define noundef <2 x double> @returned_zero_vector() {
+; CHECK-NEXT:    call void @unknown()
+; CHECK-NEXT:    ret <2 x double> zeroinitializer
+;
+  call void @unknown()
+  ret <2 x double> zeroinitializer
+}
+
+define <2 x double> @returned_negzero_vector() {
+; CHECK-LABEL: define noundef <2 x double> @returned_negzero_vector() {
+; CHECK-NEXT:    call void @unknown()
+; CHECK-NEXT:    ret <2 x double> <double -0.000000e+00, double -0.000000e+00>
+;
+  call void @unknown()
+  ret <2 x double> <double -0.0, double -0.0>
+}
+
+define <2 x double> @returned_qnan_zero_vector() {
+; CHECK-LABEL: define noundef <2 x double> @returned_qnan_zero_vector() {
+; CHECK-NEXT:    call void @unknown()
+; CHECK-NEXT:    ret <2 x double> <double 0x7FF8000000000000, double 0.000000e+00>
+;
+  call void @unknown()
+  ret <2 x double> <double 0x7FF8000000000000, double 0.0>
+}
+
+; Return a float trivially nofpclass(nan) (call return attribute)
+define float @return_nofpclass_nan_decl_return() {
+; CHECK-LABEL: define float @return_nofpclass_nan_decl_return() {
+; CHECK-NEXT:    [[RET:%.*]] = call float @ret_nofpclass_nan()
+; CHECK-NEXT:    ret float [[RET]]
+;
+  %ret = call float @ret_nofpclass_nan()
+  ret float %ret
+}
+
+; Return a float trivially nofpclass(nan) (argument attribute)
+define float @return_nofpclass_nan_arg(float returned nofpclass(nan) %p) {
+; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define float @return_nofpclass_nan_arg
+; CHECK-SAME: (float returned nofpclass(nan) [[P:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-NEXT:    ret float [[P]]
+;
+  ret float %p
+}
+
+define [2 x [3 x float]] @return_nofpclass_inf_ret_array() {
+; CHECK-LABEL: define [2 x [3 x float]] @return_nofpclass_inf_ret_array() {
+; CHECK-NEXT:    [[RET:%.*]] = call nofpclass(inf) [2 x [3 x float]] @ret_array()
+; CHECK-NEXT:    ret [2 x [3 x float]] [[RET]]
+;
+  %ret = call nofpclass(inf) [2 x [3 x float]]  @ret_array()
+  ret [2 x [3 x float]] %ret
+}
+
+define float @returned_nnan_fadd(float %arg0, float %arg1) {
+; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define float @returned_nnan_fadd
+; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT:    [[FADD:%.*]] = fadd nnan float [[ARG0]], [[ARG1]]
+; CHECK-NEXT:    ret float [[FADD]]
+;
+  %fadd = fadd nnan float %arg0, %arg1
+  ret float %fadd
+}
+
+define float @return_nofpclass_nan_callsite() {
+; CHECK-LABEL: define float @return_nofpclass_nan_callsite() {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @extern()
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call nofpclass(nan) float @extern()
+  ret float %call
+}
+
+; Can union the return classes
+define nofpclass(inf) float @return_ninf_nofpclass_nan_callsite() {
+; CHECK-LABEL: define nofpclass(inf) float @return_ninf_nofpclass_nan_callsite() {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan) float @extern()
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call nofpclass(nan) float @extern()
+  ret float %call
+}
+
+define void @arg_used_by_nofpclass_nan_callsite(float %arg) {
+; CHECK-LABEL: define void @arg_used_by_nofpclass_nan_callsite
+; CHECK-SAME: (float [[ARG:%.*]]) {
+; CHECK-NEXT:    call void @extern.use(float nofpclass(nan) [[ARG]])
+; CHECK-NEXT:    ret void
+;
+  call void @extern.use(float nofpclass(nan) %arg)
+  ret void
+}
+
+; Callsite can union the incoming and outgoing
+define void @ninf_arg_used_by_nofpclass_nan_callsite(float nofpclass(inf) %arg) {
+; CHECK-LABEL: define void @ninf_arg_used_by_nofpclass_nan_callsite
+; CHECK-SAME: (float nofpclass(inf) [[ARG:%.*]]) {
+; CHECK-NEXT:    call void @extern.use(float nofpclass(nan) [[ARG]])
+; CHECK-NEXT:    ret void
+;
+  call void @extern.use(float nofpclass(nan) %arg)
+  ret void
+}
+
+define void @ninf_arg_used_by_callsite_array([2 x [3 x float]] nofpclass(inf) %arg) {
+; CHECK-LABEL: define void @ninf_arg_used_by_callsite_array
+; CHECK-SAME: ([2 x [3 x float]] nofpclass(inf) [[ARG:%.*]]) {
+; CHECK-NEXT:    call void @extern.use.array([2 x [3 x float]] [[ARG]])
+; CHECK-NEXT:    ret void
+;
+  call void @extern.use.array([2 x [3 x float]]  %arg)
+  ret void
+}
+
+define float @mutually_recursive0(float %arg) {
+; TUNIT: Function Attrs: nofree nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define float @mutually_recursive0
+; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR3:[0-9]+]] {
+; TUNIT-NEXT:    ret float undef
+;
+; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define float @mutually_recursive0
+; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR2]] {
+; CGSCC-NEXT:    ret float undef
+;
+  %call = call float @mutually_recursive1(float %arg)
+  ret float %call
+}
+
+define float @mutually_recursive1(float %arg) {
+; TUNIT: Function Attrs: nofree nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define float @mutually_recursive1
+; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR3]] {
+; TUNIT-NEXT:    ret float undef
+;
+; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define float @mutually_recursive1
+; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR2]] {
+; CGSCC-NEXT:    ret float undef
+;
+  %call = call float @mutually_recursive0(float %arg)
+  ret float %call
+}
+
+define float @recursive_phi(ptr %ptr) {
+; CHECK-LABEL: define float @recursive_phi
+; CHECK-SAME: (ptr nofree [[PTR:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[RET:%.*]] = call float @ret_nofpclass_nan()
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[PHI:%.*]] = phi float [ [[RET]], [[ENTRY:%.*]] ], [ [[RET]], [[LOOP]] ]
+; CHECK-NEXT:    [[COND:%.*]] = load volatile i1, ptr [[PTR]], align 1
+; CHECK-NEXT:    br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret float [[RET]]
+;
+entry:
+  %ret = call float @ret_nofpclass_nan()
+  br label %loop
+
+loop:
+  %phi = phi float [%ret, %entry], [%phi, %loop]
+  %cond = load volatile i1, ptr %ptr
+  br i1 %cond, label %loop, label %exit
+
+exit:
+  ret float %phi
+}
+
+; Should be able to infer nofpclass(nan) return
+define float @fcmp_uno_check(float %arg) local_unnamed_addr {
+; CHECK-LABEL: define float @fcmp_uno_check
+; CHECK-SAME: (float [[ARG:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ISNAN:%.*]] = fcmp uno float [[ARG]], 0.000000e+00
+; CHECK-NEXT:    br i1 [[ISNAN]], label [[BB0:%.*]], label [[BB1:%.*]]
+; CHECK:       bb0:
+; CHECK-NEXT:    [[CALL:%.*]] = call float @ret_nofpclass_nan()
+; CHECK-NEXT:    br label [[BB1]]
+; CHECK:       bb1:
+; CHECK-NEXT:    [[PHI:%.*]] = phi float [ [[CALL]], [[BB0]] ], [ [[ARG]], [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret float [[PHI]]
+;
+entry:
+  %isnan = fcmp uno float %arg, 0.0
+  br i1 %isnan, label %bb0, label %bb1
+
+bb0:
+  %call = call float @ret_nofpclass_nan()
+  br label %bb1
+
+bb1:
+  %phi = phi float [ %call, %bb0 ], [ %arg, %entry ]
+  ret float %phi
+}
+
+; Should be able to infer nofpclass(nan) on %arg use
+define void @fcmp_ord_guard_callsite_arg(float %arg) {
+; CHECK-LABEL: define void @fcmp_ord_guard_callsite_arg
+; CHECK-SAME: (float [[ARG:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IS_NOT_NAN:%.*]] = fcmp ord float [[ARG]], 0.000000e+00
+; CHECK-NEXT:    br i1 [[IS_NOT_NAN]], label [[BB0:%.*]], label [[BB1:%.*]]
+; CHECK:       bb0:
+; CHECK-NEXT:    call void @extern.use(float [[ARG]])
+; CHECK-NEXT:    br label [[BB1]]
+; CHECK:       bb1:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %is.not.nan = fcmp ord float %arg, 0.0
+  br i1 %is.not.nan, label %bb0, label %bb1
+
+bb0:
+  call void @extern.use(float %arg)
+  br label %bb1
+
+bb1:
+  ret void
+}
+
+; Should be able to infer nofpclass on both %arg uses
+define float @fcmp_ord_assume_callsite_arg_return(float %arg) {
+; CHECK-LABEL: define float @fcmp_ord_assume_callsite_arg_return
+; CHECK-SAME: (float returned [[ARG:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IS_NOT_NAN:%.*]] = fcmp ord float [[ARG]], 0.000000e+00
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_NOT_NAN]]) #[[ATTR4:[0-9]+]]
+; CHECK-NEXT:    call void @extern.use(float [[ARG]])
+; CHECK-NEXT:    ret float [[ARG]]
+;
+entry:
+  %is.not.nan = fcmp ord float %arg, 0.0
+  call void @llvm.assume(i1 %is.not.nan)
+  call void @extern.use(float %arg)
+  ret float %arg
+}
+
+define internal float @returned_dead() {
+; CHECK-LABEL: define internal float @returned_dead() {
+; CHECK-NEXT:    call void @unknown()
+; CHECK-NEXT:    ret float undef
+;
+  call void @unknown()
+  ret float 0.0
+}
+
+define void @returned_dead_caller() {
+; CHECK-LABEL: define void @returned_dead_caller() {
+; CHECK-NEXT:    [[TMP1:%.*]] = call float @returned_dead()
+; CHECK-NEXT:    ret void
+;
+  call float @returned_dead()
+  ret void
+}
+
+define internal float @only_nofpclass_inf_callers(float %arg) {
+; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define internal float @only_nofpclass_inf_callers
+; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %arg, %arg
+  ret float %add
+}
+
+define float @call_noinf_0(float nofpclass(inf) %arg) {
+; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define float @call_noinf_0
+; TUNIT-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float [[ARG]]) #[[ATTR5:[0-9]+]]
+; TUNIT-NEXT:    ret float [[RESULT]]
+;
+; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define float @call_noinf_0
+; CGSCC-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR3:[0-9]+]] {
+; CGSCC-NEXT:    [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float [[ARG]]) #[[ATTR4]]
+; CGSCC-NEXT:    ret float [[RESULT]]
+;
+  %result = call float @only_nofpclass_inf_callers(float %arg)
+  ret float %result
+}
+
+define float @call_noinf_1(float %arg) {
+; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define float @call_noinf_1
+; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR5]]
+; TUNIT-NEXT:    ret float [[RESULT]]
+;
+; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define float @call_noinf_1
+; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:    [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR4]]
+; CGSCC-NEXT:    ret float [[RESULT]]
+;
+  %result = call float @only_nofpclass_inf_callers(float nofpclass(inf) %arg)
+  ret float %result
+}
+
+; TODO: Should be able to infer nofpclass(inf) on return
+define internal float @only_nofpclass_inf_return_users(float %arg) {
+; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
+; CHECK-LABEL: define internal float @only_nofpclass_inf_return_users
+; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
+; CHECK-NEXT:    ret float [[ADD]]
+;
+  %add = fadd float %arg, %arg
+  ret float %add
+}
+
+define float @call_noinf_return_0(float %arg) {
+; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define float @call_noinf_return_0
+; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR5]]
+; TUNIT-NEXT:    ret float [[RESULT]]
+;
+; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define float @call_noinf_return_0
+; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:    [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR4]]
+; CGSCC-NEXT:    ret float [[RESULT]]
+;
+  %result = call nofpclass(inf) float @only_nofpclass_inf_return_users(float %arg)
+  ret float %result
+}
+
+define float @call_noinf_return_1(float %arg) {
+; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
+; TUNIT-LABEL: define float @call_noinf_return_1
+; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR2]] {
+; TUNIT-NEXT:    [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR5]]
+; TUNIT-NEXT:    ret float [[RESULT]]
+;
+; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
+; CGSCC-LABEL: define float @call_noinf_return_1
+; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR3]] {
+; CGSCC-NEXT:    [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR4]]
+; CGSCC-NEXT:    ret float [[RESULT]]
+;
+  %result = call nofpclass(inf) float @only_nofpclass_inf_return_users(float %arg)
+  ret float %result
+}
+
+define float @fcmp_olt_assume_one_0_callsite_arg_return(float %arg) {
+; CHECK-LABEL: define float @fcmp_olt_assume_one_0_callsite_arg_return
+; CHECK-SAME: (float returned [[ARG:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IS_NOT_ZERO_OR_NAN:%.*]] = fcmp one float [[ARG]], 0.000000e+00
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR4]]
+; CHECK-NEXT:    call void @extern.use(float [[ARG]])
+; CHECK-NEXT:    ret float [[ARG]]
+;
+entry:
+  %is.not.zero.or.nan = fcmp one float %arg, 0.0
+  call void @llvm.assume(i1 %is.not.zero.or.nan)
+  call void @extern.use(float %arg)
+  ret float %arg
+}
+
+define float @fcmp_olt_assume_une_0_callsite_arg_return(float %arg) {
+; CHECK-LABEL: define float @fcmp_olt_assume_une_0_callsite_arg_return
+; CHECK-SAME: (float returned [[ARG:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IS_NOT_ZERO_OR_NAN:%.*]] = fcmp une float [[ARG]], 0.000000e+00
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_NOT_ZERO_OR_NAN]]) #[[ATTR4]]
+; CHECK-NEXT:    call void @extern.use(float [[ARG]])
+; CHECK-NEXT:    ret float [[ARG]]
+;
+entry:
+  %is.not.zero.or.nan = fcmp une float %arg, 0.0
+  call void @llvm.assume(i1 %is.not.zero.or.nan)
+  call void @extern.use(float %arg)
+  ret float %arg
+}
+
+define half @fcmp_assume_issubnormal_callsite_arg_return(half %arg) {
+; CHECK-LABEL: define half @fcmp_assume_issubnormal_callsite_arg_return
+; CHECK-SAME: (half returned [[ARG:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[ARG]]) #[[ATTR4]]
+; CHECK-NEXT:    [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR4]]
+; CHECK-NEXT:    call void @extern.use.f16(half [[ARG]])
+; CHECK-NEXT:    ret half [[ARG]]
+;
+entry:
+  %fabs = call half @llvm.fabs.f16(half %arg)
+  %is.subnormal = fcmp olt half %fabs, 0xH0400
+  call void @llvm.assume(i1 %is.subnormal)
+  call void @extern.use.f16(half %arg)
+  ret half %arg
+}
+
+; Assume is after the call, shouldn't mark callsite.
+define half @fcmp_assume_not_inf_after_call(half %arg) {
+; CHECK-LABEL: define half @fcmp_assume_not_inf_after_call
+; CHECK-SAME: (half returned [[ARG:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    call void @extern.use.f16(half [[ARG]])
+; CHECK-NEXT:    [[NOT_INF:%.*]] = fcmp oeq half [[ARG]], 0xH7C00
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[NOT_INF]])
+; CHECK-NEXT:    ret half [[ARG]]
+;
+entry:
+  call void @extern.use.f16(half %arg)
+  %not.inf = fcmp oeq half %arg, 0xH7C00
+  call void @llvm.assume(i1 %not.inf)
+  ret half %arg
+}
+
+; Assume not subnormal or zero, and not infinity
+define half @fcmp_assume2_callsite_arg_return(half %arg) {
+; CHECK-LABEL: define half @fcmp_assume2_callsite_arg_return
+; CHECK-SAME: (half returned [[ARG:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[ARG]]) #[[ATTR4]]
+; CHECK-NEXT:    [[NOT_SUBNORMAL_OR_ZERO:%.*]] = fcmp oge half [[FABS]], 0xH0400
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[NOT_SUBNORMAL_OR_ZERO]]) #[[ATTR4]]
+; CHECK-NEXT:    [[NOT_INF:%.*]] = fcmp oeq half [[ARG]], 0xH7C00
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[NOT_INF]]) #[[ATTR4]]
+; CHECK-NEXT:    call void @extern.use.f16(half [[ARG]])
+; CHECK-NEXT:    ret half [[ARG]]
+;
+entry:
+  %fabs = call half @llvm.fabs.f16(half %arg)
+  %not.subnormal.or.zero = fcmp oge half %fabs, 0xH0400
+  call void @llvm.assume(i1 %not.subnormal.or.zero)
+
+  %not.inf = fcmp oeq half %arg, 0xH7C00
+  call void @llvm.assume(i1 %not.inf)
+
+  call void @extern.use.f16(half %arg)
+  ret half %arg
+}
+
+define float @is_fpclass_assume_arg_return(float %arg) {
+; CHECK-LABEL: define float @is_fpclass_assume_arg_return
+; CHECK-SAME: (float returned [[ARG:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CLASS_TEST:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 noundef 292) #[[ATTR4]]
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[CLASS_TEST]]) #[[ATTR4]]
+; CHECK-NEXT:    call void @extern.use(float [[ARG]])
+; CHECK-NEXT:    ret float [[ARG]]
+;
+entry:
+  %class.test = call i1 @llvm.is.fpclass.f32(float %arg, i32 292)
+  call void @llvm.assume(i1 %class.test)
+  call void @extern.use(float %arg)
+  ret float %arg
+}
+
+; Make sure we don't get confused by looking at an unrelated assume
+; based on the fabs of the value.
+define half @assume_fcmp_fabs_with_other_fabs_assume(half %arg) {
+; CHECK-LABEL: define half @assume_fcmp_fabs_with_other_fabs_assume
+; CHECK-SAME: (half returned [[ARG:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[ARG]]) #[[ATTR4]]
+; CHECK-NEXT:    [[UNRELATED_FABS:%.*]] = fcmp one half [[FABS]], 0xH0000
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[UNRELATED_FABS]]) #[[ATTR4]]
+; CHECK-NEXT:    [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR4]]
+; CHECK-NEXT:    call void @extern.use.f16(half [[ARG]])
+; CHECK-NEXT:    call void @extern.use.f16(half [[FABS]])
+; CHECK-NEXT:    ret half [[ARG]]
+;
+entry:
+
+  %fabs = call half @llvm.fabs.f16(half %arg)
+  %unrelated.fabs = fcmp one half %fabs, 0.0
+  call void @llvm.assume(i1 %unrelated.fabs)
+  %is.subnormal = fcmp olt half %fabs, 0xH0400
+  call void @llvm.assume(i1 %is.subnormal)
+  call void @extern.use.f16(half %arg)
+  call void @extern.use.f16(half %fabs)
+  ret half %arg
+}
+
+; Make sure if looking through the fabs finds a 
diff erent source
+; value, we still identify a test mask by ignoring the fabs
+define half @assume_fcmp_fabs_with_other_fabs_assume_fallback(half %arg) {
+; CHECK-LABEL: define half @assume_fcmp_fabs_with_other_fabs_assume_fallback
+; CHECK-SAME: (half returned [[ARG:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[FABS:%.*]] = call half @llvm.fabs.f16(half [[ARG]]) #[[ATTR4]]
+; CHECK-NEXT:    [[ONE_INF:%.*]] = fcmp oeq half [[ARG]], 0xH7C00
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[ONE_INF]]) #[[ATTR4]]
+; CHECK-NEXT:    [[UNRELATED_FABS:%.*]] = fcmp oeq half [[FABS]], 0xH0000
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[UNRELATED_FABS]]) #[[ATTR4]]
+; CHECK-NEXT:    [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef [[IS_SUBNORMAL]]) #[[ATTR4]]
+; CHECK-NEXT:    call void @extern.use.f16(half [[ARG]])
+; CHECK-NEXT:    call void @extern.use.f16(half [[FABS]])
+; CHECK-NEXT:    ret half [[ARG]]
+;
+entry:
+
+  %fabs = call half @llvm.fabs.f16(half %arg)
+
+  %one.inf = fcmp oeq half %arg, 0xH7C00
+  call void @llvm.assume(i1 %one.inf)
+
+  %unrelated.fabs = fcmp oeq half %fabs, 0.0
+  call void @llvm.assume(i1 %unrelated.fabs)
+
+  %is.subnormal = fcmp olt half %fabs, 0xH0400
+  call void @llvm.assume(i1 %is.subnormal)
+  call void @extern.use.f16(half %arg)
+  call void @extern.use.f16(half %fabs)
+  ret half %arg
+}
+
+define float @assume_bundles(i1 %c, float %ret) {
+; CHECK-LABEL: define float @assume_bundles
+; CHECK-SAME: (i1 noundef [[C:%.*]], float returned [[RET:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
+; CHECK:       A:
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) #[[ATTR4]] [ "nofpclass"(float [[RET]], i32 3) ]
+; CHECK-NEXT:    call void @extern.use(float [[RET]])
+; CHECK-NEXT:    ret float [[RET]]
+; CHECK:       B:
+; CHECK-NEXT:    call void @llvm.assume(i1 noundef true) [ "nofpclass"(float [[RET]], i32 12) ]
+; CHECK-NEXT:    call void @extern.use(float [[RET]])
+; CHECK-NEXT:    ret float [[RET]]
+;
+entry:
+  br i1 %c, label %A, label %B
+
+A:
+  call void @llvm.assume(i1 true) [ "nofpclass"(float %ret, i32 3) ]
+  call void @extern.use(float %ret)
+  ret float %ret
+
+B:
+  call void @llvm.assume(i1 true) [ "nofpclass"(float %ret, i32 12) ]
+  call void @extern.use(float %ret)
+  ret float %ret
+}


        


More information about the llvm-commits mailing list