• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 class Config;
86 
87 // JITBuilder holds all the LLVM state for building routines.
88 class JITBuilder
89 {
90 public:
91 	JITBuilder(const rr::Config &config);
92 
93 	void optimize(const rr::Config &cfg);
94 
95 	std::shared_ptr<rr::Routine> acquireRoutine(const char *name, llvm::Function **funcs, size_t count, const rr::Config &cfg);
96 
97 	const Config config;
98 	std::unique_ptr<llvm::LLVMContext> context;
99 	std::unique_ptr<llvm::Module> module;
100 	std::unique_ptr<llvm::IRBuilder<>> builder;
101 	llvm::Function *function = nullptr;
102 
103 	struct CoroutineState
104 	{
105 		llvm::Function *await = nullptr;
106 		llvm::Function *destroy = nullptr;
107 		llvm::Value *handle = nullptr;
108 		llvm::Value *id = nullptr;
109 		llvm::Value *promise = nullptr;
110 		llvm::Type *yieldType = nullptr;
111 		llvm::BasicBlock *entryBlock = nullptr;
112 		llvm::BasicBlock *suspendBlock = nullptr;
113 		llvm::BasicBlock *endBlock = nullptr;
114 		llvm::BasicBlock *destroyBlock = nullptr;
115 	};
116 	CoroutineState coroutine;
117 
118 #ifdef ENABLE_RR_DEBUG_INFO
119 	std::unique_ptr<rr::DebugInfo> debugInfo;
120 #endif
121 
122 	bool msanInstrumentation = false;
123 };
124 
atomicOrdering(llvm::AtomicOrdering memoryOrder)125 inline std::memory_order atomicOrdering(llvm::AtomicOrdering memoryOrder)
126 {
127 	switch(memoryOrder)
128 	{
129 	case llvm::AtomicOrdering::Monotonic: return std::memory_order_relaxed;  // https://llvm.org/docs/Atomics.html#monotonic
130 	case llvm::AtomicOrdering::Acquire: return std::memory_order_acquire;
131 	case llvm::AtomicOrdering::Release: return std::memory_order_release;
132 	case llvm::AtomicOrdering::AcquireRelease: return std::memory_order_acq_rel;
133 	case llvm::AtomicOrdering::SequentiallyConsistent: return std::memory_order_seq_cst;
134 	default:
135 		UNREACHABLE("memoryOrder: %d", int(memoryOrder));
136 		return std::memory_order_acq_rel;
137 	}
138 }
139 
atomicOrdering(bool atomic,std::memory_order memoryOrder)140 inline llvm::AtomicOrdering atomicOrdering(bool atomic, std::memory_order memoryOrder)
141 {
142 	if(!atomic)
143 	{
144 		return llvm::AtomicOrdering::NotAtomic;
145 	}
146 
147 	switch(memoryOrder)
148 	{
149 	case std::memory_order_relaxed: return llvm::AtomicOrdering::Monotonic;  // https://llvm.org/docs/Atomics.html#monotonic
150 	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."
151 	case std::memory_order_acquire: return llvm::AtomicOrdering::Acquire;
152 	case std::memory_order_release: return llvm::AtomicOrdering::Release;
153 	case std::memory_order_acq_rel: return llvm::AtomicOrdering::AcquireRelease;
154 	case std::memory_order_seq_cst: return llvm::AtomicOrdering::SequentiallyConsistent;
155 	default:
156 		UNREACHABLE("memoryOrder: %d", int(memoryOrder));
157 		return llvm::AtomicOrdering::AcquireRelease;
158 	}
159 }
160 
161 }  // namespace rr
162 
163 #endif  // rr_LLVMReactor_hpp
164