aboutsummaryrefslogtreecommitdiff
path: root/include/EASTL/internal/atomic/compiler/compiler.h
blob: 65a4cd001a94f526a5933d3df110e791cf4e84ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////


#ifndef EASTL_ATOMIC_INTERNAL_COMPILER_H
#define EASTL_ATOMIC_INTERNAL_COMPILER_H

#if defined(EA_PRAGMA_ONCE_SUPPORTED)
	#pragma once
#endif


/////////////////////////////////////////////////////////////////////////////////
//
// Include the compiler specific implementations
//
#if defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)

	#include "gcc/compiler_gcc.h"

#elif defined(EA_COMPILER_MSVC)

	#include "msvc/compiler_msvc.h"

#endif


/////////////////////////////////////////////////////////////////////////////////


namespace eastl
{


namespace internal
{


/**
 * NOTE:
 *
 * This can be used by specific compiler implementations to implement a data dependency compiler barrier.
 * Some compiler barriers do not take in input dependencies as is possible with the gcc asm syntax.
 * Thus we need a way to create a false dependency on the input variable so the compiler does not dead-store
 * remove it.
 * A volatile function pointer ensures the compiler must always load the function pointer and call thru it
 * since the compiler cannot reason about any side effects. Thus the compiler must always assume the
 * input variable may be accessed and thus cannot be dead-stored. This technique works even in the presence
 * of Link-Time Optimization. A compiler barrier with a data dependency is useful in these situations.
 *
 * void foo()
 * {
 *    eastl::vector<int> v;
 *    while (Benchmark.ContinueRunning())
 *    {
 *      v.push_back(0);
 *      eastl::compiler_barrier(); OR eastl::compiler_barrier_data_dependency(v);
 *    }
 * }
 *
 * We are trying to benchmark the push_back function of a vector. The vector v has only local scope.
 * The compiler is well within its writes to remove all accesses to v even with the compiler barrier
 * because there are no observable uses of the vector v.
 * The compiler barrier data dependency ensures there is an input dependency on the variable so that
 * it isn't removed. This is also useful when writing test code that the compiler may remove.
 */

typedef void (*CompilerBarrierDataDependencyFuncPtr)(void*);

extern EASTL_API volatile CompilerBarrierDataDependencyFuncPtr gCompilerBarrierDataDependencyFunc;


#define EASTL_COMPILER_ATOMIC_COMPILER_BARRIER_DATA_DEPENDENCY_FUNC(ptr) \
	eastl::internal::gCompilerBarrierDataDependencyFunc(ptr)


} // namespace internal


} // namespace eastl


/////////////////////////////////////////////////////////////////////////////////


#include "compiler_fetch_add.h"
#include "compiler_fetch_sub.h"

#include "compiler_fetch_and.h"
#include "compiler_fetch_xor.h"
#include "compiler_fetch_or.h"

#include "compiler_add_fetch.h"
#include "compiler_sub_fetch.h"

#include "compiler_and_fetch.h"
#include "compiler_xor_fetch.h"
#include "compiler_or_fetch.h"

#include "compiler_exchange.h"

#include "compiler_cmpxchg_weak.h"
#include "compiler_cmpxchg_strong.h"

#include "compiler_load.h"
#include "compiler_store.h"

#include "compiler_barrier.h"

#include "compiler_cpu_pause.h"

#include "compiler_memory_barrier.h"

#include "compiler_signal_fence.h"

#include "compiler_thread_fence.h"


#endif /* EASTL_ATOMIC_INTERNAL_COMPILER_H */