Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / src / gallium / auxiliary / gallivm / storagesoa.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 "storagesoa.h"
29
30 #include "gallivm_p.h"
31
32 #include "pipe/p_shader_tokens.h"
33 #include "pipe/p_debug.h"
34
35 #include <llvm/BasicBlock.h>
36 #include <llvm/Module.h>
37 #include <llvm/Value.h>
38
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>
44
45 using namespace llvm;
46
47
48 StorageSoa::StorageSoa(llvm::BasicBlock *block,
49 llvm::Value *input,
50 llvm::Value *output,
51 llvm::Value *consts,
52 llvm::Value *temps)
53 : m_block(block),
54 m_input(input),
55 m_output(output),
56 m_consts(consts),
57 m_temps(temps),
58 m_immediates(0),
59 m_idx(0)
60 {
61 }
62
63 void StorageSoa::addImmediate(float *vec)
64 {
65 std::vector<float> vals(4);
66 vals[0] = vec[0];
67 vals[1] = vec[1];
68 vals[2] = vec[2];
69 vals[3] = vec[3];
70 m_immediatesToFlush.push_back(vals);
71 }
72
73 void StorageSoa::declareImmediates()
74 {
75 if (m_immediatesToFlush.empty())
76 return;
77
78 VectorType *vectorType = VectorType::get(Type::FloatTy, 4);
79 ArrayType *vectorChannels = ArrayType::get(vectorType, 4);
80 ArrayType *arrayType = ArrayType::get(vectorChannels, m_immediatesToFlush.size());
81
82 m_immediates = new GlobalVariable(
83 /*Type=*/arrayType,
84 /*isConstant=*/false,
85 /*Linkage=*/GlobalValue::ExternalLinkage,
86 /*Initializer=*/0, // has initializer, specified below
87 /*Name=*/name("immediates"),
88 currentModule());
89
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;
95
96 vals[0] = vec[0]; vals[1] = vec[1]; vals[2] = vec[2]; vals[3] = vec[3];
97 llvm::Constant *xChannel = createConstGlobalVector(vals);
98
99 vals[0] = vec[1]; vals[1] = vec[1]; vals[2] = vec[1]; vals[3] = vec[1];
100 llvm::Constant *yChannel = createConstGlobalVector(vals);
101
102 vals[0] = vec[2]; vals[1] = vec[2]; vals[2] = vec[2]; vals[3] = vec[2];
103 llvm::Constant *zChannel = createConstGlobalVector(vals);
104
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,
112 channelArray);
113 arrayVals.push_back(constChannels);
114 }
115 Constant *constArray = ConstantArray::get(arrayType, arrayVals);
116 m_immediates->setInitializer(constArray);
117
118 m_immediatesToFlush.clear();
119 }
120
121 llvm::Value *StorageSoa::addrElement(int idx) const
122 {
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");
126 return 0;
127 }
128 llvm::Value * res = (*itr).second;
129
130 res = new LoadInst(res, name("addr"), false, m_block);
131
132 return res;
133 }
134
135 std::vector<llvm::Value*> StorageSoa::inputElement(llvm::Value *idx)
136 {
137 std::vector<llvm::Value*> res(4);
138
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);
143
144 return res;
145 }
146
147 llvm::Value* StorageSoa::unpackConstElement(llvm::IRBuilder<>* m_builder, llvm::Value* vector, int cc)
148 {
149 std::vector<llvm::Value*> x(4);
150 x[0] = m_builder->CreateExtractElement(vector,
151 constantInt(cc),
152 name("x"));
153
154 VectorType *vectorType = VectorType::get(Type::FloatTy, 4);
155 Constant *constVector = Constant::getNullValue(vectorType);
156 Value *res = m_builder->CreateInsertElement(constVector, x[0],
157 constantInt(0),
158 name("vecx"));
159 res = m_builder->CreateInsertElement(res, x[0], constantInt(1),
160 name("vecxx"));
161 res = m_builder->CreateInsertElement(res, x[0], constantInt(2),
162 name("vecxxx"));
163 res = m_builder->CreateInsertElement(res, x[0], constantInt(3),
164 name("vecxxxx"));
165 return res;
166 }
167
168 std::vector<llvm::Value*> StorageSoa::constElement(llvm::IRBuilder<>* m_builder, llvm::Value *idx)
169 {
170 llvm::Value* res;
171 std::vector<llvm::Value*> res2(4);
172 llvm::Value *xChannel, *yChannel, *zChannel, *wChannel;
173
174 xChannel = elementPointer(m_consts, idx, 0);
175
176 res = alignedArrayLoad(xChannel);
177
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);
182
183 return res2;
184 }
185
186 std::vector<llvm::Value*> StorageSoa::outputElement(llvm::Value *idx)
187 {
188 std::vector<llvm::Value*> res(4);
189
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);
194
195 return res;
196 }
197
198 std::vector<llvm::Value*> StorageSoa::tempElement(llvm::Value *idx)
199 {
200 std::vector<llvm::Value*> res(4);
201
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);
206
207 return res;
208 }
209
210 std::vector<llvm::Value*> StorageSoa::immediateElement(llvm::Value *idx)
211 {
212 std::vector<llvm::Value*> res(4);
213
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);
218
219 return res;
220 }
221
222 llvm::Value * StorageSoa::elementPointer(llvm::Value *ptr, llvm::Value *index,
223 int channel) const
224 {
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));
230
231 GetElementPtrInst *getElem = GetElementPtrInst::Create(ptr,
232 indices.begin(),
233 indices.end(),
234 name("ptr"),
235 m_block);
236 return getElem;
237 }
238
239 llvm::Value * StorageSoa::element(llvm::Value *ptr, llvm::Value *index,
240 int channel) const
241 {
242 llvm::Value *res = elementPointer(ptr, index, channel);
243 LoadInst *load = new LoadInst(res, name("element"), false, m_block);
244 //load->setAlignment(8);
245 return load;
246 }
247
248 const char * StorageSoa::name(const char *prefix) const
249 {
250 ++m_idx;
251 snprintf(m_name, 32, "%s%d", prefix, m_idx);
252 return m_name;
253 }
254
255 llvm::ConstantInt * StorageSoa::constantInt(int idx) const
256 {
257 if (m_constInts.find(idx) != m_constInts.end()) {
258 return m_constInts[idx];
259 }
260 ConstantInt *constInt = ConstantInt::get(APInt(32, idx));
261 m_constInts[idx] = constInt;
262 return constInt;
263 }
264
265 llvm::Value *StorageSoa::alignedArrayLoad(llvm::Value *val)
266 {
267 VectorType *vectorType = VectorType::get(Type::FloatTy, 4);
268 PointerType *vectorPtr = PointerType::get(vectorType, 0);
269
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);
273 return load;
274 }
275
276 llvm::Module * StorageSoa::currentModule() const
277 {
278 if (!m_block || !m_block->getParent())
279 return 0;
280
281 return m_block->getParent()->getParent();
282 }
283
284 llvm::Constant * StorageSoa::createConstGlobalFloat(const float val)
285 {
286 Constant*c = ConstantFP::get(APFloat(val));
287 return c;
288 }
289
290 llvm::Constant * StorageSoa::createConstGlobalVector(const std::vector<float> &vec)
291 {
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);
303
304 return constVector;
305 }
306
307 std::vector<llvm::Value*> StorageSoa::load(enum tgsi_file_type type, int idx, int swizzle,
308 llvm::IRBuilder<>* m_builder,llvm::Value *indIdx)
309 {
310 std::vector<llvm::Value*> val(4);
311
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;
315 if (indIdx)
316 realIndex = indIdx;
317 else
318 realIndex = constantInt(idx);
319 debug_printf("XXXXXXXXX realIdx = %p, indIdx = %p\n", realIndex, indIdx);
320
321 switch(type) {
322 case TGSI_FILE_INPUT:
323 val = inputElement(realIndex);
324 break;
325 case TGSI_FILE_OUTPUT:
326 val = outputElement(realIndex);
327 break;
328 case TGSI_FILE_TEMPORARY:
329 val = tempElement(realIndex);
330 break;
331 case TGSI_FILE_CONSTANT:
332 val = constElement(m_builder, realIndex);
333 break;
334 case TGSI_FILE_IMMEDIATE:
335 val = immediateElement(realIndex);
336 break;
337 case TGSI_FILE_ADDRESS:
338 debug_printf("Address not handled in the load phase!\n");
339 assert(0);
340 break;
341 default:
342 debug_printf("Unknown load!\n");
343 assert(0);
344 break;
345 }
346 if (!gallivm_is_swizzle(swizzle))
347 return val;
348
349 std::vector<llvm::Value*> res(4);
350
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)];
355 return res;
356 }
357
358 void StorageSoa::store(enum tgsi_file_type type, int idx, const std::vector<llvm::Value*> &val,
359 int mask)
360 {
361 llvm::Value *out = 0;
362 switch(type) {
363 case TGSI_FILE_OUTPUT:
364 out = m_output;
365 break;
366 case TGSI_FILE_TEMPORARY:
367 out = m_temps;
368 break;
369 case TGSI_FILE_INPUT:
370 out = m_input;
371 break;
372 case TGSI_FILE_ADDRESS: {
373 llvm::Value *addr = m_addresses[idx];
374 if (!addr) {
375 addAddress(idx);
376 addr = m_addresses[idx];
377 assert(addr);
378 }
379 new StoreInst(val[0], addr, false, m_block);
380 return;
381 break;
382 }
383 default:
384 debug_printf("Can't save output of this type: %d !\n", type);
385 assert(0);
386 break;
387 }
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);
392 }
393 if ((mask & TGSI_WRITEMASK_Y)) {
394 llvm::Value *yChannel = elementPointer(out, realIndex, 1);
395 new StoreInst(val[1], yChannel, false, m_block);
396 }
397 if ((mask & TGSI_WRITEMASK_Z)) {
398 llvm::Value *zChannel = elementPointer(out, realIndex, 2);
399 new StoreInst(val[2], zChannel, false, m_block);
400 }
401 if ((mask & TGSI_WRITEMASK_W)) {
402 llvm::Value *wChannel = elementPointer(out, realIndex, 3);
403 new StoreInst(val[3], wChannel, false, m_block);
404 }
405 }
406
407 void StorageSoa::addAddress(int idx)
408 {
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"),
415 currentModule());
416 val->setInitializer(Constant::getNullValue(IntegerType::get(32)));
417
418 debug_printf("adding to %d\n", idx);
419 m_addresses[idx] = val;
420 }