| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| // RUN: %clang_cc1 -triple aarch64_be-apple-darwin -emit-llvm -o - -O1 %s | \ | ||
| // RUN: FileCheck -check-prefixes=CHECK,CHECK-BE %s | ||
| // RUN: %clang_cc1 -triple aarch64-apple-darwin -emit-llvm -o - -O1 %s | \ | ||
| // RUN: FileCheck -check-prefixes=CHECK,CHECK-LE %s | ||
| // | ||
| // Check that TBAA metadata for structs containing bitfields is | ||
| // consistent between big and little endian layouts. | ||
| // | ||
| // FIXME: The metadata below is invalid for the big endian layout: the | ||
| // start offset of 2 is incorrect. | ||
|
|
||
| struct NamedBitfields { | ||
| int f1 : 8; | ||
| int f2 : 8; | ||
| unsigned f3 : 1; | ||
| unsigned f4 : 15; | ||
| int f5; | ||
| double f6; | ||
| }; | ||
|
|
||
| // CHECK-LABEL: _Z4copyP14NamedBitfieldsS0_ | ||
| // CHECK-SAME: ptr nocapture noundef writeonly [[A1:%.*]], ptr nocapture noundef readonly [[A2:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { | ||
| // CHECK-NEXT: entry: | ||
| // CHECK-NEXT: tail call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(16) [[A1]], ptr noundef nonnull align 8 dereferenceable(16) [[A2]], i64 16, i1 false), !tbaa.struct [[TBAA_STRUCT2:![0-9]+]] | ||
| // CHECK-NEXT: ret void | ||
| // | ||
| void copy(NamedBitfields *a1, NamedBitfields *a2) { | ||
| *a1 = *a2; | ||
| } | ||
|
|
||
| // CHECK-BE: [[TBAA_STRUCT2]] = !{i64 2, i64 4, [[META3:![0-9]+]], i64 4, i64 4, [[META6:![0-9]+]], i64 8, i64 8, [[META8:![0-9]+]]} | ||
| // CHECK-LE: [[TBAA_STRUCT2]] = !{i64 0, i64 4, [[META3:![0-9]+]], i64 4, i64 4, [[META6:![0-9]+]], i64 8, i64 8, [[META8:![0-9]+]]} | ||
| // CHECK: [[META3]] = !{[[META4:![0-9]+]], [[META4]], i64 0} | ||
| // CHECK: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0} | ||
| // CHECK: [[META5]] = !{!"Simple C++ TBAA"} | ||
| // CHECK: [[META6]] = !{[[META7:![0-9]+]], [[META7]], i64 0} | ||
| // CHECK: [[META7]] = !{!"int", [[META4]], i64 0} | ||
| // CHECK: [[META8]] = !{[[META9:![0-9]+]], [[META9]], i64 0} | ||
| // CHECK: [[META9]] = !{!"double", [[META4]], i64 0} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| // REQUIRES: host-supports-jit, x86_64-linux | ||
| // UNSUPPORTED: system-aix | ||
| // | ||
| // RUN: rm -rf %t | ||
| // RUN: mkdir -p %t | ||
| // RUN: split-file %s %t | ||
| // | ||
| // RUN: cat %t/inline-asm.txt | clang-repl -Xcc="-I%t" | ||
|
|
||
| //--- inline-asm.cpp | ||
| __asm(".globl _ZSt21ios_base_library_initv"); | ||
| int x; | ||
|
|
||
| //--- inline-asm.txt | ||
| #include "inline-asm.cpp" | ||
| x = 10; | ||
| %quit |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| ! NOTE: Assertions have been autogenerated by utils/generate-test-checks.py | ||
|
|
||
| ! The script is designed to make adding checks to | ||
| ! a test case fast, it is *not* designed to be authoritative | ||
| ! about what constitutes a good test! The CHECK should be | ||
| ! minimized and named to reflect the test intent. | ||
|
|
||
| ! RUN: bbc -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s | ||
| ! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s | ||
|
|
||
|
|
||
|
|
||
| ! CHECK-LABEL: omp.declare_reduction @add_reduction_byref_box_Uxi32 : !fir.ref<!fir.box<!fir.array<?xi32>>> init { | ||
| ! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<?xi32>>>): | ||
| ! CHECK: %[[VAL_1:.*]] = arith.constant 0 : i32 | ||
| ! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<?xi32>>> | ||
| ! CHECK: %[[VAL_3:.*]] = arith.constant 0 : index | ||
| ! CHECK: %[[VAL_4:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_3]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index) | ||
| ! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]]#1 : (index) -> !fir.shape<1> | ||
| ! CHECK: %[[VAL_6:.*]] = fir.alloca !fir.array<?xi32>, %[[VAL_4]]#1 {bindc_name = ".tmp"} | ||
| ! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.ref<!fir.array<?xi32>>) | ||
| ! CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_7]]#0 : i32, !fir.box<!fir.array<?xi32>> | ||
| ! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.box<!fir.array<?xi32>> | ||
| ! CHECK: fir.store %[[VAL_7]]#0 to %[[VAL_8]] : !fir.ref<!fir.box<!fir.array<?xi32>>> | ||
| ! CHECK: omp.yield(%[[VAL_8]] : !fir.ref<!fir.box<!fir.array<?xi32>>>) | ||
|
|
||
| ! CHECK-LABEL: } combiner { | ||
| ! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<?xi32>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.array<?xi32>>>): | ||
| ! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<?xi32>>> | ||
| ! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.array<?xi32>>> | ||
| ! CHECK: %[[VAL_4:.*]] = arith.constant 0 : index | ||
| ! CHECK: %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_4]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index) | ||
| ! CHECK: %[[VAL_6:.*]] = fir.shape_shift %[[VAL_5]]#0, %[[VAL_5]]#1 : (index, index) -> !fir.shapeshift<1> | ||
| ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : index | ||
| ! CHECK: fir.do_loop %[[VAL_8:.*]] = %[[VAL_7]] to %[[VAL_5]]#1 step %[[VAL_7]] unordered { | ||
| ! CHECK: %[[VAL_9:.*]] = fir.array_coor %[[VAL_2]](%[[VAL_6]]) %[[VAL_8]] : (!fir.box<!fir.array<?xi32>>, !fir.shapeshift<1>, index) -> !fir.ref<i32> | ||
| ! CHECK: %[[VAL_10:.*]] = fir.array_coor %[[VAL_3]](%[[VAL_6]]) %[[VAL_8]] : (!fir.box<!fir.array<?xi32>>, !fir.shapeshift<1>, index) -> !fir.ref<i32> | ||
| ! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_9]] : !fir.ref<i32> | ||
| ! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_10]] : !fir.ref<i32> | ||
| ! CHECK: %[[VAL_13:.*]] = arith.addi %[[VAL_11]], %[[VAL_12]] : i32 | ||
| ! CHECK: fir.store %[[VAL_13]] to %[[VAL_9]] : !fir.ref<i32> | ||
| ! CHECK: } | ||
| ! CHECK: omp.yield(%[[VAL_0]] : !fir.ref<!fir.box<!fir.array<?xi32>>>) | ||
| ! CHECK: } | ||
|
|
||
| ! CHECK-LABEL: func.func @_QPs( | ||
| ! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<i32> {fir.bindc_name = "x"}) { | ||
| ! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFsEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) | ||
| ! CHECK: %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsEi"} | ||
| ! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFsEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) | ||
| ! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<i32> | ||
| ! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i32) -> i64 | ||
| ! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i64) -> index | ||
| ! CHECK: %[[VAL_7:.*]] = arith.constant 0 : index | ||
| ! CHECK: %[[VAL_8:.*]] = arith.cmpi sgt, %[[VAL_6]], %[[VAL_7]] : index | ||
| ! CHECK: %[[VAL_9:.*]] = arith.select %[[VAL_8]], %[[VAL_6]], %[[VAL_7]] : index | ||
| ! CHECK: %[[VAL_10:.*]] = fir.alloca !fir.array<?xi32>, %[[VAL_9]] {bindc_name = "c", uniq_name = "_QFsEc"} | ||
| ! CHECK: %[[VAL_11:.*]] = fir.shape %[[VAL_9]] : (index) -> !fir.shape<1> | ||
| ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]](%[[VAL_11]]) {uniq_name = "_QFsEc"} : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.ref<!fir.array<?xi32>>) | ||
| ! CHECK: %[[VAL_13:.*]] = arith.constant 0 : i32 | ||
| ! CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_12]]#0 : i32, !fir.box<!fir.array<?xi32>> | ||
| ! CHECK: omp.parallel { | ||
| ! CHECK: %[[VAL_14:.*]] = fir.alloca i32 {adapt.valuebyref, pinned} | ||
| ! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] {uniq_name = "_QFsEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) | ||
| ! CHECK: %[[VAL_16:.*]] = arith.constant 1 : i32 | ||
| ! CHECK: %[[VAL_17:.*]] = arith.constant 100 : i32 | ||
| ! CHECK: %[[VAL_18:.*]] = arith.constant 1 : i32 | ||
| ! CHECK: %[[VAL_19:.*]] = fir.alloca !fir.box<!fir.array<?xi32>> | ||
| ! CHECK: fir.store %[[VAL_12]]#0 to %[[VAL_19]] : !fir.ref<!fir.box<!fir.array<?xi32>>> | ||
| ! CHECK: omp.wsloop byref reduction(@add_reduction_byref_box_Uxi32 %[[VAL_19]] -> %[[VAL_20:.*]] : !fir.ref<!fir.box<!fir.array<?xi32>>>) for (%[[VAL_21:.*]]) : i32 = (%[[VAL_16]]) to (%[[VAL_17]]) inclusive step (%[[VAL_18]]) { | ||
| ! CHECK: fir.store %[[VAL_21]] to %[[VAL_15]]#1 : !fir.ref<i32> | ||
| ! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_20]] {uniq_name = "_QFsEc"} : (!fir.ref<!fir.box<!fir.array<?xi32>>>) -> (!fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.ref<!fir.box<!fir.array<?xi32>>>) | ||
| ! CHECK: %[[VAL_23:.*]] = fir.load %[[VAL_22]]#0 : !fir.ref<!fir.box<!fir.array<?xi32>>> | ||
| ! CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_15]]#0 : !fir.ref<i32> | ||
| ! CHECK: %[[VAL_25:.*]] = arith.constant 0 : index | ||
| ! CHECK: %[[VAL_26:.*]]:3 = fir.box_dims %[[VAL_23]], %[[VAL_25]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index) | ||
| ! CHECK: %[[VAL_27:.*]] = fir.shape %[[VAL_26]]#1 : (index) -> !fir.shape<1> | ||
| ! CHECK: %[[VAL_28:.*]] = hlfir.elemental %[[VAL_27]] unordered : (!fir.shape<1>) -> !hlfir.expr<?xi32> { | ||
| ! CHECK: ^bb0(%[[VAL_29:.*]]: index): | ||
| ! CHECK: %[[VAL_30:.*]] = arith.constant 0 : index | ||
| ! CHECK: %[[VAL_31:.*]]:3 = fir.box_dims %[[VAL_23]], %[[VAL_30]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index) | ||
| ! CHECK: %[[VAL_32:.*]] = arith.constant 1 : index | ||
| ! CHECK: %[[VAL_33:.*]] = arith.subi %[[VAL_31]]#0, %[[VAL_32]] : index | ||
| ! CHECK: %[[VAL_34:.*]] = arith.addi %[[VAL_29]], %[[VAL_33]] : index | ||
| ! CHECK: %[[VAL_35:.*]] = hlfir.designate %[[VAL_23]] (%[[VAL_34]]) : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32> | ||
| ! CHECK: %[[VAL_36:.*]] = fir.load %[[VAL_35]] : !fir.ref<i32> | ||
| ! CHECK: %[[VAL_37:.*]] = arith.addi %[[VAL_36]], %[[VAL_24]] : i32 | ||
| ! CHECK: hlfir.yield_element %[[VAL_37]] : i32 | ||
| ! CHECK: } | ||
| ! CHECK: %[[VAL_38:.*]] = fir.load %[[VAL_22]]#0 : !fir.ref<!fir.box<!fir.array<?xi32>>> | ||
| ! CHECK: hlfir.assign %[[VAL_28]] to %[[VAL_38]] : !hlfir.expr<?xi32>, !fir.box<!fir.array<?xi32>> | ||
| ! CHECK: hlfir.destroy %[[VAL_28]] : !hlfir.expr<?xi32> | ||
| ! CHECK: omp.yield | ||
| ! CHECK: } | ||
| ! CHECK: omp.terminator | ||
| ! CHECK: } | ||
| ! CHECK: %[[VAL_39:.*]] = arith.constant 1 : index | ||
| ! CHECK: %[[VAL_40:.*]] = hlfir.designate %[[VAL_12]]#0 (%[[VAL_39]]) : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32> | ||
| ! CHECK: %[[VAL_41:.*]] = fir.load %[[VAL_40]] : !fir.ref<i32> | ||
| ! CHECK: %[[VAL_42:.*]] = arith.constant 5050 : i32 | ||
| ! CHECK: %[[VAL_43:.*]] = arith.cmpi ne, %[[VAL_41]], %[[VAL_42]] : i32 | ||
| ! CHECK: cf.cond_br %[[VAL_43]], ^bb1, ^bb2 | ||
| ! CHECK: ^bb1: | ||
| ! CHECK: %[[VAL_44:.*]] = arith.constant 1 : i32 | ||
| ! CHECK: %[[VAL_45:.*]] = arith.constant false | ||
| ! CHECK: %[[VAL_46:.*]] = arith.constant false | ||
| ! CHECK: %[[VAL_47:.*]] = fir.call @_FortranAStopStatement(%[[VAL_44]], %[[VAL_45]], %[[VAL_46]]) fastmath<contract> : (i32, i1, i1) -> none | ||
| ! CHECK: fir.unreachable | ||
| ! CHECK: ^bb2: | ||
| ! CHECK: return | ||
| ! CHECK: } | ||
| ! CHECK: func.func private @_FortranAStopStatement(i32, i1, i1) -> none attributes {fir.runtime} | ||
|
|
||
| subroutine s(x) | ||
| integer :: x | ||
| integer :: c(x) | ||
| c = 0 | ||
| !$omp parallel do reduction(+:c) | ||
| do i = 1, 100 | ||
| c = c + i | ||
| end do | ||
| !$omp end parallel do | ||
|
|
||
| if (c(1) /= 5050) stop 1 | ||
| end subroutine s |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| ! RUN: bbc -emit-hlfir -fopenmp -o - %s | FileCheck %s | ||
| ! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s | FileCheck %s | ||
|
|
||
| program reduce_assumed_shape | ||
| real(8), dimension(2) :: r | ||
| r = 0 | ||
| call reduce(r) | ||
| print *, r | ||
|
|
||
| contains | ||
| subroutine reduce(r) | ||
| implicit none | ||
| real(8),intent(inout) :: r(:) | ||
| integer :: i = 0 | ||
|
|
||
| !$omp parallel do reduction(+:r) | ||
| do i=0,10 | ||
| r(1) = i | ||
| r(2) = 1 | ||
| enddo | ||
| !$omp end parallel do | ||
| end subroutine | ||
| end program | ||
|
|
||
| ! CHECK-LABEL: omp.declare_reduction @add_reduction_byref_box_Uxf64 : !fir.ref<!fir.box<!fir.array<?xf64>>> init { | ||
| ! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<?xf64>>>): | ||
| ! CHECK: %[[VAL_1:.*]] = arith.constant 0.000000e+00 : f64 | ||
| ! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<?xf64>>> | ||
| ! CHECK: %[[VAL_3:.*]] = arith.constant 0 : index | ||
| ! CHECK: %[[VAL_4:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_3]] : (!fir.box<!fir.array<?xf64>>, index) -> (index, index, index) | ||
| ! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]]#1 : (index) -> !fir.shape<1> | ||
| ! CHECK: %[[VAL_6:.*]] = fir.alloca !fir.array<?xf64>, %[[VAL_4]]#1 {bindc_name = ".tmp"} | ||
| ! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_5]]) {uniq_name = ".tmp"} : (!fir.ref<!fir.array<?xf64>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xf64>>, !fir.ref<!fir.array<?xf64>>) | ||
| ! CHECK: hlfir.assign %[[VAL_1]] to %[[VAL_7]]#0 : f64, !fir.box<!fir.array<?xf64>> | ||
| ! CHECK: %[[VAL_8:.*]] = fir.alloca !fir.box<!fir.array<?xf64>> | ||
| ! CHECK: fir.store %[[VAL_7]]#0 to %[[VAL_8]] : !fir.ref<!fir.box<!fir.array<?xf64>>> | ||
| ! CHECK: omp.yield(%[[VAL_8]] : !fir.ref<!fir.box<!fir.array<?xf64>>>) | ||
|
|
||
| ! CHECK-LABEL: } combiner { | ||
| ! CHECK: ^bb0(%[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.array<?xf64>>>, %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.array<?xf64>>>): | ||
| ! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.box<!fir.array<?xf64>>> | ||
| ! CHECK: %[[VAL_3:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.array<?xf64>>> | ||
| ! CHECK: %[[VAL_4:.*]] = arith.constant 0 : index | ||
| ! CHECK: %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_4]] : (!fir.box<!fir.array<?xf64>>, index) -> (index, index, index) | ||
| ! CHECK: %[[VAL_6:.*]] = fir.shape_shift %[[VAL_5]]#0, %[[VAL_5]]#1 : (index, index) -> !fir.shapeshift<1> | ||
| ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : index | ||
| ! CHECK: fir.do_loop %[[VAL_8:.*]] = %[[VAL_7]] to %[[VAL_5]]#1 step %[[VAL_7]] unordered { | ||
| ! CHECK: %[[VAL_9:.*]] = fir.array_coor %[[VAL_2]](%[[VAL_6]]) %[[VAL_8]] : (!fir.box<!fir.array<?xf64>>, !fir.shapeshift<1>, index) -> !fir.ref<f64> | ||
| ! CHECK: %[[VAL_10:.*]] = fir.array_coor %[[VAL_3]](%[[VAL_6]]) %[[VAL_8]] : (!fir.box<!fir.array<?xf64>>, !fir.shapeshift<1>, index) -> !fir.ref<f64> | ||
| ! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_9]] : !fir.ref<f64> | ||
| ! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_10]] : !fir.ref<f64> | ||
| ! CHECK: %[[VAL_13:.*]] = arith.addf %[[VAL_11]], %[[VAL_12]] fastmath<contract> : f64 | ||
| ! CHECK: fir.store %[[VAL_13]] to %[[VAL_9]] : !fir.ref<f64> | ||
| ! CHECK: } | ||
| ! CHECK: omp.yield(%[[VAL_0]] : !fir.ref<!fir.box<!fir.array<?xf64>>>) | ||
| ! CHECK: } | ||
|
|
||
| ! CHECK-LABEL: func.func private @_QFPreduce( | ||
| ! CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?xf64>> {fir.bindc_name = "r"}) attributes {{.*}} { | ||
| ! CHECK: %[[VAL_1:.*]] = fir.address_of(@_QFFreduceEi) : !fir.ref<i32> | ||
| ! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFFreduceEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) | ||
| ! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] {fortran_attrs = {{.*}}, uniq_name = "_QFFreduceEr"} : (!fir.box<!fir.array<?xf64>>) -> (!fir.box<!fir.array<?xf64>>, !fir.box<!fir.array<?xf64>>) | ||
| ! CHECK: omp.parallel { | ||
| ! CHECK: %[[VAL_4:.*]] = fir.alloca i32 {adapt.valuebyref, pinned} | ||
| ! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = "_QFFreduceEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) | ||
| ! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 | ||
| ! CHECK: %[[VAL_7:.*]] = arith.constant 10 : i32 | ||
| ! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i32 | ||
| ! CHECK: %[[VAL_9:.*]] = fir.alloca !fir.box<!fir.array<?xf64>> | ||
| ! CHECK: fir.store %[[VAL_3]]#1 to %[[VAL_9]] : !fir.ref<!fir.box<!fir.array<?xf64>>> | ||
| ! CHECK: omp.wsloop byref reduction(@add_reduction_byref_box_Uxf64 %[[VAL_9]] -> %[[VAL_10:.*]] : !fir.ref<!fir.box<!fir.array<?xf64>>>) for (%[[VAL_11:.*]]) : i32 = (%[[VAL_6]]) to (%[[VAL_7]]) inclusive step (%[[VAL_8]]) { | ||
| ! CHECK: fir.store %[[VAL_11]] to %[[VAL_5]]#1 : !fir.ref<i32> | ||
| ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {fortran_attrs = {{.*}}, uniq_name = "_QFFreduceEr"} : (!fir.ref<!fir.box<!fir.array<?xf64>>>) -> (!fir.ref<!fir.box<!fir.array<?xf64>>>, !fir.ref<!fir.box<!fir.array<?xf64>>>) | ||
| ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32> | ||
| ! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (i32) -> f64 | ||
| ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref<!fir.box<!fir.array<?xf64>>> | ||
| ! CHECK: %[[VAL_16:.*]] = arith.constant 1 : index | ||
| ! CHECK: %[[VAL_17:.*]] = hlfir.designate %[[VAL_15]] (%[[VAL_16]]) : (!fir.box<!fir.array<?xf64>>, index) -> !fir.ref<f64> | ||
| ! CHECK: hlfir.assign %[[VAL_14]] to %[[VAL_17]] : f64, !fir.ref<f64> | ||
| ! CHECK: %[[VAL_18:.*]] = arith.constant 1.000000e+00 : f64 | ||
| ! CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref<!fir.box<!fir.array<?xf64>>> | ||
| ! CHECK: %[[VAL_20:.*]] = arith.constant 2 : index | ||
| ! CHECK: %[[VAL_21:.*]] = hlfir.designate %[[VAL_19]] (%[[VAL_20]]) : (!fir.box<!fir.array<?xf64>>, index) -> !fir.ref<f64> | ||
| ! CHECK: hlfir.assign %[[VAL_18]] to %[[VAL_21]] : f64, !fir.ref<f64> | ||
| ! CHECK: omp.yield | ||
| ! CHECK: } | ||
| ! CHECK: omp.terminator | ||
| ! CHECK: } | ||
| ! CHECK: return | ||
| ! CHECK: } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| add_libc_fuzzer( | ||
| uint_fuzz | ||
| SRCS | ||
| uint_fuzz.cpp | ||
| DEPENDS | ||
| libc.src.__support.uint | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| #include "src/__support/CPP/bit.h" | ||
| #include "src/__support/UInt.h" | ||
| #include "src/string/memory_utils/inline_memcpy.h" | ||
|
|
||
| using namespace LIBC_NAMESPACE; | ||
|
|
||
| // Helper function when using gdb / lldb to set a breakpoint and inspect values. | ||
| template <typename T> void debug_and_trap(const char *msg, T a, T b) { | ||
| __builtin_trap(); | ||
| } | ||
|
|
||
| #define DEBUG_AND_TRAP() | ||
|
|
||
| #define TEST_BINOP(OP) \ | ||
| if ((a OP b) != (static_cast<T>(BigInt(a) OP BigInt(b)))) \ | ||
| debug_and_trap(#OP, a, b); | ||
|
|
||
| #define TEST_SHIFTOP(OP) \ | ||
| if ((a OP b) != (static_cast<T>(BigInt(a) OP b))) \ | ||
| debug_and_trap(#OP, a, b); | ||
|
|
||
| #define TEST_FUNCTION(FUN) \ | ||
| if (FUN(a) != FUN(BigInt(a))) \ | ||
| debug_and_trap(#FUN, a, b); | ||
|
|
||
| // Test that basic arithmetic operations of BigInt behave like their scalar | ||
| // counterparts. | ||
| template <typename T, typename BigInt> void run_tests(T a, T b) { | ||
| TEST_BINOP(+) | ||
| TEST_BINOP(-) | ||
| TEST_BINOP(*) | ||
| if (b != 0) | ||
| TEST_BINOP(/) | ||
| if (b >= 0 && b < cpp::numeric_limits<T>::digits) { | ||
| TEST_SHIFTOP(<<) | ||
| TEST_SHIFTOP(>>) | ||
| } | ||
| if constexpr (!BigInt::SIGNED) { | ||
| TEST_FUNCTION(cpp::has_single_bit) | ||
| TEST_FUNCTION(cpp::countr_zero) | ||
| TEST_FUNCTION(cpp::countl_zero) | ||
| TEST_FUNCTION(cpp::countl_one) | ||
| TEST_FUNCTION(cpp::countr_one) | ||
| } | ||
| } | ||
|
|
||
| // Reads a T from libfuzzer data. | ||
| template <typename T> T read(const uint8_t *data, size_t &remainder) { | ||
| T out = 0; | ||
| constexpr size_t T_SIZE = sizeof(T); | ||
| const size_t copy_size = remainder < T_SIZE ? remainder : T_SIZE; | ||
| inline_memcpy(&out, data, copy_size); | ||
| remainder -= copy_size; | ||
| return out; | ||
| } | ||
|
|
||
| template <typename T, typename BigInt> | ||
| void run_tests(const uint8_t *data, size_t size) { | ||
| const auto a = read<T>(data, size); | ||
| const auto b = read<T>(data, size); | ||
| run_tests<T, BigInt>(a, b); | ||
| } | ||
|
|
||
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { | ||
| // unsigned | ||
| run_tests<uint64_t, BigInt<64, false, uint16_t>>(data, size); | ||
| // signed | ||
| run_tests<int64_t, BigInt<64, true, uint16_t>>(data, size); | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| //===-- Implementation header for exp2m1f -----------------------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIBC_SRC_MATH_EXP2M1F_H | ||
| #define LLVM_LIBC_SRC_MATH_EXP2M1F_H | ||
|
|
||
| namespace LIBC_NAMESPACE { | ||
|
|
||
| float exp2m1f(float x); | ||
|
|
||
| } // namespace LIBC_NAMESPACE | ||
|
|
||
| #endif // LLVM_LIBC_SRC_MATH_EXP2M1F_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| //===-- Implementation of exp2m1f function --------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/math/exp2m1f.h" | ||
| #include "src/__support/FPUtil/FEnvImpl.h" | ||
| #include "src/__support/FPUtil/FPBits.h" | ||
| #include "src/__support/FPUtil/PolyEval.h" | ||
| #include "src/__support/FPUtil/except_value_utils.h" | ||
| #include "src/__support/FPUtil/multiply_add.h" | ||
| #include "src/__support/FPUtil/rounding_mode.h" | ||
| #include "src/__support/common.h" | ||
| #include "src/__support/macros/optimization.h" | ||
| #include "src/__support/macros/properties/cpu_features.h" | ||
| #include "src/errno/libc_errno.h" | ||
|
|
||
| #include "explogxf.h" | ||
|
|
||
| namespace LIBC_NAMESPACE { | ||
|
|
||
| static constexpr size_t N_EXCEPTS_LO = 8; | ||
|
|
||
| static constexpr fputil::ExceptValues<float, N_EXCEPTS_LO> EXP2M1F_EXCEPTS_LO = | ||
| {{ | ||
| // (input, RZ output, RU offset, RD offset, RN offset) | ||
| // x = 0x1.36dc8ep-36, exp2m1f(x) = 0x1.aef212p-37 (RZ) | ||
| {0x2d9b'6e47U, 0x2d57'7909U, 1U, 0U, 0U}, | ||
| // x = 0x1.224936p-19, exp2m1f(x) = 0x1.926c0ep-20 (RZ) | ||
| {0x3611'249bU, 0x35c9'3607U, 1U, 0U, 1U}, | ||
| // x = 0x1.d16d2p-20, exp2m1f(x) = 0x1.429becp-20 (RZ) | ||
| {0x35e8'b690U, 0x35a1'4df6U, 1U, 0U, 1U}, | ||
| // x = 0x1.17949ep-14, exp2m1f(x) = 0x1.8397p-15 (RZ) | ||
| {0x388b'ca4fU, 0x3841'cb80U, 1U, 0U, 1U}, | ||
| // x = -0x1.9c3e1ep-38, exp2m1f(x) = -0x1.1dbeacp-38 (RZ) | ||
| {0xacce'1f0fU, 0xac8e'df56U, 0U, 1U, 0U}, | ||
| // x = -0x1.4d89b4p-32, exp2m1f(x) = -0x1.ce61b6p-33 (RZ) | ||
| {0xafa6'c4daU, 0xaf67'30dbU, 0U, 1U, 1U}, | ||
| // x = -0x1.a6eac4p-10, exp2m1f(x) = -0x1.24fadap-10 (RZ) | ||
| {0xbad3'7562U, 0xba92'7d6dU, 0U, 1U, 1U}, | ||
| // x = -0x1.e7526ep-6, exp2m1f(x) = -0x1.4e53dep-6 (RZ) | ||
| {0xbcf3'a937U, 0xbca7'29efU, 0U, 1U, 1U}, | ||
| }}; | ||
|
|
||
| static constexpr size_t N_EXCEPTS_HI = 3; | ||
|
|
||
| static constexpr fputil::ExceptValues<float, N_EXCEPTS_HI> EXP2M1F_EXCEPTS_HI = | ||
| {{ | ||
| // (input, RZ output, RU offset, RD offset, RN offset) | ||
| // x = 0x1.16a972p-1, exp2m1f(x) = 0x1.d545b2p-2 (RZ) | ||
| {0x3f0b'54b9U, 0x3eea'a2d9U, 1U, 0U, 0U}, | ||
| // x = -0x1.9f12acp-5, exp2m1f(x) = -0x1.1ab68cp-5 (RZ) | ||
| {0xbd4f'8956U, 0xbd0d'5b46U, 0U, 1U, 0U}, | ||
| // x = -0x1.de7b9cp-5, exp2m1f(x) = -0x1.4508f4p-5 (RZ) | ||
| {0xbd6f'3dceU, 0xbd22'847aU, 0U, 1U, 1U}, | ||
| }}; | ||
|
|
||
| LLVM_LIBC_FUNCTION(float, exp2m1f, (float x)) { | ||
| using FPBits = fputil::FPBits<float>; | ||
| FPBits xbits(x); | ||
|
|
||
| uint32_t x_u = xbits.uintval(); | ||
| uint32_t x_abs = x_u & 0x7fff'ffffU; | ||
|
|
||
| // When |x| >= 128, or x is nan, or |x| <= 2^-5 | ||
| if (LIBC_UNLIKELY(x_abs >= 0x4300'0000U || x_abs <= 0x3d00'0000U)) { | ||
| // |x| <= 2^-5 | ||
| if (x_abs <= 0x3d00'0000U) { | ||
| if (auto r = EXP2M1F_EXCEPTS_LO.lookup(x_u); LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
|
|
||
| // Minimax polynomial generated by Sollya with: | ||
| // > display = hexadecimal; | ||
| // > fpminimax((2^x - 1)/x, 5, [|D...|], [-2^-5, 2^-5]); | ||
| constexpr double COEFFS[] = { | ||
| 0x1.62e42fefa39f3p-1, 0x1.ebfbdff82c57bp-3, 0x1.c6b08d6f2d7aap-5, | ||
| 0x1.3b2ab6fc92f5dp-7, 0x1.5d897cfe27125p-10, 0x1.43090e61e6af1p-13}; | ||
| double xd = x; | ||
| double xsq = xd * xd; | ||
| double c0 = fputil::multiply_add(xd, COEFFS[1], COEFFS[0]); | ||
| double c1 = fputil::multiply_add(xd, COEFFS[3], COEFFS[2]); | ||
| double c2 = fputil::multiply_add(xd, COEFFS[5], COEFFS[4]); | ||
| double p = fputil::polyeval(xsq, c0, c1, c2); | ||
| return static_cast<float>(p * xd); | ||
| } | ||
|
|
||
| // x >= 128, or x is nan | ||
| if (xbits.is_pos()) { | ||
| if (xbits.is_finite()) { | ||
| int rounding = fputil::quick_get_round(); | ||
| if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO) | ||
| return FPBits::max_normal().get_val(); | ||
|
|
||
| fputil::set_errno_if_required(ERANGE); | ||
| fputil::raise_except_if_required(FE_OVERFLOW); | ||
| } | ||
|
|
||
| // x >= 128 and 2^x - 1 rounds to +inf, or x is +inf or nan | ||
| return x + FPBits::inf().get_val(); | ||
| } | ||
| } | ||
|
|
||
| if (LIBC_UNLIKELY(x <= -25.0f)) { | ||
| // 2^(-inf) - 1 = -1 | ||
| if (xbits.is_inf()) | ||
| return -1.0f; | ||
| // 2^nan - 1 = nan | ||
| if (xbits.is_nan()) | ||
| return x; | ||
|
|
||
| int rounding = fputil::quick_get_round(); | ||
| if (rounding == FE_UPWARD || rounding == FE_TOWARDZERO) | ||
| return -0x1.ffff'fep-1f; // -1.0f + 0x1.0p-24f | ||
| fputil::set_errno_if_required(ERANGE); | ||
| fputil::raise_except_if_required(FE_UNDERFLOW); | ||
| return -1.0f; | ||
| } | ||
| if (auto r = EXP2M1F_EXCEPTS_HI.lookup(x_u); LIBC_UNLIKELY(r.has_value())) | ||
| return r.value(); | ||
| // For -25 < x < 128, to compute 2^x, we perform the following range | ||
| // reduction: find hi, mid, lo such that: | ||
| // x = hi + mid + lo, in which: | ||
| // hi is an integer, | ||
| // 0 <= mid * 2^5 < 32 is an integer, | ||
| // -2^(-6) <= lo <= 2^(-6). | ||
| // In particular, | ||
| // hi + mid = round(x * 2^5) * 2^(-5). | ||
| // Then, | ||
| // 2^x = 2^(hi + mid + lo) = 2^hi * 2^mid * 2^lo. | ||
| // 2^mid is stored in the lookup table of 32 elements. | ||
| // 2^lo is computed using a degree-4 minimax polynomial generated by Sollya. | ||
| // We perform 2^hi * 2^mid by simply add hi to the exponent field of 2^mid. | ||
| // kf = (hi + mid) * 2^5 = round(x * 2^5) | ||
| float kf; | ||
| int k; | ||
| #ifdef LIBC_TARGET_CPU_HAS_NEAREST_INT | ||
| kf = fputil::nearest_integer(x * 32.0f); | ||
| k = static_cast<int>(kf); | ||
| #else | ||
| constexpr float HALF[2] = {0.5f, -0.5f}; | ||
| k = static_cast<int>(fputil::multiply_add(x, 32.0f, HALF[x < 0.0f])); | ||
| kf = static_cast<float>(k); | ||
| #endif // LIBC_TARGET_CPU_HAS_NEAREST_INT | ||
| // lo = x - (hi + mid) = x - kf * 2^(-5) | ||
| double lo = fputil::multiply_add(-0x1.0p-5f, kf, x); | ||
| // hi = floor(kf * 2^(-4)) | ||
| // exp2_hi = shift hi to the exponent field of double precision. | ||
| int64_t exp2_hi = | ||
| static_cast<int64_t>(static_cast<uint64_t>(k >> ExpBase::MID_BITS) | ||
| << fputil::FPBits<double>::FRACTION_LEN); | ||
| // mh = 2^hi * 2^mid | ||
| // mh_bits = bit field of mh | ||
| int64_t mh_bits = ExpBase::EXP_2_MID[k & ExpBase::MID_MASK] + exp2_hi; | ||
| double mh = fputil::FPBits<double>(static_cast<uint64_t>(mh_bits)).get_val(); | ||
| // Degree-4 polynomial approximating (2^x - 1)/x generated by Sollya with: | ||
| // > display = hexadecimal; | ||
| // > fpminimax((2^x - 1)/x, 4, [|D...|], [-2^-6, 2^-6]); | ||
| constexpr double COEFFS[5] = {0x1.62e42fefa39efp-1, 0x1.ebfbdff8131c4p-3, | ||
| 0x1.c6b08d7061695p-5, 0x1.3b2b1bee74b2ap-7, | ||
| 0x1.5d88091198529p-10}; | ||
| double lo_sq = lo * lo; | ||
| double c1 = fputil::multiply_add(lo, COEFFS[0], 1.0); | ||
| double c2 = fputil::multiply_add(lo, COEFFS[2], COEFFS[1]); | ||
| double c3 = fputil::multiply_add(lo, COEFFS[4], COEFFS[3]); | ||
| double exp2_lo = fputil::polyeval(lo_sq, c1, c2, c3); | ||
| // 2^x - 1 = 2^(hi + mid + lo) - 1 | ||
| // = 2^(hi + mid) * 2^lo - 1 | ||
| // ~ mh * (1 + lo * P(lo)) - 1 | ||
| // = mh * exp2_lo - 1 | ||
| return static_cast<float>(fputil::multiply_add(exp2_lo, mh, -1.0)); | ||
| } | ||
| } // namespace LIBC_NAMESPACE |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| //===-- Exhaustive test for exp2m1f ---------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "exhaustive_test.h" | ||
| #include "src/math/exp2m1f.h" | ||
| #include "utils/MPFRWrapper/MPFRUtils.h" | ||
|
|
||
| namespace mpfr = LIBC_NAMESPACE::testing::mpfr; | ||
|
|
||
| using LlvmLibcExp2m1fExhaustiveTest = | ||
| LlvmLibcUnaryOpExhaustiveMathTest<float, mpfr::Operation::Exp2m1, | ||
| LIBC_NAMESPACE::exp2m1f>; | ||
|
|
||
| // Range: [0, Inf]; | ||
| static constexpr uint32_t POS_START = 0x0000'0000U; | ||
| static constexpr uint32_t POS_STOP = 0x7f80'0000U; | ||
|
|
||
| TEST_F(LlvmLibcExp2m1fExhaustiveTest, PostiveRange) { | ||
| test_full_range_all_roundings(POS_START, POS_STOP); | ||
| } | ||
|
|
||
| // Range: [-Inf, 0]; | ||
| static constexpr uint32_t NEG_START = 0x8000'0000U; | ||
| static constexpr uint32_t NEG_STOP = 0xff80'0000U; | ||
|
|
||
| TEST_F(LlvmLibcExp2m1fExhaustiveTest, NegativeRange) { | ||
| test_full_range_all_roundings(NEG_START, NEG_STOP); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| //===-- Unittests for exp2m1f ---------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "include/llvm-libc-macros/math-macros.h" | ||
| #include "src/__support/CPP/array.h" | ||
| #include "src/__support/FPUtil/FPBits.h" | ||
| #include "src/errno/libc_errno.h" | ||
| #include "src/math/exp2m1f.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
| #include "utils/MPFRWrapper/MPFRUtils.h" | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| using LlvmLibcExp2m1fTest = LIBC_NAMESPACE::testing::FPTest<float>; | ||
|
|
||
| namespace mpfr = LIBC_NAMESPACE::testing::mpfr; | ||
|
|
||
| TEST_F(LlvmLibcExp2m1fTest, TrickyInputs) { | ||
| constexpr LIBC_NAMESPACE::cpp::array<float, 10> INPUTS = { | ||
| // EXP2M1F_EXCEPTS_LO | ||
| 0x1.36dc8ep-36, | ||
| 0x1.224936p-19, | ||
| 0x1.d16d2p-20, | ||
| 0x1.17949ep-14, | ||
| -0x1.9c3e1ep-38, | ||
| -0x1.4d89b4p-32, | ||
| -0x1.a6eac4p-10, | ||
| -0x1.e7526ep-6, | ||
| // EXP2M1F_EXCEPTS_HI | ||
| 0x1.16a972p-1, | ||
| -0x1.9f12acp-5, | ||
| }; | ||
|
|
||
| for (float x : INPUTS) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2m1, x, | ||
| LIBC_NAMESPACE::exp2m1f(x), 0.5); | ||
| } | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcExp2m1fTest, InFloatRange) { | ||
| constexpr uint32_t COUNT = 100'000; | ||
| constexpr uint32_t STEP = UINT32_MAX / COUNT; | ||
| for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) { | ||
| float x = FPBits(v).get_val(); | ||
| if (isnan(x) || isinf(x)) | ||
| continue; | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
| float result = LIBC_NAMESPACE::exp2m1f(x); | ||
|
|
||
| // If the computation resulted in an error or did not produce valid result | ||
| // in the single-precision floating point range, then ignore comparing with | ||
| // MPFR result as MPFR can still produce valid results because of its | ||
| // wider precision. | ||
| if (isnan(result) || isinf(result) || LIBC_NAMESPACE::libc_errno != 0) | ||
| continue; | ||
| ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Exp2m1, x, | ||
| LIBC_NAMESPACE::exp2m1f(x), 0.5); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| //===-- Unittests for exp2m1f ---------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "src/errno/libc_errno.h" | ||
| #include "src/math/exp2m1f.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
|
|
||
| using LlvmLibcExp2m1fTest = LIBC_NAMESPACE::testing::FPTest<float>; | ||
| using LIBC_NAMESPACE::fputil::testing::ForceRoundingMode; | ||
| using LIBC_NAMESPACE::fputil::testing::RoundingMode; | ||
|
|
||
| TEST_F(LlvmLibcExp2m1fTest, SpecialNumbers) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::exp2m1f(aNaN)); | ||
| EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::exp2m1f(inf)); | ||
| EXPECT_FP_EQ_ALL_ROUNDING(-1.0f, LIBC_NAMESPACE::exp2m1f(neg_inf)); | ||
| EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::exp2m1f(0.0f)); | ||
| EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::exp2m1f(-0.0f)); | ||
|
|
||
| EXPECT_FP_EQ_ALL_ROUNDING(1.0f, LIBC_NAMESPACE::exp2m1f(1.0f)); | ||
| EXPECT_FP_EQ_ALL_ROUNDING(-0.5f, LIBC_NAMESPACE::exp2m1f(-1.0f)); | ||
| EXPECT_FP_EQ_ALL_ROUNDING(3.0f, LIBC_NAMESPACE::exp2m1f(2.0f)); | ||
| EXPECT_FP_EQ_ALL_ROUNDING(-0.75f, LIBC_NAMESPACE::exp2m1f(-2.0f)); | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcExp2m1fTest, Overflow) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp2m1f(0x1.fffffep+127), | ||
| FE_OVERFLOW); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp2m1f(128.0f), | ||
| FE_OVERFLOW); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::exp2m1f(0x1.000002p+7), | ||
| FE_OVERFLOW); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcExp2m1fTest, Underflow) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(-1.0f, LIBC_NAMESPACE::exp2m1f(-0x1.fffffep+127), | ||
| FE_UNDERFLOW); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(-1.0f, LIBC_NAMESPACE::exp2m1f(-25.0f), | ||
| FE_UNDERFLOW); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
|
|
||
| EXPECT_FP_EQ_WITH_EXCEPTION(-1.0f, LIBC_NAMESPACE::exp2m1f(-0x1.900002p4), | ||
| FE_UNDERFLOW); | ||
| EXPECT_MATH_ERRNO(ERANGE); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,7 @@ enum class Operation : int { | |
| Erf, | ||
| Exp, | ||
| Exp2, | ||
| Exp2m1, | ||
| Exp10, | ||
| Expm1, | ||
| Floor, | ||
|
|
||