00001
#include "ShOptimizations.hpp"
00002
#include <map>
00003
#include <set>
00004
#include <utility>
00005
#include <iostream>
00006
#include "ShBitSet.hpp"
00007
#include "ShCtrlGraph.hpp"
00008
#include "ShDebug.hpp"
00009
#include "ShEvaluate.hpp"
00010
#include "ShContext.hpp"
00011
#include "ShSyntax.hpp"
00012
#include <sstream>
00013
#include <fstream>
00014
00015
00016
00017
00018
#ifdef SH_DEBUG_OPTIMIZER
00019
#ifndef SH_DEBUG_CONSTPROP
00020
#define SH_DEBUG_CONSTPROP
00021
#endif
00022
#endif
00023
00024
namespace {
00025
00026
using namespace SH;
00027
00028
typedef std::queue<ValueTracking::Def> ConstWorkList;
00029
00030
struct ConstProp :
public ShStatementInfo {
00031 ConstProp(ShStatement* stmt,
00032 ConstWorkList& worklist)
00033 : stmt(stmt)
00034 {
00035
for (
int i = 0; i <
opInfo[stmt->op].arity ; i++) {
00036
for (
int j = 0; j < stmt->src[i].size(); j++) {
00037
switch(stmt->src[i].node()->kind()) {
00038
case SH_INPUT:
00039
case SH_OUTPUT:
00040
case SH_INOUT:
00041
case SH_TEXTURE:
00042
case SH_STREAM:
00043 src[i].push_back(Cell(Cell::BOTTOM));
00044
break;
00045
case SH_TEMP:
00046
if (stmt->src[i].uniform()) {
00047 src[i].push_back(Cell(Cell::UNIFORM, stmt->src[i], j));
00048 }
else {
00049 src[i].push_back(Cell(Cell::TOP));
00050 }
00051
break;
00052
case SH_CONST:
00053 src[i].push_back(Cell(Cell::CONSTANT, stmt->src[i].getValue(j)));
00054
break;
00055 }
00056 }
00057 }
00058 updateDest(worklist);
00059 }
00060
00061
ShStatementInfo* clone() const;
00062
00063
int idx(
int destindex,
int source)
00064 {
00065
return (stmt->src[source].size() == 1 ? 0 : destindex);
00066 }
00067
00068
void updateDest(ConstWorkList& worklist)
00069 {
00070 dest.clear();
00071
00072
00073
if (
opInfo[stmt->op].result_source == ShOperationInfo::IGNORE)
return;
00074
00075
if (stmt->op ==
SH_OP_ASN) {
00076
for (
int i = 0; i < stmt->dest.size(); i++) {
00077 dest.push_back(src[0][i]);
00078
if (src[0][i].state == Cell::UNIFORM ||
00079 src[0][i].state == Cell::CONSTANT) {
00080 worklist.push(ValueTracking::Def(stmt, i));
00081 }
00082 }
00083 }
else if (
opInfo[stmt->op].result_source == ShOperationInfo::EXTERNAL) {
00084
00085
00086
for (
int i = 0; i < stmt->dest.size(); i++) {
00087 dest.push_back(Cell(Cell::BOTTOM));
00088 }
00089 }
else if (
opInfo[stmt->op].result_source == ShOperationInfo::LINEAR) {
00090
00091
00092
00093
bool all_fields_uniform =
true;
00094
for (
int i = 0; i < stmt->dest.size(); i++) {
00095
bool alluniform =
true;
00096
bool allconst =
true;
00097
for (
int s = 0; s <
opInfo[stmt->op].arity; s++) {
00098
if (src[s][idx(i,s)].state != Cell::CONSTANT) {
00099 allconst =
false;
00100
if (src[s][idx(i,s)].state != Cell::UNIFORM) {
00101 alluniform =
false;
00102 }
00103 }
00104 }
00105
if (!alluniform) all_fields_uniform =
false;
00106
if (allconst) {
00107 ShVariable tmpdest(
new ShVariableNode(SH_CONST, 1));
00108 ShStatement eval(*stmt);
00109 eval.dest = tmpdest;
00110
for (
int k = 0; k <
opInfo[stmt->op].arity; k++) {
00111 ShVariable tmpsrc(
new ShVariableNode(SH_CONST, 1));
00112 tmpsrc.setValue(0, src[k][idx(i,k)].value);
00113 eval.src[k] = tmpsrc;
00114 }
00115 evaluate(eval);
00116 dest.push_back(Cell(Cell::CONSTANT, tmpdest.getValue(0)));
00117 worklist.push(ValueTracking::Def(stmt, i));
00118 }
else {
00119 dest.push_back(Cell(Cell::BOTTOM));
00120 }
00121 }
00122
00123
00124
00125
00126
00127
if (all_fields_uniform) {
00128 dest.clear();
00129
for (
int i = 0; i < stmt->dest.size(); i++) {
00130 dest.push_back(Cell(Cell::UNIFORM,
this, i));
00131 worklist.push(ValueTracking::Def(stmt, i));
00132 }
00133 }
00134 }
else if (
opInfo[stmt->op].result_source == ShOperationInfo::ALL) {
00135
00136
bool allconst =
true;
00137
bool alluniform =
true;
00138
for (
int s = 0; s <
opInfo[stmt->op].arity; s++) {
00139
for (
unsigned int k = 0; k < src[s].size(); k++) {
00140
if (src[s][k].state != Cell::CONSTANT) {
00141 allconst =
false;
00142
if (src[s][k].state != Cell::UNIFORM) {
00143 alluniform =
false;
00144 }
00145 }
00146 }
00147 }
00148
if (allconst) {
00149 ShVariable tmpdest(
new ShVariableNode(SH_CONST, stmt->dest.size()));
00150 ShStatement eval(*stmt);
00151 eval.dest = tmpdest;
00152
for (
int i = 0; i <
opInfo[stmt->op].arity; i++) {
00153 ShVariable tmpsrc(
new ShVariableNode(SH_CONST, stmt->src[i].size()));
00154
for (
int j = 0; j < stmt->src[i].size(); j++) {
00155 tmpsrc.setValue(j, src[i][j].value);
00156 }
00157 eval.src[i] = tmpsrc;
00158 }
00159 evaluate(eval);
00160
for (
int i = 0; i < stmt->dest.size(); i++) {
00161 dest.push_back(Cell(Cell::CONSTANT, tmpdest.getValue(i)));
00162 worklist.push(ValueTracking::Def(stmt, i));
00163 }
00164 }
else if (alluniform) {
00165
for (
int i = 0; i < stmt->dest.size(); i++) {
00166 dest.push_back(Cell(Cell::UNIFORM,
this, i));
00167 worklist.push(ValueTracking::Def(stmt, i));
00168 }
00169 }
else {
00170
for (
int i = 0; i < stmt->dest.size(); i++) {
00171 dest.push_back(Cell(Cell::BOTTOM));
00172 worklist.push(ValueTracking::Def(stmt, i));
00173 }
00174 }
00175 }
else {
00176 SH_DEBUG_ASSERT(0 &&
"Invalid result source type");
00177 }
00178 }
00179
00180
typedef int ValueNum;
00181
00182
struct Uniform {
00183 Uniform()
00184 : constant(false),
00185 valuenum(-1)
00186 {
00187 }
00188
00189 Uniform(
float constval)
00190 : constant(true),
00191 constval(constval)
00192 {
00193 }
00194
00195 Uniform(
int valuenum,
int index,
bool neg)
00196 : constant(false),
00197 valuenum(valuenum), index(index), neg(neg)
00198 {
00199 }
00200
00201
bool operator==(
const Uniform& other)
const
00202
{
00203
if (constant != other.constant)
return false;
00204
00205
if (constant) {
00206
return constval == other.constval;
00207 }
else {
00208
if (valuenum != other.valuenum)
return false;
00209
if (index != other.index)
return false;
00210
if (neg != other.neg)
return false;
00211
return true;
00212 }
00213 }
00214
00215
bool operator!=(
const Uniform& other)
const
00216
{
00217
return !(*
this == other);
00218 }
00219
00220
bool constant;
00221
00222 ValueNum valuenum;
00223
int index;
00224
bool neg;
00225
00226
float constval;
00227 };
00228
00229
class Value {
00230
public:
00231
enum Type {
00232 NODE,
00233 STMT
00234 };
00235
00236 Type type;
00237
00238
00239 ShVariableNodePtr node;
00240
00241
00242
ShOperation op;
00243
int destsize;
00244 std::vector<Uniform> src[3];
00245
00246
static void clear()
00247 {
00248 m_values.clear();
00249 }
00250
00251
static ValueNum lookup(
const ShVariableNodePtr& node)
00252 {
00253
for (std::size_t i = 0; i < m_values.size(); i++) {
00254
if (m_values[i]->type == NODE && m_values[i]->node == node)
return i;
00255 }
00256 m_values.push_back(
new Value(node));
00257
return m_values.size() - 1;
00258 }
00259
00260
bool operator==(
const Value& other)
const
00261
{
00262
if (type != other.type)
return false;
00263
if (type == NODE) {
00264
return node == other.node;
00265 }
else if (type == STMT) {
00266
if (op != other.op || destsize != other.destsize)
return false;
00267
for (
int i = 0; i <
opInfo[op].arity; i++) {
00268
if (src[i].size() != other.src[i].size())
return false;
00269
for (std::size_t j = 0; j < src[i].size(); j++) {
00270
if (src[i][j] != other.src[i][j])
return false;
00271 }
00272 }
00273
return true;
00274 }
00275
return false;
00276 }
00277
00278
bool operator!=(
const Value& other)
const
00279
{
00280
return !(*
this == other);
00281 }
00282
00283
static ValueNum lookup(ConstProp* cp)
00284 {
00285 Value* val =
new Value(cp);
00286
00287
for (std::size_t i = 0; i < m_values.size(); i++) {
00288
if (m_values[i]->type != STMT)
continue;
00289
if (m_values[i]->op != cp->stmt->op)
continue;
00290
00291
if (*val == *m_values[i]) {
00292
delete val;
00293
return i;
00294 }
00295 }
00296 m_values.push_back(val);
00297
return m_values.size() - 1;
00298 }
00299
00300
static Value* get(ValueNum n)
00301 {
00302
return m_values[n];
00303 }
00304
00305
static void dump(std::ostream& out);
00306
00307
private:
00308 Value(
const ShVariableNodePtr& node)
00309 : type(NODE), node(node)
00310 {
00311 }
00312
00313 Value(ConstProp* cp)
00314 : type(STMT), node(0), op(cp->stmt->op), destsize(cp->stmt->dest.size())
00315 {
00316
for (
int i = 0; i <
opInfo[cp->stmt->op].arity; i++) {
00317
for (std::size_t j = 0; j < cp->src[i].size(); j++) {
00318
if (cp->src[i][j].state == Cell::UNIFORM) {
00319 src[i].push_back(cp->src[i][j].uniform);
00320 }
else {
00321 src[i].push_back(Uniform(cp->src[i][j].value));
00322 }
00323 }
00324 }
00325 }
00326
00327
static std::vector<Value*> m_values;
00328 };
00329
00330
struct Cell {
00331
enum State {
00332 BOTTOM,
00333 CONSTANT,
00334 UNIFORM,
00335 TOP
00336 };
00337
00338 Cell(State state,
float value = 0.0)
00339 : state(state), value(value)
00340 {
00341 }
00342
00343 Cell(State state,
const ShVariable& var,
int index)
00344 : state(state), value(0.0),
00345 uniform(Value::lookup(var.node()), var.swizzle()[index], var.neg())
00346 {
00347 }
00348
00349 Cell(State state, ConstProp* cp,
int index)
00350 : state(state), value(0.0),
00351 uniform(Value::lookup(cp), index, false)
00352 {
00353 }
00354
00355
bool operator==(
const Cell& other)
const
00356
{
00357
return state == other.state && value == other.value;
00358 }
00359
bool operator!=(
const Cell& other)
const
00360
{
00361
return !(*
this == other);
00362 }
00363
00364 State state;
00365
float value;
00366
00367 Uniform uniform;
00368 };
00369
00370 ShStatement* stmt;
00371 std::vector<Cell> dest;
00372 std::vector<Cell> src[3];
00373 };
00374
00375
ShStatementInfo* ConstProp::clone()
const
00376
{
00377
return new ConstProp(*
this);
00378 }
00379
00380 ConstProp::Cell meet(
const ConstProp::Cell& a,
const ConstProp::Cell& b)
00381 {
00382
if (a.state == ConstProp::Cell::BOTTOM || b.state == ConstProp::Cell::BOTTOM) {
00383
return ConstProp::Cell(ConstProp::Cell::BOTTOM);
00384 }
00385
if (a.state != b.state
00386 && (a.state != ConstProp::Cell::TOP && b.state != ConstProp::Cell::TOP)) {
00387
return ConstProp::Cell(ConstProp::Cell::BOTTOM);
00388 }
00389
00390
00391
if (a.state == b.state) {
00392
if (a.state == ConstProp::Cell::CONSTANT) {
00393
if (a.value == b.value) {
00394
return a;
00395 }
else {
00396
return ConstProp::Cell(ConstProp::Cell::BOTTOM);
00397 }
00398 }
00399
if (a.state == ConstProp::Cell::UNIFORM) {
00400
if (a.uniform == b.uniform)
return a;
00401
return ConstProp::Cell(ConstProp::Cell::BOTTOM);
00402 }
00403 }
00404
00405
if (a.state != ConstProp::Cell::TOP)
return a;
00406
if (b.state != ConstProp::Cell::TOP)
return b;
00407
00408
return ConstProp::Cell(ConstProp::Cell::TOP);
00409 }
00410
00411 std::vector<ConstProp::Value*> ConstProp::Value::m_values = std::vector<ConstProp::Value*>();
00412
00413 std::ostream&
operator<<(std::ostream& out,
const ConstProp::Uniform& uniform)
00414 {
00415
if (uniform.constant) {
00416 out << uniform.constval;
00417 }
else {
00418
if (uniform.neg) out <<
'-';
00419 out <<
"v" << uniform.valuenum <<
"[" << uniform.index <<
"]";
00420 }
00421
return out;
00422 }
00423
00424
void ConstProp::Value::dump(std::ostream& out)
00425 {
00426 out <<
"--- uniform values ---" << std::endl;
00427
for (std::size_t i = 0; i < m_values.size(); i++) {
00428 out << i <<
": ";
00429
if (m_values[i]->type == NODE) {
00430 out <<
"node " << m_values[i]->node->name() << std::endl;
00431 }
else if (m_values[i]->type == STMT) {
00432 out <<
"stmt [" << m_values[i]->destsize <<
"] " <<
opInfo[m_values[i]->op].name <<
" ";
00433
for (
int j = 0; j <
opInfo[m_values[i]->op].arity; j++) {
00434
if (j) out <<
", ";
00435
for (std::vector<Uniform>::iterator U = m_values[i]->src[j].begin();
00436 U != m_values[i]->src[j].end(); ++U) {
00437 out << *U;
00438 }
00439 }
00440 out <<
";" << std::endl;
00441 }
00442 }
00443 }
00444
00445 std::ostream&
operator<<(std::ostream& out,
const ConstProp::Cell& cell)
00446 {
00447
switch(cell.state) {
00448
case ConstProp::Cell::BOTTOM:
00449 out <<
"[bot]";
00450
break;
00451
case ConstProp::Cell::CONSTANT:
00452 out <<
"[" << cell.value <<
"]";
00453
break;
00454
case ConstProp::Cell::TOP:
00455 out <<
"[top]";
00456
break;
00457
case ConstProp::Cell::UNIFORM:
00458 out <<
"<" << cell.uniform <<
">";
00459
break;
00460 }
00461
return out;
00462 }
00463
00464
struct InitConstProp {
00465 InitConstProp(ConstWorkList& worklist)
00466 : worklist(worklist)
00467 {
00468 }
00469
00470
void operator()(
const ShCtrlGraphNodePtr& node)
00471 {
00472
if (!node)
return;
00473 ShBasicBlockPtr block = node->block;
00474
if (!block)
return;
00475
for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) {
00476 I->template destroy_info<ConstProp>();
00477 ConstProp* cp =
new ConstProp(&(*I), worklist);
00478 I->add_info(cp);
00479 }
00480 }
00481
00482 ConstWorkList& worklist;
00483 };
00484
00485
struct DumpConstProp {
00486
void operator()(
const ShCtrlGraphNodePtr& node)
00487 {
00488
if (!node)
return;
00489 ShBasicBlockPtr block = node->block;
00490
if (!block)
return;
00491
for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) {
00492 std::cerr <<
"{" << *I <<
"} --- ";
00493 ConstProp* cp = I->template get_info<ConstProp>();
00494
00495
if (!cp) {
00496 std::cerr <<
"NO CP INFORMATION" << std::endl;
00497
continue;
00498 }
00499
00500 std::cerr <<
"dest = {";
00501
for (std::size_t i = 0; i < cp->dest.size(); i++) {
00502 std::cerr << cp->dest[i];
00503 }
00504 std::cerr <<
"}; ";
00505
for (
int s = 0; s <
opInfo[I->op].arity; s++) {
00506
if (s) std::cerr <<
", ";
00507 std::cerr <<
"src" << s <<
" = {";
00508
for (std::size_t i = 0; i < cp->src[s].size(); i++) {
00509 std::cerr << cp->src[s][i];
00510 }
00511 std::cerr <<
"}";
00512 }
00513 std::cerr << std::endl;
00514 }
00515
00516 }
00517 };
00518
00519
struct FinishConstProp
00520 {
00521 FinishConstProp(
bool lift_uniforms)
00522 : lift_uniforms(lift_uniforms)
00523 {
00524 }
00525
00526
void operator()(
const ShCtrlGraphNodePtr& node) {
00527
if (!node)
return;
00528 ShBasicBlockPtr block = node->block;
00529
if (!block)
return;
00530
for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) {
00531 ConstProp* cp = I->template get_info<ConstProp>();
00532
00533
if (!cp)
continue;
00534
00535
if (!cp->dest.empty()) {
00536
00537
00538
00539
if (I->op !=
SH_OP_ASN || I->src[0].node()->kind() != SH_CONST) {
00540 ShVariable newconst(
new ShVariableNode(SH_CONST, I->dest.size()));
00541
bool allconst =
true;
00542
for (
int i = 0; i < I->dest.size(); i++) {
00543
if (cp->dest[i].state != ConstProp::Cell::CONSTANT) {
00544 allconst =
false;
00545
break;
00546 }
00547 newconst.setValue(i, cp->dest[i].value);
00548 }
00549
if (allconst) {
00550
#ifdef SH_DEBUG_CONSTPROP
00551
SH_DEBUG_PRINT(
"Replaced {" << *I <<
"} with " << newconst);
00552
#endif
00553
*I = ShStatement(I->dest, SH_OP_ASN, newconst);
00554 }
else {
00555
00556
for (
int s = 0; s <
opInfo[I->op].arity; s++) {
00557
if (I->src[s].node()->kind() == SH_CONST)
continue;
00558
00559 ShVariable newconst(
new ShVariableNode(SH_CONST, I->src[s].size()));
00560
bool allconst =
true;
00561
for (
int i = 0; i < I->src[s].size(); i++) {
00562
if (cp->src[s][i].state != ConstProp::Cell::CONSTANT) {
00563 allconst =
false;
00564
break;
00565 }
00566 newconst.setValue(i, cp->src[s][i].value);
00567 }
00568
if (allconst) {
00569
#ifdef SH_DEBUG_CONSTPROP
00570
SH_DEBUG_PRINT(
"Replaced {" << *I <<
"}.src[" << s <<
"] with " << newconst);
00571
#endif
00572
I->src[s] = newconst;
00573 }
00574 }
00575 }
00576
00577
if (!lift_uniforms || allconst) {
00578
00579
continue;
00580 }
00581
00582
bool alluniform =
true;
00583
for (
int s = 0; s <
opInfo[I->op].arity; s++) {
00584
for (
int i = 0; i < I->src[s].size(); i++) {
00585
if (cp->src[s][i].state != ConstProp::Cell::UNIFORM
00586 && cp->src[s][i].state != ConstProp::Cell::CONSTANT) {
00587 alluniform =
false;
00588
break;
00589 }
00590 }
00591
if (!alluniform)
break;
00592 }
00593
if (!alluniform || I->dest.node()->kind() == SH_OUTPUT
00594 || I->dest.node()->kind() == SH_INOUT) {
00595
#ifdef SH_DEBUG_CONSTPROP
00596
SH_DEBUG_PRINT(
"Considering " << *I <<
" for uniform lifting");
00597
#endif
00598
for (
int s = 0; s <
opInfo[I->op].arity; s++) {
00599
if (I->src[s].uniform()) {
00600
#ifdef SH_DEBUG_CONSTPROP
00601
SH_DEBUG_PRINT(*I <<
".src[" << s <<
"] is already a uniform");
00602
#endif
00603
continue;
00604 }
00605
00606
bool mixed =
false;
00607
bool neg =
false;
00608 ConstProp::ValueNum uniform = -1;
00609 std::vector<int> indices;
00610
00611
for (
int i = 0; i < I->src[s].size(); i++) {
00612
if (cp->src[s][i].state == ConstProp::Cell::UNIFORM) {
00613
if (uniform < 0) {
00614 uniform = cp->src[s][i].uniform.valuenum;
00615 neg = cp->src[s][i].uniform.neg;
00616 indices.push_back(cp->src[s][i].uniform.index);
00617 }
else {
00618
if (uniform != cp->src[s][i].uniform.valuenum
00619 || neg != cp->src[s][i].uniform.neg) {
00620 mixed =
true;
00621
break;
00622 }
00623 indices.push_back(cp->src[s][i].uniform.index);
00624 }
00625 }
else {
00626
00627 mixed =
true;
00628 }
00629 }
00630
00631
00632
if (mixed) {
00633
#ifdef SH_DEBUG_CONSTPROP
00634
SH_DEBUG_PRINT(*I <<
".src[" << s <<
"] is mixed");
00635
#endif
00636
continue;
00637 }
00638
if (uniform < 0) {
00639
#ifdef SH_DEBUG_CONSTPROP
00640
SH_DEBUG_PRINT(*I <<
".src[" << s <<
"] is not uniform");
00641
#endif
00642
continue;
00643 }
00644 ConstProp::Value* value = ConstProp::Value::get(uniform);
00645
00646
00647
#ifdef SH_DEBUG_CONSTPROP
00648
SH_DEBUG_PRINT(
"Lifting {" << *I <<
"}.src[" << s <<
"]: " << uniform);
00649
#endif
00650
int srcsize;
00651
if (value->type == ConstProp::Value::NODE) {
00652 srcsize = value->node->size();
00653 }
else {
00654 srcsize = value->destsize;
00655 }
00656 ShSwizzle swizzle(srcsize, indices.size(), &(*indices.begin()));
00657
00658 ShVariableNodePtr node = build_uniform(value, uniform);
00659
if (node) {
00660 I->src[s] = ShVariable(node, swizzle, neg);
00661 }
else {
00662
#ifdef SH_DEBUG_CONSTPROP
00663
SH_DEBUG_PRINT(
"Could not lift " << *I <<
".src[" << s <<
"] for some reason");
00664
#endif
00665
}
00666 }
00667 }
00668 }
00669 }
00670 }
00671
00672
00673
for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) {
00674
00675 I->template destroy_info<ConstProp>();
00676 }
00677 }
00678
00679 ShVariableNodePtr build_uniform(ConstProp::Value* value,
00680 ConstProp::ValueNum valuenum)
00681 {
00682
if (value->type == ConstProp::Value::NODE) {
00683
return value->node;
00684 }
00685
00686 ShContext::current()->enter(0);
00687 ShVariableNodePtr node =
new ShVariableNode(SH_TEMP, value->destsize);
00688 {
00689 std::ostringstream s;
00690 s <<
"dep_" << valuenum;
00691 node->name(s.str());
00692 }
00693 ShContext::current()->exit();
00694
00695
#ifdef SH_DEBUG_CONSTPROP
00696
SH_DEBUG_PRINT(
"Lifting value #" << valuenum);
00697
#endif
00698
00699
bool broken =
false;
00700
00701 ShProgram prg =
SH_BEGIN_PROGRAM(
"uniform") {
00702 ShStatement stmt(node, value->op);
00703
00704
for (
int i = 0; i <
opInfo[value->op].arity; i++) {
00705 stmt.src[i] = compute(value->src[i]);
00706
if (stmt.src[i].null()) broken =
true;
00707 }
00708
00709 ShContext::current()->parsing()->tokenizer.blockList()->addStatement(stmt);
00710 } SH_END;
00711
00712
#ifdef SH_DEBUG_CONSTPROP
00713
{
00714 std::ostringstream s;
00715 s <<
"lifted_" << valuenum;
00716 std::string dotfilename(s.str() +
".dot");
00717 std::ofstream
dot(dotfilename.c_str());
00718 prg.node()->ctrlGraph->graphvizDump(dot);
00719
dot.close();
00720 std::string cmdline = std::string(
"dot -Tps -o ") + s.str() +
".ps " + s.str() +
".dot";
00721 system(cmdline.c_str());
00722 }
00723
#endif
00724
00725
if (broken)
return 0;
00726 node->attach(prg.node());
00727
00728 value->type = ConstProp::Value::NODE;
00729 value->node = node;
00730
00731
return node;
00732 }
00733
00734 ShVariable compute(
const std::vector<ConstProp::Uniform>& src)
00735 {
00736 ConstProp::ValueNum v = -1;
00737
00738
bool allsame =
true;
00739
bool neg =
false;
00740 std::vector<int> indices;
00741 std::vector<float> constvals;
00742
for (std::size_t i = 0; i < src.size(); i++) {
00743
if (src[i].constant) {
00744
if (v >= 0) {
00745 allsame =
false;
00746
break;
00747 }
00748 constvals.push_back(src[i].constval);
00749 }
else {
00750
if (v < 0 && constvals.empty()) {
00751 v = src[i].valuenum;
00752 neg = src[i].neg;
00753 }
else {
00754
if (v != src[i].valuenum || neg != src[i].neg || !constvals.empty()) {
00755 allsame =
false;
00756 }
00757 }
00758 indices.push_back(src[i].index);
00759 }
00760 }
00761
if (!allsame) {
00762
00763 ShVariable r = ShVariable(
new ShVariableNode(SH_TEMP, src.size()));
00764
00765
for (std::size_t i = 0; i < src.size(); i++) {
00766 std::vector<ConstProp::Uniform> v;
00767 v.push_back(src[i]);
00768 ShVariable scalar = compute(v);
00769 ShStatement stmt(r(i), SH_OP_ASN, scalar);
00770 ShContext::current()->parsing()->tokenizer.blockList()->addStatement(stmt);
00771 }
00772
return r;
00773 }
00774
00775
if (!constvals.empty()) {
00776 ShVariable var(
new ShVariableNode(SH_CONST, constvals.size()));
00777 var.setValues(&*constvals.begin());
00778
return var;
00779 }
00780
00781 ConstProp::Value* value = ConstProp::Value::get(v);
00782
00783
if (value->type == ConstProp::Value::NODE) {
00784 ShSwizzle swizzle(value->node->size(), indices.size(), &*indices.begin());
00785
return ShVariable(value->node, swizzle, neg);
00786 }
00787
if (value->type == ConstProp::Value::STMT) {
00788 ShVariableNodePtr node =
new ShVariableNode(SH_TEMP, value->destsize);
00789 ShStatement stmt(node, value->op);
00790
00791
for (
int i = 0; i <
opInfo[value->op].arity; i++) {
00792 stmt.src[i] = compute(value->src[i]);
00793
if (stmt.src[i].null())
return ShVariable();
00794 }
00795
00796 ShContext::current()->parsing()->tokenizer.blockList()->addStatement(stmt);
00797 ShSwizzle swizzle(node->size(), indices.size(), &*indices.begin());
00798
return ShVariable(node, swizzle, neg);
00799 }
00800
00801
#ifdef SH_DEBUG_CONSTPROP
00802
SH_DEBUG_PRINT(
"Reached invalid point");
00803
#endif
00804
00805
00806
return ShVariable();
00807 }
00808
00809
bool lift_uniforms;
00810 };
00811
00812 }
00813
00814
namespace SH {
00815
00816
00817 void propagate_constants(
ShProgram& p)
00818 {
00819
ShCtrlGraphPtr graph = p.
node()->ctrlGraph;
00820
00821 ConstWorkList worklist;
00822
00823
00824
00825 InitConstProp init(worklist);
00826 graph->dfs(init);
00827
00828
#ifdef SH_DEBUG_CONSTPROP
00829
SH_DEBUG_PRINT(
"Const Prop Initial Values:");
00830 DumpConstProp dump_pre;
00831 graph->dfs(dump_pre);
00832
#endif
00833
00834
00835
while (!worklist.empty()) {
00836 ValueTracking::Def def = worklist.front(); worklist.pop();
00837 ValueTracking* vt = def.stmt->template get_info<ValueTracking>();
00838
if (!vt) {
00839
#ifdef SH_DEBUG_CONSTPROP
00840
SH_DEBUG_PRINT(*def.stmt <<
" on worklist does not have VT information?");
00841
#endif
00842
continue;
00843 }
00844
00845
00846
for (ValueTracking::DefUseChain::iterator use = vt->uses[def.index].begin();
00847 use != vt->uses[def.index].end(); ++use) {
00848 ConstProp* cp = use->stmt->template get_info<ConstProp>();
00849
if (!cp) {
00850
#ifdef SH_DEBUG_CONSTPROP
00851
SH_DEBUG_PRINT(
"Use " << *use->stmt <<
" does not have const prop information!");
00852
#endif
00853
continue;
00854 }
00855
00856 ConstProp::Cell cell = cp->src[use->source][use->index];
00857
00858 ValueTracking* ut = use->stmt->template get_info<ValueTracking>();
00859
if (!ut) {
00860
00861
#ifdef SH_DEBUG_CONSTPROP
00862
SH_DEBUG_PRINT(
"Use " << *use->stmt <<
" on worklist does not have VT information?");
00863
#endif
00864
continue;
00865 }
00866
00867
#ifdef SH_DEBUG_CONSTPROP
00868
SH_DEBUG_PRINT(
"Meeting cell for {" << *use->stmt
00869 <<
"}.src" << use->source <<
"[" << use->index <<
"]");
00870
#endif
00871
00872 ConstProp::Cell new_cell(ConstProp::Cell::TOP);
00873
00874
for (ValueTracking::UseDefChain::iterator possdef
00875 = ut->defs[use->source][use->index].begin();
00876 possdef != ut->defs[use->source][use->index].end(); ++possdef) {
00877 ConstProp* dcp = possdef->stmt->template get_info<ConstProp>();
00878
if (!dcp) {
00879
#ifdef SH_DEBUG_CONSTPROP
00880
SH_DEBUG_PRINT(
"Possible def " << *dcp->stmt <<
" on worklist does not have CP information?");
00881
#endif
00882
continue;
00883 }
00884
00885 ConstProp::Cell destcell = dcp->dest[possdef->index];
00886
00887
00888
if (use->stmt->src[use->source].neg()) {
00889
if (destcell.state == ConstProp::Cell::CONSTANT) {
00890 destcell.value = -destcell.value;
00891 }
else if (destcell.state == ConstProp::Cell::UNIFORM) {
00892 destcell.uniform.neg = !destcell.uniform.neg;
00893 }
00894 }
00895
#ifdef SH_DEBUG_CONSTPROP
00896
SH_DEBUG_PRINT(
" meet(" << new_cell <<
", " << destcell <<
") = " <<
00897 meet(new_cell, destcell));
00898
#endif
00899
new_cell = meet(new_cell, destcell);
00900 }
00901
00902
if (cell != new_cell) {
00903
#ifdef SH_DEBUG_CONSTPROP
00904
SH_DEBUG_PRINT(
" ...replacing cell");
00905
#endif
00906
cp->src[use->source][use->index] = new_cell;
00907 cp->updateDest(worklist);
00908 }
00909 }
00910 }
00911
00912
00913
00914
#ifdef SH_DEBUG_CONSTPROP
00915
ConstProp::Value::dump(std::cerr);
00916
00917 DumpConstProp dump;
00918 graph->dfs(dump);
00919
#endif
00920
00921 FinishConstProp finish(p.
node()->target().find(
"gpu:") == 0
00922 && !ShContext::current()->optimization_disabled(
"uniform lifting"));
00923 graph->dfs(finish);
00924
00925 }
00926
00927 }