00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00027 #include <algorithm>
00028 #include <map>
00029 #include <list>
00030 #include "ShError.hpp"
00031 #include "ShDebug.hpp"
00032 #include "ShTypeInfo.hpp"
00033 #include "ShVariable.hpp"
00034 #include "ShVariableNode.hpp"
00035 #include "ShInternals.hpp"
00036 #include "ShSyntax.hpp"
00037 #include "ShProgram.hpp"
00038 #include "ShInstructions.hpp"
00039 #include "ShTransformer.hpp"
00040
00041 namespace {
00042
00043 using namespace SH;
00044
00045
00046
00047 ShProgram intervalADD(int N, ShValueType valueType)
00048 {
00049 ShProgram result = SH_BEGIN_PROGRAM() {
00050 ShVariable a_lo(new ShVariableNode(SH_INPUT, N, valueType));
00051 ShVariable a_hi(new ShVariableNode(SH_INPUT, N, valueType));
00052 ShVariable b_lo(new ShVariableNode(SH_INPUT, N, valueType));
00053 ShVariable b_hi(new ShVariableNode(SH_INPUT, N, valueType));
00054
00055 ShVariable r_lo(new ShVariableNode(SH_OUTPUT, N, valueType));
00056 ShVariable r_hi(new ShVariableNode(SH_OUTPUT, N, valueType));
00057
00058 shADD(r_lo, a_lo, b_lo);
00059 shADD(r_hi, a_hi, b_hi);
00060 } SH_END;
00061 return result;
00062 }
00063
00064 ShProgram intervalMUL(int N, ShValueType valueType)
00065 {
00066 ShProgram result = SH_BEGIN_PROGRAM() {
00067 ShVariable a_lo(new ShVariableNode(SH_INPUT, N, valueType));
00068 ShVariable a_hi(new ShVariableNode(SH_INPUT, N, valueType));
00069 ShVariable b_lo(new ShVariableNode(SH_INPUT, N, valueType));
00070 ShVariable b_hi(new ShVariableNode(SH_INPUT, N, valueType));
00071
00072 ShVariable r_lo(new ShVariableNode(SH_OUTPUT, N, valueType));
00073 ShVariable r_hi(new ShVariableNode(SH_OUTPUT, N, valueType));
00074
00075 ShVariable ll(new ShVariableNode(SH_TEMP, N, valueType));
00076 ShVariable lh(new ShVariableNode(SH_TEMP, N, valueType));
00077 ShVariable hl(new ShVariableNode(SH_TEMP, N, valueType));
00078 ShVariable hh(new ShVariableNode(SH_TEMP, N, valueType));
00079 ShVariable temp(new ShVariableNode(SH_TEMP, N, valueType));
00080
00081 shMUL(ll, a_lo, b_lo);
00082 shMUL(lh, a_lo, b_hi);
00083 shMUL(hl, a_hi, b_lo);
00084 shMUL(hh, a_hi, b_hi);
00085
00086 shMIN(temp, ll, lh);
00087 shMIN(r_lo, hl, hh);
00088 shMIN(r_lo, r_lo, temp);
00089
00090 shMAX(temp, ll, lh);
00091 shMAX(r_hi, hl, hh);
00092 shMAX(r_hi, r_hi, temp);
00093 } SH_END;
00094 return result;
00095 }
00096
00097 ShProgram getProgram(ShOperation op, int N, ShValueType valueType) {
00098 switch(op) {
00099 case SH_OP_ADD: return intervalADD(N, valueType);
00100 case SH_OP_MUL: return intervalMUL(N, valueType);
00101 default:
00102 shError(ShTransformerException(
00103 "Cannot translate interval arithmetic"));
00104 }
00105 return ShProgram();
00106 }
00107
00108 typedef std::map<int, int> ValueTypeMap;
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 struct IntervalSplitter {
00120
00121 IntervalSplitter(ShTransformer::VarSplitMap& splits, bool &changed)
00122 : splits(splits), changed(changed) {
00123 }
00124
00125 void operator()(ShCtrlGraphNodePtr node) {
00126 if (!node) return;
00127 ShBasicBlockPtr block = node->block;
00128 if (!block) return;
00129 for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) {
00130 splitVars(*I);
00131 }
00132 }
00133
00134
00135
00136 void splitVarList(ShProgramNode::VarList &vars) {
00137 for(ShProgramNode::VarList::iterator I = vars.begin();
00138 I != vars.end();) {
00139 if(split(*I)) {
00140
00141
00142
00143
00144 vars.insert(I, splits[*I].begin(), splits[*I].end());
00145 I = vars.erase(I);
00146 } else ++I;
00147 }
00148 }
00149
00150 ShVariableNodePtr cloneNode(ShVariableNodePtr node, ShValueType rangeValueType) {
00151 return node->clone(SH_BINDINGTYPE_END, 0, rangeValueType, SH_SEMANTICTYPE_END, false);
00152 }
00153
00154 void splitVars(ShStatement& stmt) {
00155 stmt.marked = false;
00156 if(stmt.dest.node()) stmt.marked = split(stmt.dest.node()) || stmt.marked;
00157 for(int i = 0; i < 3; ++i) if(stmt.src[i].node()) stmt.marked = split(stmt.src[i].node()) || stmt.marked;
00158 }
00159
00160
00161
00162
00163
00164 bool split(ShVariableNodePtr node)
00165 {
00166 ShValueType valueType = node->valueType();
00167
00168 if(!shIsInterval(valueType)) return false;
00169 else if(splits.count(node) > 0) return true;
00170
00171 if( node->kind() == SH_TEXTURE || node->kind() == SH_STREAM ) {
00172 shError( ShTransformerException(
00173 "Interval Arithmetic support is not implemented for textures or streams"));
00174 }
00175 changed = true;
00176
00177 ShTransformer::VarNodeVec &splitNodes = splits[node];
00178 ShValueType newValueType = shRegularValueType(valueType);
00179
00180 splitNodes.push_back(cloneNode(node, newValueType));
00181 splitNodes.push_back(cloneNode(node, newValueType));
00182
00183
00184 return true;
00185 }
00186
00187 ShTransformer::VarSplitMap &splits;
00188 bool& changed;
00189 };
00190
00191
00192
00193
00197 struct IntervalStatementFixer {
00198 typedef std::vector<ShVariable> VarVec;
00199
00200 IntervalStatementFixer(ShTransformer::VarSplitMap &splits)
00201 : splits(splits), dirty(false) {}
00202
00203 void operator()(ShCtrlGraphNodePtr node) {
00204 if (dirty) return;
00205 if (!node) return;
00206 ShBasicBlockPtr block = node->block;
00207 if (!block) return;
00208
00209 for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) {
00210 if(I->marked) splitStatement(I, node);
00211 }
00212 }
00213
00214
00215 void splitStatement(ShBasicBlock::ShStmtList::iterator stmtI, ShCtrlGraphNodePtr node)
00216 {
00217 int i;
00218 ShStatement &stmt = *stmtI;
00219
00220
00221 int opSize = 0;
00222 for(i = 0; stmt.src[i].node(); ++i) opSize = std::max(opSize, stmt.src[i].size());
00223
00224 switch(stmt.op) {
00225
00226 case SH_OP_LO:
00227 stmt.src[0] = ShVariable(splits[stmt.src[0].node()][0], stmt.src[0].swizzle(), stmt.src[0].neg());
00228 stmt.op = SH_OP_ASN;
00229 break;
00230
00231 case SH_OP_HI:
00232 stmt.src[0] = ShVariable(splits[stmt.src[0].node()][1], stmt.src[0].swizzle(), stmt.src[0].neg());
00233 stmt.op = SH_OP_ASN;
00234 break;
00235
00236 case SH_OP_SETLO:
00237 stmt.dest = ShVariable(splits[stmt.dest.node()][0], stmt.dest.swizzle(), stmt.dest.neg());
00238 stmt.op = SH_OP_ASN;
00239 break;
00240
00241 case SH_OP_SETHI:
00242 stmt.dest = ShVariable(splits[stmt.dest.node()][1], stmt.dest.swizzle(), stmt.dest.neg());
00243 stmt.op = SH_OP_ASN;
00244 break;
00245
00246 default:
00247
00248 dirty = true;
00249
00250
00251 ShCtrlGraphNodePtr after = node->split(stmtI);
00252
00253
00254
00255
00256
00257
00258 ShValueType iaType = stmt.dest.valueType();
00259 ShValueType newType = shRegularValueType(iaType);
00260
00261 ShProgram newProgram = getProgram(stmt.op, opSize, newType);
00262
00263
00264
00265
00266
00267
00268 ShVarMap varMap;
00269 ShProgramNode::VarList destNodes;
00270 ShProgramNode::VarList srcNodes;
00271 ShProgramNodePtr pnode = newProgram.node();
00272 ShVariableNodePtr temp;
00273 ShProgramNode::VarList::const_iterator I;
00274 ShProgramNode::VarList::const_iterator O;
00275
00276 for(I = pnode->inputs.begin(); I != pnode->inputs.end(); ++I) {
00277 varMap[*I] = temp = (*I)->clone(SH_TEMP);
00278 srcNodes.push_back(temp);
00279 }
00280
00281 for(O = pnode->outputs.begin(); O != pnode->outputs.end(); ++O) {
00282 varMap[*O] = temp = (*O)->clone(SH_TEMP);
00283 destNodes.push_back(temp);
00284 }
00285
00286 ShVariableReplacer varFix(varMap);
00287 newProgram.node()->ctrlGraph->dfs(varFix);
00288
00289
00290
00291
00292
00293 ShBasicBlockPtr beforeBlock = node->block;
00294 I = srcNodes.begin();
00295 for(i = 0; stmt.src[i].node() && I != srcNodes.end(); ++i) {
00296
00297 beforeBlock->addStatement(ShStatement(ShVariable(*I), SH_OP_ASN,
00298 ShVariable(splits[stmt.src[i].node()][0],stmt.src[i].swizzle(), stmt.src[i].neg())));
00299 ++I;
00300 SH_DEBUG_ASSERT(I != srcNodes.end());
00301 beforeBlock->addStatement(ShStatement(ShVariable(*I), SH_OP_ASN,
00302 ShVariable(splits[stmt.src[i].node()][1],stmt.src[i].swizzle(), stmt.src[i].neg())));
00303 ++I;
00304 }
00305
00306 ShBasicBlockPtr afterBlock = after->block;
00307 I = srcNodes.begin();
00308
00309 afterBlock->addStatement(ShStatement(ShVariable(splits[stmt.dest.node()][0],stmt.dest.swizzle(), stmt.dest.neg()),
00310 SH_OP_ASN, ShVariable(*I)));
00311 ++I;
00312 SH_DEBUG_ASSERT(I != srcNodes.end());
00313 afterBlock->addStatement(ShStatement(ShVariable(splits[stmt.dest.node()][1],stmt.dest.swizzle(), stmt.dest.neg()),
00314 SH_OP_ASN, ShVariable(*I)));
00315
00316
00317 node->append(newProgram.node()->ctrlGraph->entry());
00318 newProgram.node()->ctrlGraph->exit()->append(after);
00319
00320
00321
00322 afterBlock->erase(stmtI);
00323 }
00324 }
00325
00326 void resetDirt() {
00327 dirty = false;
00328 }
00329
00330 bool isDirty() {
00331 return dirty;
00332 }
00333
00334 ShTransformer::VarSplitMap &splits;
00335 bool dirty;
00336 };
00337
00338 }
00339
00340 namespace SH {
00341
00342 void ShTransformer::convertIntervalTypes(ShTransformer::VarSplitMap &splits) {
00343 IntervalSplitter is(splits, m_changed);
00344 is.splitVarList(m_program->inputs);
00345 is.splitVarList(m_program->outputs);
00346 m_program->ctrlGraph->dfs(is);
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 IntervalStatementFixer isf(splits);
00364 do {
00365 isf.resetDirt();
00366 m_program->ctrlGraph->dfs(isf);
00367 m_changed = m_changed || isf.isDirty();
00368 } while(isf.isDirty());
00369 }
00370
00371 }