ac: add LLVM code for triangle culling
[mesa.git] / src / amd / common / ac_llvm_helper.cpp
1 /*
2 * Copyright 2014 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sub license, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
15 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
17 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
18 * USE OR OTHER DEALINGS IN THE SOFTWARE.
19 *
20 * The above copyright notice and this permission notice (including the
21 * next paragraph) shall be included in all copies or substantial portions
22 * of the Software.
23 *
24 */
25
26 /* based on Marek's patch to lp_bld_misc.cpp */
27
28 // Workaround http://llvm.org/PR23628
29 #pragma push_macro("DEBUG")
30 #undef DEBUG
31
32 #include "ac_binary.h"
33 #include "ac_llvm_util.h"
34 #include "ac_llvm_build.h"
35
36 #include <llvm-c/Core.h>
37 #include <llvm/Target/TargetMachine.h>
38 #include <llvm/IR/IRBuilder.h>
39 #include <llvm/Analysis/TargetLibraryInfo.h>
40 #include <llvm/Transforms/IPO.h>
41
42 #include <llvm/IR/LegacyPassManager.h>
43
44 void ac_add_attr_dereferenceable(LLVMValueRef val, uint64_t bytes)
45 {
46 llvm::Argument *A = llvm::unwrap<llvm::Argument>(val);
47 A->addAttr(llvm::Attribute::getWithDereferenceableBytes(A->getContext(), bytes));
48 }
49
50 bool ac_is_sgpr_param(LLVMValueRef arg)
51 {
52 llvm::Argument *A = llvm::unwrap<llvm::Argument>(arg);
53 llvm::AttributeList AS = A->getParent()->getAttributes();
54 unsigned ArgNo = A->getArgNo();
55 return AS.hasAttribute(ArgNo + 1, llvm::Attribute::InReg);
56 }
57
58 LLVMValueRef ac_llvm_get_called_value(LLVMValueRef call)
59 {
60 return LLVMGetCalledValue(call);
61 }
62
63 bool ac_llvm_is_function(LLVMValueRef v)
64 {
65 return LLVMGetValueKind(v) == LLVMFunctionValueKind;
66 }
67
68 LLVMModuleRef ac_create_module(LLVMTargetMachineRef tm, LLVMContextRef ctx)
69 {
70 llvm::TargetMachine *TM = reinterpret_cast<llvm::TargetMachine*>(tm);
71 LLVMModuleRef module = LLVMModuleCreateWithNameInContext("mesa-shader", ctx);
72
73 llvm::unwrap(module)->setTargetTriple(TM->getTargetTriple().getTriple());
74 llvm::unwrap(module)->setDataLayout(TM->createDataLayout());
75 return module;
76 }
77
78 LLVMBuilderRef ac_create_builder(LLVMContextRef ctx,
79 enum ac_float_mode float_mode)
80 {
81 LLVMBuilderRef builder = LLVMCreateBuilderInContext(ctx);
82
83 llvm::FastMathFlags flags;
84
85 switch (float_mode) {
86 case AC_FLOAT_MODE_DEFAULT:
87 break;
88 case AC_FLOAT_MODE_NO_SIGNED_ZEROS_FP_MATH:
89 flags.setNoSignedZeros();
90 llvm::unwrap(builder)->setFastMathFlags(flags);
91 break;
92 case AC_FLOAT_MODE_UNSAFE_FP_MATH:
93 flags.setFast();
94 llvm::unwrap(builder)->setFastMathFlags(flags);
95 break;
96 }
97
98 return builder;
99 }
100
101 LLVMTargetLibraryInfoRef
102 ac_create_target_library_info(const char *triple)
103 {
104 return reinterpret_cast<LLVMTargetLibraryInfoRef>(new llvm::TargetLibraryInfoImpl(llvm::Triple(triple)));
105 }
106
107 void
108 ac_dispose_target_library_info(LLVMTargetLibraryInfoRef library_info)
109 {
110 delete reinterpret_cast<llvm::TargetLibraryInfoImpl *>(library_info);
111 }
112
113 /* The LLVM compiler is represented as a pass manager containing passes for
114 * optimizations, instruction selection, and code generation.
115 */
116 struct ac_compiler_passes {
117 ac_compiler_passes(): ostream(code_string) {}
118
119 llvm::SmallString<0> code_string; /* ELF shader binary */
120 llvm::raw_svector_ostream ostream; /* stream for appending data to the binary */
121 llvm::legacy::PassManager passmgr; /* list of passes */
122 };
123
124 struct ac_compiler_passes *ac_create_llvm_passes(LLVMTargetMachineRef tm)
125 {
126 struct ac_compiler_passes *p = new ac_compiler_passes();
127 if (!p)
128 return NULL;
129
130 llvm::TargetMachine *TM = reinterpret_cast<llvm::TargetMachine*>(tm);
131
132 if (TM->addPassesToEmitFile(p->passmgr, p->ostream,
133 nullptr,
134 llvm::TargetMachine::CGFT_ObjectFile)) {
135 fprintf(stderr, "amd: TargetMachine can't emit a file of this type!\n");
136 delete p;
137 return NULL;
138 }
139 return p;
140 }
141
142 void ac_destroy_llvm_passes(struct ac_compiler_passes *p)
143 {
144 delete p;
145 }
146
147 /* This returns false on failure. */
148 bool ac_compile_module_to_binary(struct ac_compiler_passes *p, LLVMModuleRef module,
149 struct ac_shader_binary *binary)
150 {
151 p->passmgr.run(*llvm::unwrap(module));
152
153 llvm::StringRef data = p->ostream.str();
154 bool success = ac_elf_read(data.data(), data.size(), binary);
155 p->code_string = ""; /* release the ELF shader binary */
156
157 if (!success)
158 fprintf(stderr, "amd: cannot read an ELF shader binary\n");
159 return success;
160 }
161
162 void ac_llvm_add_barrier_noop_pass(LLVMPassManagerRef passmgr)
163 {
164 llvm::unwrap(passmgr)->add(llvm::createBarrierNoopPass());
165 }
166
167 void ac_enable_global_isel(LLVMTargetMachineRef tm)
168 {
169 reinterpret_cast<llvm::TargetMachine*>(tm)->setGlobalISel(true);
170 }
171
172 LLVMValueRef ac_build_atomic_rmw(struct ac_llvm_context *ctx, LLVMAtomicRMWBinOp op,
173 LLVMValueRef ptr, LLVMValueRef val,
174 const char *sync_scope) {
175 llvm::AtomicRMWInst::BinOp binop;
176 switch (op) {
177 case LLVMAtomicRMWBinOpXchg:
178 binop = llvm::AtomicRMWInst::Xchg;
179 break;
180 case LLVMAtomicRMWBinOpAdd:
181 binop = llvm::AtomicRMWInst::Add;
182 break;
183 case LLVMAtomicRMWBinOpSub:
184 binop = llvm::AtomicRMWInst::Sub;
185 break;
186 case LLVMAtomicRMWBinOpAnd:
187 binop = llvm::AtomicRMWInst::And;
188 break;
189 case LLVMAtomicRMWBinOpNand:
190 binop = llvm::AtomicRMWInst::Nand;
191 break;
192 case LLVMAtomicRMWBinOpOr:
193 binop = llvm::AtomicRMWInst::Or;
194 break;
195 case LLVMAtomicRMWBinOpXor:
196 binop = llvm::AtomicRMWInst::Xor;
197 break;
198 case LLVMAtomicRMWBinOpMax:
199 binop = llvm::AtomicRMWInst::Max;
200 break;
201 case LLVMAtomicRMWBinOpMin:
202 binop = llvm::AtomicRMWInst::Min;
203 break;
204 case LLVMAtomicRMWBinOpUMax:
205 binop = llvm::AtomicRMWInst::UMax;
206 break;
207 case LLVMAtomicRMWBinOpUMin:
208 binop = llvm::AtomicRMWInst::UMin;
209 break;
210 default:
211 unreachable(!"invalid LLVMAtomicRMWBinOp");
212 break;
213 }
214 unsigned SSID = llvm::unwrap(ctx->context)->getOrInsertSyncScopeID(sync_scope);
215 return llvm::wrap(llvm::unwrap(ctx->builder)->CreateAtomicRMW(
216 binop, llvm::unwrap(ptr), llvm::unwrap(val),
217 llvm::AtomicOrdering::SequentiallyConsistent, SSID));
218 }
219
220 LLVMValueRef ac_build_atomic_cmp_xchg(struct ac_llvm_context *ctx, LLVMValueRef ptr,
221 LLVMValueRef cmp, LLVMValueRef val,
222 const char *sync_scope) {
223 unsigned SSID = llvm::unwrap(ctx->context)->getOrInsertSyncScopeID(sync_scope);
224 return llvm::wrap(llvm::unwrap(ctx->builder)->CreateAtomicCmpXchg(
225 llvm::unwrap(ptr), llvm::unwrap(cmp), llvm::unwrap(val),
226 llvm::AtomicOrdering::SequentiallyConsistent,
227 llvm::AtomicOrdering::SequentiallyConsistent, SSID));
228 }