nv50/ir/gk110: use shl/shr instead of lshf/rshf so that c[] is supported
[mesa.git] / src / gallium / drivers / nouveau / codegen / nv50_ir_emit_gk110.cpp
index 29e246d1571b527cfdb94671a9be371fe38e57c6..07d7e1929fe15ae2cfa2dc7617c858980bac68c4 100644 (file)
@@ -534,7 +534,10 @@ CodeEmitterGK110::emitFADD(const Instruction *i)
       assert(i->rnd == ROUND_N);
       assert(!i->saturate);
 
-      emitForm_L(i, 0x400, 0, i->src(1).mod);
+      Modifier mod = i->src(1).mod ^
+         Modifier(i->op == OP_SUB ? NV50_IR_MOD_NEG : 0);
+
+      emitForm_L(i, 0x400, 0, mod);
 
       FTZ_(3a);
       NEG_(3b, 0);
@@ -549,9 +552,11 @@ CodeEmitterGK110::emitFADD(const Instruction *i)
 
       if (code[0] & 0x1) {
          modNegAbsF32_3b(i, 1);
+         if (i->op == OP_SUB) code[1] ^= 1 << 27;
       } else {
          ABS_(34, 1);
          NEG_(30, 1);
+         if (i->op == OP_SUB) code[1] ^= 1 << 16;
       }
    }
 }
@@ -690,33 +695,22 @@ CodeEmitterGK110::emitINSBF(const Instruction *i)
 void
 CodeEmitterGK110::emitShift(const Instruction *i)
 {
-   const bool sar = i->op == OP_SHR && isSignedType(i->sType);
-
-   if (sar) {
-      emitForm_21(i, 0x214, 0x014);
-      code[1] |= 1 << 19;
-   } else
    if (i->op == OP_SHR) {
-      // this is actually RSHF
-      emitForm_21(i, 0x27c, 0x87c);
-      code[1] |= GK110_GPR_ZERO << 10;
+      emitForm_21(i, 0x214, 0xc14);
+      if (isSignedType(i->dType))
+         code[1] |= 1 << 19;
    } else {
-      // this is actually LSHF
-      emitForm_21(i, 0x1fc, 0xb7c);
-      code[1] |= GK110_GPR_ZERO << 10;
+      emitForm_21(i, 0x224, 0xc24);
    }
 
-   if (i->subOp == NV50_IR_SUBOP_SHIFT_WRAP) {
-      if (!sar)
-         code[1] |= 1 << 21;
-      // XXX: find wrap modifier for SHR S32
-   }
+   if (i->subOp == NV50_IR_SUBOP_SHIFT_WRAP)
+      code[1] |= 1 << 10;
 }
 
 void
 CodeEmitterGK110::emitPreOp(const Instruction *i)
 {
-   emitForm_21(i, 0x248, -1);
+   emitForm_C(i, 0x248, 0x2);
 
    if (i->op == OP_PREEX2)
       code[1] |= 1 << 10;
@@ -949,7 +943,17 @@ void CodeEmitterGK110::emitTEXBAR(const Instruction *i)
 
 void CodeEmitterGK110::emitTEXCSAA(const TexInstruction *i)
 {
-   emitNOP(i); // TODO
+   code[0] = 0x00000002;
+   code[1] = 0x76c00000;
+
+   code[1] |= i->tex.r << 9;
+   // code[1] |= i->tex.s << (9 + 8);
+
+   if (i->tex.liveOnly)
+      code[0] |= 0x80000000;
+
+   defId(i->def(0), 2);
+   srcId(i->src(0), 10);
 }
 
 static inline bool
@@ -973,6 +977,9 @@ CodeEmitterGK110::emitTEX(const TexInstruction *i)
       case OP_TXD:
          code[1] = 0x7e000000;
          break;
+      case OP_TXF:
+         code[1] = 0x78000000;
+         break;
       default:
          code[1] = 0x7d800000;
          break;
@@ -982,42 +989,48 @@ CodeEmitterGK110::emitTEX(const TexInstruction *i)
       case OP_TXD:
          code[0] = 0x00000002;
          code[1] = 0x76000000;
+         code[1] |= i->tex.r << 9;
+         break;
+      case OP_TXF:
+         code[0] = 0x00000002;
+         code[1] = 0x70000000;
+         code[1] |= i->tex.r << 13;
          break;
       default:
          code[0] = 0x00000001;
          code[1] = 0x60000000;
+         code[1] |= i->tex.r << 15;
          break;
       }
-      code[1] |= i->tex.r << 15;
    }
 
    code[1] |= isNextIndependentTex(i) ? 0x1 : 0x2; // t : p mode
 
-   // if (i->tex.liveOnly)
-   //    ?
+   if (i->tex.liveOnly)
+      code[0] |= 0x80000000;
 
    switch (i->op) {
    case OP_TEX: break;
    case OP_TXB: code[1] |= 0x2000; break;
    case OP_TXL: code[1] |= 0x3000; break;
-   case OP_TXF: break; // XXX
+   case OP_TXF: break;
    case OP_TXG: break; // XXX
    case OP_TXD: break;
    default:
       assert(!"invalid texture op");
       break;
    }
-   /*
+
    if (i->op == OP_TXF) {
       if (!i->tex.levelZero)
-         code[1] |= 0x02000000;
-   } else */
+         code[1] |= 0x1000;
+   } else
    if (i->tex.levelZero) {
       code[1] |= 0x1000;
    }
 
-   // if (i->op != OP_TXD && i->tex.derivAll)
-   //   code[1] |= 1 << 13;
+   if (i->op != OP_TXD && i->tex.derivAll)
+      code[1] |= 0x200;
 
    emitPredicate(i);
 
@@ -1035,30 +1048,67 @@ CodeEmitterGK110::emitTEX(const TexInstruction *i)
    code[1] |= (i->tex.target.isCube() ? 3 : (i->tex.target.getDim() - 1)) << 7;
    if (i->tex.target.isArray())
       code[1] |= 0x40;
-   // if (i->tex.target.isShadow())
-   //   ?
-   // if (i->tex.target == TEX_TARGET_2D_MS ||
-   //     i->tex.target == TEX_TARGET_2D_MS_ARRAY)
-   //   ?
+   if (i->tex.target.isShadow())
+      code[1] |= 0x400;
+   if (i->tex.target == TEX_TARGET_2D_MS ||
+       i->tex.target == TEX_TARGET_2D_MS_ARRAY)
+      code[1] |= 0x800;
 
    if (i->srcExists(src1) && i->src(src1).getFile() == FILE_IMMEDIATE) {
       // ?
    }
 
-   // if (i->tex.useOffsets)
-   //   ?
+   if (i->tex.useOffsets) {
+      switch (i->op) {
+      case OP_TXF: code[1] |= 0x200; break;
+      default: code[1] |= 0x800; break;
+      }
+   }
 }
 
 void
 CodeEmitterGK110::emitTXQ(const TexInstruction *i)
 {
-   emitNOP(i); // TODO
+   code[0] = 0x00000002;
+   code[1] = 0x75400001;
+
+   switch (i->tex.query) {
+   case TXQ_DIMS:            code[0] |= 0x01 << 25; break;
+   case TXQ_TYPE:            code[0] |= 0x02 << 25; break;
+   case TXQ_SAMPLE_POSITION: code[0] |= 0x05 << 25; break;
+   case TXQ_FILTER:          code[0] |= 0x10 << 25; break;
+   case TXQ_LOD:             code[0] |= 0x12 << 25; break;
+   case TXQ_BORDER_COLOUR:   code[0] |= 0x16 << 25; break;
+   default:
+      assert(!"invalid texture query");
+      break;
+   }
+
+   code[1] |= i->tex.mask << 2;
+   code[1] |= i->tex.r << 9;
+   if (/*i->tex.sIndirectSrc >= 0 || */i->tex.rIndirectSrc >= 0)
+      code[1] |= 0x08000000;
+
+   defId(i->def(0), 2);
+   srcId(i->src(0), 10);
+
+   emitPredicate(i);
 }
 
 void
 CodeEmitterGK110::emitQUADOP(const Instruction *i, uint8_t qOp, uint8_t laneMask)
 {
-   emitNOP(i); // TODO
+   code[0] = 0x00000002 | ((qOp & 1) << 31);
+   code[1] = 0x7fc00000 | (qOp >> 1) | (laneMask << 12);
+
+   defId(i->def(0), 2);
+   srcId(i->src(0), 10);
+   srcId(i->srcExists(1) ? i->src(1) : i->src(0), 23);
+
+   if (i->op == OP_QUADOP && progType != Program::TYPE_FRAGMENT)
+      code[1] |= 1 << 9; // dall
+
+   emitPredicate(i);
 }
 
 void
@@ -1142,16 +1192,26 @@ CodeEmitterGK110::emitFlow(const Instruction *i)
 void
 CodeEmitterGK110::emitPFETCH(const Instruction *i)
 {
-   emitNOP(i); // TODO
+   uint32_t prim = i->src(0).get()->reg.data.u32;
+
+   code[0] = 0x00000002 | ((prim & 0xff) << 23);
+   code[1] = 0x7f800000;
+
+   emitPredicate(i);
+
+   defId(i->def(0), 2);
+   srcId(i->src(1), 10);
 }
 
 void
 CodeEmitterGK110::emitVFETCH(const Instruction *i)
 {
+   unsigned int size = typeSizeof(i->dType);
    uint32_t offset = i->src(0).get()->reg.data.offset;
 
    code[0] = 0x00000002 | (offset << 23);
    code[1] = 0x7ec00000 | (offset >> 9);
+   code[1] |= (size / 4 - 1) << 18;
 
 #if 0
    if (i->perPatch)
@@ -1170,10 +1230,12 @@ CodeEmitterGK110::emitVFETCH(const Instruction *i)
 void
 CodeEmitterGK110::emitEXPORT(const Instruction *i)
 {
+   unsigned int size = typeSizeof(i->dType);
    uint32_t offset = i->src(0).get()->reg.data.offset;
 
    code[0] = 0x00000002 | (offset << 23);
    code[1] = 0x7f000000 | (offset >> 9);
+   code[1] |= (size / 4 - 1) << 18;
 
 #if 0
    if (i->perPatch)
@@ -1192,7 +1254,14 @@ CodeEmitterGK110::emitEXPORT(const Instruction *i)
 void
 CodeEmitterGK110::emitOUT(const Instruction *i)
 {
-   emitNOP(i); // TODO
+   assert(i->src(0).getFile() == FILE_GPR);
+
+   emitForm_21(i, 0x1f0, 0xb70);
+
+   if (i->op == OP_EMIT)
+      code[1] |= 1 << 10;
+   if (i->op == OP_RESTART || i->subOp == NV50_IR_SUBOP_EMIT_RESTART)
+      code[1] |= 1 << 11;
 }
 
 void
@@ -1411,7 +1480,11 @@ CodeEmitterGK110::emitMOV(const Instruction *i)
       setImmediate32(i, 0, Modifier(0));
    } else
    if (i->src(0).getFile() == FILE_PREDICATE) {
-      // TODO
+      code[0] = 0x00000002;
+      code[1] = 0x84401c07;
+      emitPredicate(i);
+      defId(i->def(0), 2);
+      srcId(i->src(0), 14);
    } else {
       emitForm_C(i, 0x24c, 2);
       code[1] |= i->lanes << 10;
@@ -1449,7 +1522,7 @@ CodeEmitterGK110::emitInstruction(Instruction *insn)
       case 1: data[0] |= insn->sched << 10; break;
       case 2: data[0] |= insn->sched << 18; break;
       case 3: data[0] |= insn->sched << 26; data[1] |= insn->sched >> 6; break;
-      case 4: data[1] |= insn->sched << 2;
+      case 4: data[1] |= insn->sched << 2; break;
       case 5: data[1] |= insn->sched << 10; break;
       case 6: data[1] |= insn->sched << 18; break;
       default: