1 /**************************************************************************
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
27 #include "instructionssoa.h"
29 #include "storagesoa.h"
31 #include "pipe/p_shader_tokens.h"
32 #include "util/u_memory.h"
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>
48 /* disable some warnings. this file is autogenerated */
50 #pragma GCC diagnostic ignored "-Wunused-variable"
53 #include "gallivmsoabuiltins.cpp"
55 #pragma GCC diagnostic warning "-Wunused-variable"
58 InstructionsSoa::InstructionsSoa(llvm::Module
*mod
, llvm::Function
*func
,
59 llvm::BasicBlock
*block
, StorageSoa
*storage
)
68 const char * InstructionsSoa::name(const char *prefix
) const
71 snprintf(m_name
, 32, "%s%d", prefix
, m_idx
);
75 llvm::Value
* InstructionsSoa::vectorFromVals(llvm::Value
*x
, llvm::Value
*y
,
76 llvm::Value
*z
, llvm::Value
*w
)
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),
83 res
= m_builder
.CreateInsertElement(res
, y
, m_storage
->constantInt(1),
85 res
= m_builder
.CreateInsertElement(res
, z
, m_storage
->constantInt(2),
88 res
= m_builder
.CreateInsertElement(res
, w
, m_storage
->constantInt(3),
93 void InstructionsSoa::end()
95 m_builder
.CreateRetVoid();
98 std::vector
<llvm::Value
*> InstructionsSoa::extractVector(llvm::Value
*vector
)
100 std::vector
<llvm::Value
*> res(4);
101 res
[0] = m_builder
.CreateExtractElement(vector
,
102 m_storage
->constantInt(0),
104 res
[1] = m_builder
.CreateExtractElement(vector
,
105 m_storage
->constantInt(1),
107 res
[2] = m_builder
.CreateExtractElement(vector
,
108 m_storage
->constantInt(2),
110 res
[3] = m_builder
.CreateExtractElement(vector
,
111 m_storage
->constantInt(3),
117 llvm::IRBuilder
<>* InstructionsSoa::getIRBuilder()
122 void InstructionsSoa::createFunctionMap()
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";
135 void InstructionsSoa::createDependencies()
138 std::vector
<std::string
> powDeps(2);
140 powDeps
[1] = "powvec";
141 m_builtinDependencies
["pow"] = powDeps
;
144 std::vector
<std::string
> absDeps(2);
145 absDeps
[0] = "fabsf";
146 absDeps
[1] = "absvec";
147 m_builtinDependencies
["abs"] = absDeps
;
150 std::vector
<std::string
> maxDeps(1);
151 maxDeps
[0] = "maxvec";
152 m_builtinDependencies
["max"] = maxDeps
;
155 std::vector
<std::string
> minDeps(1);
156 minDeps
[0] = "minvec";
157 m_builtinDependencies
["min"] = minDeps
;
160 std::vector
<std::string
> litDeps(4);
161 litDeps
[0] = "minvec";
162 litDeps
[1] = "maxvec";
164 litDeps
[3] = "powvec";
165 m_builtinDependencies
["lit"] = litDeps
;
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
;
177 llvm::Function
* InstructionsSoa::function(int op
)
179 if (m_functions
.find(op
) != m_functions
.end())
180 return m_functions
[op
];
182 std::string name
= m_functionsMap
[op
];
184 std::cout
<<"For op = "<<op
<<", func is '"<<name
<<"'"<<std::endl
;
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
);
193 llvm::Function
*originalFunc
= m_builtins
->getFunction(name
);
194 injectFunction(originalFunc
, op
);
195 return m_functions
[op
];
198 llvm::Module
* InstructionsSoa::currentModule() const
200 BasicBlock
*block
= m_builder
.GetInsertBlock();
201 if (!block
|| !block
->getParent())
204 return block
->getParent()->getParent();
207 void InstructionsSoa::createBuiltins()
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
;
216 createDependencies();
220 std::vector
<llvm::Value
*> InstructionsSoa::abs(const std::vector
<llvm::Value
*> in1
)
222 llvm::Function
*func
= function(TGSI_OPCODE_ABS
);
223 return callBuiltin(func
, in1
);
226 std::vector
<llvm::Value
*> InstructionsSoa::add(const std::vector
<llvm::Value
*> in1
,
227 const std::vector
<llvm::Value
*> in2
)
229 std::vector
<llvm::Value
*> res(4);
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"));
239 std::vector
<llvm::Value
*> InstructionsSoa::arl(const std::vector
<llvm::Value
*> in
)
241 std::vector
<llvm::Value
*> res(4);
244 llvm::Value
*x1
= m_builder
.CreateExtractElement(in
[0],
245 m_storage
->constantInt(0),
247 //cast it to an unsigned int
248 x1
= m_builder
.CreateFPToUI(x1
, IntegerType::get(32), name("x1IntCast"));
250 res
[0] = x1
;//vectorFromVals(x1, x2, x3, x4);
251 //only x is valid. the others shouldn't be necessary
253 res[1] = Constant::getNullValue(m_floatVecType);
254 res[2] = Constant::getNullValue(m_floatVecType);
255 res[3] = Constant::getNullValue(m_floatVecType);
261 std::vector
<llvm::Value
*> InstructionsSoa::dp3(const std::vector
<llvm::Value
*> in1
,
262 const std::vector
<llvm::Value
*> in2
)
264 llvm::Function
*func
= function(TGSI_OPCODE_DP3
);
265 return callBuiltin(func
, in1
, in2
);
268 std::vector
<llvm::Value
*> InstructionsSoa::lit(const std::vector
<llvm::Value
*> in
)
270 llvm::Function
*func
= function(TGSI_OPCODE_LIT
);
271 return callBuiltin(func
, in
);
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
)
278 std::vector
<llvm::Value
*> res
= mul(in1
, in2
);
279 return add(res
, in3
);
282 std::vector
<llvm::Value
*> InstructionsSoa::max(const std::vector
<llvm::Value
*> in1
,
283 const std::vector
<llvm::Value
*> in2
)
285 llvm::Function
*func
= function(TGSI_OPCODE_MAX
);
286 return callBuiltin(func
, in1
, in2
);
289 std::vector
<llvm::Value
*> InstructionsSoa::min(const std::vector
<llvm::Value
*> in1
,
290 const std::vector
<llvm::Value
*> in2
)
292 llvm::Function
*func
= function(TGSI_OPCODE_MIN
);
293 return callBuiltin(func
, in1
, in2
);
296 std::vector
<llvm::Value
*> InstructionsSoa::mul(const std::vector
<llvm::Value
*> in1
,
297 const std::vector
<llvm::Value
*> in2
)
299 std::vector
<llvm::Value
*> res(4);
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"));
309 std::vector
<llvm::Value
*> InstructionsSoa::pow(const std::vector
<llvm::Value
*> in1
,
310 const std::vector
<llvm::Value
*> in2
)
312 llvm::Function
*func
= function(TGSI_OPCODE_POWER
);
313 return callBuiltin(func
, in1
, in2
);
316 std::vector
<llvm::Value
*> InstructionsSoa::rsq(const std::vector
<llvm::Value
*> in
)
318 llvm::Function
*func
= function(TGSI_OPCODE_RSQ
);
319 return callBuiltin(func
, in
);
322 std::vector
<llvm::Value
*> InstructionsSoa::slt(const std::vector
<llvm::Value
*> in1
,
323 const std::vector
<llvm::Value
*> in2
)
325 llvm::Function
*func
= function(TGSI_OPCODE_SLT
);
326 return callBuiltin(func
, in1
, in2
);
329 std::vector
<llvm::Value
*> InstructionsSoa::sub(const std::vector
<llvm::Value
*> in1
,
330 const std::vector
<llvm::Value
*> in2
)
332 std::vector
<llvm::Value
*> res(4);
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"));
342 void checkFunction(Function
*func
)
344 for (Function::const_iterator BI
= func
->begin(), BE
= func
->end();
346 const BasicBlock
&BB
= *BI
;
347 for (BasicBlock::const_iterator II
= BB
.begin(), IE
= BB
.end();
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);
360 llvm::Value
* InstructionsSoa::allocaTemp()
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());
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
,
374 m_builder
.GetInsertBlock());
378 std::vector
<llvm::Value
*> InstructionsSoa::allocaToResult(llvm::Value
*allocaPtr
)
380 GetElementPtrInst
*xElemPtr
= GetElementPtrInst::Create(allocaPtr
,
381 m_storage
->constantInt(0),
383 m_builder
.GetInsertBlock());
384 GetElementPtrInst
*yElemPtr
= GetElementPtrInst::Create(allocaPtr
,
385 m_storage
->constantInt(1),
387 m_builder
.GetInsertBlock());
388 GetElementPtrInst
*zElemPtr
= GetElementPtrInst::Create(allocaPtr
,
389 m_storage
->constantInt(2),
391 m_builder
.GetInsertBlock());
392 GetElementPtrInst
*wElemPtr
= GetElementPtrInst::Create(allocaPtr
,
393 m_storage
->constantInt(3),
395 m_builder
.GetInsertBlock());
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());
406 std::vector
<llvm::Value
*> InstructionsSoa::dp4(const std::vector
<llvm::Value
*> in1
,
407 const std::vector
<llvm::Value
*> in2
)
409 llvm::Function
*func
= function(TGSI_OPCODE_DP4
);
410 return callBuiltin(func
, in1
, in2
);
413 std::vector
<Value
*> InstructionsSoa::callBuiltin(llvm::Function
*func
, const std::vector
<llvm::Value
*> in1
)
415 std::vector
<Value
*> params
;
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);
427 return allocaToResult(allocaPtr
);
430 std::vector
<Value
*> InstructionsSoa::callBuiltin(llvm::Function
*func
, const std::vector
<llvm::Value
*> in1
,
431 const std::vector
<llvm::Value
*> in2
)
433 std::vector
<Value
*> params
;
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);
449 return allocaToResult(allocaPtr
);
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
)
456 std::vector
<Value
*> params
;
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);
476 return allocaToResult(allocaPtr
);
479 void InstructionsSoa::injectFunction(llvm::Function
*originalFunc
, int op
)
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
487 llvm::Function
*func
= currentModule()->getFunction(originalFunc
->getName());
489 m_functions
[op
] = func
;
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();
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
);
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
;
514 std::cout
<<"XXXX = " <<val
[m_builtins
->getFunction("powf")]<<std::endl
;
516 currentModule()->getFunctionList().push_back(func
);
518 if (op
!= TGSI_OPCODE_LAST
) {
519 m_functions
[op
] = func
;