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