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
[0]; vals
[2] = vec
[0]; vals
[3] = vec
[0];
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 std::vector
<llvm::Value
*> StorageSoa::constElement(llvm::Value
*idx
)
149 std::vector
<llvm::Value
*> res(4);
150 llvm::Value
*xChannel
, *yChannel
, *zChannel
, *wChannel
;
152 xChannel
= elementPointer(m_consts
, idx
, 0);
153 yChannel
= elementPointer(m_consts
, idx
, 1);
154 zChannel
= elementPointer(m_consts
, idx
, 2);
155 wChannel
= elementPointer(m_consts
, idx
, 3);
157 res
[0] = alignedArrayLoad(xChannel
);
158 res
[1] = alignedArrayLoad(yChannel
);
159 res
[2] = alignedArrayLoad(zChannel
);
160 res
[3] = alignedArrayLoad(wChannel
);
165 std::vector
<llvm::Value
*> StorageSoa::outputElement(llvm::Value
*idx
)
167 std::vector
<llvm::Value
*> res(4);
169 res
[0] = element(m_output
, idx
, 0);
170 res
[1] = element(m_output
, idx
, 1);
171 res
[2] = element(m_output
, idx
, 2);
172 res
[3] = element(m_output
, idx
, 3);
177 std::vector
<llvm::Value
*> StorageSoa::tempElement(llvm::Value
*idx
)
179 std::vector
<llvm::Value
*> res(4);
181 res
[0] = element(m_temps
, idx
, 0);
182 res
[1] = element(m_temps
, idx
, 1);
183 res
[2] = element(m_temps
, idx
, 2);
184 res
[3] = element(m_temps
, idx
, 3);
189 std::vector
<llvm::Value
*> StorageSoa::immediateElement(llvm::Value
*idx
)
191 std::vector
<llvm::Value
*> res(4);
193 res
[0] = element(m_immediates
, idx
, 0);
194 res
[1] = element(m_immediates
, idx
, 1);
195 res
[2] = element(m_immediates
, idx
, 2);
196 res
[3] = element(m_immediates
, idx
, 3);
201 llvm::Value
* StorageSoa::elementPointer(llvm::Value
*ptr
, llvm::Value
*index
,
204 std::vector
<Value
*> indices
;
205 if (m_immediates
== ptr
)
206 indices
.push_back(constantInt(0));
207 indices
.push_back(index
);
208 indices
.push_back(constantInt(channel
));
210 GetElementPtrInst
*getElem
= GetElementPtrInst::Create(ptr
,
218 llvm::Value
* StorageSoa::element(llvm::Value
*ptr
, llvm::Value
*index
,
221 llvm::Value
*res
= elementPointer(ptr
, index
, channel
);
222 LoadInst
*load
= new LoadInst(res
, name("element"), false, m_block
);
223 //load->setAlignment(8);
227 const char * StorageSoa::name(const char *prefix
) const
230 snprintf(m_name
, 32, "%s%d", prefix
, m_idx
);
234 llvm::ConstantInt
* StorageSoa::constantInt(int idx
) const
236 if (m_constInts
.find(idx
) != m_constInts
.end()) {
237 return m_constInts
[idx
];
239 ConstantInt
*constInt
= ConstantInt::get(APInt(32, idx
));
240 m_constInts
[idx
] = constInt
;
244 llvm::Value
*StorageSoa::alignedArrayLoad(llvm::Value
*val
)
246 VectorType
*vectorType
= VectorType::get(Type::FloatTy
, 4);
247 PointerType
*vectorPtr
= PointerType::get(vectorType
, 0);
249 CastInst
*cast
= new BitCastInst(val
, vectorPtr
, name("toVector"), m_block
);
250 LoadInst
*load
= new LoadInst(cast
, name("alignLoad"), false, m_block
);
251 load
->setAlignment(8);
255 llvm::Module
* StorageSoa::currentModule() const
257 if (!m_block
|| !m_block
->getParent())
260 return m_block
->getParent()->getParent();
263 llvm::Constant
* StorageSoa::createConstGlobalVector(const std::vector
<float> &vec
)
265 VectorType
*vectorType
= VectorType::get(Type::FloatTy
, 4);
266 std::vector
<Constant
*> immValues
;
267 ConstantFP
*constx
= ConstantFP::get(APFloat(vec
[0]));
268 ConstantFP
*consty
= ConstantFP::get(APFloat(vec
[1]));
269 ConstantFP
*constz
= ConstantFP::get(APFloat(vec
[2]));
270 ConstantFP
*constw
= ConstantFP::get(APFloat(vec
[3]));
271 immValues
.push_back(constx
);
272 immValues
.push_back(consty
);
273 immValues
.push_back(constz
);
274 immValues
.push_back(constw
);
275 Constant
*constVector
= ConstantVector::get(vectorType
, immValues
);
280 std::vector
<llvm::Value
*> StorageSoa::load(enum tgsi_file_type type
, int idx
, int swizzle
,
283 std::vector
<llvm::Value
*> val(4);
285 //if we have an indirect index, always use that
286 // if not use the integer offset to create one
287 llvm::Value
*realIndex
= 0;
291 realIndex
= constantInt(idx
);
292 debug_printf("XXXXXXXXX realIdx = %p, indIdx = %p\n", realIndex
, indIdx
);
295 case TGSI_FILE_INPUT
:
296 val
= inputElement(realIndex
);
298 case TGSI_FILE_OUTPUT
:
299 val
= outputElement(realIndex
);
301 case TGSI_FILE_TEMPORARY
:
302 val
= tempElement(realIndex
);
304 case TGSI_FILE_CONSTANT
:
305 val
= constElement(realIndex
);
307 case TGSI_FILE_IMMEDIATE
:
308 val
= immediateElement(realIndex
);
310 case TGSI_FILE_ADDRESS
:
311 debug_printf("Address not handled in the load phase!\n");
315 debug_printf("Unknown load!\n");
319 if (!gallivm_is_swizzle(swizzle
))
322 std::vector
<llvm::Value
*> res(4);
324 res
[0] = val
[gallivm_x_swizzle(swizzle
)];
325 res
[1] = val
[gallivm_y_swizzle(swizzle
)];
326 res
[2] = val
[gallivm_z_swizzle(swizzle
)];
327 res
[3] = val
[gallivm_w_swizzle(swizzle
)];
331 void StorageSoa::store(enum tgsi_file_type type
, int idx
, const std::vector
<llvm::Value
*> &val
,
334 llvm::Value
*out
= 0;
336 case TGSI_FILE_OUTPUT
:
339 case TGSI_FILE_TEMPORARY
:
342 case TGSI_FILE_INPUT
:
345 case TGSI_FILE_ADDRESS
: {
346 llvm::Value
*addr
= m_addresses
[idx
];
349 addr
= m_addresses
[idx
];
352 new StoreInst(val
[0], addr
, false, m_block
);
357 debug_printf("Can't save output of this type: %d !\n", type
);
361 llvm::Value
*realIndex
= constantInt(idx
);
362 if ((mask
& TGSI_WRITEMASK_X
)) {
363 llvm::Value
*xChannel
= elementPointer(out
, realIndex
, 0);
364 new StoreInst(val
[0], xChannel
, false, m_block
);
366 if ((mask
& TGSI_WRITEMASK_Y
)) {
367 llvm::Value
*yChannel
= elementPointer(out
, realIndex
, 1);
368 new StoreInst(val
[1], yChannel
, false, m_block
);
370 if ((mask
& TGSI_WRITEMASK_Z
)) {
371 llvm::Value
*zChannel
= elementPointer(out
, realIndex
, 2);
372 new StoreInst(val
[2], zChannel
, false, m_block
);
374 if ((mask
& TGSI_WRITEMASK_W
)) {
375 llvm::Value
*wChannel
= elementPointer(out
, realIndex
, 3);
376 new StoreInst(val
[3], wChannel
, false, m_block
);
380 void StorageSoa::addAddress(int idx
)
382 GlobalVariable
*val
= new GlobalVariable(
383 /*Type=*/IntegerType::get(32),
384 /*isConstant=*/false,
385 /*Linkage=*/GlobalValue::ExternalLinkage
,
386 /*Initializer=*/0, // has initializer, specified below
387 /*Name=*/name("address"),
389 val
->setInitializer(Constant::getNullValue(IntegerType::get(32)));
391 debug_printf("adding to %d\n", idx
);
392 m_addresses
[idx
] = val
;