radeon/r200/r300: cleanup some of the renderbuffer code
[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 : m_block(block),
53 m_input(input),
54 m_output(output),
55 m_consts(consts),
56 m_immediates(0),
57 m_idx(0)
58 {
59 }
60
61 void StorageSoa::addImmediate(float *vec)
62 {
63 std::vector<float> vals(4);
64 vals[0] = vec[0];
65 vals[1] = vec[1];
66 vals[2] = vec[2];
67 vals[3] = vec[3];
68 m_immediatesToFlush.push_back(vals);
69 }
70
71 void StorageSoa::declareImmediates()
72 {
73 if (m_immediatesToFlush.empty())
74 return;
75
76 VectorType *vectorType = VectorType::get(Type::FloatTy, 4);
77 ArrayType *vectorChannels = ArrayType::get(vectorType, 4);
78 ArrayType *arrayType = ArrayType::get(vectorChannels, m_immediatesToFlush.size());
79
80 m_immediates = new GlobalVariable(
81 /*Type=*/arrayType,
82 /*isConstant=*/false,
83 /*Linkage=*/GlobalValue::ExternalLinkage,
84 /*Initializer=*/0, // has initializer, specified below
85 /*Name=*/name("immediates"),
86 currentModule());
87
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;
93
94 vals[0] = vec[0]; vals[1] = vec[1]; vals[2] = vec[2]; vals[3] = vec[3];
95 llvm::Constant *xChannel = createConstGlobalVector(vals);
96
97 vals[0] = vec[1]; vals[1] = vec[1]; vals[2] = vec[1]; vals[3] = vec[1];
98 llvm::Constant *yChannel = createConstGlobalVector(vals);
99
100 vals[0] = vec[2]; vals[1] = vec[2]; vals[2] = vec[2]; vals[3] = vec[2];
101 llvm::Constant *zChannel = createConstGlobalVector(vals);
102
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,
110 channelArray);
111 arrayVals.push_back(constChannels);
112 }
113 Constant *constArray = ConstantArray::get(arrayType, arrayVals);
114 m_immediates->setInitializer(constArray);
115
116 m_immediatesToFlush.clear();
117 }
118
119 llvm::Value *StorageSoa::addrElement(int idx) const
120 {
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");
124 return 0;
125 }
126 llvm::Value * res = (*itr).second;
127
128 res = new LoadInst(res, name("addr"), false, m_block);
129
130 return res;
131 }
132
133 std::vector<llvm::Value*> StorageSoa::inputElement(llvm::Value *idx)
134 {
135 std::vector<llvm::Value*> res(4);
136
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);
141
142 return res;
143 }
144
145 llvm::Value* StorageSoa::unpackConstElement(llvm::IRBuilder<>* m_builder, llvm::Value* vector, int cc)
146 {
147 std::vector<llvm::Value*> x(4);
148 x[0] = m_builder->CreateExtractElement(vector,
149 constantInt(cc),
150 name("x"));
151
152 VectorType *vectorType = VectorType::get(Type::FloatTy, 4);
153 Constant *constVector = Constant::getNullValue(vectorType);
154 Value *res = m_builder->CreateInsertElement(constVector, x[0],
155 constantInt(0),
156 name("vecx"));
157 res = m_builder->CreateInsertElement(res, x[0], constantInt(1),
158 name("vecxx"));
159 res = m_builder->CreateInsertElement(res, x[0], constantInt(2),
160 name("vecxxx"));
161 res = m_builder->CreateInsertElement(res, x[0], constantInt(3),
162 name("vecxxxx"));
163 return res;
164 }
165
166 std::vector<llvm::Value*> StorageSoa::constElement(llvm::IRBuilder<>* m_builder, llvm::Value *idx)
167 {
168 llvm::Value* res;
169 std::vector<llvm::Value*> res2(4);
170 llvm::Value *xChannel;
171
172 xChannel = elementPointer(m_consts, idx, 0);
173
174 res = alignedArrayLoad(xChannel);
175
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);
180
181 return res2;
182 }
183
184 std::vector<llvm::Value*> StorageSoa::outputElement(llvm::Value *idx)
185 {
186 std::vector<llvm::Value*> res(4);
187
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);
192
193 return res;
194 }
195
196 std::vector<llvm::Value*> StorageSoa::tempElement(llvm::IRBuilder<>* m_builder, int idx)
197 {
198 std::vector<llvm::Value*> res(4);
199 llvm::Value *temp = m_temps[idx];
200
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);
205
206 return res;
207 }
208
209 std::vector<llvm::Value*> StorageSoa::immediateElement(llvm::Value *idx)
210 {
211 std::vector<llvm::Value*> res(4);
212
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);
217
218 return res;
219 }
220
221 llvm::Value * StorageSoa::elementPointer(llvm::Value *ptr, llvm::Value *index,
222 int channel) const
223 {
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));
229
230 GetElementPtrInst *getElem = GetElementPtrInst::Create(ptr,
231 indices.begin(),
232 indices.end(),
233 name("ptr"),
234 m_block);
235 return getElem;
236 }
237
238 llvm::Value * StorageSoa::element(llvm::Value *ptr, llvm::Value *index,
239 int channel) const
240 {
241 llvm::Value *res = elementPointer(ptr, index, channel);
242 LoadInst *load = new LoadInst(res, name("element"), false, m_block);
243 //load->setAlignment(8);
244 return load;
245 }
246
247 const char * StorageSoa::name(const char *prefix) const
248 {
249 ++m_idx;
250 snprintf(m_name, 32, "%s%d", prefix, m_idx);
251 return m_name;
252 }
253
254 llvm::ConstantInt * StorageSoa::constantInt(int idx) const
255 {
256 if (m_constInts.find(idx) != m_constInts.end()) {
257 return m_constInts[idx];
258 }
259 ConstantInt *constInt = ConstantInt::get(APInt(32, idx));
260 m_constInts[idx] = constInt;
261 return constInt;
262 }
263
264 llvm::Value *StorageSoa::alignedArrayLoad(llvm::Value *val)
265 {
266 VectorType *vectorType = VectorType::get(Type::FloatTy, 4);
267 PointerType *vectorPtr = PointerType::get(vectorType, 0);
268
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);
272 return load;
273 }
274
275 llvm::Module * StorageSoa::currentModule() const
276 {
277 if (!m_block || !m_block->getParent())
278 return 0;
279
280 return m_block->getParent()->getParent();
281 }
282
283 llvm::Constant * StorageSoa::createConstGlobalFloat(const float val)
284 {
285 Constant*c = ConstantFP::get(APFloat(val));
286 return c;
287 }
288
289 llvm::Constant * StorageSoa::createConstGlobalVector(const std::vector<float> &vec)
290 {
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);
302
303 return constVector;
304 }
305
306 std::vector<llvm::Value*> StorageSoa::load(enum tgsi_file_type type, int idx, int swizzle,
307 llvm::IRBuilder<>* m_builder,llvm::Value *indIdx)
308 {
309 std::vector<llvm::Value*> val(4);
310
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;
314 if (indIdx)
315 realIndex = indIdx;
316 else
317 realIndex = constantInt(idx);
318 debug_printf("XXXXXXXXX realIdx = %p, indIdx = %p\n", realIndex, indIdx);
319
320 switch(type) {
321 case TGSI_FILE_INPUT:
322 val = inputElement(realIndex);
323 break;
324 case TGSI_FILE_OUTPUT:
325 val = outputElement(realIndex);
326 break;
327 case TGSI_FILE_TEMPORARY:
328 val = tempElement(m_builder, idx);
329 break;
330 case TGSI_FILE_CONSTANT:
331 val = constElement(m_builder, realIndex);
332 break;
333 case TGSI_FILE_IMMEDIATE:
334 val = immediateElement(realIndex);
335 break;
336 case TGSI_FILE_ADDRESS:
337 debug_printf("Address not handled in the load phase!\n");
338 assert(0);
339 break;
340 default:
341 debug_printf("Unknown load!\n");
342 assert(0);
343 break;
344 }
345 if (!gallivm_is_swizzle(swizzle))
346 return val;
347
348 std::vector<llvm::Value*> res(4);
349
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)];
354 return res;
355 }
356
357 llvm::Value * StorageSoa::allocaTemp(llvm::IRBuilder<>* m_builder)
358 {
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());
363
364 return alloca;
365 }
366
367
368 void StorageSoa::store(enum tgsi_file_type type, int idx, const std::vector<llvm::Value*> &val,
369 int mask, llvm::IRBuilder<>* m_builder)
370 {
371 llvm::Value *out = 0;
372 llvm::Value *realIndex = 0;
373 switch(type) {
374 case TGSI_FILE_OUTPUT:
375 out = m_output;
376 realIndex = constantInt(idx);
377 break;
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);
382
383 out = m_temps[idx];
384
385 realIndex = constantInt(0);
386 break;
387 case TGSI_FILE_INPUT:
388 out = m_input;
389 realIndex = constantInt(idx);
390 break;
391 case TGSI_FILE_ADDRESS: {
392 llvm::Value *addr = m_addresses[idx];
393 if (!addr) {
394 addAddress(idx);
395 addr = m_addresses[idx];
396 assert(addr);
397 }
398 new StoreInst(val[0], addr, false, m_block);
399 return;
400 break;
401 }
402 default:
403 debug_printf("Can't save output of this type: %d !\n", type);
404 assert(0);
405 break;
406 }
407 if ((mask & TGSI_WRITEMASK_X)) {
408 llvm::Value *xChannel = elementPointer(out, realIndex, 0);
409 new StoreInst(val[0], xChannel, false, m_block);
410 }
411 if ((mask & TGSI_WRITEMASK_Y)) {
412 llvm::Value *yChannel = elementPointer(out, realIndex, 1);
413 new StoreInst(val[1], yChannel, false, m_block);
414 }
415 if ((mask & TGSI_WRITEMASK_Z)) {
416 llvm::Value *zChannel = elementPointer(out, realIndex, 2);
417 new StoreInst(val[2], zChannel, false, m_block);
418 }
419 if ((mask & TGSI_WRITEMASK_W)) {
420 llvm::Value *wChannel = elementPointer(out, realIndex, 3);
421 new StoreInst(val[3], wChannel, false, m_block);
422 }
423 }
424
425 void StorageSoa::addAddress(int idx)
426 {
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"),
433 currentModule());
434 val->setInitializer(Constant::getNullValue(IntegerType::get(32)));
435
436 debug_printf("adding to %d\n", idx);
437 m_addresses[idx] = val;
438 }