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 **************************************************************************/
28 #include "storagesoa.h"
30 #include "gallivm_p.h"
32 #include "pipe/p_shader_tokens.h"
33 #include "pipe/p_debug.h"
35 #include <llvm/BasicBlock.h>
36 #include <llvm/Module.h>
37 #include <llvm/Value.h>
39 #include <llvm/CallingConv.h>
40 #include <llvm/Constants.h>
41 #include <llvm/DerivedTypes.h>
42 #include <llvm/InstrTypes.h>
43 #include <llvm/Instructions.h>
48 StorageSoa::StorageSoa(llvm::BasicBlock
*block
,
63 void StorageSoa::addImmediate(float *vec
)
65 std::vector
<float> vals(4);
70 m_immediatesToFlush
.push_back(vals
);
73 void StorageSoa::declareImmediates()
75 if (m_immediatesToFlush
.empty())
78 VectorType
*vectorType
= VectorType::get(Type::FloatTy
, 4);
79 ArrayType
*vectorChannels
= ArrayType::get(vectorType
, 4);
80 ArrayType
*arrayType
= ArrayType::get(vectorChannels
, m_immediatesToFlush
.size());
82 m_immediates
= new GlobalVariable(
85 /*Linkage=*/GlobalValue::ExternalLinkage
,
86 /*Initializer=*/0, // has initializer, specified below
87 /*Name=*/name("immediates"),
90 std::vector
<Constant
*> arrayVals
;
91 for (unsigned int i
= 0; i
< m_immediatesToFlush
.size(); ++i
) {
92 std::vector
<float> vec
= m_immediatesToFlush
[i
];
93 std::vector
<float> vals(4);
94 std::vector
<Constant
*> channelArray
;
96 vals
[0] = vec
[0]; vals
[1] = vec
[1]; vals
[2] = vec
[2]; vals
[3] = vec
[3];
97 llvm::Constant
*xChannel
= createConstGlobalVector(vals
);
99 vals
[0] = vec
[1]; vals
[1] = vec
[1]; vals
[2] = vec
[1]; vals
[3] = vec
[1];
100 llvm::Constant
*yChannel
= createConstGlobalVector(vals
);
102 vals
[0] = vec
[2]; vals
[1] = vec
[2]; vals
[2] = vec
[2]; vals
[3] = vec
[2];
103 llvm::Constant
*zChannel
= createConstGlobalVector(vals
);
105 vals
[0] = vec
[3]; vals
[1] = vec
[3]; vals
[2] = vec
[3]; vals
[3] = vec
[3];
106 llvm::Constant
*wChannel
= createConstGlobalVector(vals
);
107 channelArray
.push_back(xChannel
);
108 channelArray
.push_back(yChannel
);
109 channelArray
.push_back(zChannel
);
110 channelArray
.push_back(wChannel
);
111 Constant
*constChannels
= ConstantArray::get(vectorChannels
,
113 arrayVals
.push_back(constChannels
);
115 Constant
*constArray
= ConstantArray::get(arrayType
, arrayVals
);
116 m_immediates
->setInitializer(constArray
);
118 m_immediatesToFlush
.clear();
121 llvm::Value
*StorageSoa::addrElement(int idx
) const
123 std::map
<int, llvm::Value
*>::const_iterator itr
= m_addresses
.find(idx
);
124 if (itr
== m_addresses
.end()) {
125 debug_printf("Trying to access invalid shader 'address'\n");
128 llvm::Value
* res
= (*itr
).second
;
130 res
= new LoadInst(res
, name("addr"), false, m_block
);
135 std::vector
<llvm::Value
*> StorageSoa::inputElement(llvm::Value
*idx
)
137 std::vector
<llvm::Value
*> res(4);
139 res
[0] = element(m_input
, idx
, 0);
140 res
[1] = element(m_input
, idx
, 1);
141 res
[2] = element(m_input
, idx
, 2);
142 res
[3] = element(m_input
, idx
, 3);
147 llvm::Value
* StorageSoa::unpackConstElement(llvm::IRBuilder
<>* m_builder
, llvm::Value
* vector
, int cc
)
149 std::vector
<llvm::Value
*> x(4);
150 x
[0] = m_builder
->CreateExtractElement(vector
,
154 VectorType
*vectorType
= VectorType::get(Type::FloatTy
, 4);
155 Constant
*constVector
= Constant::getNullValue(vectorType
);
156 Value
*res
= m_builder
->CreateInsertElement(constVector
, x
[0],
159 res
= m_builder
->CreateInsertElement(res
, x
[0], constantInt(1),
161 res
= m_builder
->CreateInsertElement(res
, x
[0], constantInt(2),
163 res
= m_builder
->CreateInsertElement(res
, x
[0], constantInt(3),
168 std::vector
<llvm::Value
*> StorageSoa::constElement(llvm::IRBuilder
<>* m_builder
, llvm::Value
*idx
)
171 std::vector
<llvm::Value
*> res2(4);
172 llvm::Value
*xChannel
, *yChannel
, *zChannel
, *wChannel
;
174 xChannel
= elementPointer(m_consts
, idx
, 0);
176 res
= alignedArrayLoad(xChannel
);
178 res2
[0]=unpackConstElement(m_builder
, res
,0);
179 res2
[1]=unpackConstElement(m_builder
, res
,1);
180 res2
[2]=unpackConstElement(m_builder
, res
,2);
181 res2
[3]=unpackConstElement(m_builder
, res
,3);
186 std::vector
<llvm::Value
*> StorageSoa::outputElement(llvm::Value
*idx
)
188 std::vector
<llvm::Value
*> res(4);
190 res
[0] = element(m_output
, idx
, 0);
191 res
[1] = element(m_output
, idx
, 1);
192 res
[2] = element(m_output
, idx
, 2);
193 res
[3] = element(m_output
, idx
, 3);
198 std::vector
<llvm::Value
*> StorageSoa::tempElement(llvm::Value
*idx
)
200 std::vector
<llvm::Value
*> res(4);
202 res
[0] = element(m_temps
, idx
, 0);
203 res
[1] = element(m_temps
, idx
, 1);
204 res
[2] = element(m_temps
, idx
, 2);
205 res
[3] = element(m_temps
, idx
, 3);
210 std::vector
<llvm::Value
*> StorageSoa::immediateElement(llvm::Value
*idx
)
212 std::vector
<llvm::Value
*> res(4);
214 res
[0] = element(m_immediates
, idx
, 0);
215 res
[1] = element(m_immediates
, idx
, 1);
216 res
[2] = element(m_immediates
, idx
, 2);
217 res
[3] = element(m_immediates
, idx
, 3);
222 llvm::Value
* StorageSoa::elementPointer(llvm::Value
*ptr
, llvm::Value
*index
,
225 std::vector
<Value
*> indices
;
226 if (m_immediates
== ptr
)
227 indices
.push_back(constantInt(0));
228 indices
.push_back(index
);
229 indices
.push_back(constantInt(channel
));
231 GetElementPtrInst
*getElem
= GetElementPtrInst::Create(ptr
,
239 llvm::Value
* StorageSoa::element(llvm::Value
*ptr
, llvm::Value
*index
,
242 llvm::Value
*res
= elementPointer(ptr
, index
, channel
);
243 LoadInst
*load
= new LoadInst(res
, name("element"), false, m_block
);
244 //load->setAlignment(8);
248 const char * StorageSoa::name(const char *prefix
) const
251 snprintf(m_name
, 32, "%s%d", prefix
, m_idx
);
255 llvm::ConstantInt
* StorageSoa::constantInt(int idx
) const
257 if (m_constInts
.find(idx
) != m_constInts
.end()) {
258 return m_constInts
[idx
];
260 ConstantInt
*constInt
= ConstantInt::get(APInt(32, idx
));
261 m_constInts
[idx
] = constInt
;
265 llvm::Value
*StorageSoa::alignedArrayLoad(llvm::Value
*val
)
267 VectorType
*vectorType
= VectorType::get(Type::FloatTy
, 4);
268 PointerType
*vectorPtr
= PointerType::get(vectorType
, 0);
270 CastInst
*cast
= new BitCastInst(val
, vectorPtr
, name("toVector"), m_block
);
271 LoadInst
*load
= new LoadInst(cast
, name("alignLoad"), false, m_block
);
272 load
->setAlignment(8);
276 llvm::Module
* StorageSoa::currentModule() const
278 if (!m_block
|| !m_block
->getParent())
281 return m_block
->getParent()->getParent();
284 llvm::Constant
* StorageSoa::createConstGlobalFloat(const float val
)
286 Constant
*c
= ConstantFP::get(APFloat(val
));
290 llvm::Constant
* StorageSoa::createConstGlobalVector(const std::vector
<float> &vec
)
292 VectorType
*vectorType
= VectorType::get(Type::FloatTy
, 4);
293 std::vector
<Constant
*> immValues
;
294 ConstantFP
*constx
= ConstantFP::get(APFloat(vec
[0]));
295 ConstantFP
*consty
= ConstantFP::get(APFloat(vec
[1]));
296 ConstantFP
*constz
= ConstantFP::get(APFloat(vec
[2]));
297 ConstantFP
*constw
= ConstantFP::get(APFloat(vec
[3]));
298 immValues
.push_back(constx
);
299 immValues
.push_back(consty
);
300 immValues
.push_back(constz
);
301 immValues
.push_back(constw
);
302 Constant
*constVector
= ConstantVector::get(vectorType
, immValues
);
307 std::vector
<llvm::Value
*> StorageSoa::load(enum tgsi_file_type type
, int idx
, int swizzle
,
308 llvm::IRBuilder
<>* m_builder
,llvm::Value
*indIdx
)
310 std::vector
<llvm::Value
*> val(4);
312 //if we have an indirect index, always use that
313 // if not use the integer offset to create one
314 llvm::Value
*realIndex
= 0;
318 realIndex
= constantInt(idx
);
319 debug_printf("XXXXXXXXX realIdx = %p, indIdx = %p\n", realIndex
, indIdx
);
322 case TGSI_FILE_INPUT
:
323 val
= inputElement(realIndex
);
325 case TGSI_FILE_OUTPUT
:
326 val
= outputElement(realIndex
);
328 case TGSI_FILE_TEMPORARY
:
329 val
= tempElement(realIndex
);
331 case TGSI_FILE_CONSTANT
:
332 val
= constElement(m_builder
, realIndex
);
334 case TGSI_FILE_IMMEDIATE
:
335 val
= immediateElement(realIndex
);
337 case TGSI_FILE_ADDRESS
:
338 debug_printf("Address not handled in the load phase!\n");
342 debug_printf("Unknown load!\n");
346 if (!gallivm_is_swizzle(swizzle
))
349 std::vector
<llvm::Value
*> res(4);
351 res
[0] = val
[gallivm_x_swizzle(swizzle
)];
352 res
[1] = val
[gallivm_y_swizzle(swizzle
)];
353 res
[2] = val
[gallivm_z_swizzle(swizzle
)];
354 res
[3] = val
[gallivm_w_swizzle(swizzle
)];
358 void StorageSoa::store(enum tgsi_file_type type
, int idx
, const std::vector
<llvm::Value
*> &val
,
361 llvm::Value
*out
= 0;
363 case TGSI_FILE_OUTPUT
:
366 case TGSI_FILE_TEMPORARY
:
369 case TGSI_FILE_INPUT
:
372 case TGSI_FILE_ADDRESS
: {
373 llvm::Value
*addr
= m_addresses
[idx
];
376 addr
= m_addresses
[idx
];
379 new StoreInst(val
[0], addr
, false, m_block
);
384 debug_printf("Can't save output of this type: %d !\n", type
);
388 llvm::Value
*realIndex
= constantInt(idx
);
389 if ((mask
& TGSI_WRITEMASK_X
)) {
390 llvm::Value
*xChannel
= elementPointer(out
, realIndex
, 0);
391 new StoreInst(val
[0], xChannel
, false, m_block
);
393 if ((mask
& TGSI_WRITEMASK_Y
)) {
394 llvm::Value
*yChannel
= elementPointer(out
, realIndex
, 1);
395 new StoreInst(val
[1], yChannel
, false, m_block
);
397 if ((mask
& TGSI_WRITEMASK_Z
)) {
398 llvm::Value
*zChannel
= elementPointer(out
, realIndex
, 2);
399 new StoreInst(val
[2], zChannel
, false, m_block
);
401 if ((mask
& TGSI_WRITEMASK_W
)) {
402 llvm::Value
*wChannel
= elementPointer(out
, realIndex
, 3);
403 new StoreInst(val
[3], wChannel
, false, m_block
);
407 void StorageSoa::addAddress(int idx
)
409 GlobalVariable
*val
= new GlobalVariable(
410 /*Type=*/IntegerType::get(32),
411 /*isConstant=*/false,
412 /*Linkage=*/GlobalValue::ExternalLinkage
,
413 /*Initializer=*/0, // has initializer, specified below
414 /*Name=*/name("address"),
416 val
->setInitializer(Constant::getNullValue(IntegerType::get(32)));
418 debug_printf("adding to %d\n", idx
);
419 m_addresses
[idx
] = val
;