OSDN Git Service

fb2aec62144b5f2675e0eb08ff931177299778c2
[android-x86/external-mesa.git] / src / gallium / drivers / nouveau / codegen / nv50_ir_lowering_nvc0.cpp
1 /*
2  * Copyright 2011 Christoph Bumiller
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  */
22
23 #include "codegen/nv50_ir.h"
24 #include "codegen/nv50_ir_build_util.h"
25
26 #include "codegen/nv50_ir_target_nvc0.h"
27 #include "codegen/nv50_ir_lowering_nvc0.h"
28
29 #include <limits>
30
31 namespace nv50_ir {
32
33 #define QOP_ADD  0
34 #define QOP_SUBR 1
35 #define QOP_SUB  2
36 #define QOP_MOV2 3
37
38 //             UL UR LL LR
39 #define QUADOP(q, r, s, t)                      \
40    ((QOP_##q << 6) | (QOP_##r << 4) |           \
41     (QOP_##s << 2) | (QOP_##t << 0))
42
43 void
44 NVC0LegalizeSSA::handleDIV(Instruction *i)
45 {
46    FlowInstruction *call;
47    int builtin;
48    Value *def[2];
49
50    bld.setPosition(i, false);
51    def[0] = bld.mkMovToReg(0, i->getSrc(0))->getDef(0);
52    def[1] = bld.mkMovToReg(1, i->getSrc(1))->getDef(0);
53    switch (i->dType) {
54    case TYPE_U32: builtin = NVC0_BUILTIN_DIV_U32; break;
55    case TYPE_S32: builtin = NVC0_BUILTIN_DIV_S32; break;
56    default:
57       return;
58    }
59    call = bld.mkFlow(OP_CALL, NULL, CC_ALWAYS, NULL);
60    bld.mkMov(i->getDef(0), def[(i->op == OP_DIV) ? 0 : 1]);
61    bld.mkClobber(FILE_GPR, (i->op == OP_DIV) ? 0xe : 0xd, 2);
62    bld.mkClobber(FILE_PREDICATE, (i->dType == TYPE_S32) ? 0xf : 0x3, 0);
63
64    call->fixed = 1;
65    call->absolute = call->builtin = 1;
66    call->target.builtin = builtin;
67    delete_Instruction(prog, i);
68 }
69
70 void
71 NVC0LegalizeSSA::handleRCPRSQ(Instruction *i)
72 {
73    assert(i->dType == TYPE_F64);
74    // There are instructions that will compute the high 32 bits of the 64-bit
75    // float. We will just stick 0 in the bottom 32 bits.
76
77    bld.setPosition(i, false);
78
79    // 1. Take the source and it up.
80    Value *src[2], *dst[2], *def = i->getDef(0);
81    bld.mkSplit(src, 4, i->getSrc(0));
82
83    // 2. We don't care about the low 32 bits of the destination. Stick a 0 in.
84    dst[0] = bld.loadImm(NULL, 0);
85    dst[1] = bld.getSSA();
86
87    // 3. The new version of the instruction takes the high 32 bits of the
88    // source and outputs the high 32 bits of the destination.
89    i->setSrc(0, src[1]);
90    i->setDef(0, dst[1]);
91    i->setType(TYPE_F32);
92    i->subOp = NV50_IR_SUBOP_RCPRSQ_64H;
93
94    // 4. Recombine the two dst pieces back into the original destination.
95    bld.setPosition(i, true);
96    bld.mkOp2(OP_MERGE, TYPE_U64, def, dst[0], dst[1]);
97 }
98
99 void
100 NVC0LegalizeSSA::handleFTZ(Instruction *i)
101 {
102    // Only want to flush float inputs
103    assert(i->sType == TYPE_F32);
104
105    // If we're already flushing denorms (and NaN's) to zero, no need for this.
106    if (i->dnz)
107       return;
108
109    // Only certain classes of operations can flush
110    OpClass cls = prog->getTarget()->getOpClass(i->op);
111    if (cls != OPCLASS_ARITH && cls != OPCLASS_COMPARE &&
112        cls != OPCLASS_CONVERT)
113       return;
114
115    i->ftz = true;
116 }
117
118 bool
119 NVC0LegalizeSSA::visit(Function *fn)
120 {
121    bld.setProgram(fn->getProgram());
122    return true;
123 }
124
125 bool
126 NVC0LegalizeSSA::visit(BasicBlock *bb)
127 {
128    Instruction *next;
129    for (Instruction *i = bb->getEntry(); i; i = next) {
130       next = i->next;
131       if (i->sType == TYPE_F32) {
132          if (prog->getType() != Program::TYPE_COMPUTE)
133             handleFTZ(i);
134          continue;
135       }
136       switch (i->op) {
137       case OP_DIV:
138       case OP_MOD:
139          handleDIV(i);
140          break;
141       case OP_RCP:
142       case OP_RSQ:
143          if (i->dType == TYPE_F64)
144             handleRCPRSQ(i);
145          break;
146       default:
147          break;
148       }
149    }
150    return true;
151 }
152
153 NVC0LegalizePostRA::NVC0LegalizePostRA(const Program *prog)
154    : rZero(NULL),
155      carry(NULL),
156      needTexBar(prog->getTarget()->getChipset() >= 0xe0)
157 {
158 }
159
160 bool
161 NVC0LegalizePostRA::insnDominatedBy(const Instruction *later,
162                                     const Instruction *early) const
163 {
164    if (early->bb == later->bb)
165       return early->serial < later->serial;
166    return later->bb->dominatedBy(early->bb);
167 }
168
169 void
170 NVC0LegalizePostRA::addTexUse(std::list<TexUse> &uses,
171                               Instruction *usei, const Instruction *texi)
172 {
173    bool add = true;
174    for (std::list<TexUse>::iterator it = uses.begin();
175         it != uses.end();) {
176       if (insnDominatedBy(usei, it->insn)) {
177          add = false;
178          break;
179       }
180       if (insnDominatedBy(it->insn, usei))
181          it = uses.erase(it);
182       else
183          ++it;
184    }
185    if (add)
186       uses.push_back(TexUse(usei, texi));
187 }
188
189 // While it might be tempting to use the an algorithm that just looks at tex
190 // uses, not all texture results are guaranteed to be used on all paths. In
191 // the case where along some control flow path a texture result is never used,
192 // we might reuse that register for something else, creating a
193 // write-after-write hazard. So we have to manually look through all
194 // instructions looking for ones that reference the registers in question.
195 void
196 NVC0LegalizePostRA::findFirstUses(
197    Instruction *texi, std::list<TexUse> &uses)
198 {
199    int minGPR = texi->def(0).rep()->reg.data.id;
200    int maxGPR = minGPR + texi->def(0).rep()->reg.size / 4 - 1;
201
202    unordered_set<const BasicBlock *> visited;
203    findFirstUsesBB(minGPR, maxGPR, texi->next, texi, uses, visited);
204 }
205
206 void
207 NVC0LegalizePostRA::findFirstUsesBB(
208    int minGPR, int maxGPR, Instruction *start,
209    const Instruction *texi, std::list<TexUse> &uses,
210    unordered_set<const BasicBlock *> &visited)
211 {
212    const BasicBlock *bb = start->bb;
213
214    // We don't process the whole bb the first time around. This is correct,
215    // however we might be in a loop and hit this BB again, and need to process
216    // the full thing. So only mark a bb as visited if we processed it from the
217    // beginning.
218    if (start == bb->getEntry()) {
219       if (visited.find(bb) != visited.end())
220          return;
221       visited.insert(bb);
222    }
223
224    for (Instruction *insn = start; insn != bb->getExit(); insn = insn->next) {
225       if (insn->isNop())
226          continue;
227
228       for (int d = 0; insn->defExists(d); ++d) {
229          if (insn->def(d).getFile() != FILE_GPR ||
230              insn->def(d).rep()->reg.data.id < minGPR ||
231              insn->def(d).rep()->reg.data.id > maxGPR)
232             continue;
233          addTexUse(uses, insn, texi);
234          return;
235       }
236
237       for (int s = 0; insn->srcExists(s); ++s) {
238          if (insn->src(s).getFile() != FILE_GPR ||
239              insn->src(s).rep()->reg.data.id < minGPR ||
240              insn->src(s).rep()->reg.data.id > maxGPR)
241             continue;
242          addTexUse(uses, insn, texi);
243          return;
244       }
245    }
246
247    for (Graph::EdgeIterator ei = bb->cfg.outgoing(); !ei.end(); ei.next()) {
248       findFirstUsesBB(minGPR, maxGPR, BasicBlock::get(ei.getNode())->getEntry(),
249                       texi, uses, visited);
250    }
251 }
252
253 // Texture barriers:
254 // This pass is a bit long and ugly and can probably be optimized.
255 //
256 // 1. obtain a list of TEXes and their outputs' first use(s)
257 // 2. calculate the barrier level of each first use (minimal number of TEXes,
258 //    over all paths, between the TEX and the use in question)
259 // 3. for each barrier, if all paths from the source TEX to that barrier
260 //    contain a barrier of lesser level, it can be culled
261 bool
262 NVC0LegalizePostRA::insertTextureBarriers(Function *fn)
263 {
264    std::list<TexUse> *uses;
265    std::vector<Instruction *> texes;
266    std::vector<int> bbFirstTex;
267    std::vector<int> bbFirstUse;
268    std::vector<int> texCounts;
269    std::vector<TexUse> useVec;
270    ArrayList insns;
271
272    fn->orderInstructions(insns);
273
274    texCounts.resize(fn->allBBlocks.getSize(), 0);
275    bbFirstTex.resize(fn->allBBlocks.getSize(), insns.getSize());
276    bbFirstUse.resize(fn->allBBlocks.getSize(), insns.getSize());
277
278    // tag BB CFG nodes by their id for later
279    for (ArrayList::Iterator i = fn->allBBlocks.iterator(); !i.end(); i.next()) {
280       BasicBlock *bb = reinterpret_cast<BasicBlock *>(i.get());
281       if (bb)
282          bb->cfg.tag = bb->getId();
283    }
284
285    // gather the first uses for each TEX
286    for (int i = 0; i < insns.getSize(); ++i) {
287       Instruction *tex = reinterpret_cast<Instruction *>(insns.get(i));
288       if (isTextureOp(tex->op)) {
289          texes.push_back(tex);
290          if (!texCounts.at(tex->bb->getId()))
291             bbFirstTex[tex->bb->getId()] = texes.size() - 1;
292          texCounts[tex->bb->getId()]++;
293       }
294    }
295    insns.clear();
296    if (texes.empty())
297       return false;
298    uses = new std::list<TexUse>[texes.size()];
299    if (!uses)
300       return false;
301    for (size_t i = 0; i < texes.size(); ++i) {
302       findFirstUses(texes[i], uses[i]);
303    }
304
305    // determine the barrier level at each use
306    for (size_t i = 0; i < texes.size(); ++i) {
307       for (std::list<TexUse>::iterator u = uses[i].begin(); u != uses[i].end();
308            ++u) {
309          BasicBlock *tb = texes[i]->bb;
310          BasicBlock *ub = u->insn->bb;
311          if (tb == ub) {
312             u->level = 0;
313             for (size_t j = i + 1; j < texes.size() &&
314                     texes[j]->bb == tb && texes[j]->serial < u->insn->serial;
315                  ++j)
316                u->level++;
317          } else {
318             u->level = fn->cfg.findLightestPathWeight(&tb->cfg,
319                                                       &ub->cfg, texCounts);
320             if (u->level < 0) {
321                WARN("Failed to find path TEX -> TEXBAR\n");
322                u->level = 0;
323                continue;
324             }
325             // this counted all TEXes in the origin block, correct that
326             u->level -= i - bbFirstTex.at(tb->getId()) + 1 /* this TEX */;
327             // and did not count the TEXes in the destination block, add those
328             for (size_t j = bbFirstTex.at(ub->getId()); j < texes.size() &&
329                     texes[j]->bb == ub && texes[j]->serial < u->insn->serial;
330                  ++j)
331                u->level++;
332          }
333          assert(u->level >= 0);
334          useVec.push_back(*u);
335       }
336    }
337    delete[] uses;
338
339    // insert the barriers
340    for (size_t i = 0; i < useVec.size(); ++i) {
341       Instruction *prev = useVec[i].insn->prev;
342       if (useVec[i].level < 0)
343          continue;
344       if (prev && prev->op == OP_TEXBAR) {
345          if (prev->subOp > useVec[i].level)
346             prev->subOp = useVec[i].level;
347          prev->setSrc(prev->srcCount(), useVec[i].tex->getDef(0));
348       } else {
349          Instruction *bar = new_Instruction(func, OP_TEXBAR, TYPE_NONE);
350          bar->fixed = 1;
351          bar->subOp = useVec[i].level;
352          // make use explicit to ease latency calculation
353          bar->setSrc(bar->srcCount(), useVec[i].tex->getDef(0));
354          useVec[i].insn->bb->insertBefore(useVec[i].insn, bar);
355       }
356    }
357
358    if (fn->getProgram()->optLevel < 3)
359       return true;
360
361    std::vector<Limits> limitT, limitB, limitS; // entry, exit, single
362
363    limitT.resize(fn->allBBlocks.getSize(), Limits(0, 0));
364    limitB.resize(fn->allBBlocks.getSize(), Limits(0, 0));
365    limitS.resize(fn->allBBlocks.getSize());
366
367    // cull unneeded barriers (should do that earlier, but for simplicity)
368    IteratorRef bi = fn->cfg.iteratorCFG();
369    // first calculate min/max outstanding TEXes for each BB
370    for (bi->reset(); !bi->end(); bi->next()) {
371       Graph::Node *n = reinterpret_cast<Graph::Node *>(bi->get());
372       BasicBlock *bb = BasicBlock::get(n);
373       int min = 0;
374       int max = std::numeric_limits<int>::max();
375       for (Instruction *i = bb->getFirst(); i; i = i->next) {
376          if (isTextureOp(i->op)) {
377             min++;
378             if (max < std::numeric_limits<int>::max())
379                max++;
380          } else
381          if (i->op == OP_TEXBAR) {
382             min = MIN2(min, i->subOp);
383             max = MIN2(max, i->subOp);
384          }
385       }
386       // limits when looking at an isolated block
387       limitS[bb->getId()].min = min;
388       limitS[bb->getId()].max = max;
389    }
390    // propagate the min/max values
391    for (unsigned int l = 0; l <= fn->loopNestingBound; ++l) {
392       for (bi->reset(); !bi->end(); bi->next()) {
393          Graph::Node *n = reinterpret_cast<Graph::Node *>(bi->get());
394          BasicBlock *bb = BasicBlock::get(n);
395          const int bbId = bb->getId();
396          for (Graph::EdgeIterator ei = n->incident(); !ei.end(); ei.next()) {
397             BasicBlock *in = BasicBlock::get(ei.getNode());
398             const int inId = in->getId();
399             limitT[bbId].min = MAX2(limitT[bbId].min, limitB[inId].min);
400             limitT[bbId].max = MAX2(limitT[bbId].max, limitB[inId].max);
401          }
402          // I just hope this is correct ...
403          if (limitS[bbId].max == std::numeric_limits<int>::max()) {
404             // no barrier
405             limitB[bbId].min = limitT[bbId].min + limitS[bbId].min;
406             limitB[bbId].max = limitT[bbId].max + limitS[bbId].min;
407          } else {
408             // block contained a barrier
409             limitB[bbId].min = MIN2(limitS[bbId].max,
410                                     limitT[bbId].min + limitS[bbId].min);
411             limitB[bbId].max = MIN2(limitS[bbId].max,
412                                     limitT[bbId].max + limitS[bbId].min);
413          }
414       }
415    }
416    // finally delete unnecessary barriers
417    for (bi->reset(); !bi->end(); bi->next()) {
418       Graph::Node *n = reinterpret_cast<Graph::Node *>(bi->get());
419       BasicBlock *bb = BasicBlock::get(n);
420       Instruction *prev = NULL;
421       Instruction *next;
422       int max = limitT[bb->getId()].max;
423       for (Instruction *i = bb->getFirst(); i; i = next) {
424          next = i->next;
425          if (i->op == OP_TEXBAR) {
426             if (i->subOp >= max) {
427                delete_Instruction(prog, i);
428                i = NULL;
429             } else {
430                max = i->subOp;
431                if (prev && prev->op == OP_TEXBAR && prev->subOp >= max) {
432                   delete_Instruction(prog, prev);
433                   prev = NULL;
434                }
435             }
436          } else
437          if (isTextureOp(i->op)) {
438             max++;
439          }
440          if (i && !i->isNop())
441             prev = i;
442       }
443    }
444    return true;
445 }
446
447 bool
448 NVC0LegalizePostRA::visit(Function *fn)
449 {
450    if (needTexBar)
451       insertTextureBarriers(fn);
452
453    rZero = new_LValue(fn, FILE_GPR);
454    carry = new_LValue(fn, FILE_FLAGS);
455
456    rZero->reg.data.id = prog->getTarget()->getFileSize(FILE_GPR);
457    carry->reg.data.id = 0;
458
459    return true;
460 }
461
462 void
463 NVC0LegalizePostRA::replaceZero(Instruction *i)
464 {
465    for (int s = 0; i->srcExists(s); ++s) {
466       if (s == 2 && i->op == OP_SUCLAMP)
467          continue;
468       ImmediateValue *imm = i->getSrc(s)->asImm();
469       if (imm && imm->reg.data.u64 == 0)
470          i->setSrc(s, rZero);
471    }
472 }
473
474 // replace CONT with BRA for single unconditional continue
475 bool
476 NVC0LegalizePostRA::tryReplaceContWithBra(BasicBlock *bb)
477 {
478    if (bb->cfg.incidentCount() != 2 || bb->getEntry()->op != OP_PRECONT)
479       return false;
480    Graph::EdgeIterator ei = bb->cfg.incident();
481    if (ei.getType() != Graph::Edge::BACK)
482       ei.next();
483    if (ei.getType() != Graph::Edge::BACK)
484       return false;
485    BasicBlock *contBB = BasicBlock::get(ei.getNode());
486
487    if (!contBB->getExit() || contBB->getExit()->op != OP_CONT ||
488        contBB->getExit()->getPredicate())
489       return false;
490    contBB->getExit()->op = OP_BRA;
491    bb->remove(bb->getEntry()); // delete PRECONT
492
493    ei.next();
494    assert(ei.end() || ei.getType() != Graph::Edge::BACK);
495    return true;
496 }
497
498 // replace branches to join blocks with join ops
499 void
500 NVC0LegalizePostRA::propagateJoin(BasicBlock *bb)
501 {
502    if (bb->getEntry()->op != OP_JOIN || bb->getEntry()->asFlow()->limit)
503       return;
504    for (Graph::EdgeIterator ei = bb->cfg.incident(); !ei.end(); ei.next()) {
505       BasicBlock *in = BasicBlock::get(ei.getNode());
506       Instruction *exit = in->getExit();
507       if (!exit) {
508          in->insertTail(new FlowInstruction(func, OP_JOIN, bb));
509          // there should always be a terminator instruction
510          WARN("inserted missing terminator in BB:%i\n", in->getId());
511       } else
512       if (exit->op == OP_BRA) {
513          exit->op = OP_JOIN;
514          exit->asFlow()->limit = 1; // must-not-propagate marker
515       }
516    }
517    bb->remove(bb->getEntry());
518 }
519
520 bool
521 NVC0LegalizePostRA::visit(BasicBlock *bb)
522 {
523    Instruction *i, *next;
524
525    // remove pseudo operations and non-fixed no-ops, split 64 bit operations
526    for (i = bb->getFirst(); i; i = next) {
527       next = i->next;
528       if (i->op == OP_EMIT || i->op == OP_RESTART) {
529          if (!i->getDef(0)->refCount())
530             i->setDef(0, NULL);
531          if (i->src(0).getFile() == FILE_IMMEDIATE)
532             i->setSrc(0, rZero); // initial value must be 0
533          replaceZero(i);
534       } else
535       if (i->isNop()) {
536          bb->remove(i);
537       } else
538       if (i->op == OP_BAR && i->subOp == NV50_IR_SUBOP_BAR_SYNC &&
539           prog->getType() != Program::TYPE_COMPUTE) {
540          // It seems like barriers are never required for tessellation since
541          // the warp size is 32, and there are always at most 32 tcs threads.
542          bb->remove(i);
543       } else
544       if (i->op == OP_LOAD && i->subOp == NV50_IR_SUBOP_LDC_IS) {
545          int offset = i->src(0).get()->reg.data.offset;
546          if (abs(offset) > 0x10000)
547             i->src(0).get()->reg.fileIndex += offset >> 16;
548          i->src(0).get()->reg.data.offset = (int)(short)offset;
549       } else {
550          // TODO: Move this to before register allocation for operations that
551          // need the $c register !
552          if (typeSizeof(i->dType) == 8) {
553             Instruction *hi;
554             hi = BuildUtil::split64BitOpPostRA(func, i, rZero, carry);
555             if (hi)
556                next = hi;
557          }
558
559          if (i->op != OP_MOV && i->op != OP_PFETCH)
560             replaceZero(i);
561       }
562    }
563    if (!bb->getEntry())
564       return true;
565
566    if (!tryReplaceContWithBra(bb))
567       propagateJoin(bb);
568
569    return true;
570 }
571
572 NVC0LoweringPass::NVC0LoweringPass(Program *prog) : targ(prog->getTarget())
573 {
574    bld.setProgram(prog);
575    gMemBase = NULL;
576 }
577
578 bool
579 NVC0LoweringPass::visit(Function *fn)
580 {
581    if (prog->getType() == Program::TYPE_GEOMETRY) {
582       assert(!strncmp(fn->getName(), "MAIN", 4));
583       // TODO: when we generate actual functions pass this value along somehow
584       bld.setPosition(BasicBlock::get(fn->cfg.getRoot()), false);
585       gpEmitAddress = bld.loadImm(NULL, 0)->asLValue();
586       if (fn->cfgExit) {
587          bld.setPosition(BasicBlock::get(fn->cfgExit)->getExit(), false);
588          bld.mkMovToReg(0, gpEmitAddress);
589       }
590    }
591    return true;
592 }
593
594 bool
595 NVC0LoweringPass::visit(BasicBlock *bb)
596 {
597    return true;
598 }
599
600 inline Value *
601 NVC0LoweringPass::loadTexHandle(Value *ptr, unsigned int slot)
602 {
603    uint8_t b = prog->driver->io.auxCBSlot;
604    uint32_t off = prog->driver->io.texBindBase + slot * 4;
605    return bld.
606       mkLoadv(TYPE_U32, bld.mkSymbol(FILE_MEMORY_CONST, b, TYPE_U32, off), ptr);
607 }
608
609 // move array source to first slot, convert to u16, add indirections
610 bool
611 NVC0LoweringPass::handleTEX(TexInstruction *i)
612 {
613    const int dim = i->tex.target.getDim() + i->tex.target.isCube();
614    const int arg = i->tex.target.getArgCount();
615    const int lyr = arg - (i->tex.target.isMS() ? 2 : 1);
616    const int chipset = prog->getTarget()->getChipset();
617
618    /* Only normalize in the non-explicit derivatives case. For explicit
619     * derivatives, this is handled in handleManualTXD.
620     */
621    if (i->tex.target.isCube() && i->dPdx[0].get() == NULL) {
622       Value *src[3], *val;
623       int c;
624       for (c = 0; c < 3; ++c)
625          src[c] = bld.mkOp1v(OP_ABS, TYPE_F32, bld.getSSA(), i->getSrc(c));
626       val = bld.getScratch();
627       bld.mkOp2(OP_MAX, TYPE_F32, val, src[0], src[1]);
628       bld.mkOp2(OP_MAX, TYPE_F32, val, src[2], val);
629       bld.mkOp1(OP_RCP, TYPE_F32, val, val);
630       for (c = 0; c < 3; ++c) {
631          i->setSrc(c, bld.mkOp2v(OP_MUL, TYPE_F32, bld.getSSA(),
632                                  i->getSrc(c), val));
633       }
634    }
635
636    // Arguments to the TEX instruction are a little insane. Even though the
637    // encoding is identical between SM20 and SM30, the arguments mean
638    // different things between Fermi and Kepler+. A lot of arguments are
639    // optional based on flags passed to the instruction. This summarizes the
640    // order of things.
641    //
642    // Fermi:
643    //  array/indirect
644    //  coords
645    //  sample
646    //  lod bias
647    //  depth compare
648    //  offsets:
649    //    - tg4: 8 bits each, either 2 (1 offset reg) or 8 (2 offset reg)
650    //    - other: 4 bits each, single reg
651    //
652    // Kepler+:
653    //  indirect handle
654    //  array (+ offsets for txd in upper 16 bits)
655    //  coords
656    //  sample
657    //  lod bias
658    //  depth compare
659    //  offsets (same as fermi, except txd which takes it with array)
660    //
661    // Maxwell (tex):
662    //  array
663    //  coords
664    //  indirect handle
665    //  sample
666    //  lod bias
667    //  depth compare
668    //  offsets
669    //
670    // Maxwell (txd):
671    //  indirect handle
672    //  coords
673    //  array + offsets
674    //  derivatives
675
676    if (chipset >= NVISA_GK104_CHIPSET) {
677       if (i->tex.rIndirectSrc >= 0 || i->tex.sIndirectSrc >= 0) {
678          // XXX this ignores tsc, and assumes a 1:1 mapping
679          assert(i->tex.rIndirectSrc >= 0);
680          Value *hnd = loadTexHandle(
681                bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(),
682                           i->getIndirectR(), bld.mkImm(2)),
683                i->tex.r);
684          i->tex.r = 0xff;
685          i->tex.s = 0x1f;
686          i->setIndirectR(hnd);
687          i->setIndirectS(NULL);
688       } else if (i->tex.r == i->tex.s || i->op == OP_TXF) {
689          i->tex.r += prog->driver->io.texBindBase / 4;
690          i->tex.s  = 0; // only a single cX[] value possible here
691       } else {
692          Value *hnd = bld.getScratch();
693          Value *rHnd = loadTexHandle(NULL, i->tex.r);
694          Value *sHnd = loadTexHandle(NULL, i->tex.s);
695
696          bld.mkOp3(OP_INSBF, TYPE_U32, hnd, rHnd, bld.mkImm(0x1400), sHnd);
697
698          i->tex.r = 0; // not used for indirect tex
699          i->tex.s = 0;
700          i->setIndirectR(hnd);
701       }
702       if (i->tex.target.isArray()) {
703          LValue *layer = new_LValue(func, FILE_GPR);
704          Value *src = i->getSrc(lyr);
705          const int sat = (i->op == OP_TXF) ? 1 : 0;
706          DataType sTy = (i->op == OP_TXF) ? TYPE_U32 : TYPE_F32;
707          bld.mkCvt(OP_CVT, TYPE_U16, layer, sTy, src)->saturate = sat;
708          if (i->op != OP_TXD || chipset < NVISA_GM107_CHIPSET) {
709             for (int s = dim; s >= 1; --s)
710                i->setSrc(s, i->getSrc(s - 1));
711             i->setSrc(0, layer);
712          } else {
713             i->setSrc(dim, layer);
714          }
715       }
716       // Move the indirect reference to the first place
717       if (i->tex.rIndirectSrc >= 0 && (
718                 i->op == OP_TXD || chipset < NVISA_GM107_CHIPSET)) {
719          Value *hnd = i->getIndirectR();
720
721          i->setIndirectR(NULL);
722          i->moveSources(0, 1);
723          i->setSrc(0, hnd);
724          i->tex.rIndirectSrc = 0;
725          i->tex.sIndirectSrc = -1;
726       }
727    } else
728    // (nvc0) generate and move the tsc/tic/array source to the front
729    if (i->tex.target.isArray() || i->tex.rIndirectSrc >= 0 || i->tex.sIndirectSrc >= 0) {
730       LValue *src = new_LValue(func, FILE_GPR); // 0xttxsaaaa
731
732       Value *ticRel = i->getIndirectR();
733       Value *tscRel = i->getIndirectS();
734
735       if (ticRel) {
736          i->setSrc(i->tex.rIndirectSrc, NULL);
737          if (i->tex.r)
738             ticRel = bld.mkOp2v(OP_ADD, TYPE_U32, bld.getScratch(),
739                                 ticRel, bld.mkImm(i->tex.r));
740       }
741       if (tscRel) {
742          i->setSrc(i->tex.sIndirectSrc, NULL);
743          if (i->tex.s)
744             tscRel = bld.mkOp2v(OP_ADD, TYPE_U32, bld.getScratch(),
745                                 tscRel, bld.mkImm(i->tex.s));
746       }
747
748       Value *arrayIndex = i->tex.target.isArray() ? i->getSrc(lyr) : NULL;
749       if (arrayIndex) {
750          for (int s = dim; s >= 1; --s)
751             i->setSrc(s, i->getSrc(s - 1));
752          i->setSrc(0, arrayIndex);
753       } else {
754          i->moveSources(0, 1);
755       }
756
757       if (arrayIndex) {
758          int sat = (i->op == OP_TXF) ? 1 : 0;
759          DataType sTy = (i->op == OP_TXF) ? TYPE_U32 : TYPE_F32;
760          bld.mkCvt(OP_CVT, TYPE_U16, src, sTy, arrayIndex)->saturate = sat;
761       } else {
762          bld.loadImm(src, 0);
763       }
764
765       if (ticRel)
766          bld.mkOp3(OP_INSBF, TYPE_U32, src, ticRel, bld.mkImm(0x0917), src);
767       if (tscRel)
768          bld.mkOp3(OP_INSBF, TYPE_U32, src, tscRel, bld.mkImm(0x0710), src);
769
770       i->setSrc(0, src);
771    }
772
773    // For nvc0, the sample id has to be in the second operand, as the offset
774    // does. Right now we don't know how to pass both in, and this case can't
775    // happen with OpenGL. On nve0, the sample id is part of the texture
776    // coordinate argument.
777    assert(chipset >= NVISA_GK104_CHIPSET ||
778           !i->tex.useOffsets || !i->tex.target.isMS());
779
780    // offset is between lod and dc
781    if (i->tex.useOffsets) {
782       int n, c;
783       int s = i->srcCount(0xff, true);
784       if (i->op != OP_TXD || chipset < NVISA_GK104_CHIPSET) {
785          if (i->tex.target.isShadow())
786             s--;
787          if (i->srcExists(s)) // move potential predicate out of the way
788             i->moveSources(s, 1);
789          if (i->tex.useOffsets == 4 && i->srcExists(s + 1))
790             i->moveSources(s + 1, 1);
791       }
792       if (i->op == OP_TXG) {
793          // Either there is 1 offset, which goes into the 2 low bytes of the
794          // first source, or there are 4 offsets, which go into 2 sources (8
795          // values, 1 byte each).
796          Value *offs[2] = {NULL, NULL};
797          for (n = 0; n < i->tex.useOffsets; n++) {
798             for (c = 0; c < 2; ++c) {
799                if ((n % 2) == 0 && c == 0)
800                   offs[n / 2] = i->offset[n][c].get();
801                else
802                   bld.mkOp3(OP_INSBF, TYPE_U32,
803                             offs[n / 2],
804                             i->offset[n][c].get(),
805                             bld.mkImm(0x800 | ((n * 16 + c * 8) % 32)),
806                             offs[n / 2]);
807             }
808          }
809          i->setSrc(s, offs[0]);
810          if (offs[1])
811             i->setSrc(s + 1, offs[1]);
812       } else {
813          unsigned imm = 0;
814          assert(i->tex.useOffsets == 1);
815          for (c = 0; c < 3; ++c) {
816             ImmediateValue val;
817             if (!i->offset[0][c].getImmediate(val))
818                assert(!"non-immediate offset passed to non-TXG");
819             imm |= (val.reg.data.u32 & 0xf) << (c * 4);
820          }
821          if (i->op == OP_TXD && chipset >= NVISA_GK104_CHIPSET) {
822             // The offset goes into the upper 16 bits of the array index. So
823             // create it if it's not already there, and INSBF it if it already
824             // is.
825             s = (i->tex.rIndirectSrc >= 0) ? 1 : 0;
826             if (chipset >= NVISA_GM107_CHIPSET)
827                s += dim;
828             if (i->tex.target.isArray()) {
829                bld.mkOp3(OP_INSBF, TYPE_U32, i->getSrc(s),
830                          bld.loadImm(NULL, imm), bld.mkImm(0xc10),
831                          i->getSrc(s));
832             } else {
833                i->moveSources(s, 1);
834                i->setSrc(s, bld.loadImm(NULL, imm << 16));
835             }
836          } else {
837             i->setSrc(s, bld.loadImm(NULL, imm));
838          }
839       }
840    }
841
842    if (chipset >= NVISA_GK104_CHIPSET) {
843       //
844       // If TEX requires more than 4 sources, the 2nd register tuple must be
845       // aligned to 4, even if it consists of just a single 4-byte register.
846       //
847       // XXX HACK: We insert 0 sources to avoid the 5 or 6 regs case.
848       //
849       int s = i->srcCount(0xff, true);
850       if (s > 4 && s < 7) {
851          if (i->srcExists(s)) // move potential predicate out of the way
852             i->moveSources(s, 7 - s);
853          while (s < 7)
854             i->setSrc(s++, bld.loadImm(NULL, 0));
855       }
856    }
857
858    return true;
859 }
860
861 bool
862 NVC0LoweringPass::handleManualTXD(TexInstruction *i)
863 {
864    static const uint8_t qOps[4][2] =
865    {
866       { QUADOP(MOV2, ADD,  MOV2, ADD),  QUADOP(MOV2, MOV2, ADD,  ADD) }, // l0
867       { QUADOP(SUBR, MOV2, SUBR, MOV2), QUADOP(MOV2, MOV2, ADD,  ADD) }, // l1
868       { QUADOP(MOV2, ADD,  MOV2, ADD),  QUADOP(SUBR, SUBR, MOV2, MOV2) }, // l2
869       { QUADOP(SUBR, MOV2, SUBR, MOV2), QUADOP(SUBR, SUBR, MOV2, MOV2) }, // l3
870    };
871    Value *def[4][4];
872    Value *crd[3];
873    Instruction *tex;
874    Value *zero = bld.loadImm(bld.getSSA(), 0);
875    int l, c;
876    const int dim = i->tex.target.getDim() + i->tex.target.isCube();
877
878    // This function is invoked after handleTEX lowering, so we have to expect
879    // the arguments in the order that the hw wants them. For Fermi, array and
880    // indirect are both in the leading arg, while for Kepler, array and
881    // indirect are separate (and both precede the coordinates). Maxwell is
882    // handled in a separate function.
883    unsigned array;
884    if (targ->getChipset() < NVISA_GK104_CHIPSET)
885       array = i->tex.target.isArray() || i->tex.rIndirectSrc >= 0;
886    else
887       array = i->tex.target.isArray() + (i->tex.rIndirectSrc >= 0);
888
889    i->op = OP_TEX; // no need to clone dPdx/dPdy later
890
891    for (c = 0; c < dim; ++c)
892       crd[c] = bld.getScratch();
893
894    bld.mkOp(OP_QUADON, TYPE_NONE, NULL);
895    for (l = 0; l < 4; ++l) {
896       Value *src[3], *val;
897       // mov coordinates from lane l to all lanes
898       for (c = 0; c < dim; ++c)
899          bld.mkQuadop(0x00, crd[c], l, i->getSrc(c + array), zero);
900       // add dPdx from lane l to lanes dx
901       for (c = 0; c < dim; ++c)
902          bld.mkQuadop(qOps[l][0], crd[c], l, i->dPdx[c].get(), crd[c]);
903       // add dPdy from lane l to lanes dy
904       for (c = 0; c < dim; ++c)
905          bld.mkQuadop(qOps[l][1], crd[c], l, i->dPdy[c].get(), crd[c]);
906       // normalize cube coordinates
907       if (i->tex.target.isCube()) {
908          for (c = 0; c < 3; ++c)
909             src[c] = bld.mkOp1v(OP_ABS, TYPE_F32, bld.getSSA(), crd[c]);
910          val = bld.getScratch();
911          bld.mkOp2(OP_MAX, TYPE_F32, val, src[0], src[1]);
912          bld.mkOp2(OP_MAX, TYPE_F32, val, src[2], val);
913          bld.mkOp1(OP_RCP, TYPE_F32, val, val);
914          for (c = 0; c < 3; ++c)
915             src[c] = bld.mkOp2v(OP_MUL, TYPE_F32, bld.getSSA(), crd[c], val);
916       } else {
917          for (c = 0; c < dim; ++c)
918             src[c] = crd[c];
919       }
920       // texture
921       bld.insert(tex = cloneForward(func, i));
922       for (c = 0; c < dim; ++c)
923          tex->setSrc(c + array, src[c]);
924       // save results
925       for (c = 0; i->defExists(c); ++c) {
926          Instruction *mov;
927          def[c][l] = bld.getSSA();
928          mov = bld.mkMov(def[c][l], tex->getDef(c));
929          mov->fixed = 1;
930          mov->lanes = 1 << l;
931       }
932    }
933    bld.mkOp(OP_QUADPOP, TYPE_NONE, NULL);
934
935    for (c = 0; i->defExists(c); ++c) {
936       Instruction *u = bld.mkOp(OP_UNION, TYPE_U32, i->getDef(c));
937       for (l = 0; l < 4; ++l)
938          u->setSrc(l, def[c][l]);
939    }
940
941    i->bb->remove(i);
942    return true;
943 }
944
945 bool
946 NVC0LoweringPass::handleTXD(TexInstruction *txd)
947 {
948    int dim = txd->tex.target.getDim() + txd->tex.target.isCube();
949    unsigned arg = txd->tex.target.getArgCount();
950    unsigned expected_args = arg;
951    const int chipset = prog->getTarget()->getChipset();
952
953    if (chipset >= NVISA_GK104_CHIPSET) {
954       if (!txd->tex.target.isArray() && txd->tex.useOffsets)
955          expected_args++;
956       if (txd->tex.rIndirectSrc >= 0 || txd->tex.sIndirectSrc >= 0)
957          expected_args++;
958    } else {
959       if (txd->tex.useOffsets)
960          expected_args++;
961       if (!txd->tex.target.isArray() && (
962                 txd->tex.rIndirectSrc >= 0 || txd->tex.sIndirectSrc >= 0))
963          expected_args++;
964    }
965
966    if (expected_args > 4 ||
967        dim > 2 ||
968        txd->tex.target.isShadow())
969       txd->op = OP_TEX;
970
971    handleTEX(txd);
972    while (txd->srcExists(arg))
973       ++arg;
974
975    txd->tex.derivAll = true;
976    if (txd->op == OP_TEX)
977       return handleManualTXD(txd);
978
979    assert(arg == expected_args);
980    for (int c = 0; c < dim; ++c) {
981       txd->setSrc(arg + c * 2 + 0, txd->dPdx[c]);
982       txd->setSrc(arg + c * 2 + 1, txd->dPdy[c]);
983       txd->dPdx[c].set(NULL);
984       txd->dPdy[c].set(NULL);
985    }
986    return true;
987 }
988
989 bool
990 NVC0LoweringPass::handleTXQ(TexInstruction *txq)
991 {
992    const int chipset = prog->getTarget()->getChipset();
993    if (chipset >= NVISA_GK104_CHIPSET && txq->tex.rIndirectSrc < 0)
994       txq->tex.r += prog->driver->io.texBindBase / 4;
995
996    if (txq->tex.rIndirectSrc < 0)
997       return true;
998
999    Value *ticRel = txq->getIndirectR();
1000
1001    txq->setIndirectS(NULL);
1002    txq->tex.sIndirectSrc = -1;
1003
1004    assert(ticRel);
1005
1006    if (chipset < NVISA_GK104_CHIPSET) {
1007       LValue *src = new_LValue(func, FILE_GPR); // 0xttxsaaaa
1008
1009       txq->setSrc(txq->tex.rIndirectSrc, NULL);
1010       if (txq->tex.r)
1011          ticRel = bld.mkOp2v(OP_ADD, TYPE_U32, bld.getScratch(),
1012                              ticRel, bld.mkImm(txq->tex.r));
1013
1014       bld.mkOp2(OP_SHL, TYPE_U32, src, ticRel, bld.mkImm(0x17));
1015
1016       txq->moveSources(0, 1);
1017       txq->setSrc(0, src);
1018    } else {
1019       Value *hnd = loadTexHandle(
1020             bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(),
1021                        txq->getIndirectR(), bld.mkImm(2)),
1022             txq->tex.r);
1023       txq->tex.r = 0xff;
1024       txq->tex.s = 0x1f;
1025
1026       txq->setIndirectR(NULL);
1027       txq->moveSources(0, 1);
1028       txq->setSrc(0, hnd);
1029       txq->tex.rIndirectSrc = 0;
1030    }
1031
1032    return true;
1033 }
1034
1035 bool
1036 NVC0LoweringPass::handleTXLQ(TexInstruction *i)
1037 {
1038    /* The outputs are inverted compared to what the TGSI instruction
1039     * expects. Take that into account in the mask.
1040     */
1041    assert((i->tex.mask & ~3) == 0);
1042    if (i->tex.mask == 1)
1043       i->tex.mask = 2;
1044    else if (i->tex.mask == 2)
1045       i->tex.mask = 1;
1046    handleTEX(i);
1047    bld.setPosition(i, true);
1048
1049    /* The returned values are not quite what we want:
1050     * (a) convert from s16/u16 to f32
1051     * (b) multiply by 1/256
1052     */
1053    for (int def = 0; def < 2; ++def) {
1054       if (!i->defExists(def))
1055          continue;
1056       enum DataType type = TYPE_S16;
1057       if (i->tex.mask == 2 || def > 0)
1058          type = TYPE_U16;
1059       bld.mkCvt(OP_CVT, TYPE_F32, i->getDef(def), type, i->getDef(def));
1060       bld.mkOp2(OP_MUL, TYPE_F32, i->getDef(def),
1061                 i->getDef(def), bld.loadImm(NULL, 1.0f / 256));
1062    }
1063    if (i->tex.mask == 3) {
1064       LValue *t = new_LValue(func, FILE_GPR);
1065       bld.mkMov(t, i->getDef(0));
1066       bld.mkMov(i->getDef(0), i->getDef(1));
1067       bld.mkMov(i->getDef(1), t);
1068    }
1069    return true;
1070 }
1071
1072 bool
1073 NVC0LoweringPass::handleSUQ(Instruction *suq)
1074 {
1075    suq->op = OP_MOV;
1076    suq->setSrc(0, loadBufLength32(suq->getIndirect(0, 1),
1077                                   suq->getSrc(0)->reg.fileIndex * 16));
1078    suq->setIndirect(0, 0, NULL);
1079    suq->setIndirect(0, 1, NULL);
1080    return true;
1081 }
1082
1083 void
1084 NVC0LoweringPass::handleSharedATOMNVE4(Instruction *atom)
1085 {
1086    assert(atom->src(0).getFile() == FILE_MEMORY_SHARED);
1087
1088    BasicBlock *currBB = atom->bb;
1089    BasicBlock *tryLockBB = atom->bb->splitBefore(atom, false);
1090    BasicBlock *joinBB = atom->bb->splitAfter(atom);
1091    BasicBlock *setAndUnlockBB = new BasicBlock(func);
1092    BasicBlock *failLockBB = new BasicBlock(func);
1093
1094    bld.setPosition(currBB, true);
1095    assert(!currBB->joinAt);
1096    currBB->joinAt = bld.mkFlow(OP_JOINAT, joinBB, CC_ALWAYS, NULL);
1097
1098    CmpInstruction *pred =
1099       bld.mkCmp(OP_SET, CC_EQ, TYPE_U32, bld.getSSA(1, FILE_PREDICATE),
1100                 TYPE_U32, bld.mkImm(0), bld.mkImm(1));
1101
1102    bld.mkFlow(OP_BRA, tryLockBB, CC_ALWAYS, NULL);
1103    currBB->cfg.attach(&tryLockBB->cfg, Graph::Edge::TREE);
1104
1105    bld.setPosition(tryLockBB, true);
1106
1107    Instruction *ld =
1108       bld.mkLoad(TYPE_U32, atom->getDef(0),
1109                  bld.mkSymbol(FILE_MEMORY_SHARED, 0, TYPE_U32, 0), NULL);
1110    ld->setDef(1, bld.getSSA(1, FILE_PREDICATE));
1111    ld->subOp = NV50_IR_SUBOP_LOAD_LOCKED;
1112
1113    bld.mkFlow(OP_BRA, setAndUnlockBB, CC_P, ld->getDef(1));
1114    bld.mkFlow(OP_BRA, failLockBB, CC_ALWAYS, NULL);
1115    tryLockBB->cfg.attach(&failLockBB->cfg, Graph::Edge::CROSS);
1116    tryLockBB->cfg.attach(&setAndUnlockBB->cfg, Graph::Edge::TREE);
1117
1118    tryLockBB->cfg.detach(&joinBB->cfg);
1119    bld.remove(atom);
1120
1121    bld.setPosition(setAndUnlockBB, true);
1122    Value *stVal;
1123    if (atom->subOp == NV50_IR_SUBOP_ATOM_EXCH) {
1124       // Read the old value, and write the new one.
1125       stVal = atom->getSrc(1);
1126    } else if (atom->subOp == NV50_IR_SUBOP_ATOM_CAS) {
1127       CmpInstruction *set =
1128          bld.mkCmp(OP_SET, CC_EQ, TYPE_U32, bld.getSSA(),
1129                    TYPE_U32, ld->getDef(0), atom->getSrc(1));
1130
1131       bld.mkCmp(OP_SLCT, CC_NE, TYPE_U32, (stVal = bld.getSSA()),
1132                 TYPE_U32, atom->getSrc(2), ld->getDef(0), set->getDef(0));
1133    } else {
1134       operation op;
1135
1136       switch (atom->subOp) {
1137       case NV50_IR_SUBOP_ATOM_ADD:
1138          op = OP_ADD;
1139          break;
1140       case NV50_IR_SUBOP_ATOM_AND:
1141          op = OP_AND;
1142          break;
1143       case NV50_IR_SUBOP_ATOM_OR:
1144          op = OP_OR;
1145          break;
1146       case NV50_IR_SUBOP_ATOM_XOR:
1147          op = OP_XOR;
1148          break;
1149       case NV50_IR_SUBOP_ATOM_MIN:
1150          op = OP_MIN;
1151          break;
1152       case NV50_IR_SUBOP_ATOM_MAX:
1153          op = OP_MAX;
1154          break;
1155       default:
1156          assert(0);
1157          return;
1158       }
1159
1160       stVal = bld.mkOp2v(op, atom->dType, bld.getSSA(), ld->getDef(0),
1161                          atom->getSrc(1));
1162    }
1163
1164    Instruction *st =
1165       bld.mkStore(OP_STORE, TYPE_U32,
1166                   bld.mkSymbol(FILE_MEMORY_SHARED, 0, TYPE_U32, 0),
1167                   NULL, stVal);
1168    st->setDef(0, pred->getDef(0));
1169    st->subOp = NV50_IR_SUBOP_STORE_UNLOCKED;
1170
1171    bld.mkFlow(OP_BRA, failLockBB, CC_ALWAYS, NULL);
1172    setAndUnlockBB->cfg.attach(&failLockBB->cfg, Graph::Edge::TREE);
1173
1174    // Lock until the store has not been performed.
1175    bld.setPosition(failLockBB, true);
1176    bld.mkFlow(OP_BRA, tryLockBB, CC_NOT_P, pred->getDef(0));
1177    bld.mkFlow(OP_BRA, joinBB, CC_ALWAYS, NULL);
1178    failLockBB->cfg.attach(&tryLockBB->cfg, Graph::Edge::BACK);
1179    failLockBB->cfg.attach(&joinBB->cfg, Graph::Edge::TREE);
1180
1181    bld.setPosition(joinBB, false);
1182    bld.mkFlow(OP_JOIN, NULL, CC_ALWAYS, NULL)->fixed = 1;
1183 }
1184
1185 void
1186 NVC0LoweringPass::handleSharedATOM(Instruction *atom)
1187 {
1188    assert(atom->src(0).getFile() == FILE_MEMORY_SHARED);
1189
1190    BasicBlock *currBB = atom->bb;
1191    BasicBlock *tryLockAndSetBB = atom->bb->splitBefore(atom, false);
1192    BasicBlock *joinBB = atom->bb->splitAfter(atom);
1193
1194    bld.setPosition(currBB, true);
1195    assert(!currBB->joinAt);
1196    currBB->joinAt = bld.mkFlow(OP_JOINAT, joinBB, CC_ALWAYS, NULL);
1197
1198    bld.mkFlow(OP_BRA, tryLockAndSetBB, CC_ALWAYS, NULL);
1199    currBB->cfg.attach(&tryLockAndSetBB->cfg, Graph::Edge::TREE);
1200
1201    bld.setPosition(tryLockAndSetBB, true);
1202
1203    Instruction *ld =
1204       bld.mkLoad(TYPE_U32, atom->getDef(0),
1205                  bld.mkSymbol(FILE_MEMORY_SHARED, 0, TYPE_U32, 0), NULL);
1206    ld->setDef(1, bld.getSSA(1, FILE_PREDICATE));
1207    ld->subOp = NV50_IR_SUBOP_LOAD_LOCKED;
1208
1209    Value *stVal;
1210    if (atom->subOp == NV50_IR_SUBOP_ATOM_EXCH) {
1211       // Read the old value, and write the new one.
1212       stVal = atom->getSrc(1);
1213    } else if (atom->subOp == NV50_IR_SUBOP_ATOM_CAS) {
1214       CmpInstruction *set =
1215          bld.mkCmp(OP_SET, CC_EQ, TYPE_U32, bld.getSSA(1, FILE_PREDICATE),
1216                    TYPE_U32, ld->getDef(0), atom->getSrc(1));
1217       set->setPredicate(CC_P, ld->getDef(1));
1218
1219       Instruction *selp =
1220          bld.mkOp3(OP_SELP, TYPE_U32, bld.getSSA(), ld->getDef(0),
1221                    atom->getSrc(2), set->getDef(0));
1222       selp->src(2).mod = Modifier(NV50_IR_MOD_NOT);
1223       selp->setPredicate(CC_P, ld->getDef(1));
1224
1225       stVal = selp->getDef(0);
1226    } else {
1227       operation op;
1228
1229       switch (atom->subOp) {
1230       case NV50_IR_SUBOP_ATOM_ADD:
1231          op = OP_ADD;
1232          break;
1233       case NV50_IR_SUBOP_ATOM_AND:
1234          op = OP_AND;
1235          break;
1236       case NV50_IR_SUBOP_ATOM_OR:
1237          op = OP_OR;
1238          break;
1239       case NV50_IR_SUBOP_ATOM_XOR:
1240          op = OP_XOR;
1241          break;
1242       case NV50_IR_SUBOP_ATOM_MIN:
1243          op = OP_MIN;
1244          break;
1245       case NV50_IR_SUBOP_ATOM_MAX:
1246          op = OP_MAX;
1247          break;
1248       default:
1249          assert(0);
1250          return;
1251       }
1252
1253       Instruction *i =
1254          bld.mkOp2(op, atom->dType, bld.getSSA(), ld->getDef(0),
1255                    atom->getSrc(1));
1256       i->setPredicate(CC_P, ld->getDef(1));
1257
1258       stVal = i->getDef(0);
1259    }
1260
1261    Instruction *st =
1262       bld.mkStore(OP_STORE, TYPE_U32,
1263                   bld.mkSymbol(FILE_MEMORY_SHARED, 0, TYPE_U32, 0),
1264                   NULL, stVal);
1265    st->setPredicate(CC_P, ld->getDef(1));
1266    st->subOp = NV50_IR_SUBOP_STORE_UNLOCKED;
1267
1268    // Loop until the lock is acquired.
1269    bld.mkFlow(OP_BRA, tryLockAndSetBB, CC_NOT_P, ld->getDef(1));
1270    tryLockAndSetBB->cfg.attach(&tryLockAndSetBB->cfg, Graph::Edge::BACK);
1271    tryLockAndSetBB->cfg.attach(&joinBB->cfg, Graph::Edge::CROSS);
1272    bld.mkFlow(OP_BRA, joinBB, CC_ALWAYS, NULL);
1273
1274    bld.remove(atom);
1275
1276    bld.setPosition(joinBB, false);
1277    bld.mkFlow(OP_JOIN, NULL, CC_ALWAYS, NULL)->fixed = 1;
1278 }
1279
1280 bool
1281 NVC0LoweringPass::handleATOM(Instruction *atom)
1282 {
1283    SVSemantic sv;
1284    Value *ptr = atom->getIndirect(0, 0), *ind = atom->getIndirect(0, 1), *base;
1285
1286    switch (atom->src(0).getFile()) {
1287    case FILE_MEMORY_LOCAL:
1288       sv = SV_LBASE;
1289       break;
1290    case FILE_MEMORY_SHARED:
1291       if (targ->getChipset() >= NVISA_GK104_CHIPSET) {
1292          handleSharedATOMNVE4(atom);
1293       } else {
1294          handleSharedATOM(atom);
1295       }
1296       return true;
1297    default:
1298       assert(atom->src(0).getFile() == FILE_MEMORY_GLOBAL);
1299       base = loadBufInfo64(ind, atom->getSrc(0)->reg.fileIndex * 16);
1300       assert(base->reg.size == 8);
1301       if (ptr)
1302          base = bld.mkOp2v(OP_ADD, TYPE_U64, base, base, ptr);
1303       assert(base->reg.size == 8);
1304       atom->setIndirect(0, 0, base);
1305       return true;
1306    }
1307    base =
1308       bld.mkOp1v(OP_RDSV, TYPE_U32, bld.getScratch(), bld.mkSysVal(sv, 0));
1309
1310    atom->setSrc(0, cloneShallow(func, atom->getSrc(0)));
1311    atom->getSrc(0)->reg.file = FILE_MEMORY_GLOBAL;
1312    if (ptr)
1313       base = bld.mkOp2v(OP_ADD, TYPE_U32, base, base, ptr);
1314    atom->setIndirect(0, 1, NULL);
1315    atom->setIndirect(0, 0, base);
1316
1317    return true;
1318 }
1319
1320 bool
1321 NVC0LoweringPass::handleCasExch(Instruction *cas, bool needCctl)
1322 {
1323    if (cas->src(0).getFile() == FILE_MEMORY_SHARED) {
1324       // ATOM_CAS and ATOM_EXCH are handled in handleSharedATOM().
1325       return false;
1326    }
1327
1328    if (cas->subOp != NV50_IR_SUBOP_ATOM_CAS &&
1329        cas->subOp != NV50_IR_SUBOP_ATOM_EXCH)
1330       return false;
1331    bld.setPosition(cas, true);
1332
1333    if (needCctl) {
1334       Instruction *cctl = bld.mkOp1(OP_CCTL, TYPE_NONE, NULL, cas->getSrc(0));
1335       cctl->setIndirect(0, 0, cas->getIndirect(0, 0));
1336       cctl->fixed = 1;
1337       cctl->subOp = NV50_IR_SUBOP_CCTL_IV;
1338       if (cas->isPredicated())
1339          cctl->setPredicate(cas->cc, cas->getPredicate());
1340    }
1341
1342    if (cas->subOp == NV50_IR_SUBOP_ATOM_CAS) {
1343       // CAS is crazy. It's 2nd source is a double reg, and the 3rd source
1344       // should be set to the high part of the double reg or bad things will
1345       // happen elsewhere in the universe.
1346       // Also, it sometimes returns the new value instead of the old one
1347       // under mysterious circumstances.
1348       Value *dreg = bld.getSSA(8);
1349       bld.setPosition(cas, false);
1350       bld.mkOp2(OP_MERGE, TYPE_U64, dreg, cas->getSrc(1), cas->getSrc(2));
1351       cas->setSrc(1, dreg);
1352       cas->setSrc(2, dreg);
1353    }
1354
1355    return true;
1356 }
1357
1358 inline Value *
1359 NVC0LoweringPass::loadResInfo32(Value *ptr, uint32_t off, uint16_t base)
1360 {
1361    uint8_t b = prog->driver->io.auxCBSlot;
1362    off += base;
1363
1364    return bld.
1365       mkLoadv(TYPE_U32, bld.mkSymbol(FILE_MEMORY_CONST, b, TYPE_U32, off), ptr);
1366 }
1367
1368 inline Value *
1369 NVC0LoweringPass::loadResInfo64(Value *ptr, uint32_t off, uint16_t base)
1370 {
1371    uint8_t b = prog->driver->io.auxCBSlot;
1372    off += base;
1373
1374    if (ptr)
1375       ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getScratch(), ptr, bld.mkImm(4));
1376
1377    return bld.
1378       mkLoadv(TYPE_U64, bld.mkSymbol(FILE_MEMORY_CONST, b, TYPE_U64, off), ptr);
1379 }
1380
1381 inline Value *
1382 NVC0LoweringPass::loadResLength32(Value *ptr, uint32_t off, uint16_t base)
1383 {
1384    uint8_t b = prog->driver->io.auxCBSlot;
1385    off += base;
1386
1387    if (ptr)
1388       ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getScratch(), ptr, bld.mkImm(4));
1389
1390    return bld.
1391       mkLoadv(TYPE_U32, bld.mkSymbol(FILE_MEMORY_CONST, b, TYPE_U64, off + 8), ptr);
1392 }
1393
1394 inline Value *
1395 NVC0LoweringPass::loadSuInfo32(Value *ptr, uint32_t off)
1396 {
1397    return loadResInfo32(ptr, off, prog->driver->io.suInfoBase);
1398 }
1399
1400 inline Value *
1401 NVC0LoweringPass::loadSuInfo64(Value *ptr, uint32_t off)
1402 {
1403    return loadResInfo64(ptr, off, prog->driver->io.suInfoBase);
1404 }
1405
1406 inline Value *
1407 NVC0LoweringPass::loadSuLength32(Value *ptr, uint32_t off)
1408 {
1409    return loadResLength32(ptr, off, prog->driver->io.suInfoBase);
1410 }
1411
1412 inline Value *
1413 NVC0LoweringPass::loadBufInfo32(Value *ptr, uint32_t off)
1414 {
1415    return loadResInfo32(ptr, off, prog->driver->io.bufInfoBase);
1416 }
1417
1418 inline Value *
1419 NVC0LoweringPass::loadBufInfo64(Value *ptr, uint32_t off)
1420 {
1421    return loadResInfo64(ptr, off, prog->driver->io.bufInfoBase);
1422 }
1423
1424 inline Value *
1425 NVC0LoweringPass::loadBufLength32(Value *ptr, uint32_t off)
1426 {
1427    return loadResLength32(ptr, off, prog->driver->io.bufInfoBase);
1428 }
1429
1430 inline Value *
1431 NVC0LoweringPass::loadUboInfo32(Value *ptr, uint32_t off)
1432 {
1433    return loadResInfo32(ptr, off, prog->driver->io.uboInfoBase);
1434 }
1435
1436 inline Value *
1437 NVC0LoweringPass::loadUboInfo64(Value *ptr, uint32_t off)
1438 {
1439    return loadResInfo64(ptr, off, prog->driver->io.uboInfoBase);
1440 }
1441
1442 inline Value *
1443 NVC0LoweringPass::loadUboLength32(Value *ptr, uint32_t off)
1444 {
1445    return loadResLength32(ptr, off, prog->driver->io.uboInfoBase);
1446 }
1447
1448 inline Value *
1449 NVC0LoweringPass::loadMsInfo32(Value *ptr, uint32_t off)
1450 {
1451    uint8_t b = prog->driver->io.msInfoCBSlot;
1452    off += prog->driver->io.msInfoBase;
1453    return bld.
1454       mkLoadv(TYPE_U32, bld.mkSymbol(FILE_MEMORY_CONST, b, TYPE_U32, off), ptr);
1455 }
1456
1457 /* On nvc0, surface info is obtained via the surface binding points passed
1458  * to the SULD/SUST instructions.
1459  * On nve4, surface info is stored in c[] and is used by various special
1460  * instructions, e.g. for clamping coordiantes or generating an address.
1461  * They couldn't just have added an equivalent to TIC now, couldn't they ?
1462  */
1463 #define NVE4_SU_INFO_ADDR   0x00
1464 #define NVE4_SU_INFO_FMT    0x04
1465 #define NVE4_SU_INFO_DIM_X  0x08
1466 #define NVE4_SU_INFO_PITCH  0x0c
1467 #define NVE4_SU_INFO_DIM_Y  0x10
1468 #define NVE4_SU_INFO_ARRAY  0x14
1469 #define NVE4_SU_INFO_DIM_Z  0x18
1470 #define NVE4_SU_INFO_UNK1C  0x1c
1471 #define NVE4_SU_INFO_WIDTH  0x20
1472 #define NVE4_SU_INFO_HEIGHT 0x24
1473 #define NVE4_SU_INFO_DEPTH  0x28
1474 #define NVE4_SU_INFO_TARGET 0x2c
1475 #define NVE4_SU_INFO_CALL   0x30
1476 #define NVE4_SU_INFO_RAW_X  0x34
1477 #define NVE4_SU_INFO_MS_X   0x38
1478 #define NVE4_SU_INFO_MS_Y   0x3c
1479
1480 #define NVE4_SU_INFO__STRIDE 0x40
1481
1482 #define NVE4_SU_INFO_DIM(i)  (0x08 + (i) * 8)
1483 #define NVE4_SU_INFO_SIZE(i) (0x20 + (i) * 4)
1484 #define NVE4_SU_INFO_MS(i)   (0x38 + (i) * 4)
1485
1486 static inline uint16_t getSuClampSubOp(const TexInstruction *su, int c)
1487 {
1488    switch (su->tex.target.getEnum()) {
1489    case TEX_TARGET_BUFFER:      return NV50_IR_SUBOP_SUCLAMP_PL(0, 1);
1490    case TEX_TARGET_RECT:        return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1491    case TEX_TARGET_1D:          return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1492    case TEX_TARGET_1D_ARRAY:    return (c == 1) ?
1493                                    NV50_IR_SUBOP_SUCLAMP_PL(0, 2) :
1494                                    NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1495    case TEX_TARGET_2D:          return NV50_IR_SUBOP_SUCLAMP_BL(0, 2);
1496    case TEX_TARGET_2D_MS:       return NV50_IR_SUBOP_SUCLAMP_BL(0, 2);
1497    case TEX_TARGET_2D_ARRAY:    return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1498    case TEX_TARGET_2D_MS_ARRAY: return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1499    case TEX_TARGET_3D:          return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1500    case TEX_TARGET_CUBE:        return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1501    case TEX_TARGET_CUBE_ARRAY:  return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1502    default:
1503       assert(0);
1504       return 0;
1505    }
1506 }
1507
1508 void
1509 NVC0LoweringPass::adjustCoordinatesMS(TexInstruction *tex)
1510 {
1511    const uint16_t base = tex->tex.r * NVE4_SU_INFO__STRIDE;
1512    const int arg = tex->tex.target.getArgCount();
1513
1514    if (tex->tex.target == TEX_TARGET_2D_MS)
1515       tex->tex.target = TEX_TARGET_2D;
1516    else
1517    if (tex->tex.target == TEX_TARGET_2D_MS_ARRAY)
1518       tex->tex.target = TEX_TARGET_2D_ARRAY;
1519    else
1520       return;
1521
1522    Value *x = tex->getSrc(0);
1523    Value *y = tex->getSrc(1);
1524    Value *s = tex->getSrc(arg - 1);
1525
1526    Value *tx = bld.getSSA(), *ty = bld.getSSA(), *ts = bld.getSSA();
1527
1528    Value *ms_x = loadSuInfo32(NULL, base + NVE4_SU_INFO_MS(0));
1529    Value *ms_y = loadSuInfo32(NULL, base + NVE4_SU_INFO_MS(1));
1530
1531    bld.mkOp2(OP_SHL, TYPE_U32, tx, x, ms_x);
1532    bld.mkOp2(OP_SHL, TYPE_U32, ty, y, ms_y);
1533
1534    s = bld.mkOp2v(OP_AND, TYPE_U32, ts, s, bld.loadImm(NULL, 0x7));
1535    s = bld.mkOp2v(OP_SHL, TYPE_U32, ts, ts, bld.mkImm(3));
1536
1537    Value *dx = loadMsInfo32(ts, 0x0);
1538    Value *dy = loadMsInfo32(ts, 0x4);
1539
1540    bld.mkOp2(OP_ADD, TYPE_U32, tx, tx, dx);
1541    bld.mkOp2(OP_ADD, TYPE_U32, ty, ty, dy);
1542
1543    tex->setSrc(0, tx);
1544    tex->setSrc(1, ty);
1545    tex->moveSources(arg, -1);
1546 }
1547
1548 // Sets 64-bit "generic address", predicate and format sources for SULD/SUST.
1549 // They're computed from the coordinates using the surface info in c[] space.
1550 void
1551 NVC0LoweringPass::processSurfaceCoordsNVE4(TexInstruction *su)
1552 {
1553    Instruction *insn;
1554    const bool atom = su->op == OP_SUREDB || su->op == OP_SUREDP;
1555    const bool raw =
1556       su->op == OP_SULDB || su->op == OP_SUSTB || su->op == OP_SUREDB;
1557    const int idx = su->tex.r;
1558    const int dim = su->tex.target.getDim();
1559    const int arg = dim + (su->tex.target.isArray() ? 1 : 0);
1560    const uint16_t base = idx * NVE4_SU_INFO__STRIDE;
1561    int c;
1562    Value *zero = bld.mkImm(0);
1563    Value *p1 = NULL;
1564    Value *v;
1565    Value *src[3];
1566    Value *bf, *eau, *off;
1567    Value *addr, *pred;
1568
1569    off = bld.getScratch(4);
1570    bf = bld.getScratch(4);
1571    addr = bld.getSSA(8);
1572    pred = bld.getScratch(1, FILE_PREDICATE);
1573
1574    bld.setPosition(su, false);
1575
1576    adjustCoordinatesMS(su);
1577
1578    // calculate clamped coordinates
1579    for (c = 0; c < arg; ++c) {
1580       src[c] = bld.getScratch();
1581       if (c == 0 && raw)
1582          v = loadSuInfo32(NULL, base + NVE4_SU_INFO_RAW_X);
1583       else
1584          v = loadSuInfo32(NULL, base + NVE4_SU_INFO_DIM(c));
1585       bld.mkOp3(OP_SUCLAMP, TYPE_S32, src[c], su->getSrc(c), v, zero)
1586          ->subOp = getSuClampSubOp(su, c);
1587    }
1588    for (; c < 3; ++c)
1589       src[c] = zero;
1590
1591    // set predicate output
1592    if (su->tex.target == TEX_TARGET_BUFFER) {
1593       src[0]->getInsn()->setFlagsDef(1, pred);
1594    } else
1595    if (su->tex.target.isArray()) {
1596       p1 = bld.getSSA(1, FILE_PREDICATE);
1597       src[dim]->getInsn()->setFlagsDef(1, p1);
1598    }
1599
1600    // calculate pixel offset
1601    if (dim == 1) {
1602       if (su->tex.target != TEX_TARGET_BUFFER)
1603          bld.mkOp2(OP_AND, TYPE_U32, off, src[0], bld.loadImm(NULL, 0xffff));
1604    } else
1605    if (dim == 3) {
1606       v = loadSuInfo32(NULL, base + NVE4_SU_INFO_UNK1C);
1607       bld.mkOp3(OP_MADSP, TYPE_U32, off, src[2], v, src[1])
1608          ->subOp = NV50_IR_SUBOP_MADSP(4,2,8); // u16l u16l u16l
1609
1610       v = loadSuInfo32(NULL, base + NVE4_SU_INFO_PITCH);
1611       bld.mkOp3(OP_MADSP, TYPE_U32, off, off, v, src[0])
1612          ->subOp = NV50_IR_SUBOP_MADSP(0,2,8); // u32 u16l u16l
1613    } else {
1614       assert(dim == 2);
1615       v = loadSuInfo32(NULL, base + NVE4_SU_INFO_PITCH);
1616       bld.mkOp3(OP_MADSP, TYPE_U32, off, src[1], v, src[0])
1617          ->subOp = su->tex.target.isArray() ?
1618          NV50_IR_SUBOP_MADSP_SD : NV50_IR_SUBOP_MADSP(4,2,8); // u16l u16l u16l
1619    }
1620
1621    // calculate effective address part 1
1622    if (su->tex.target == TEX_TARGET_BUFFER) {
1623       if (raw) {
1624          bf = src[0];
1625       } else {
1626          v = loadSuInfo32(NULL, base + NVE4_SU_INFO_FMT);
1627          bld.mkOp3(OP_VSHL, TYPE_U32, bf, src[0], v, zero)
1628             ->subOp = NV50_IR_SUBOP_V1(7,6,8|2);
1629       }
1630    } else {
1631       Value *y = src[1];
1632       Value *z = src[2];
1633       uint16_t subOp = 0;
1634
1635       switch (dim) {
1636       case 1:
1637          y = zero;
1638          z = zero;
1639          break;
1640       case 2:
1641          z = off;
1642          if (!su->tex.target.isArray()) {
1643             z = loadSuInfo32(NULL, base + NVE4_SU_INFO_UNK1C);
1644             subOp = NV50_IR_SUBOP_SUBFM_3D;
1645          }
1646          break;
1647       default:
1648          subOp = NV50_IR_SUBOP_SUBFM_3D;
1649          assert(dim == 3);
1650          break;
1651       }
1652       insn = bld.mkOp3(OP_SUBFM, TYPE_U32, bf, src[0], y, z);
1653       insn->subOp = subOp;
1654       insn->setFlagsDef(1, pred);
1655    }
1656
1657    // part 2
1658    v = loadSuInfo32(NULL, base + NVE4_SU_INFO_ADDR);
1659
1660    if (su->tex.target == TEX_TARGET_BUFFER) {
1661       eau = v;
1662    } else {
1663       eau = bld.mkOp3v(OP_SUEAU, TYPE_U32, bld.getScratch(4), off, bf, v);
1664    }
1665    // add array layer offset
1666    if (su->tex.target.isArray()) {
1667       v = loadSuInfo32(NULL, base + NVE4_SU_INFO_ARRAY);
1668       if (dim == 1)
1669          bld.mkOp3(OP_MADSP, TYPE_U32, eau, src[1], v, eau)
1670             ->subOp = NV50_IR_SUBOP_MADSP(4,0,0); // u16 u24 u32
1671       else
1672          bld.mkOp3(OP_MADSP, TYPE_U32, eau, v, src[2], eau)
1673             ->subOp = NV50_IR_SUBOP_MADSP(0,0,0); // u32 u24 u32
1674       // combine predicates
1675       assert(p1);
1676       bld.mkOp2(OP_OR, TYPE_U8, pred, pred, p1);
1677    }
1678
1679    if (atom) {
1680       Value *lo = bf;
1681       if (su->tex.target == TEX_TARGET_BUFFER) {
1682          lo = zero;
1683          bld.mkMov(off, bf);
1684       }
1685       //  bf == g[] address & 0xff
1686       // eau == g[] address >> 8
1687       bld.mkOp3(OP_PERMT, TYPE_U32,  bf,   lo, bld.loadImm(NULL, 0x6540), eau);
1688       bld.mkOp3(OP_PERMT, TYPE_U32, eau, zero, bld.loadImm(NULL, 0x0007), eau);
1689    } else
1690    if (su->op == OP_SULDP && su->tex.target == TEX_TARGET_BUFFER) {
1691       // Convert from u32 to u8 address format, which is what the library code
1692       // doing SULDP currently uses.
1693       // XXX: can SUEAU do this ?
1694       // XXX: does it matter that we don't mask high bytes in bf ?
1695       // Grrr.
1696       bld.mkOp2(OP_SHR, TYPE_U32, off, bf, bld.mkImm(8));
1697       bld.mkOp2(OP_ADD, TYPE_U32, eau, eau, off);
1698    }
1699
1700    bld.mkOp2(OP_MERGE, TYPE_U64, addr, bf, eau);
1701
1702    if (atom && su->tex.target == TEX_TARGET_BUFFER)
1703       bld.mkOp2(OP_ADD, TYPE_U64, addr, addr, off);
1704
1705    // let's just set it 0 for raw access and hope it works
1706    v = raw ?
1707       bld.mkImm(0) : loadSuInfo32(NULL, base + NVE4_SU_INFO_FMT);
1708
1709    // get rid of old coordinate sources, make space for fmt info and predicate
1710    su->moveSources(arg, 3 - arg);
1711    // set 64 bit address and 32-bit format sources
1712    su->setSrc(0, addr);
1713    su->setSrc(1, v);
1714    su->setSrc(2, pred);
1715 }
1716
1717 void
1718 NVC0LoweringPass::handleSurfaceOpNVE4(TexInstruction *su)
1719 {
1720    processSurfaceCoordsNVE4(su);
1721
1722    // Who do we hate more ? The person who decided that nvc0's SULD doesn't
1723    // have to support conversion or the person who decided that, in OpenCL,
1724    // you don't have to specify the format here like you do in OpenGL ?
1725
1726    if (su->op == OP_SULDP) {
1727       // We don't patch shaders. Ever.
1728       // You get an indirect call to our library blob here.
1729       // But at least it's uniform.
1730       FlowInstruction *call;
1731       LValue *p[3];
1732       LValue *r[5];
1733       uint16_t base = su->tex.r * NVE4_SU_INFO__STRIDE + NVE4_SU_INFO_CALL;
1734
1735       for (int i = 0; i < 4; ++i)
1736          (r[i] = bld.getScratch(4, FILE_GPR))->reg.data.id = i;
1737       for (int i = 0; i < 3; ++i)
1738          (p[i] = bld.getScratch(1, FILE_PREDICATE))->reg.data.id = i;
1739       (r[4] = bld.getScratch(8, FILE_GPR))->reg.data.id = 4;
1740
1741       bld.mkMov(p[1], bld.mkImm((su->cache == CACHE_CA) ? 1 : 0), TYPE_U8);
1742       bld.mkMov(p[2], bld.mkImm((su->cache == CACHE_CG) ? 1 : 0), TYPE_U8);
1743       bld.mkMov(p[0], su->getSrc(2), TYPE_U8);
1744       bld.mkMov(r[4], su->getSrc(0), TYPE_U64);
1745       bld.mkMov(r[2], su->getSrc(1), TYPE_U32);
1746
1747       call = bld.mkFlow(OP_CALL, NULL, su->cc, su->getPredicate());
1748
1749       call->indirect = 1;
1750       call->absolute = 1;
1751       call->setSrc(0, bld.mkSymbol(FILE_MEMORY_CONST,
1752                                    prog->driver->io.auxCBSlot, TYPE_U32,
1753                                    prog->driver->io.suInfoBase + base));
1754       call->setSrc(1, r[2]);
1755       call->setSrc(2, r[4]);
1756       for (int i = 0; i < 3; ++i)
1757          call->setSrc(3 + i, p[i]);
1758       for (int i = 0; i < 4; ++i) {
1759          call->setDef(i, r[i]);
1760          bld.mkMov(su->getDef(i), r[i]);
1761       }
1762       call->setDef(4, p[1]);
1763       delete_Instruction(bld.getProgram(), su);
1764    }
1765
1766    if (su->op == OP_SUREDB || su->op == OP_SUREDP) {
1767       // FIXME: for out of bounds access, destination value will be undefined !
1768       Value *pred = su->getSrc(2);
1769       CondCode cc = CC_NOT_P;
1770       if (su->getPredicate()) {
1771          pred = bld.getScratch(1, FILE_PREDICATE);
1772          cc = su->cc;
1773          if (cc == CC_NOT_P) {
1774             bld.mkOp2(OP_OR, TYPE_U8, pred, su->getPredicate(), su->getSrc(2));
1775          } else {
1776             bld.mkOp2(OP_AND, TYPE_U8, pred, su->getPredicate(), su->getSrc(2));
1777             pred->getInsn()->src(1).mod = Modifier(NV50_IR_MOD_NOT);
1778          }
1779       }
1780       Instruction *red = bld.mkOp(OP_ATOM, su->dType, su->getDef(0));
1781       red->subOp = su->subOp;
1782       if (!gMemBase)
1783          gMemBase = bld.mkSymbol(FILE_MEMORY_GLOBAL, 0, TYPE_U32, 0);
1784       red->setSrc(0, gMemBase);
1785       red->setSrc(1, su->getSrc(3));
1786       if (su->subOp == NV50_IR_SUBOP_ATOM_CAS)
1787          red->setSrc(2, su->getSrc(4));
1788       red->setIndirect(0, 0, su->getSrc(0));
1789       red->setPredicate(cc, pred);
1790       delete_Instruction(bld.getProgram(), su);
1791       handleCasExch(red, true);
1792    } else {
1793       su->sType = (su->tex.target == TEX_TARGET_BUFFER) ? TYPE_U32 : TYPE_U8;
1794    }
1795 }
1796
1797 bool
1798 NVC0LoweringPass::handleWRSV(Instruction *i)
1799 {
1800    Instruction *st;
1801    Symbol *sym;
1802    uint32_t addr;
1803
1804    // must replace, $sreg are not writeable
1805    addr = targ->getSVAddress(FILE_SHADER_OUTPUT, i->getSrc(0)->asSym());
1806    if (addr >= 0x400)
1807       return false;
1808    sym = bld.mkSymbol(FILE_SHADER_OUTPUT, 0, i->sType, addr);
1809
1810    st = bld.mkStore(OP_EXPORT, i->dType, sym, i->getIndirect(0, 0),
1811                     i->getSrc(1));
1812    st->perPatch = i->perPatch;
1813
1814    bld.getBB()->remove(i);
1815    return true;
1816 }
1817
1818 void
1819 NVC0LoweringPass::handleLDST(Instruction *i)
1820 {
1821    if (i->src(0).getFile() == FILE_SHADER_INPUT) {
1822       if (prog->getType() == Program::TYPE_COMPUTE) {
1823          i->getSrc(0)->reg.file = FILE_MEMORY_CONST;
1824          i->getSrc(0)->reg.fileIndex = 0;
1825       } else
1826       if (prog->getType() == Program::TYPE_GEOMETRY &&
1827           i->src(0).isIndirect(0)) {
1828          // XXX: this assumes vec4 units
1829          Value *ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(),
1830                                  i->getIndirect(0, 0), bld.mkImm(4));
1831          i->setIndirect(0, 0, ptr);
1832          i->op = OP_VFETCH;
1833       } else {
1834          i->op = OP_VFETCH;
1835          assert(prog->getType() != Program::TYPE_FRAGMENT); // INTERP
1836       }
1837    } else if (i->src(0).getFile() == FILE_MEMORY_CONST) {
1838       if (targ->getChipset() >= NVISA_GK104_CHIPSET &&
1839           prog->getType() == Program::TYPE_COMPUTE) {
1840          // The launch descriptor only allows to set up 8 CBs, but OpenGL
1841          // requires at least 12 UBOs. To bypass this limitation, we store the
1842          // addrs into the driver constbuf and we directly load from the global
1843          // memory.
1844          int8_t fileIndex = i->getSrc(0)->reg.fileIndex - 1;
1845          Value *ind = i->getIndirect(0, 1);
1846          Value *ptr = loadUboInfo64(ind, fileIndex * 16);
1847
1848          // TODO: clamp the offset to the maximum number of const buf.
1849          if (i->src(0).isIndirect(1)) {
1850             Value *offset = bld.loadImm(NULL, i->getSrc(0)->reg.data.offset + typeSizeof(i->sType));
1851             Value *length = loadUboLength32(ind, fileIndex * 16);
1852             Value *pred = new_LValue(func, FILE_PREDICATE);
1853             if (i->src(0).isIndirect(0)) {
1854                bld.mkOp2(OP_ADD, TYPE_U64, ptr, ptr, i->getIndirect(0, 0));
1855                bld.mkOp2(OP_ADD, TYPE_U32, offset, offset, i->getIndirect(0, 0));
1856             }
1857             i->getSrc(0)->reg.file = FILE_MEMORY_GLOBAL;
1858             i->setIndirect(0, 1, NULL);
1859             i->setIndirect(0, 0, ptr);
1860             bld.mkCmp(OP_SET, CC_GT, TYPE_U32, pred, TYPE_U32, offset, length);
1861             i->setPredicate(CC_NOT_P, pred);
1862             if (i->defExists(0)) {
1863                bld.mkMov(i->getDef(0), bld.mkImm(0));
1864             }
1865          } else if (fileIndex >= 0) {
1866             if (i->src(0).isIndirect(0)) {
1867                bld.mkOp2(OP_ADD, TYPE_U64, ptr, ptr, i->getIndirect(0, 0));
1868             }
1869             i->getSrc(0)->reg.file = FILE_MEMORY_GLOBAL;
1870             i->setIndirect(0, 1, NULL);
1871             i->setIndirect(0, 0, ptr);
1872          }
1873       } else if (i->src(0).isIndirect(1)) {
1874          Value *ptr;
1875          if (i->src(0).isIndirect(0))
1876             ptr = bld.mkOp3v(OP_INSBF, TYPE_U32, bld.getSSA(),
1877                              i->getIndirect(0, 1), bld.mkImm(0x1010),
1878                              i->getIndirect(0, 0));
1879          else
1880             ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(),
1881                              i->getIndirect(0, 1), bld.mkImm(16));
1882          i->setIndirect(0, 1, NULL);
1883          i->setIndirect(0, 0, ptr);
1884          i->subOp = NV50_IR_SUBOP_LDC_IS;
1885       }
1886    } else if (i->src(0).getFile() == FILE_SHADER_OUTPUT) {
1887       assert(prog->getType() == Program::TYPE_TESSELLATION_CONTROL);
1888       i->op = OP_VFETCH;
1889    } else if (i->src(0).getFile() == FILE_MEMORY_GLOBAL) {
1890       Value *ind = i->getIndirect(0, 1);
1891       Value *ptr = loadBufInfo64(ind, i->getSrc(0)->reg.fileIndex * 16);
1892       // XXX come up with a way not to do this for EVERY little access but
1893       // rather to batch these up somehow. Unfortunately we've lost the
1894       // information about the field width by the time we get here.
1895       Value *offset = bld.loadImm(NULL, i->getSrc(0)->reg.data.offset + typeSizeof(i->sType));
1896       Value *length = loadBufLength32(ind, i->getSrc(0)->reg.fileIndex * 16);
1897       Value *pred = new_LValue(func, FILE_PREDICATE);
1898       if (i->src(0).isIndirect(0)) {
1899          bld.mkOp2(OP_ADD, TYPE_U64, ptr, ptr, i->getIndirect(0, 0));
1900          bld.mkOp2(OP_ADD, TYPE_U32, offset, offset, i->getIndirect(0, 0));
1901       }
1902       i->setIndirect(0, 1, NULL);
1903       i->setIndirect(0, 0, ptr);
1904       bld.mkCmp(OP_SET, CC_GT, TYPE_U32, pred, TYPE_U32, offset, length);
1905       i->setPredicate(CC_NOT_P, pred);
1906       if (i->defExists(0)) {
1907          bld.mkMov(i->getDef(0), bld.mkImm(0));
1908       }
1909    }
1910 }
1911
1912 void
1913 NVC0LoweringPass::readTessCoord(LValue *dst, int c)
1914 {
1915    Value *laneid = bld.getSSA();
1916    Value *x, *y;
1917
1918    bld.mkOp1(OP_RDSV, TYPE_U32, laneid, bld.mkSysVal(SV_LANEID, 0));
1919
1920    if (c == 0) {
1921       x = dst;
1922       y = NULL;
1923    } else
1924    if (c == 1) {
1925       x = NULL;
1926       y = dst;
1927    } else {
1928       assert(c == 2);
1929       x = bld.getSSA();
1930       y = bld.getSSA();
1931    }
1932    if (x)
1933       bld.mkFetch(x, TYPE_F32, FILE_SHADER_OUTPUT, 0x2f0, NULL, laneid);
1934    if (y)
1935       bld.mkFetch(y, TYPE_F32, FILE_SHADER_OUTPUT, 0x2f4, NULL, laneid);
1936
1937    if (c == 2) {
1938       bld.mkOp2(OP_ADD, TYPE_F32, dst, x, y);
1939       bld.mkOp2(OP_SUB, TYPE_F32, dst, bld.loadImm(NULL, 1.0f), dst);
1940    }
1941 }
1942
1943 bool
1944 NVC0LoweringPass::handleRDSV(Instruction *i)
1945 {
1946    Symbol *sym = i->getSrc(0)->asSym();
1947    const SVSemantic sv = sym->reg.data.sv.sv;
1948    Value *vtx = NULL;
1949    Instruction *ld;
1950    uint32_t addr = targ->getSVAddress(FILE_SHADER_INPUT, sym);
1951
1952    if (addr >= 0x400) {
1953       // mov $sreg
1954       if (sym->reg.data.sv.index == 3) {
1955          // TGSI backend may use 4th component of TID,NTID,CTAID,NCTAID
1956          i->op = OP_MOV;
1957          i->setSrc(0, bld.mkImm((sv == SV_NTID || sv == SV_NCTAID) ? 1 : 0));
1958       }
1959       if (sv == SV_VERTEX_COUNT) {
1960          bld.setPosition(i, true);
1961          bld.mkOp2(OP_EXTBF, TYPE_U32, i->getDef(0), i->getDef(0), bld.mkImm(0x808));
1962       }
1963       return true;
1964    }
1965
1966    switch (sv) {
1967    case SV_POSITION:
1968       assert(prog->getType() == Program::TYPE_FRAGMENT);
1969       if (i->srcExists(1)) {
1970          // Pass offset through to the interpolation logic
1971          ld = bld.mkInterp(NV50_IR_INTERP_LINEAR | NV50_IR_INTERP_OFFSET,
1972                            i->getDef(0), addr, NULL);
1973          ld->setSrc(1, i->getSrc(1));
1974       } else {
1975          bld.mkInterp(NV50_IR_INTERP_LINEAR, i->getDef(0), addr, NULL);
1976       }
1977       break;
1978    case SV_FACE:
1979    {
1980       Value *face = i->getDef(0);
1981       bld.mkInterp(NV50_IR_INTERP_FLAT, face, addr, NULL);
1982       if (i->dType == TYPE_F32) {
1983          bld.mkOp2(OP_OR, TYPE_U32, face, face, bld.mkImm(0x00000001));
1984          bld.mkOp1(OP_NEG, TYPE_S32, face, face);
1985          bld.mkCvt(OP_CVT, TYPE_F32, face, TYPE_S32, face);
1986       }
1987    }
1988       break;
1989    case SV_TESS_COORD:
1990       assert(prog->getType() == Program::TYPE_TESSELLATION_EVAL);
1991       readTessCoord(i->getDef(0)->asLValue(), i->getSrc(0)->reg.data.sv.index);
1992       break;
1993    case SV_NTID:
1994    case SV_NCTAID:
1995    case SV_GRIDID:
1996       assert(targ->getChipset() >= NVISA_GK104_CHIPSET); // mov $sreg otherwise
1997       if (sym->reg.data.sv.index == 3) {
1998          i->op = OP_MOV;
1999          i->setSrc(0, bld.mkImm(sv == SV_GRIDID ? 0 : 1));
2000          return true;
2001       }
2002       addr += prog->driver->prop.cp.gridInfoBase;
2003       bld.mkLoad(TYPE_U32, i->getDef(0),
2004                  bld.mkSymbol(FILE_MEMORY_CONST, prog->driver->io.auxCBSlot,
2005                               TYPE_U32, addr), NULL);
2006       break;
2007    case SV_SAMPLE_INDEX:
2008       // TODO: Properly pass source as an address in the PIX address space
2009       // (which can be of the form [r0+offset]). But this is currently
2010       // unnecessary.
2011       ld = bld.mkOp1(OP_PIXLD, TYPE_U32, i->getDef(0), bld.mkImm(0));
2012       ld->subOp = NV50_IR_SUBOP_PIXLD_SAMPLEID;
2013       break;
2014    case SV_SAMPLE_POS: {
2015       Value *off = new_LValue(func, FILE_GPR);
2016       ld = bld.mkOp1(OP_PIXLD, TYPE_U32, i->getDef(0), bld.mkImm(0));
2017       ld->subOp = NV50_IR_SUBOP_PIXLD_SAMPLEID;
2018       bld.mkOp2(OP_SHL, TYPE_U32, off, i->getDef(0), bld.mkImm(3));
2019       bld.mkLoad(TYPE_F32,
2020                  i->getDef(0),
2021                  bld.mkSymbol(
2022                        FILE_MEMORY_CONST, prog->driver->io.auxCBSlot,
2023                        TYPE_U32, prog->driver->io.sampleInfoBase +
2024                        4 * sym->reg.data.sv.index),
2025                  off);
2026       break;
2027    }
2028    case SV_SAMPLE_MASK:
2029       ld = bld.mkOp1(OP_PIXLD, TYPE_U32, i->getDef(0), bld.mkImm(0));
2030       ld->subOp = NV50_IR_SUBOP_PIXLD_COVMASK;
2031       break;
2032    case SV_BASEVERTEX:
2033    case SV_BASEINSTANCE:
2034    case SV_DRAWID:
2035       ld = bld.mkLoad(TYPE_U32, i->getDef(0),
2036                       bld.mkSymbol(FILE_MEMORY_CONST,
2037                                    prog->driver->io.auxCBSlot,
2038                                    TYPE_U32,
2039                                    prog->driver->io.drawInfoBase +
2040                                    4 * (sv - SV_BASEVERTEX)),
2041                       NULL);
2042       break;
2043    default:
2044       if (prog->getType() == Program::TYPE_TESSELLATION_EVAL && !i->perPatch)
2045          vtx = bld.mkOp1v(OP_PFETCH, TYPE_U32, bld.getSSA(), bld.mkImm(0));
2046       ld = bld.mkFetch(i->getDef(0), i->dType,
2047                        FILE_SHADER_INPUT, addr, i->getIndirect(0, 0), vtx);
2048       ld->perPatch = i->perPatch;
2049       break;
2050    }
2051    bld.getBB()->remove(i);
2052    return true;
2053 }
2054
2055 bool
2056 NVC0LoweringPass::handleDIV(Instruction *i)
2057 {
2058    if (!isFloatType(i->dType))
2059       return true;
2060    bld.setPosition(i, false);
2061    Instruction *rcp = bld.mkOp1(OP_RCP, i->dType, bld.getSSA(typeSizeof(i->dType)), i->getSrc(1));
2062    i->op = OP_MUL;
2063    i->setSrc(1, rcp->getDef(0));
2064    return true;
2065 }
2066
2067 bool
2068 NVC0LoweringPass::handleMOD(Instruction *i)
2069 {
2070    if (!isFloatType(i->dType))
2071       return true;
2072    LValue *value = bld.getScratch(typeSizeof(i->dType));
2073    bld.mkOp1(OP_RCP, i->dType, value, i->getSrc(1));
2074    bld.mkOp2(OP_MUL, i->dType, value, i->getSrc(0), value);
2075    bld.mkOp1(OP_TRUNC, i->dType, value, value);
2076    bld.mkOp2(OP_MUL, i->dType, value, i->getSrc(1), value);
2077    i->op = OP_SUB;
2078    i->setSrc(1, value);
2079    return true;
2080 }
2081
2082 bool
2083 NVC0LoweringPass::handleSQRT(Instruction *i)
2084 {
2085    if (i->dType == TYPE_F64) {
2086       Value *pred = bld.getSSA(1, FILE_PREDICATE);
2087       Value *zero = bld.loadImm(NULL, 0.0);
2088       Value *dst = bld.getSSA(8);
2089       bld.mkOp1(OP_RSQ, i->dType, dst, i->getSrc(0));
2090       bld.mkCmp(OP_SET, CC_LE, i->dType, pred, i->dType, i->getSrc(0), zero);
2091       bld.mkOp3(OP_SELP, TYPE_U64, dst, zero, dst, pred);
2092       i->op = OP_MUL;
2093       i->setSrc(1, dst);
2094       // TODO: Handle this properly with a library function
2095    } else {
2096       bld.setPosition(i, true);
2097       i->op = OP_RSQ;
2098       bld.mkOp1(OP_RCP, i->dType, i->getDef(0), i->getDef(0));
2099    }
2100
2101    return true;
2102 }
2103
2104 bool
2105 NVC0LoweringPass::handlePOW(Instruction *i)
2106 {
2107    LValue *val = bld.getScratch();
2108
2109    bld.mkOp1(OP_LG2, TYPE_F32, val, i->getSrc(0));
2110    bld.mkOp2(OP_MUL, TYPE_F32, val, i->getSrc(1), val)->dnz = 1;
2111    bld.mkOp1(OP_PREEX2, TYPE_F32, val, val);
2112
2113    i->op = OP_EX2;
2114    i->setSrc(0, val);
2115    i->setSrc(1, NULL);
2116
2117    return true;
2118 }
2119
2120 bool
2121 NVC0LoweringPass::handleEXPORT(Instruction *i)
2122 {
2123    if (prog->getType() == Program::TYPE_FRAGMENT) {
2124       int id = i->getSrc(0)->reg.data.offset / 4;
2125
2126       if (i->src(0).isIndirect(0)) // TODO, ugly
2127          return false;
2128       i->op = OP_MOV;
2129       i->subOp = NV50_IR_SUBOP_MOV_FINAL;
2130       i->src(0).set(i->src(1));
2131       i->setSrc(1, NULL);
2132       i->setDef(0, new_LValue(func, FILE_GPR));
2133       i->getDef(0)->reg.data.id = id;
2134
2135       prog->maxGPR = MAX2(prog->maxGPR, id);
2136    } else
2137    if (prog->getType() == Program::TYPE_GEOMETRY) {
2138       i->setIndirect(0, 1, gpEmitAddress);
2139    }
2140    return true;
2141 }
2142
2143 bool
2144 NVC0LoweringPass::handleOUT(Instruction *i)
2145 {
2146    Instruction *prev = i->prev;
2147    ImmediateValue stream, prevStream;
2148
2149    // Only merge if the stream ids match. Also, note that the previous
2150    // instruction would have already been lowered, so we take arg1 from it.
2151    if (i->op == OP_RESTART && prev && prev->op == OP_EMIT &&
2152        i->src(0).getImmediate(stream) &&
2153        prev->src(1).getImmediate(prevStream) &&
2154        stream.reg.data.u32 == prevStream.reg.data.u32) {
2155       i->prev->subOp = NV50_IR_SUBOP_EMIT_RESTART;
2156       delete_Instruction(prog, i);
2157    } else {
2158       assert(gpEmitAddress);
2159       i->setDef(0, gpEmitAddress);
2160       i->setSrc(1, i->getSrc(0));
2161       i->setSrc(0, gpEmitAddress);
2162    }
2163    return true;
2164 }
2165
2166 // Generate a binary predicate if an instruction is predicated by
2167 // e.g. an f32 value.
2168 void
2169 NVC0LoweringPass::checkPredicate(Instruction *insn)
2170 {
2171    Value *pred = insn->getPredicate();
2172    Value *pdst;
2173
2174    if (!pred || pred->reg.file == FILE_PREDICATE)
2175       return;
2176    pdst = new_LValue(func, FILE_PREDICATE);
2177
2178    // CAUTION: don't use pdst->getInsn, the definition might not be unique,
2179    //  delay turning PSET(FSET(x,y),0) into PSET(x,y) to a later pass
2180
2181    bld.mkCmp(OP_SET, CC_NEU, insn->dType, pdst, insn->dType, bld.mkImm(0), pred);
2182
2183    insn->setPredicate(insn->cc, pdst);
2184 }
2185
2186 //
2187 // - add quadop dance for texturing
2188 // - put FP outputs in GPRs
2189 // - convert instruction sequences
2190 //
2191 bool
2192 NVC0LoweringPass::visit(Instruction *i)
2193 {
2194    bool ret = true;
2195    bld.setPosition(i, false);
2196
2197    if (i->cc != CC_ALWAYS)
2198       checkPredicate(i);
2199
2200    switch (i->op) {
2201    case OP_TEX:
2202    case OP_TXB:
2203    case OP_TXL:
2204    case OP_TXF:
2205    case OP_TXG:
2206       return handleTEX(i->asTex());
2207    case OP_TXD:
2208       return handleTXD(i->asTex());
2209    case OP_TXLQ:
2210       return handleTXLQ(i->asTex());
2211    case OP_TXQ:
2212      return handleTXQ(i->asTex());
2213    case OP_EX2:
2214       bld.mkOp1(OP_PREEX2, TYPE_F32, i->getDef(0), i->getSrc(0));
2215       i->setSrc(0, i->getDef(0));
2216       break;
2217    case OP_POW:
2218       return handlePOW(i);
2219    case OP_DIV:
2220       return handleDIV(i);
2221    case OP_MOD:
2222       return handleMOD(i);
2223    case OP_SQRT:
2224       return handleSQRT(i);
2225    case OP_EXPORT:
2226       ret = handleEXPORT(i);
2227       break;
2228    case OP_EMIT:
2229    case OP_RESTART:
2230       return handleOUT(i);
2231    case OP_RDSV:
2232       return handleRDSV(i);
2233    case OP_WRSV:
2234       return handleWRSV(i);
2235    case OP_STORE:
2236    case OP_LOAD:
2237       handleLDST(i);
2238       break;
2239    case OP_ATOM:
2240    {
2241       const bool cctl = i->src(0).getFile() == FILE_MEMORY_GLOBAL;
2242       handleATOM(i);
2243       handleCasExch(i, cctl);
2244    }
2245       break;
2246    case OP_SULDB:
2247    case OP_SULDP:
2248    case OP_SUSTB:
2249    case OP_SUSTP:
2250    case OP_SUREDB:
2251    case OP_SUREDP:
2252       if (targ->getChipset() >= NVISA_GK104_CHIPSET)
2253          handleSurfaceOpNVE4(i->asTex());
2254       break;
2255    case OP_SUQ:
2256       handleSUQ(i);
2257       break;
2258    default:
2259       break;
2260    }
2261
2262    /* Kepler+ has a special opcode to compute a new base address to be used
2263     * for indirect loads.
2264     */
2265    if (targ->getChipset() >= NVISA_GK104_CHIPSET && !i->perPatch &&
2266        (i->op == OP_VFETCH || i->op == OP_EXPORT) && i->src(0).isIndirect(0)) {
2267       Instruction *afetch = bld.mkOp1(OP_AFETCH, TYPE_U32, bld.getSSA(),
2268                                       cloneShallow(func, i->getSrc(0)));
2269       afetch->setIndirect(0, 0, i->getIndirect(0, 0));
2270       i->src(0).get()->reg.data.offset = 0;
2271       i->setIndirect(0, 0, afetch->getDef(0));
2272    }
2273
2274    return ret;
2275 }
2276
2277 bool
2278 TargetNVC0::runLegalizePass(Program *prog, CGStage stage) const
2279 {
2280    if (stage == CG_STAGE_PRE_SSA) {
2281       NVC0LoweringPass pass(prog);
2282       return pass.run(prog, false, true);
2283    } else
2284    if (stage == CG_STAGE_POST_RA) {
2285       NVC0LegalizePostRA pass(prog);
2286       return pass.run(prog, false, true);
2287    } else
2288    if (stage == CG_STAGE_SSA) {
2289       NVC0LegalizeSSA pass;
2290       return pass.run(prog, false, true);
2291    }
2292    return false;
2293 }
2294
2295 } // namespace nv50_ir