xref: /aosp_15_r20/external/swiftshader/src/Reactor/LLVMReactor.hpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //  http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef rr_LLVMReactor_hpp
16 #define rr_LLVMReactor_hpp
17 
18 #include "Nucleus.hpp"
19 
20 #include "Debug.hpp"
21 #include "LLVMReactorDebugInfo.hpp"
22 #include "Print.hpp"
23 
24 #ifdef _MSC_VER
25 __pragma(warning(push))
26     __pragma(warning(disable : 4146))  // unary minus operator applied to unsigned type, result still unsigned
27 #endif
28 
29 #include "llvm/IR/IRBuilder.h"
30 #include "llvm/IR/LLVMContext.h"
31 
32 #ifdef _MSC_VER
33     __pragma(warning(pop))
34 #endif
35 
36 #include <memory>
37 
38         namespace llvm
39 {
40 
41 	class Type;
42 	class Value;
43 
44 }  // namespace llvm
45 
46 namespace rr {
47 
48 class Type;
49 class Value;
50 
51 llvm::Type *T(Type *t);
52 
T(llvm::Type * t)53 inline Type *T(llvm::Type *t)
54 {
55 	return reinterpret_cast<Type *>(t);
56 }
57 
V(Value * t)58 inline llvm::Value *V(Value *t)
59 {
60 	return reinterpret_cast<llvm::Value *>(t);
61 }
62 
V(llvm::Value * t)63 inline Value *V(llvm::Value *t)
64 {
65 	return reinterpret_cast<Value *>(t);
66 }
67 
V(const std::vector<Value * > & values)68 inline std::vector<llvm::Value *> V(const std::vector<Value *> &values)
69 {
70 	std::vector<llvm::Value *> result;
71 	result.reserve(values.size());
72 	for(auto &v : values)
73 	{
74 		result.push_back(V(v));
75 	}
76 	return result;
77 }
78 
79 // Emits a no-op instruction that will not be optimized away.
80 // Useful for emitting something that can have a source location without
81 // effect.
82 void Nop();
83 
84 class Routine;
85 
86 // JITBuilder holds all the LLVM state for building routines.
87 class JITBuilder
88 {
89 public:
90 	JITBuilder();
91 
92 	void runPasses();
93 
94 	std::shared_ptr<rr::Routine> acquireRoutine(const char *name, llvm::Function **funcs, size_t count);
95 
96 	std::unique_ptr<llvm::LLVMContext> context;
97 	std::unique_ptr<llvm::Module> module;
98 	std::unique_ptr<llvm::IRBuilder<>> builder;
99 	llvm::Function *function = nullptr;
100 
101 	struct CoroutineState
102 	{
103 		llvm::Function *await = nullptr;
104 		llvm::Function *destroy = nullptr;
105 		llvm::Value *handle = nullptr;
106 		llvm::Value *id = nullptr;
107 		llvm::Value *promise = nullptr;
108 		llvm::Type *yieldType = nullptr;
109 		llvm::BasicBlock *entryBlock = nullptr;
110 		llvm::BasicBlock *suspendBlock = nullptr;
111 		llvm::BasicBlock *endBlock = nullptr;
112 		llvm::BasicBlock *destroyBlock = nullptr;
113 	};
114 	CoroutineState coroutine;
115 
116 #ifdef ENABLE_RR_DEBUG_INFO
117 	std::unique_ptr<rr::DebugInfo> debugInfo;
118 #endif
119 
120 	bool msanInstrumentation = false;
121 };
122 
atomicOrdering(llvm::AtomicOrdering memoryOrder)123 inline std::memory_order atomicOrdering(llvm::AtomicOrdering memoryOrder)
124 {
125 	switch(memoryOrder)
126 	{
127 	case llvm::AtomicOrdering::Monotonic: return std::memory_order_relaxed;  // https://llvm.org/docs/Atomics.html#monotonic
128 	case llvm::AtomicOrdering::Acquire: return std::memory_order_acquire;
129 	case llvm::AtomicOrdering::Release: return std::memory_order_release;
130 	case llvm::AtomicOrdering::AcquireRelease: return std::memory_order_acq_rel;
131 	case llvm::AtomicOrdering::SequentiallyConsistent: return std::memory_order_seq_cst;
132 	default:
133 		UNREACHABLE("memoryOrder: %d", int(memoryOrder));
134 		return std::memory_order_acq_rel;
135 	}
136 }
137 
atomicOrdering(bool atomic,std::memory_order memoryOrder)138 inline llvm::AtomicOrdering atomicOrdering(bool atomic, std::memory_order memoryOrder)
139 {
140 	if(!atomic)
141 	{
142 		return llvm::AtomicOrdering::NotAtomic;
143 	}
144 
145 	switch(memoryOrder)
146 	{
147 	case std::memory_order_relaxed: return llvm::AtomicOrdering::Monotonic;  // https://llvm.org/docs/Atomics.html#monotonic
148 	case std::memory_order_consume: return llvm::AtomicOrdering::Acquire;    // https://llvm.org/docs/Atomics.html#acquire: "It should also be used for C++11/C11 memory_order_consume."
149 	case std::memory_order_acquire: return llvm::AtomicOrdering::Acquire;
150 	case std::memory_order_release: return llvm::AtomicOrdering::Release;
151 	case std::memory_order_acq_rel: return llvm::AtomicOrdering::AcquireRelease;
152 	case std::memory_order_seq_cst: return llvm::AtomicOrdering::SequentiallyConsistent;
153 	default:
154 		UNREACHABLE("memoryOrder: %d", int(memoryOrder));
155 		return llvm::AtomicOrdering::AcquireRelease;
156 	}
157 }
158 
159 }  // namespace rr
160 
161 #endif  // rr_LLVMReactor_hpp
162