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
,
61 void StorageSoa::addImmediate(float *vec
)
63 std::vector
<float> vals(4);
68 m_immediatesToFlush
.push_back(vals
);
71 void StorageSoa::declareImmediates()
73 if (m_immediatesToFlush
.empty())
76 VectorType
*vectorType
= VectorType::get(Type::FloatTy
, 4);
77 ArrayType
*vectorChannels
= ArrayType::get(vectorType
, 4);
78 ArrayType
*arrayType
= ArrayType::get(vectorChannels
, m_immediatesToFlush
.size());
80 m_immediates
= new GlobalVariable(
83 /*Linkage=*/GlobalValue::ExternalLinkage
,
84 /*Initializer=*/0, // has initializer, specified below
85 /*Name=*/name("immediates"),
88 std::vector
<Constant
*> arrayVals
;
89 for (unsigned int i
= 0; i
< m_immediatesToFlush
.size(); ++i
) {
90 std::vector
<float> vec
= m_immediatesToFlush
[i
];
91 std::vector
<float> vals(4);
92 std::vector
<Constant
*> channelArray
;
94 vals
[0] = vec
[0]; vals
[1] = vec
[1]; vals
[2] = vec
[2]; vals
[3] = vec
[3];
95 llvm::Constant
*xChannel
= createConstGlobalVector(vals
);
97 vals
[0] = vec
[1]; vals
[1] = vec
[1]; vals
[2] = vec
[1]; vals
[3] = vec
[1];
98 llvm::Constant
*yChannel
= createConstGlobalVector(vals
);
100 vals
[0] = vec
[2]; vals
[1] = vec
[2]; vals
[2] = vec
[2]; vals
[3] = vec
[2];
101 llvm::Constant
*zChannel
= createConstGlobalVector(vals
);
103 vals
[0] = vec
[3]; vals
[1] = vec
[3]; vals
[2] = vec
[3]; vals
[3] = vec
[3];
104 llvm::Constant
*wChannel
= createConstGlobalVector(vals
);
105 channelArray
.push_back(xChannel
);
106 channelArray
.push_back(yChannel
);
107 channelArray
.push_back(zChannel
);
108 channelArray
.push_back(wChannel
);
109 Constant
*constChannels
= ConstantArray::get(vectorChannels
,
111 arrayVals
.push_back(constChannels
);
113 Constant
*constArray
= ConstantArray::get(arrayType
, arrayVals
);
114 m_immediates
->setInitializer(constArray
);
116 m_immediatesToFlush
.clear();
119 llvm::Value
*StorageSoa::addrElement(int idx
) const
121 std::map
<int, llvm::Value
*>::const_iterator itr
= m_addresses
.find(idx
);
122 if (itr
== m_addresses
.end()) {
123 debug_printf("Trying to access invalid shader 'address'\n");
126 llvm::Value
* res
= (*itr
).second
;
128 res
= new LoadInst(res
, name("addr"), false, m_block
);
133 std::vector
<llvm::Value
*> StorageSoa::inputElement(llvm::Value
*idx
)
135 std::vector
<llvm::Value
*> res(4);
137 res
[0] = element(m_input
, idx
, 0);
138 res
[1] = element(m_input
, idx
, 1);
139 res
[2] = element(m_input
, idx
, 2);
140 res
[3] = element(m_input
, idx
, 3);
145 llvm::Value
* StorageSoa::unpackConstElement(llvm::IRBuilder
<>* m_builder
, llvm::Value
* vector
, int cc
)
147 std::vector
<llvm::Value
*> x(4);
148 x
[0] = m_builder
->CreateExtractElement(vector
,
152 VectorType
*vectorType
= VectorType::get(Type::FloatTy
, 4);
153 Constant
*constVector
= Constant::getNullValue(vectorType
);
154 Value
*res
= m_builder
->CreateInsertElement(constVector
, x
[0],
157 res
= m_builder
->CreateInsertElement(res
, x
[0], constantInt(1),
159 res
= m_builder
->CreateInsertElement(res
, x
[0], constantInt(2),
161 res
= m_builder
->CreateInsertElement(res
, x
[0], constantInt(3),
166 std::vector
<llvm::Value
*> StorageSoa::constElement(llvm::IRBuilder
<>* m_builder
, llvm::Value
*idx
)
169 std::vector
<llvm::Value
*> res2(4);
170 llvm::Value
*xChannel
;
172 xChannel
= elementPointer(m_consts
, idx
, 0);
174 res
= alignedArrayLoad(xChannel
);
176 res2
[0]=unpackConstElement(m_builder
, res
,0);
177 res2
[1]=unpackConstElement(m_builder
, res
,1);
178 res2
[2]=unpackConstElement(m_builder
, res
,2);
179 res2
[3]=unpackConstElement(m_builder
, res
,3);
184 std::vector
<llvm::Value
*> StorageSoa::outputElement(llvm::Value
*idx
)
186 std::vector
<llvm::Value
*> res(4);
188 res
[0] = element(m_output
, idx
, 0);
189 res
[1] = element(m_output
, idx
, 1);
190 res
[2] = element(m_output
, idx
, 2);
191 res
[3] = element(m_output
, idx
, 3);
196 std::vector
<llvm::Value
*> StorageSoa::tempElement(llvm::IRBuilder
<>* m_builder
, int idx
)
198 std::vector
<llvm::Value
*> res(4);
199 llvm::Value
*temp
= m_temps
[idx
];
201 res
[0] = element(temp
, constantInt(0), 0);
202 res
[1] = element(temp
, constantInt(0), 1);
203 res
[2] = element(temp
, constantInt(0), 2);
204 res
[3] = element(temp
, constantInt(0), 3);
209 std::vector
<llvm::Value
*> StorageSoa::immediateElement(llvm::Value
*idx
)
211 std::vector
<llvm::Value
*> res(4);
213 res
[0] = element(m_immediates
, idx
, 0);
214 res
[1] = element(m_immediates
, idx
, 1);
215 res
[2] = element(m_immediates
, idx
, 2);
216 res
[3] = element(m_immediates
, idx
, 3);
221 llvm::Value
* StorageSoa::elementPointer(llvm::Value
*ptr
, llvm::Value
*index
,
224 std::vector
<Value
*> indices
;
225 if (m_immediates
== ptr
)
226 indices
.push_back(constantInt(0));
227 indices
.push_back(index
);
228 indices
.push_back(constantInt(channel
));
230 GetElementPtrInst
*getElem
= GetElementPtrInst::Create(ptr
,
238 llvm::Value
* StorageSoa::element(llvm::Value
*ptr
, llvm::Value
*index
,
241 llvm::Value
*res
= elementPointer(ptr
, index
, channel
);
242 LoadInst
*load
= new LoadInst(res
, name("element"), false, m_block
);
243 //load->setAlignment(8);
247 const char * StorageSoa::name(const char *prefix
) const
250 snprintf(m_name
, 32, "%s%d", prefix
, m_idx
);
254 llvm::ConstantInt
* StorageSoa::constantInt(int idx
) const
256 if (m_constInts
.find(idx
) != m_constInts
.end()) {
257 return m_constInts
[idx
];
259 ConstantInt
*constInt
= ConstantInt::get(APInt(32, idx
));
260 m_constInts
[idx
] = constInt
;
264 llvm::Value
*StorageSoa::alignedArrayLoad(llvm::Value
*val
)
266 VectorType
*vectorType
= VectorType::get(Type::FloatTy
, 4);
267 PointerType
*vectorPtr
= PointerType::get(vectorType
, 0);
269 CastInst
*cast
= new BitCastInst(val
, vectorPtr
, name("toVector"), m_block
);
270 LoadInst
*load
= new LoadInst(cast
, name("alignLoad"), false, m_block
);
271 load
->setAlignment(8);
275 llvm::Module
* StorageSoa::currentModule() const
277 if (!m_block
|| !m_block
->getParent())
280 return m_block
->getParent()->getParent();
283 llvm::Constant
* StorageSoa::createConstGlobalFloat(const float val
)
285 Constant
*c
= ConstantFP::get(APFloat(val
));
289 llvm::Constant
* StorageSoa::createConstGlobalVector(const std::vector
<float> &vec
)
291 VectorType
*vectorType
= VectorType::get(Type::FloatTy
, 4);
292 std::vector
<Constant
*> immValues
;
293 ConstantFP
*constx
= ConstantFP::get(APFloat(vec
[0]));
294 ConstantFP
*consty
= ConstantFP::get(APFloat(vec
[1]));
295 ConstantFP
*constz
= ConstantFP::get(APFloat(vec
[2]));
296 ConstantFP
*constw
= ConstantFP::get(APFloat(vec
[3]));
297 immValues
.push_back(constx
);
298 immValues
.push_back(consty
);
299 immValues
.push_back(constz
);
300 immValues
.push_back(constw
);
301 Constant
*constVector
= ConstantVector::get(vectorType
, immValues
);
306 std::vector
<llvm::Value
*> StorageSoa::load(enum tgsi_file_type type
, int idx
, int swizzle
,
307 llvm::IRBuilder
<>* m_builder
,llvm::Value
*indIdx
)
309 std::vector
<llvm::Value
*> val(4);
311 //if we have an indirect index, always use that
312 // if not use the integer offset to create one
313 llvm::Value
*realIndex
= 0;
317 realIndex
= constantInt(idx
);
318 debug_printf("XXXXXXXXX realIdx = %p, indIdx = %p\n", realIndex
, indIdx
);
321 case TGSI_FILE_INPUT
:
322 val
= inputElement(realIndex
);
324 case TGSI_FILE_OUTPUT
:
325 val
= outputElement(realIndex
);
327 case TGSI_FILE_TEMPORARY
:
328 val
= tempElement(m_builder
, idx
);
330 case TGSI_FILE_CONSTANT
:
331 val
= constElement(m_builder
, realIndex
);
333 case TGSI_FILE_IMMEDIATE
:
334 val
= immediateElement(realIndex
);
336 case TGSI_FILE_ADDRESS
:
337 debug_printf("Address not handled in the load phase!\n");
341 debug_printf("Unknown load!\n");
345 if (!gallivm_is_swizzle(swizzle
))
348 std::vector
<llvm::Value
*> res(4);
350 res
[0] = val
[gallivm_x_swizzle(swizzle
)];
351 res
[1] = val
[gallivm_y_swizzle(swizzle
)];
352 res
[2] = val
[gallivm_z_swizzle(swizzle
)];
353 res
[3] = val
[gallivm_w_swizzle(swizzle
)];
357 llvm::Value
* StorageSoa::allocaTemp(llvm::IRBuilder
<>* m_builder
)
359 VectorType
*vector
= VectorType::get(Type::FloatTy
, 4);
360 ArrayType
*vecArray
= ArrayType::get(vector
, 4);
361 AllocaInst
*alloca
= new AllocaInst(vecArray
, "temp",
362 m_builder
->GetInsertBlock());
368 void StorageSoa::store(enum tgsi_file_type type
, int idx
, const std::vector
<llvm::Value
*> &val
,
369 int mask
, llvm::IRBuilder
<>* m_builder
)
371 llvm::Value
*out
= 0;
372 llvm::Value
*realIndex
= 0;
374 case TGSI_FILE_OUTPUT
:
376 realIndex
= constantInt(idx
);
378 case TGSI_FILE_TEMPORARY
:
379 // if that temp doesn't already exist, alloca it
380 if (m_temps
.find(idx
) == m_temps
.end())
381 m_temps
[idx
] = allocaTemp(m_builder
);
385 realIndex
= constantInt(0);
387 case TGSI_FILE_INPUT
:
389 realIndex
= constantInt(idx
);
391 case TGSI_FILE_ADDRESS
: {
392 llvm::Value
*addr
= m_addresses
[idx
];
395 addr
= m_addresses
[idx
];
398 new StoreInst(val
[0], addr
, false, m_block
);
403 debug_printf("Can't save output of this type: %d !\n", type
);
407 if ((mask
& TGSI_WRITEMASK_X
)) {
408 llvm::Value
*xChannel
= elementPointer(out
, realIndex
, 0);
409 new StoreInst(val
[0], xChannel
, false, m_block
);
411 if ((mask
& TGSI_WRITEMASK_Y
)) {
412 llvm::Value
*yChannel
= elementPointer(out
, realIndex
, 1);
413 new StoreInst(val
[1], yChannel
, false, m_block
);
415 if ((mask
& TGSI_WRITEMASK_Z
)) {
416 llvm::Value
*zChannel
= elementPointer(out
, realIndex
, 2);
417 new StoreInst(val
[2], zChannel
, false, m_block
);
419 if ((mask
& TGSI_WRITEMASK_W
)) {
420 llvm::Value
*wChannel
= elementPointer(out
, realIndex
, 3);
421 new StoreInst(val
[3], wChannel
, false, m_block
);
425 void StorageSoa::addAddress(int idx
)
427 GlobalVariable
*val
= new GlobalVariable(
428 /*Type=*/IntegerType::get(32),
429 /*isConstant=*/false,
430 /*Linkage=*/GlobalValue::ExternalLinkage
,
431 /*Initializer=*/0, // has initializer, specified below
432 /*Name=*/name("address"),
434 val
->setInitializer(Constant::getNullValue(IntegerType::get(32)));
436 debug_printf("adding to %d\n", idx
);
437 m_addresses
[idx
] = val
;