OSDN Git Service

nvc0/ir: do not lower shared+atomics on GM107+
[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       // For Fermi/Kepler, we have to use ld lock/st unlock to perform atomic
1292       // operations on shared memory. For Maxwell, ATOMS is enough.
1293       if (targ->getChipset() < NVISA_GK104_CHIPSET)
1294          handleSharedATOM(atom);
1295       else if (targ->getChipset() < NVISA_GM107_CHIPSET)
1296          handleSharedATOMNVE4(atom);
1297       return true;
1298    default:
1299       assert(atom->src(0).getFile() == FILE_MEMORY_GLOBAL);
1300       base = loadBufInfo64(ind, atom->getSrc(0)->reg.fileIndex * 16);
1301       assert(base->reg.size == 8);
1302       if (ptr)
1303          base = bld.mkOp2v(OP_ADD, TYPE_U64, base, base, ptr);
1304       assert(base->reg.size == 8);
1305       atom->setIndirect(0, 0, base);
1306       return true;
1307    }
1308    base =
1309       bld.mkOp1v(OP_RDSV, TYPE_U32, bld.getScratch(), bld.mkSysVal(sv, 0));
1310
1311    atom->setSrc(0, cloneShallow(func, atom->getSrc(0)));
1312    atom->getSrc(0)->reg.file = FILE_MEMORY_GLOBAL;
1313    if (ptr)
1314       base = bld.mkOp2v(OP_ADD, TYPE_U32, base, base, ptr);
1315    atom->setIndirect(0, 1, NULL);
1316    atom->setIndirect(0, 0, base);
1317
1318    return true;
1319 }
1320
1321 bool
1322 NVC0LoweringPass::handleCasExch(Instruction *cas, bool needCctl)
1323 {
1324    if (targ->getChipset() < NVISA_GM107_CHIPSET) {
1325       if (cas->src(0).getFile() == FILE_MEMORY_SHARED) {
1326          // ATOM_CAS and ATOM_EXCH are handled in handleSharedATOM().
1327          return false;
1328       }
1329    }
1330
1331    if (cas->subOp != NV50_IR_SUBOP_ATOM_CAS &&
1332        cas->subOp != NV50_IR_SUBOP_ATOM_EXCH)
1333       return false;
1334    bld.setPosition(cas, true);
1335
1336    if (needCctl) {
1337       Instruction *cctl = bld.mkOp1(OP_CCTL, TYPE_NONE, NULL, cas->getSrc(0));
1338       cctl->setIndirect(0, 0, cas->getIndirect(0, 0));
1339       cctl->fixed = 1;
1340       cctl->subOp = NV50_IR_SUBOP_CCTL_IV;
1341       if (cas->isPredicated())
1342          cctl->setPredicate(cas->cc, cas->getPredicate());
1343    }
1344
1345    if (cas->subOp == NV50_IR_SUBOP_ATOM_CAS) {
1346       // CAS is crazy. It's 2nd source is a double reg, and the 3rd source
1347       // should be set to the high part of the double reg or bad things will
1348       // happen elsewhere in the universe.
1349       // Also, it sometimes returns the new value instead of the old one
1350       // under mysterious circumstances.
1351       Value *dreg = bld.getSSA(8);
1352       bld.setPosition(cas, false);
1353       bld.mkOp2(OP_MERGE, TYPE_U64, dreg, cas->getSrc(1), cas->getSrc(2));
1354       cas->setSrc(1, dreg);
1355       cas->setSrc(2, dreg);
1356    }
1357
1358    return true;
1359 }
1360
1361 inline Value *
1362 NVC0LoweringPass::loadResInfo32(Value *ptr, uint32_t off, uint16_t base)
1363 {
1364    uint8_t b = prog->driver->io.auxCBSlot;
1365    off += base;
1366
1367    return bld.
1368       mkLoadv(TYPE_U32, bld.mkSymbol(FILE_MEMORY_CONST, b, TYPE_U32, off), ptr);
1369 }
1370
1371 inline Value *
1372 NVC0LoweringPass::loadResInfo64(Value *ptr, uint32_t off, uint16_t base)
1373 {
1374    uint8_t b = prog->driver->io.auxCBSlot;
1375    off += base;
1376
1377    if (ptr)
1378       ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getScratch(), ptr, bld.mkImm(4));
1379
1380    return bld.
1381       mkLoadv(TYPE_U64, bld.mkSymbol(FILE_MEMORY_CONST, b, TYPE_U64, off), ptr);
1382 }
1383
1384 inline Value *
1385 NVC0LoweringPass::loadResLength32(Value *ptr, uint32_t off, uint16_t base)
1386 {
1387    uint8_t b = prog->driver->io.auxCBSlot;
1388    off += base;
1389
1390    if (ptr)
1391       ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getScratch(), ptr, bld.mkImm(4));
1392
1393    return bld.
1394       mkLoadv(TYPE_U32, bld.mkSymbol(FILE_MEMORY_CONST, b, TYPE_U64, off + 8), ptr);
1395 }
1396
1397 inline Value *
1398 NVC0LoweringPass::loadSuInfo32(Value *ptr, uint32_t off)
1399 {
1400    return loadResInfo32(ptr, off, prog->driver->io.suInfoBase);
1401 }
1402
1403 inline Value *
1404 NVC0LoweringPass::loadSuInfo64(Value *ptr, uint32_t off)
1405 {
1406    return loadResInfo64(ptr, off, prog->driver->io.suInfoBase);
1407 }
1408
1409 inline Value *
1410 NVC0LoweringPass::loadSuLength32(Value *ptr, uint32_t off)
1411 {
1412    return loadResLength32(ptr, off, prog->driver->io.suInfoBase);
1413 }
1414
1415 inline Value *
1416 NVC0LoweringPass::loadBufInfo32(Value *ptr, uint32_t off)
1417 {
1418    return loadResInfo32(ptr, off, prog->driver->io.bufInfoBase);
1419 }
1420
1421 inline Value *
1422 NVC0LoweringPass::loadBufInfo64(Value *ptr, uint32_t off)
1423 {
1424    return loadResInfo64(ptr, off, prog->driver->io.bufInfoBase);
1425 }
1426
1427 inline Value *
1428 NVC0LoweringPass::loadBufLength32(Value *ptr, uint32_t off)
1429 {
1430    return loadResLength32(ptr, off, prog->driver->io.bufInfoBase);
1431 }
1432
1433 inline Value *
1434 NVC0LoweringPass::loadUboInfo32(Value *ptr, uint32_t off)
1435 {
1436    return loadResInfo32(ptr, off, prog->driver->io.uboInfoBase);
1437 }
1438
1439 inline Value *
1440 NVC0LoweringPass::loadUboInfo64(Value *ptr, uint32_t off)
1441 {
1442    return loadResInfo64(ptr, off, prog->driver->io.uboInfoBase);
1443 }
1444
1445 inline Value *
1446 NVC0LoweringPass::loadUboLength32(Value *ptr, uint32_t off)
1447 {
1448    return loadResLength32(ptr, off, prog->driver->io.uboInfoBase);
1449 }
1450
1451 inline Value *
1452 NVC0LoweringPass::loadMsInfo32(Value *ptr, uint32_t off)
1453 {
1454    uint8_t b = prog->driver->io.msInfoCBSlot;
1455    off += prog->driver->io.msInfoBase;
1456    return bld.
1457       mkLoadv(TYPE_U32, bld.mkSymbol(FILE_MEMORY_CONST, b, TYPE_U32, off), ptr);
1458 }
1459
1460 /* On nvc0, surface info is obtained via the surface binding points passed
1461  * to the SULD/SUST instructions.
1462  * On nve4, surface info is stored in c[] and is used by various special
1463  * instructions, e.g. for clamping coordiantes or generating an address.
1464  * They couldn't just have added an equivalent to TIC now, couldn't they ?
1465  */
1466 #define NVE4_SU_INFO_ADDR   0x00
1467 #define NVE4_SU_INFO_FMT    0x04
1468 #define NVE4_SU_INFO_DIM_X  0x08
1469 #define NVE4_SU_INFO_PITCH  0x0c
1470 #define NVE4_SU_INFO_DIM_Y  0x10
1471 #define NVE4_SU_INFO_ARRAY  0x14
1472 #define NVE4_SU_INFO_DIM_Z  0x18
1473 #define NVE4_SU_INFO_UNK1C  0x1c
1474 #define NVE4_SU_INFO_WIDTH  0x20
1475 #define NVE4_SU_INFO_HEIGHT 0x24
1476 #define NVE4_SU_INFO_DEPTH  0x28
1477 #define NVE4_SU_INFO_TARGET 0x2c
1478 #define NVE4_SU_INFO_CALL   0x30
1479 #define NVE4_SU_INFO_RAW_X  0x34
1480 #define NVE4_SU_INFO_MS_X   0x38
1481 #define NVE4_SU_INFO_MS_Y   0x3c
1482
1483 #define NVE4_SU_INFO__STRIDE 0x40
1484
1485 #define NVE4_SU_INFO_DIM(i)  (0x08 + (i) * 8)
1486 #define NVE4_SU_INFO_SIZE(i) (0x20 + (i) * 4)
1487 #define NVE4_SU_INFO_MS(i)   (0x38 + (i) * 4)
1488
1489 static inline uint16_t getSuClampSubOp(const TexInstruction *su, int c)
1490 {
1491    switch (su->tex.target.getEnum()) {
1492    case TEX_TARGET_BUFFER:      return NV50_IR_SUBOP_SUCLAMP_PL(0, 1);
1493    case TEX_TARGET_RECT:        return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1494    case TEX_TARGET_1D:          return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1495    case TEX_TARGET_1D_ARRAY:    return (c == 1) ?
1496                                    NV50_IR_SUBOP_SUCLAMP_PL(0, 2) :
1497                                    NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1498    case TEX_TARGET_2D:          return NV50_IR_SUBOP_SUCLAMP_BL(0, 2);
1499    case TEX_TARGET_2D_MS:       return NV50_IR_SUBOP_SUCLAMP_BL(0, 2);
1500    case TEX_TARGET_2D_ARRAY:    return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1501    case TEX_TARGET_2D_MS_ARRAY: return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1502    case TEX_TARGET_3D:          return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1503    case TEX_TARGET_CUBE:        return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1504    case TEX_TARGET_CUBE_ARRAY:  return NV50_IR_SUBOP_SUCLAMP_SD(0, 2);
1505    default:
1506       assert(0);
1507       return 0;
1508    }
1509 }
1510
1511 void
1512 NVC0LoweringPass::adjustCoordinatesMS(TexInstruction *tex)
1513 {
1514    const uint16_t base = tex->tex.r * NVE4_SU_INFO__STRIDE;
1515    const int arg = tex->tex.target.getArgCount();
1516
1517    if (tex->tex.target == TEX_TARGET_2D_MS)
1518       tex->tex.target = TEX_TARGET_2D;
1519    else
1520    if (tex->tex.target == TEX_TARGET_2D_MS_ARRAY)
1521       tex->tex.target = TEX_TARGET_2D_ARRAY;
1522    else
1523       return;
1524
1525    Value *x = tex->getSrc(0);
1526    Value *y = tex->getSrc(1);
1527    Value *s = tex->getSrc(arg - 1);
1528
1529    Value *tx = bld.getSSA(), *ty = bld.getSSA(), *ts = bld.getSSA();
1530
1531    Value *ms_x = loadSuInfo32(NULL, base + NVE4_SU_INFO_MS(0));
1532    Value *ms_y = loadSuInfo32(NULL, base + NVE4_SU_INFO_MS(1));
1533
1534    bld.mkOp2(OP_SHL, TYPE_U32, tx, x, ms_x);
1535    bld.mkOp2(OP_SHL, TYPE_U32, ty, y, ms_y);
1536
1537    s = bld.mkOp2v(OP_AND, TYPE_U32, ts, s, bld.loadImm(NULL, 0x7));
1538    s = bld.mkOp2v(OP_SHL, TYPE_U32, ts, ts, bld.mkImm(3));
1539
1540    Value *dx = loadMsInfo32(ts, 0x0);
1541    Value *dy = loadMsInfo32(ts, 0x4);
1542
1543    bld.mkOp2(OP_ADD, TYPE_U32, tx, tx, dx);
1544    bld.mkOp2(OP_ADD, TYPE_U32, ty, ty, dy);
1545
1546    tex->setSrc(0, tx);
1547    tex->setSrc(1, ty);
1548    tex->moveSources(arg, -1);
1549 }
1550
1551 // Sets 64-bit "generic address", predicate and format sources for SULD/SUST.
1552 // They're computed from the coordinates using the surface info in c[] space.
1553 void
1554 NVC0LoweringPass::processSurfaceCoordsNVE4(TexInstruction *su)
1555 {
1556    Instruction *insn;
1557    const bool atom = su->op == OP_SUREDB || su->op == OP_SUREDP;
1558    const bool raw =
1559       su->op == OP_SULDB || su->op == OP_SUSTB || su->op == OP_SUREDB;
1560    const int idx = su->tex.r;
1561    const int dim = su->tex.target.getDim();
1562    const int arg = dim + (su->tex.target.isArray() ? 1 : 0);
1563    const uint16_t base = idx * NVE4_SU_INFO__STRIDE;
1564    int c;
1565    Value *zero = bld.mkImm(0);
1566    Value *p1 = NULL;
1567    Value *v;
1568    Value *src[3];
1569    Value *bf, *eau, *off;
1570    Value *addr, *pred;
1571
1572    off = bld.getScratch(4);
1573    bf = bld.getScratch(4);
1574    addr = bld.getSSA(8);
1575    pred = bld.getScratch(1, FILE_PREDICATE);
1576
1577    bld.setPosition(su, false);
1578
1579    adjustCoordinatesMS(su);
1580
1581    // calculate clamped coordinates
1582    for (c = 0; c < arg; ++c) {
1583       src[c] = bld.getScratch();
1584       if (c == 0 && raw)
1585          v = loadSuInfo32(NULL, base + NVE4_SU_INFO_RAW_X);
1586       else
1587          v = loadSuInfo32(NULL, base + NVE4_SU_INFO_DIM(c));
1588       bld.mkOp3(OP_SUCLAMP, TYPE_S32, src[c], su->getSrc(c), v, zero)
1589          ->subOp = getSuClampSubOp(su, c);
1590    }
1591    for (; c < 3; ++c)
1592       src[c] = zero;
1593
1594    // set predicate output
1595    if (su->tex.target == TEX_TARGET_BUFFER) {
1596       src[0]->getInsn()->setFlagsDef(1, pred);
1597    } else
1598    if (su->tex.target.isArray()) {
1599       p1 = bld.getSSA(1, FILE_PREDICATE);
1600       src[dim]->getInsn()->setFlagsDef(1, p1);
1601    }
1602
1603    // calculate pixel offset
1604    if (dim == 1) {
1605       if (su->tex.target != TEX_TARGET_BUFFER)
1606          bld.mkOp2(OP_AND, TYPE_U32, off, src[0], bld.loadImm(NULL, 0xffff));
1607    } else
1608    if (dim == 3) {
1609       v = loadSuInfo32(NULL, base + NVE4_SU_INFO_UNK1C);
1610       bld.mkOp3(OP_MADSP, TYPE_U32, off, src[2], v, src[1])
1611          ->subOp = NV50_IR_SUBOP_MADSP(4,2,8); // u16l u16l u16l
1612
1613       v = loadSuInfo32(NULL, base + NVE4_SU_INFO_PITCH);
1614       bld.mkOp3(OP_MADSP, TYPE_U32, off, off, v, src[0])
1615          ->subOp = NV50_IR_SUBOP_MADSP(0,2,8); // u32 u16l u16l
1616    } else {
1617       assert(dim == 2);
1618       v = loadSuInfo32(NULL, base + NVE4_SU_INFO_PITCH);
1619       bld.mkOp3(OP_MADSP, TYPE_U32, off, src[1], v, src[0])
1620          ->subOp = su->tex.target.isArray() ?
1621          NV50_IR_SUBOP_MADSP_SD : NV50_IR_SUBOP_MADSP(4,2,8); // u16l u16l u16l
1622    }
1623
1624    // calculate effective address part 1
1625    if (su->tex.target == TEX_TARGET_BUFFER) {
1626       if (raw) {
1627          bf = src[0];
1628       } else {
1629          v = loadSuInfo32(NULL, base + NVE4_SU_INFO_FMT);
1630          bld.mkOp3(OP_VSHL, TYPE_U32, bf, src[0], v, zero)
1631             ->subOp = NV50_IR_SUBOP_V1(7,6,8|2);
1632       }
1633    } else {
1634       Value *y = src[1];
1635       Value *z = src[2];
1636       uint16_t subOp = 0;
1637
1638       switch (dim) {
1639       case 1:
1640          y = zero;
1641          z = zero;
1642          break;
1643       case 2:
1644          z = off;
1645          if (!su->tex.target.isArray()) {
1646             z = loadSuInfo32(NULL, base + NVE4_SU_INFO_UNK1C);
1647             subOp = NV50_IR_SUBOP_SUBFM_3D;
1648          }
1649          break;
1650       default:
1651          subOp = NV50_IR_SUBOP_SUBFM_3D;
1652          assert(dim == 3);
1653          break;
1654       }
1655       insn = bld.mkOp3(OP_SUBFM, TYPE_U32, bf, src[0], y, z);
1656       insn->subOp = subOp;
1657       insn->setFlagsDef(1, pred);
1658    }
1659
1660    // part 2
1661    v = loadSuInfo32(NULL, base + NVE4_SU_INFO_ADDR);
1662
1663    if (su->tex.target == TEX_TARGET_BUFFER) {
1664       eau = v;
1665    } else {
1666       eau = bld.mkOp3v(OP_SUEAU, TYPE_U32, bld.getScratch(4), off, bf, v);
1667    }
1668    // add array layer offset
1669    if (su->tex.target.isArray()) {
1670       v = loadSuInfo32(NULL, base + NVE4_SU_INFO_ARRAY);
1671       if (dim == 1)
1672          bld.mkOp3(OP_MADSP, TYPE_U32, eau, src[1], v, eau)
1673             ->subOp = NV50_IR_SUBOP_MADSP(4,0,0); // u16 u24 u32
1674       else
1675          bld.mkOp3(OP_MADSP, TYPE_U32, eau, v, src[2], eau)
1676             ->subOp = NV50_IR_SUBOP_MADSP(0,0,0); // u32 u24 u32
1677       // combine predicates
1678       assert(p1);
1679       bld.mkOp2(OP_OR, TYPE_U8, pred, pred, p1);
1680    }
1681
1682    if (atom) {
1683       Value *lo = bf;
1684       if (su->tex.target == TEX_TARGET_BUFFER) {
1685          lo = zero;
1686          bld.mkMov(off, bf);
1687       }
1688       //  bf == g[] address & 0xff
1689       // eau == g[] address >> 8
1690       bld.mkOp3(OP_PERMT, TYPE_U32,  bf,   lo, bld.loadImm(NULL, 0x6540), eau);
1691       bld.mkOp3(OP_PERMT, TYPE_U32, eau, zero, bld.loadImm(NULL, 0x0007), eau);
1692    } else
1693    if (su->op == OP_SULDP && su->tex.target == TEX_TARGET_BUFFER) {
1694       // Convert from u32 to u8 address format, which is what the library code
1695       // doing SULDP currently uses.
1696       // XXX: can SUEAU do this ?
1697       // XXX: does it matter that we don't mask high bytes in bf ?
1698       // Grrr.
1699       bld.mkOp2(OP_SHR, TYPE_U32, off, bf, bld.mkImm(8));
1700       bld.mkOp2(OP_ADD, TYPE_U32, eau, eau, off);
1701    }
1702
1703    bld.mkOp2(OP_MERGE, TYPE_U64, addr, bf, eau);
1704
1705    if (atom && su->tex.target == TEX_TARGET_BUFFER)
1706       bld.mkOp2(OP_ADD, TYPE_U64, addr, addr, off);
1707
1708    // let's just set it 0 for raw access and hope it works
1709    v = raw ?
1710       bld.mkImm(0) : loadSuInfo32(NULL, base + NVE4_SU_INFO_FMT);
1711
1712    // get rid of old coordinate sources, make space for fmt info and predicate
1713    su->moveSources(arg, 3 - arg);
1714    // set 64 bit address and 32-bit format sources
1715    su->setSrc(0, addr);
1716    su->setSrc(1, v);
1717    su->setSrc(2, pred);
1718 }
1719
1720 void
1721 NVC0LoweringPass::handleSurfaceOpNVE4(TexInstruction *su)
1722 {
1723    processSurfaceCoordsNVE4(su);
1724
1725    // Who do we hate more ? The person who decided that nvc0's SULD doesn't
1726    // have to support conversion or the person who decided that, in OpenCL,
1727    // you don't have to specify the format here like you do in OpenGL ?
1728
1729    if (su->op == OP_SULDP) {
1730       // We don't patch shaders. Ever.
1731       // You get an indirect call to our library blob here.
1732       // But at least it's uniform.
1733       FlowInstruction *call;
1734       LValue *p[3];
1735       LValue *r[5];
1736       uint16_t base = su->tex.r * NVE4_SU_INFO__STRIDE + NVE4_SU_INFO_CALL;
1737
1738       for (int i = 0; i < 4; ++i)
1739          (r[i] = bld.getScratch(4, FILE_GPR))->reg.data.id = i;
1740       for (int i = 0; i < 3; ++i)
1741          (p[i] = bld.getScratch(1, FILE_PREDICATE))->reg.data.id = i;
1742       (r[4] = bld.getScratch(8, FILE_GPR))->reg.data.id = 4;
1743
1744       bld.mkMov(p[1], bld.mkImm((su->cache == CACHE_CA) ? 1 : 0), TYPE_U8);
1745       bld.mkMov(p[2], bld.mkImm((su->cache == CACHE_CG) ? 1 : 0), TYPE_U8);
1746       bld.mkMov(p[0], su->getSrc(2), TYPE_U8);
1747       bld.mkMov(r[4], su->getSrc(0), TYPE_U64);
1748       bld.mkMov(r[2], su->getSrc(1), TYPE_U32);
1749
1750       call = bld.mkFlow(OP_CALL, NULL, su->cc, su->getPredicate());
1751
1752       call->indirect = 1;
1753       call->absolute = 1;
1754       call->setSrc(0, bld.mkSymbol(FILE_MEMORY_CONST,
1755                                    prog->driver->io.auxCBSlot, TYPE_U32,
1756                                    prog->driver->io.suInfoBase + base));
1757       call->setSrc(1, r[2]);
1758       call->setSrc(2, r[4]);
1759       for (int i = 0; i < 3; ++i)
1760          call->setSrc(3 + i, p[i]);
1761       for (int i = 0; i < 4; ++i) {
1762          call->setDef(i, r[i]);
1763          bld.mkMov(su->getDef(i), r[i]);
1764       }
1765       call->setDef(4, p[1]);
1766       delete_Instruction(bld.getProgram(), su);
1767    }
1768
1769    if (su->op == OP_SUREDB || su->op == OP_SUREDP) {
1770       // FIXME: for out of bounds access, destination value will be undefined !
1771       Value *pred = su->getSrc(2);
1772       CondCode cc = CC_NOT_P;
1773       if (su->getPredicate()) {
1774          pred = bld.getScratch(1, FILE_PREDICATE);
1775          cc = su->cc;
1776          if (cc == CC_NOT_P) {
1777             bld.mkOp2(OP_OR, TYPE_U8, pred, su->getPredicate(), su->getSrc(2));
1778          } else {
1779             bld.mkOp2(OP_AND, TYPE_U8, pred, su->getPredicate(), su->getSrc(2));
1780             pred->getInsn()->src(1).mod = Modifier(NV50_IR_MOD_NOT);
1781          }
1782       }
1783       Instruction *red = bld.mkOp(OP_ATOM, su->dType, su->getDef(0));
1784       red->subOp = su->subOp;
1785       if (!gMemBase)
1786          gMemBase = bld.mkSymbol(FILE_MEMORY_GLOBAL, 0, TYPE_U32, 0);
1787       red->setSrc(0, gMemBase);
1788       red->setSrc(1, su->getSrc(3));
1789       if (su->subOp == NV50_IR_SUBOP_ATOM_CAS)
1790          red->setSrc(2, su->getSrc(4));
1791       red->setIndirect(0, 0, su->getSrc(0));
1792       red->setPredicate(cc, pred);
1793       delete_Instruction(bld.getProgram(), su);
1794       handleCasExch(red, true);
1795    } else {
1796       su->sType = (su->tex.target == TEX_TARGET_BUFFER) ? TYPE_U32 : TYPE_U8;
1797    }
1798 }
1799
1800 bool
1801 NVC0LoweringPass::handleWRSV(Instruction *i)
1802 {
1803    Instruction *st;
1804    Symbol *sym;
1805    uint32_t addr;
1806
1807    // must replace, $sreg are not writeable
1808    addr = targ->getSVAddress(FILE_SHADER_OUTPUT, i->getSrc(0)->asSym());
1809    if (addr >= 0x400)
1810       return false;
1811    sym = bld.mkSymbol(FILE_SHADER_OUTPUT, 0, i->sType, addr);
1812
1813    st = bld.mkStore(OP_EXPORT, i->dType, sym, i->getIndirect(0, 0),
1814                     i->getSrc(1));
1815    st->perPatch = i->perPatch;
1816
1817    bld.getBB()->remove(i);
1818    return true;
1819 }
1820
1821 void
1822 NVC0LoweringPass::handleLDST(Instruction *i)
1823 {
1824    if (i->src(0).getFile() == FILE_SHADER_INPUT) {
1825       if (prog->getType() == Program::TYPE_COMPUTE) {
1826          i->getSrc(0)->reg.file = FILE_MEMORY_CONST;
1827          i->getSrc(0)->reg.fileIndex = 0;
1828       } else
1829       if (prog->getType() == Program::TYPE_GEOMETRY &&
1830           i->src(0).isIndirect(0)) {
1831          // XXX: this assumes vec4 units
1832          Value *ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(),
1833                                  i->getIndirect(0, 0), bld.mkImm(4));
1834          i->setIndirect(0, 0, ptr);
1835          i->op = OP_VFETCH;
1836       } else {
1837          i->op = OP_VFETCH;
1838          assert(prog->getType() != Program::TYPE_FRAGMENT); // INTERP
1839       }
1840    } else if (i->src(0).getFile() == FILE_MEMORY_CONST) {
1841       if (targ->getChipset() >= NVISA_GK104_CHIPSET &&
1842           prog->getType() == Program::TYPE_COMPUTE) {
1843          // The launch descriptor only allows to set up 8 CBs, but OpenGL
1844          // requires at least 12 UBOs. To bypass this limitation, we store the
1845          // addrs into the driver constbuf and we directly load from the global
1846          // memory.
1847          int8_t fileIndex = i->getSrc(0)->reg.fileIndex - 1;
1848          Value *ind = i->getIndirect(0, 1);
1849          Value *ptr = loadUboInfo64(ind, fileIndex * 16);
1850
1851          // TODO: clamp the offset to the maximum number of const buf.
1852          if (i->src(0).isIndirect(1)) {
1853             Value *offset = bld.loadImm(NULL, i->getSrc(0)->reg.data.offset + typeSizeof(i->sType));
1854             Value *length = loadUboLength32(ind, fileIndex * 16);
1855             Value *pred = new_LValue(func, FILE_PREDICATE);
1856             if (i->src(0).isIndirect(0)) {
1857                bld.mkOp2(OP_ADD, TYPE_U64, ptr, ptr, i->getIndirect(0, 0));
1858                bld.mkOp2(OP_ADD, TYPE_U32, offset, offset, i->getIndirect(0, 0));
1859             }
1860             i->getSrc(0)->reg.file = FILE_MEMORY_GLOBAL;
1861             i->setIndirect(0, 1, NULL);
1862             i->setIndirect(0, 0, ptr);
1863             bld.mkCmp(OP_SET, CC_GT, TYPE_U32, pred, TYPE_U32, offset, length);
1864             i->setPredicate(CC_NOT_P, pred);
1865             if (i->defExists(0)) {
1866                bld.mkMov(i->getDef(0), bld.mkImm(0));
1867             }
1868          } else if (fileIndex >= 0) {
1869             if (i->src(0).isIndirect(0)) {
1870                bld.mkOp2(OP_ADD, TYPE_U64, ptr, ptr, i->getIndirect(0, 0));
1871             }
1872             i->getSrc(0)->reg.file = FILE_MEMORY_GLOBAL;
1873             i->setIndirect(0, 1, NULL);
1874             i->setIndirect(0, 0, ptr);
1875          }
1876       } else if (i->src(0).isIndirect(1)) {
1877          Value *ptr;
1878          if (i->src(0).isIndirect(0))
1879             ptr = bld.mkOp3v(OP_INSBF, TYPE_U32, bld.getSSA(),
1880                              i->getIndirect(0, 1), bld.mkImm(0x1010),
1881                              i->getIndirect(0, 0));
1882          else
1883             ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(),
1884                              i->getIndirect(0, 1), bld.mkImm(16));
1885          i->setIndirect(0, 1, NULL);
1886          i->setIndirect(0, 0, ptr);
1887          i->subOp = NV50_IR_SUBOP_LDC_IS;
1888       }
1889    } else if (i->src(0).getFile() == FILE_SHADER_OUTPUT) {
1890       assert(prog->getType() == Program::TYPE_TESSELLATION_CONTROL);
1891       i->op = OP_VFETCH;
1892    } else if (i->src(0).getFile() == FILE_MEMORY_GLOBAL) {
1893       Value *ind = i->getIndirect(0, 1);
1894       Value *ptr = loadBufInfo64(ind, i->getSrc(0)->reg.fileIndex * 16);
1895       // XXX come up with a way not to do this for EVERY little access but
1896       // rather to batch these up somehow. Unfortunately we've lost the
1897       // information about the field width by the time we get here.
1898       Value *offset = bld.loadImm(NULL, i->getSrc(0)->reg.data.offset + typeSizeof(i->sType));
1899       Value *length = loadBufLength32(ind, i->getSrc(0)->reg.fileIndex * 16);
1900       Value *pred = new_LValue(func, FILE_PREDICATE);
1901       if (i->src(0).isIndirect(0)) {
1902          bld.mkOp2(OP_ADD, TYPE_U64, ptr, ptr, i->getIndirect(0, 0));
1903          bld.mkOp2(OP_ADD, TYPE_U32, offset, offset, i->getIndirect(0, 0));
1904       }
1905       i->setIndirect(0, 1, NULL);
1906       i->setIndirect(0, 0, ptr);
1907       bld.mkCmp(OP_SET, CC_GT, TYPE_U32, pred, TYPE_U32, offset, length);
1908       i->setPredicate(CC_NOT_P, pred);
1909       if (i->defExists(0)) {
1910          bld.mkMov(i->getDef(0), bld.mkImm(0));
1911       }
1912    }
1913 }
1914
1915 void
1916 NVC0LoweringPass::readTessCoord(LValue *dst, int c)
1917 {
1918    Value *laneid = bld.getSSA();
1919    Value *x, *y;
1920
1921    bld.mkOp1(OP_RDSV, TYPE_U32, laneid, bld.mkSysVal(SV_LANEID, 0));
1922
1923    if (c == 0) {
1924       x = dst;
1925       y = NULL;
1926    } else
1927    if (c == 1) {
1928       x = NULL;
1929       y = dst;
1930    } else {
1931       assert(c == 2);
1932       x = bld.getSSA();
1933       y = bld.getSSA();
1934    }
1935    if (x)
1936       bld.mkFetch(x, TYPE_F32, FILE_SHADER_OUTPUT, 0x2f0, NULL, laneid);
1937    if (y)
1938       bld.mkFetch(y, TYPE_F32, FILE_SHADER_OUTPUT, 0x2f4, NULL, laneid);
1939
1940    if (c == 2) {
1941       bld.mkOp2(OP_ADD, TYPE_F32, dst, x, y);
1942       bld.mkOp2(OP_SUB, TYPE_F32, dst, bld.loadImm(NULL, 1.0f), dst);
1943    }
1944 }
1945
1946 bool
1947 NVC0LoweringPass::handleRDSV(Instruction *i)
1948 {
1949    Symbol *sym = i->getSrc(0)->asSym();
1950    const SVSemantic sv = sym->reg.data.sv.sv;
1951    Value *vtx = NULL;
1952    Instruction *ld;
1953    uint32_t addr = targ->getSVAddress(FILE_SHADER_INPUT, sym);
1954
1955    if (addr >= 0x400) {
1956       // mov $sreg
1957       if (sym->reg.data.sv.index == 3) {
1958          // TGSI backend may use 4th component of TID,NTID,CTAID,NCTAID
1959          i->op = OP_MOV;
1960          i->setSrc(0, bld.mkImm((sv == SV_NTID || sv == SV_NCTAID) ? 1 : 0));
1961       }
1962       if (sv == SV_VERTEX_COUNT) {
1963          bld.setPosition(i, true);
1964          bld.mkOp2(OP_EXTBF, TYPE_U32, i->getDef(0), i->getDef(0), bld.mkImm(0x808));
1965       }
1966       return true;
1967    }
1968
1969    switch (sv) {
1970    case SV_POSITION:
1971       assert(prog->getType() == Program::TYPE_FRAGMENT);
1972       if (i->srcExists(1)) {
1973          // Pass offset through to the interpolation logic
1974          ld = bld.mkInterp(NV50_IR_INTERP_LINEAR | NV50_IR_INTERP_OFFSET,
1975                            i->getDef(0), addr, NULL);
1976          ld->setSrc(1, i->getSrc(1));
1977       } else {
1978          bld.mkInterp(NV50_IR_INTERP_LINEAR, i->getDef(0), addr, NULL);
1979       }
1980       break;
1981    case SV_FACE:
1982    {
1983       Value *face = i->getDef(0);
1984       bld.mkInterp(NV50_IR_INTERP_FLAT, face, addr, NULL);
1985       if (i->dType == TYPE_F32) {
1986          bld.mkOp2(OP_OR, TYPE_U32, face, face, bld.mkImm(0x00000001));
1987          bld.mkOp1(OP_NEG, TYPE_S32, face, face);
1988          bld.mkCvt(OP_CVT, TYPE_F32, face, TYPE_S32, face);
1989       }
1990    }
1991       break;
1992    case SV_TESS_COORD:
1993       assert(prog->getType() == Program::TYPE_TESSELLATION_EVAL);
1994       readTessCoord(i->getDef(0)->asLValue(), i->getSrc(0)->reg.data.sv.index);
1995       break;
1996    case SV_NTID:
1997    case SV_NCTAID:
1998    case SV_GRIDID:
1999       assert(targ->getChipset() >= NVISA_GK104_CHIPSET); // mov $sreg otherwise
2000       if (sym->reg.data.sv.index == 3) {
2001          i->op = OP_MOV;
2002          i->setSrc(0, bld.mkImm(sv == SV_GRIDID ? 0 : 1));
2003          return true;
2004       }
2005       addr += prog->driver->prop.cp.gridInfoBase;
2006       bld.mkLoad(TYPE_U32, i->getDef(0),
2007                  bld.mkSymbol(FILE_MEMORY_CONST, prog->driver->io.auxCBSlot,
2008                               TYPE_U32, addr), NULL);
2009       break;
2010    case SV_SAMPLE_INDEX:
2011       // TODO: Properly pass source as an address in the PIX address space
2012       // (which can be of the form [r0+offset]). But this is currently
2013       // unnecessary.
2014       ld = bld.mkOp1(OP_PIXLD, TYPE_U32, i->getDef(0), bld.mkImm(0));
2015       ld->subOp = NV50_IR_SUBOP_PIXLD_SAMPLEID;
2016       break;
2017    case SV_SAMPLE_POS: {
2018       Value *off = new_LValue(func, FILE_GPR);
2019       ld = bld.mkOp1(OP_PIXLD, TYPE_U32, i->getDef(0), bld.mkImm(0));
2020       ld->subOp = NV50_IR_SUBOP_PIXLD_SAMPLEID;
2021       bld.mkOp2(OP_SHL, TYPE_U32, off, i->getDef(0), bld.mkImm(3));
2022       bld.mkLoad(TYPE_F32,
2023                  i->getDef(0),
2024                  bld.mkSymbol(
2025                        FILE_MEMORY_CONST, prog->driver->io.auxCBSlot,
2026                        TYPE_U32, prog->driver->io.sampleInfoBase +
2027                        4 * sym->reg.data.sv.index),
2028                  off);
2029       break;
2030    }
2031    case SV_SAMPLE_MASK:
2032       ld = bld.mkOp1(OP_PIXLD, TYPE_U32, i->getDef(0), bld.mkImm(0));
2033       ld->subOp = NV50_IR_SUBOP_PIXLD_COVMASK;
2034       break;
2035    case SV_BASEVERTEX:
2036    case SV_BASEINSTANCE:
2037    case SV_DRAWID:
2038       ld = bld.mkLoad(TYPE_U32, i->getDef(0),
2039                       bld.mkSymbol(FILE_MEMORY_CONST,
2040                                    prog->driver->io.auxCBSlot,
2041                                    TYPE_U32,
2042                                    prog->driver->io.drawInfoBase +
2043                                    4 * (sv - SV_BASEVERTEX)),
2044                       NULL);
2045       break;
2046    default:
2047       if (prog->getType() == Program::TYPE_TESSELLATION_EVAL && !i->perPatch)
2048          vtx = bld.mkOp1v(OP_PFETCH, TYPE_U32, bld.getSSA(), bld.mkImm(0));
2049       ld = bld.mkFetch(i->getDef(0), i->dType,
2050                        FILE_SHADER_INPUT, addr, i->getIndirect(0, 0), vtx);
2051       ld->perPatch = i->perPatch;
2052       break;
2053    }
2054    bld.getBB()->remove(i);
2055    return true;
2056 }
2057
2058 bool
2059 NVC0LoweringPass::handleDIV(Instruction *i)
2060 {
2061    if (!isFloatType(i->dType))
2062       return true;
2063    bld.setPosition(i, false);
2064    Instruction *rcp = bld.mkOp1(OP_RCP, i->dType, bld.getSSA(typeSizeof(i->dType)), i->getSrc(1));
2065    i->op = OP_MUL;
2066    i->setSrc(1, rcp->getDef(0));
2067    return true;
2068 }
2069
2070 bool
2071 NVC0LoweringPass::handleMOD(Instruction *i)
2072 {
2073    if (!isFloatType(i->dType))
2074       return true;
2075    LValue *value = bld.getScratch(typeSizeof(i->dType));
2076    bld.mkOp1(OP_RCP, i->dType, value, i->getSrc(1));
2077    bld.mkOp2(OP_MUL, i->dType, value, i->getSrc(0), value);
2078    bld.mkOp1(OP_TRUNC, i->dType, value, value);
2079    bld.mkOp2(OP_MUL, i->dType, value, i->getSrc(1), value);
2080    i->op = OP_SUB;
2081    i->setSrc(1, value);
2082    return true;
2083 }
2084
2085 bool
2086 NVC0LoweringPass::handleSQRT(Instruction *i)
2087 {
2088    if (i->dType == TYPE_F64) {
2089       Value *pred = bld.getSSA(1, FILE_PREDICATE);
2090       Value *zero = bld.loadImm(NULL, 0.0);
2091       Value *dst = bld.getSSA(8);
2092       bld.mkOp1(OP_RSQ, i->dType, dst, i->getSrc(0));
2093       bld.mkCmp(OP_SET, CC_LE, i->dType, pred, i->dType, i->getSrc(0), zero);
2094       bld.mkOp3(OP_SELP, TYPE_U64, dst, zero, dst, pred);
2095       i->op = OP_MUL;
2096       i->setSrc(1, dst);
2097       // TODO: Handle this properly with a library function
2098    } else {
2099       bld.setPosition(i, true);
2100       i->op = OP_RSQ;
2101       bld.mkOp1(OP_RCP, i->dType, i->getDef(0), i->getDef(0));
2102    }
2103
2104    return true;
2105 }
2106
2107 bool
2108 NVC0LoweringPass::handlePOW(Instruction *i)
2109 {
2110    LValue *val = bld.getScratch();
2111
2112    bld.mkOp1(OP_LG2, TYPE_F32, val, i->getSrc(0));
2113    bld.mkOp2(OP_MUL, TYPE_F32, val, i->getSrc(1), val)->dnz = 1;
2114    bld.mkOp1(OP_PREEX2, TYPE_F32, val, val);
2115
2116    i->op = OP_EX2;
2117    i->setSrc(0, val);
2118    i->setSrc(1, NULL);
2119
2120    return true;
2121 }
2122
2123 bool
2124 NVC0LoweringPass::handleEXPORT(Instruction *i)
2125 {
2126    if (prog->getType() == Program::TYPE_FRAGMENT) {
2127       int id = i->getSrc(0)->reg.data.offset / 4;
2128
2129       if (i->src(0).isIndirect(0)) // TODO, ugly
2130          return false;
2131       i->op = OP_MOV;
2132       i->subOp = NV50_IR_SUBOP_MOV_FINAL;
2133       i->src(0).set(i->src(1));
2134       i->setSrc(1, NULL);
2135       i->setDef(0, new_LValue(func, FILE_GPR));
2136       i->getDef(0)->reg.data.id = id;
2137
2138       prog->maxGPR = MAX2(prog->maxGPR, id);
2139    } else
2140    if (prog->getType() == Program::TYPE_GEOMETRY) {
2141       i->setIndirect(0, 1, gpEmitAddress);
2142    }
2143    return true;
2144 }
2145
2146 bool
2147 NVC0LoweringPass::handleOUT(Instruction *i)
2148 {
2149    Instruction *prev = i->prev;
2150    ImmediateValue stream, prevStream;
2151
2152    // Only merge if the stream ids match. Also, note that the previous
2153    // instruction would have already been lowered, so we take arg1 from it.
2154    if (i->op == OP_RESTART && prev && prev->op == OP_EMIT &&
2155        i->src(0).getImmediate(stream) &&
2156        prev->src(1).getImmediate(prevStream) &&
2157        stream.reg.data.u32 == prevStream.reg.data.u32) {
2158       i->prev->subOp = NV50_IR_SUBOP_EMIT_RESTART;
2159       delete_Instruction(prog, i);
2160    } else {
2161       assert(gpEmitAddress);
2162       i->setDef(0, gpEmitAddress);
2163       i->setSrc(1, i->getSrc(0));
2164       i->setSrc(0, gpEmitAddress);
2165    }
2166    return true;
2167 }
2168
2169 // Generate a binary predicate if an instruction is predicated by
2170 // e.g. an f32 value.
2171 void
2172 NVC0LoweringPass::checkPredicate(Instruction *insn)
2173 {
2174    Value *pred = insn->getPredicate();
2175    Value *pdst;
2176
2177    if (!pred || pred->reg.file == FILE_PREDICATE)
2178       return;
2179    pdst = new_LValue(func, FILE_PREDICATE);
2180
2181    // CAUTION: don't use pdst->getInsn, the definition might not be unique,
2182    //  delay turning PSET(FSET(x,y),0) into PSET(x,y) to a later pass
2183
2184    bld.mkCmp(OP_SET, CC_NEU, insn->dType, pdst, insn->dType, bld.mkImm(0), pred);
2185
2186    insn->setPredicate(insn->cc, pdst);
2187 }
2188
2189 //
2190 // - add quadop dance for texturing
2191 // - put FP outputs in GPRs
2192 // - convert instruction sequences
2193 //
2194 bool
2195 NVC0LoweringPass::visit(Instruction *i)
2196 {
2197    bool ret = true;
2198    bld.setPosition(i, false);
2199
2200    if (i->cc != CC_ALWAYS)
2201       checkPredicate(i);
2202
2203    switch (i->op) {
2204    case OP_TEX:
2205    case OP_TXB:
2206    case OP_TXL:
2207    case OP_TXF:
2208    case OP_TXG:
2209       return handleTEX(i->asTex());
2210    case OP_TXD:
2211       return handleTXD(i->asTex());
2212    case OP_TXLQ:
2213       return handleTXLQ(i->asTex());
2214    case OP_TXQ:
2215      return handleTXQ(i->asTex());
2216    case OP_EX2:
2217       bld.mkOp1(OP_PREEX2, TYPE_F32, i->getDef(0), i->getSrc(0));
2218       i->setSrc(0, i->getDef(0));
2219       break;
2220    case OP_POW:
2221       return handlePOW(i);
2222    case OP_DIV:
2223       return handleDIV(i);
2224    case OP_MOD:
2225       return handleMOD(i);
2226    case OP_SQRT:
2227       return handleSQRT(i);
2228    case OP_EXPORT:
2229       ret = handleEXPORT(i);
2230       break;
2231    case OP_EMIT:
2232    case OP_RESTART:
2233       return handleOUT(i);
2234    case OP_RDSV:
2235       return handleRDSV(i);
2236    case OP_WRSV:
2237       return handleWRSV(i);
2238    case OP_STORE:
2239    case OP_LOAD:
2240       handleLDST(i);
2241       break;
2242    case OP_ATOM:
2243    {
2244       const bool cctl = i->src(0).getFile() == FILE_MEMORY_GLOBAL;
2245       handleATOM(i);
2246       handleCasExch(i, cctl);
2247    }
2248       break;
2249    case OP_SULDB:
2250    case OP_SULDP:
2251    case OP_SUSTB:
2252    case OP_SUSTP:
2253    case OP_SUREDB:
2254    case OP_SUREDP:
2255       if (targ->getChipset() >= NVISA_GK104_CHIPSET)
2256          handleSurfaceOpNVE4(i->asTex());
2257       break;
2258    case OP_SUQ:
2259       handleSUQ(i);
2260       break;
2261    default:
2262       break;
2263    }
2264
2265    /* Kepler+ has a special opcode to compute a new base address to be used
2266     * for indirect loads.
2267     */
2268    if (targ->getChipset() >= NVISA_GK104_CHIPSET && !i->perPatch &&
2269        (i->op == OP_VFETCH || i->op == OP_EXPORT) && i->src(0).isIndirect(0)) {
2270       Instruction *afetch = bld.mkOp1(OP_AFETCH, TYPE_U32, bld.getSSA(),
2271                                       cloneShallow(func, i->getSrc(0)));
2272       afetch->setIndirect(0, 0, i->getIndirect(0, 0));
2273       i->src(0).get()->reg.data.offset = 0;
2274       i->setIndirect(0, 0, afetch->getDef(0));
2275    }
2276
2277    return ret;
2278 }
2279
2280 bool
2281 TargetNVC0::runLegalizePass(Program *prog, CGStage stage) const
2282 {
2283    if (stage == CG_STAGE_PRE_SSA) {
2284       NVC0LoweringPass pass(prog);
2285       return pass.run(prog, false, true);
2286    } else
2287    if (stage == CG_STAGE_POST_RA) {
2288       NVC0LegalizePostRA pass(prog);
2289       return pass.run(prog, false, true);
2290    } else
2291    if (stage == CG_STAGE_SSA) {
2292       NVC0LegalizeSSA pass;
2293       return pass.run(prog, false, true);
2294    }
2295    return false;
2296 }
2297
2298 } // namespace nv50_ir