1/*
2 Copyright (c) 2005-2019 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17// Program for basic correctness testing of assembly-language routines.
18#include "harness_defs.h"
19//for ICC builtins mode the test will be skipped as
20//macro __TBB_GCC_BUILTIN_ATOMICS_PRESENT used to define __TBB_TEST_SKIP_GCC_BUILTINS_MODE
21//will not be defined (it is explicitly disabled for ICC)
22#if __TBB_TEST_SKIP_GCC_BUILTINS_MODE
23#include "harness.h"
24int TestMain() {
25 REPORT("Known issue: GCC builtins aren't available\n");
26 return Harness::Skipped;
27}
28#else
29
30#include "tbb/task.h"
31
32#include <new>
33#include "harness.h"
34
35using tbb::internal::reference_count;
36
37//TODO: remove this function when atomic function __TBB_XXX are dropped
38//! Test __TBB_CompareAndSwapW
39static void TestCompareExchange() {
40 ASSERT( intptr_t(-10)<10, "intptr_t not a signed integral type?" );
41 REMARK("testing __TBB_CompareAndSwapW\n");
42 for( intptr_t a=-10; a<10; ++a )
43 for( intptr_t b=-10; b<10; ++b )
44 for( intptr_t c=-10; c<10; ++c ) {
45// Workaround for a bug in GCC 4.3.0; and one more is below.
46#if __TBB_GCC_OPTIMIZER_ORDERING_BROKEN
47 intptr_t x;
48 __TBB_store_with_release( x, a );
49#else
50 intptr_t x = a;
51#endif
52 intptr_t y = __TBB_CompareAndSwapW(&x,b,c);
53 ASSERT( y==a, NULL );
54 if( a==c )
55 ASSERT( x==b, NULL );
56 else
57 ASSERT( x==a, NULL );
58 }
59}
60
61//TODO: remove this function when atomic function __TBB_XXX are dropped
62//! Test __TBB___TBB_FetchAndIncrement and __TBB___TBB_FetchAndDecrement
63static void TestAtomicCounter() {
64 // "canary" is a value used to detect illegal overwrites.
65 const reference_count canary = ~(uintptr_t)0/3;
66 REMARK("testing __TBB_FetchAndIncrement\n");
67 struct {
68 reference_count prefix, i, suffix;
69 } x;
70 x.prefix = canary;
71 x.i = 0;
72 x.suffix = canary;
73 for( int k=0; k<10; ++k ) {
74 reference_count j = __TBB_FetchAndIncrementWacquire((volatile void *)&x.i);
75 ASSERT( x.prefix==canary, NULL );
76 ASSERT( x.suffix==canary, NULL );
77 ASSERT( x.i==k+1, NULL );
78 ASSERT( j==k, NULL );
79 }
80 REMARK("testing __TBB_FetchAndDecrement\n");
81 x.i = 10;
82 for( int k=10; k>0; --k ) {
83 reference_count j = __TBB_FetchAndDecrementWrelease((volatile void *)&x.i);
84 ASSERT( j==k, NULL );
85 ASSERT( x.i==k-1, NULL );
86 ASSERT( x.prefix==canary, NULL );
87 ASSERT( x.suffix==canary, NULL );
88 }
89}
90
91static void TestTinyLock() {
92 REMARK("testing __TBB_LockByte\n");
93 __TBB_atomic_flag flags[16];
94 for( unsigned int i=0; i<16; ++i )
95 flags[i] = (__TBB_Flag)i;
96#if __TBB_GCC_OPTIMIZER_ORDERING_BROKEN
97 __TBB_store_with_release( flags[8], 0 );
98#else
99 flags[8] = 0;
100#endif
101 __TBB_LockByte(flags[8]);
102 for( unsigned int i=0; i<16; ++i )
103 #ifdef __sparc
104 ASSERT( flags[i]==(i==8?0xff:i), NULL );
105 #else
106 ASSERT( flags[i]==(i==8?1:i), NULL );
107 #endif
108 __TBB_UnlockByte(flags[8]);
109 for( unsigned int i=0; i<16; ++i )
110 ASSERT( flags[i] == (i==8?0:i), NULL );
111}
112
113static void TestLog2() {
114 REMARK("testing __TBB_Log2\n");
115 for( uintptr_t i=1; i; i<<=1 ) {
116 for( uintptr_t j=1; j<1<<16; ++j ) {
117 if( uintptr_t k = i*j ) {
118 uintptr_t actual = __TBB_Log2(k);
119 const uintptr_t ONE = 1; // warning suppression again
120 ASSERT( k >= ONE<<actual, NULL );
121 ASSERT( k>>1 < ONE<<actual, NULL );
122 }
123 }
124 }
125}
126
127static void TestPause() {
128 REMARK("testing __TBB_Pause\n");
129 __TBB_Pause(1);
130}
131
132static void TestTimeStamp() {
133 REMARK("testing __TBB_time_stamp");
134#if defined(__TBB_time_stamp)
135 tbb::internal::machine_tsc_t prev = __TBB_time_stamp();
136 for ( int i=0; i<1000; ++i ) {
137 tbb::internal::machine_tsc_t curr = __TBB_time_stamp();
138 ASSERT(curr>prev, "__TBB_time_stamp has returned non-monotonically increasing quantity");
139 prev=curr;
140 }
141 REMARK("\n");
142#else
143 REMARK(" skipped\n");
144#endif
145}
146
147int TestMain () {
148 __TBB_TRY {
149 TestLog2();
150 TestTinyLock();
151 TestCompareExchange();
152 TestAtomicCounter();
153 TestPause();
154 TestTimeStamp();
155 } __TBB_CATCH(...) {
156 ASSERT(0,"unexpected exception");
157 }
158 return Harness::Done;
159}
160#endif // __TBB_TEST_SKIP_BUILTINS_MODE
161