Merge commit 'origin/gallium-master-merge'
[mesa.git] / src / gallium / auxiliary / gallivm / instructionssoa.cpp
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27 #include "instructionssoa.h"
28
29 #include "storagesoa.h"
30
31 #include "pipe/p_shader_tokens.h"
32 #include "util/u_memory.h"
33
34 #include <llvm/CallingConv.h>
35 #include <llvm/Constants.h>
36 #include <llvm/Module.h>
37 #include <llvm/Function.h>
38 #include <llvm/Instructions.h>
39 #include <llvm/Transforms/Utils/Cloning.h>
40 #include <llvm/Attributes.h>
41 #include <llvm/Support/MemoryBuffer.h>
42 #include <llvm/Bitcode/ReaderWriter.h>
43
44
45 #include <iostream>
46
47
48 /* disable some warnings. this file is autogenerated */
49 #if defined(__GNUC__)
50 #pragma GCC diagnostic ignored "-Wunused-variable"
51 #endif
52 using namespace llvm;
53 #include "gallivmsoabuiltins.cpp"
54 #if defined(__GNUC__)
55 #pragma GCC diagnostic warning "-Wunused-variable"
56 #endif
57
58 InstructionsSoa::InstructionsSoa(llvm::Module *mod, llvm::Function *func,
59 llvm::BasicBlock *block, StorageSoa *storage)
60 : m_builder(block),
61 m_storage(storage),
62 m_idx(0)
63 {
64 createFunctionMap();
65 createBuiltins();
66 }
67
68 const char * InstructionsSoa::name(const char *prefix) const
69 {
70 ++m_idx;
71 snprintf(m_name, 32, "%s%d", prefix, m_idx);
72 return m_name;
73 }
74
75 llvm::Value * InstructionsSoa::vectorFromVals(llvm::Value *x, llvm::Value *y,
76 llvm::Value *z, llvm::Value *w)
77 {
78 VectorType *vectorType = VectorType::get(Type::FloatTy, 4);
79 Constant *constVector = Constant::getNullValue(vectorType);
80 Value *res = m_builder.CreateInsertElement(constVector, x,
81 m_storage->constantInt(0),
82 name("vecx"));
83 res = m_builder.CreateInsertElement(res, y, m_storage->constantInt(1),
84 name("vecxy"));
85 res = m_builder.CreateInsertElement(res, z, m_storage->constantInt(2),
86 name("vecxyz"));
87 if (w)
88 res = m_builder.CreateInsertElement(res, w, m_storage->constantInt(3),
89 name("vecxyzw"));
90 return res;
91 }
92
93 void InstructionsSoa::end()
94 {
95 m_builder.CreateRetVoid();
96 }
97
98 std::vector<llvm::Value*> InstructionsSoa::extractVector(llvm::Value *vector)
99 {
100 std::vector<llvm::Value*> res(4);
101 res[0] = m_builder.CreateExtractElement(vector,
102 m_storage->constantInt(0),
103 name("extract1X"));
104 res[1] = m_builder.CreateExtractElement(vector,
105 m_storage->constantInt(1),
106 name("extract2X"));
107 res[2] = m_builder.CreateExtractElement(vector,
108 m_storage->constantInt(2),
109 name("extract3X"));
110 res[3] = m_builder.CreateExtractElement(vector,
111 m_storage->constantInt(3),
112 name("extract4X"));
113
114 return res;
115 }
116
117 llvm::IRBuilder<>* InstructionsSoa::getIRBuilder()
118 {
119 return &m_builder;
120 }
121
122 void InstructionsSoa::createFunctionMap()
123 {
124 m_functionsMap[TGSI_OPCODE_ABS] = "abs";
125 m_functionsMap[TGSI_OPCODE_DP3] = "dp3";
126 m_functionsMap[TGSI_OPCODE_DP4] = "dp4";
127 m_functionsMap[TGSI_OPCODE_MIN] = "min";
128 m_functionsMap[TGSI_OPCODE_MAX] = "max";
129 m_functionsMap[TGSI_OPCODE_POWER] = "pow";
130 m_functionsMap[TGSI_OPCODE_LIT] = "lit";
131 m_functionsMap[TGSI_OPCODE_RSQ] = "rsq";
132 m_functionsMap[TGSI_OPCODE_SLT] = "slt";
133 }
134
135 void InstructionsSoa::createDependencies()
136 {
137 {
138 std::vector<std::string> powDeps(2);
139 powDeps[0] = "powf";
140 powDeps[1] = "powvec";
141 m_builtinDependencies["pow"] = powDeps;
142 }
143 {
144 std::vector<std::string> absDeps(2);
145 absDeps[0] = "fabsf";
146 absDeps[1] = "absvec";
147 m_builtinDependencies["abs"] = absDeps;
148 }
149 {
150 std::vector<std::string> maxDeps(1);
151 maxDeps[0] = "maxvec";
152 m_builtinDependencies["max"] = maxDeps;
153 }
154 {
155 std::vector<std::string> minDeps(1);
156 minDeps[0] = "minvec";
157 m_builtinDependencies["min"] = minDeps;
158 }
159 {
160 std::vector<std::string> litDeps(4);
161 litDeps[0] = "minvec";
162 litDeps[1] = "maxvec";
163 litDeps[2] = "powf";
164 litDeps[3] = "powvec";
165 m_builtinDependencies["lit"] = litDeps;
166 }
167 {
168 std::vector<std::string> rsqDeps(4);
169 rsqDeps[0] = "sqrtf";
170 rsqDeps[1] = "sqrtvec";
171 rsqDeps[2] = "fabsf";
172 rsqDeps[3] = "absvec";
173 m_builtinDependencies["rsq"] = rsqDeps;
174 }
175 }
176
177 llvm::Function * InstructionsSoa::function(int op)
178 {
179 if (m_functions.find(op) != m_functions.end())
180 return m_functions[op];
181
182 std::string name = m_functionsMap[op];
183
184 std::cout <<"For op = "<<op<<", func is '"<<name<<"'"<<std::endl;
185
186 std::vector<std::string> deps = m_builtinDependencies[name];
187 for (unsigned int i = 0; i < deps.size(); ++i) {
188 llvm::Function *func = m_builtins->getFunction(deps[i]);
189 std::cout <<"\tinjecting dep = '"<<func->getName()<<"'"<<std::endl;
190 injectFunction(func);
191 }
192
193 llvm::Function *originalFunc = m_builtins->getFunction(name);
194 injectFunction(originalFunc, op);
195 return m_functions[op];
196 }
197
198 llvm::Module * InstructionsSoa::currentModule() const
199 {
200 BasicBlock *block = m_builder.GetInsertBlock();
201 if (!block || !block->getParent())
202 return 0;
203
204 return block->getParent()->getParent();
205 }
206
207 void InstructionsSoa::createBuiltins()
208 {
209 std::string ErrMsg;
210 MemoryBuffer *buffer = MemoryBuffer::getMemBuffer(
211 (const char*)&soabuiltins_data[0],
212 (const char*)&soabuiltins_data[Elements(soabuiltins_data) - 1]);
213 m_builtins = ParseBitcodeFile(buffer, &ErrMsg);
214 std::cout<<"Builtins created at "<<m_builtins<<" ("<<ErrMsg<<")"<<std::endl;
215 assert(m_builtins);
216 createDependencies();
217 }
218
219
220 std::vector<llvm::Value*> InstructionsSoa::abs(const std::vector<llvm::Value*> in1)
221 {
222 llvm::Function *func = function(TGSI_OPCODE_ABS);
223 return callBuiltin(func, in1);
224 }
225
226 std::vector<llvm::Value*> InstructionsSoa::add(const std::vector<llvm::Value*> in1,
227 const std::vector<llvm::Value*> in2)
228 {
229 std::vector<llvm::Value*> res(4);
230
231 res[0] = m_builder.CreateAdd(in1[0], in2[0], name("addx"));
232 res[1] = m_builder.CreateAdd(in1[1], in2[1], name("addy"));
233 res[2] = m_builder.CreateAdd(in1[2], in2[2], name("addz"));
234 res[3] = m_builder.CreateAdd(in1[3], in2[3], name("addw"));
235
236 return res;
237 }
238
239 std::vector<llvm::Value*> InstructionsSoa::arl(const std::vector<llvm::Value*> in)
240 {
241 std::vector<llvm::Value*> res(4);
242
243 //Extract x's
244 llvm::Value *x1 = m_builder.CreateExtractElement(in[0],
245 m_storage->constantInt(0),
246 name("extractX"));
247 //cast it to an unsigned int
248 x1 = m_builder.CreateFPToUI(x1, IntegerType::get(32), name("x1IntCast"));
249
250 res[0] = x1;//vectorFromVals(x1, x2, x3, x4);
251 //only x is valid. the others shouldn't be necessary
252 /*
253 res[1] = Constant::getNullValue(m_floatVecType);
254 res[2] = Constant::getNullValue(m_floatVecType);
255 res[3] = Constant::getNullValue(m_floatVecType);
256 */
257
258 return res;
259 }
260
261 std::vector<llvm::Value*> InstructionsSoa::dp3(const std::vector<llvm::Value*> in1,
262 const std::vector<llvm::Value*> in2)
263 {
264 llvm::Function *func = function(TGSI_OPCODE_DP3);
265 return callBuiltin(func, in1, in2);
266 }
267
268 std::vector<llvm::Value*> InstructionsSoa::lit(const std::vector<llvm::Value*> in)
269 {
270 llvm::Function *func = function(TGSI_OPCODE_LIT);
271 return callBuiltin(func, in);
272 }
273
274 std::vector<llvm::Value*> InstructionsSoa::madd(const std::vector<llvm::Value*> in1,
275 const std::vector<llvm::Value*> in2,
276 const std::vector<llvm::Value*> in3)
277 {
278 std::vector<llvm::Value*> res = mul(in1, in2);
279 return add(res, in3);
280 }
281
282 std::vector<llvm::Value*> InstructionsSoa::max(const std::vector<llvm::Value*> in1,
283 const std::vector<llvm::Value*> in2)
284 {
285 llvm::Function *func = function(TGSI_OPCODE_MAX);
286 return callBuiltin(func, in1, in2);
287 }
288
289 std::vector<llvm::Value*> InstructionsSoa::min(const std::vector<llvm::Value*> in1,
290 const std::vector<llvm::Value*> in2)
291 {
292 llvm::Function *func = function(TGSI_OPCODE_MIN);
293 return callBuiltin(func, in1, in2);
294 }
295
296 std::vector<llvm::Value*> InstructionsSoa::mul(const std::vector<llvm::Value*> in1,
297 const std::vector<llvm::Value*> in2)
298 {
299 std::vector<llvm::Value*> res(4);
300
301 res[0] = m_builder.CreateMul(in1[0], in2[0], name("mulx"));
302 res[1] = m_builder.CreateMul(in1[1], in2[1], name("muly"));
303 res[2] = m_builder.CreateMul(in1[2], in2[2], name("mulz"));
304 res[3] = m_builder.CreateMul(in1[3], in2[3], name("mulw"));
305
306 return res;
307 }
308
309 std::vector<llvm::Value*> InstructionsSoa::pow(const std::vector<llvm::Value*> in1,
310 const std::vector<llvm::Value*> in2)
311 {
312 llvm::Function *func = function(TGSI_OPCODE_POWER);
313 return callBuiltin(func, in1, in2);
314 }
315
316 std::vector<llvm::Value*> InstructionsSoa::rsq(const std::vector<llvm::Value*> in)
317 {
318 llvm::Function *func = function(TGSI_OPCODE_RSQ);
319 return callBuiltin(func, in);
320 }
321
322 std::vector<llvm::Value*> InstructionsSoa::slt(const std::vector<llvm::Value*> in1,
323 const std::vector<llvm::Value*> in2)
324 {
325 llvm::Function *func = function(TGSI_OPCODE_SLT);
326 return callBuiltin(func, in1, in2);
327 }
328
329 std::vector<llvm::Value*> InstructionsSoa::sub(const std::vector<llvm::Value*> in1,
330 const std::vector<llvm::Value*> in2)
331 {
332 std::vector<llvm::Value*> res(4);
333
334 res[0] = m_builder.CreateSub(in1[0], in2[0], name("subx"));
335 res[1] = m_builder.CreateSub(in1[1], in2[1], name("suby"));
336 res[2] = m_builder.CreateSub(in1[2], in2[2], name("subz"));
337 res[3] = m_builder.CreateSub(in1[3], in2[3], name("subw"));
338
339 return res;
340 }
341
342 void checkFunction(Function *func)
343 {
344 for (Function::const_iterator BI = func->begin(), BE = func->end();
345 BI != BE; ++BI) {
346 const BasicBlock &BB = *BI;
347 for (BasicBlock::const_iterator II = BB.begin(), IE = BB.end();
348 II != IE; ++II) {
349 const Instruction &I = *II;
350 std::cout<< "Instr = "<<I;
351 for (unsigned op = 0, E = I.getNumOperands(); op != E; ++op) {
352 const Value *Op = I.getOperand(op);
353 std::cout<< "\top = "<<Op<<"("<<op<<")"<<std::endl;
354 //I->setOperand(op, V);
355 }
356 }
357 }
358 }
359
360 llvm::Value * InstructionsSoa::allocaTemp()
361 {
362 VectorType *vector = VectorType::get(Type::FloatTy, 4);
363 ArrayType *vecArray = ArrayType::get(vector, 4);
364 AllocaInst *alloca = new AllocaInst(vecArray, name("tmpRes"),
365 m_builder.GetInsertBlock());
366
367 std::vector<Value*> indices;
368 indices.push_back(m_storage->constantInt(0));
369 indices.push_back(m_storage->constantInt(0));
370 GetElementPtrInst *getElem = GetElementPtrInst::Create(alloca,
371 indices.begin(),
372 indices.end(),
373 name("allocaPtr"),
374 m_builder.GetInsertBlock());
375 return getElem;
376 }
377
378 std::vector<llvm::Value*> InstructionsSoa::allocaToResult(llvm::Value *allocaPtr)
379 {
380 GetElementPtrInst *xElemPtr = GetElementPtrInst::Create(allocaPtr,
381 m_storage->constantInt(0),
382 name("xPtr"),
383 m_builder.GetInsertBlock());
384 GetElementPtrInst *yElemPtr = GetElementPtrInst::Create(allocaPtr,
385 m_storage->constantInt(1),
386 name("yPtr"),
387 m_builder.GetInsertBlock());
388 GetElementPtrInst *zElemPtr = GetElementPtrInst::Create(allocaPtr,
389 m_storage->constantInt(2),
390 name("zPtr"),
391 m_builder.GetInsertBlock());
392 GetElementPtrInst *wElemPtr = GetElementPtrInst::Create(allocaPtr,
393 m_storage->constantInt(3),
394 name("wPtr"),
395 m_builder.GetInsertBlock());
396
397 std::vector<llvm::Value*> res(4);
398 res[0] = new LoadInst(xElemPtr, name("xRes"), false, m_builder.GetInsertBlock());
399 res[1] = new LoadInst(yElemPtr, name("yRes"), false, m_builder.GetInsertBlock());
400 res[2] = new LoadInst(zElemPtr, name("zRes"), false, m_builder.GetInsertBlock());
401 res[3] = new LoadInst(wElemPtr, name("wRes"), false, m_builder.GetInsertBlock());
402
403 return res;
404 }
405
406 std::vector<llvm::Value*> InstructionsSoa::dp4(const std::vector<llvm::Value*> in1,
407 const std::vector<llvm::Value*> in2)
408 {
409 llvm::Function *func = function(TGSI_OPCODE_DP4);
410 return callBuiltin(func, in1, in2);
411 }
412
413 std::vector<Value*> InstructionsSoa::callBuiltin(llvm::Function *func, const std::vector<llvm::Value*> in1)
414 {
415 std::vector<Value*> params;
416
417 llvm::Value *allocaPtr = allocaTemp();
418 params.push_back(allocaPtr);
419 params.push_back(in1[0]);
420 params.push_back(in1[1]);
421 params.push_back(in1[2]);
422 params.push_back(in1[3]);
423 CallInst *call = m_builder.CreateCall(func, params.begin(), params.end());
424 call->setCallingConv(CallingConv::C);
425 call->setTailCall(false);
426
427 return allocaToResult(allocaPtr);
428 }
429
430 std::vector<Value*> InstructionsSoa::callBuiltin(llvm::Function *func, const std::vector<llvm::Value*> in1,
431 const std::vector<llvm::Value*> in2)
432 {
433 std::vector<Value*> params;
434
435 llvm::Value *allocaPtr = allocaTemp();
436 params.push_back(allocaPtr);
437 params.push_back(in1[0]);
438 params.push_back(in1[1]);
439 params.push_back(in1[2]);
440 params.push_back(in1[3]);
441 params.push_back(in2[0]);
442 params.push_back(in2[1]);
443 params.push_back(in2[2]);
444 params.push_back(in2[3]);
445 CallInst *call = m_builder.CreateCall(func, params.begin(), params.end());
446 call->setCallingConv(CallingConv::C);
447 call->setTailCall(false);
448
449 return allocaToResult(allocaPtr);
450 }
451
452 std::vector<Value*> InstructionsSoa::callBuiltin(llvm::Function *func, const std::vector<llvm::Value*> in1,
453 const std::vector<llvm::Value*> in2,
454 const std::vector<llvm::Value*> in3)
455 {
456 std::vector<Value*> params;
457
458 llvm::Value *allocaPtr = allocaTemp();
459 params.push_back(allocaPtr);
460 params.push_back(in1[0]);
461 params.push_back(in1[1]);
462 params.push_back(in1[2]);
463 params.push_back(in1[3]);
464 params.push_back(in2[0]);
465 params.push_back(in2[1]);
466 params.push_back(in2[2]);
467 params.push_back(in2[3]);
468 params.push_back(in3[0]);
469 params.push_back(in3[1]);
470 params.push_back(in3[2]);
471 params.push_back(in3[3]);
472 CallInst *call = m_builder.CreateCall(func, params.begin(), params.end());
473 call->setCallingConv(CallingConv::C);
474 call->setTailCall(false);
475
476 return allocaToResult(allocaPtr);
477 }
478
479 void InstructionsSoa::injectFunction(llvm::Function *originalFunc, int op)
480 {
481 assert(originalFunc);
482 std::cout << "injecting function originalFunc " <<originalFunc->getName() <<std::endl;
483 if (op != TGSI_OPCODE_LAST) {
484 /* in this case it's possible the function has been already
485 * injected as part of the dependency chain, which gets
486 * injected below */
487 llvm::Function *func = currentModule()->getFunction(originalFunc->getName());
488 if (func) {
489 m_functions[op] = func;
490 return;
491 }
492 }
493 llvm::Function *func = 0;
494 if (originalFunc->isDeclaration()) {
495 func = Function::Create(originalFunc->getFunctionType(), GlobalValue::ExternalLinkage,
496 originalFunc->getName(), currentModule());
497 func->setCallingConv(CallingConv::C);
498 const AttrListPtr pal;
499 func->setAttributes(pal);
500 currentModule()->dump();
501 } else {
502 DenseMap<const Value*, Value *> val;
503 val[m_builtins->getFunction("fabsf")] = currentModule()->getFunction("fabsf");
504 val[m_builtins->getFunction("powf")] = currentModule()->getFunction("powf");
505 val[m_builtins->getFunction("sqrtf")] = currentModule()->getFunction("sqrtf");
506 func = CloneFunction(originalFunc, val);
507 #if 0
508 std::cout <<" replacing "<<m_builtins->getFunction("powf")
509 <<", with " <<currentModule()->getFunction("powf")<<std::endl;
510 std::cout<<"1111-------------------------------"<<std::endl;
511 checkFunction(originalFunc);
512 std::cout<<"2222-------------------------------"<<std::endl;
513 checkFunction(func);
514 std::cout <<"XXXX = " <<val[m_builtins->getFunction("powf")]<<std::endl;
515 #endif
516 currentModule()->getFunctionList().push_back(func);
517 }
518 if (op != TGSI_OPCODE_LAST) {
519 m_functions[op] = func;
520 }
521 }
522
523