+void
+CodeEmitterGK110::emitSHFL(const Instruction *i)
+{
+ const ImmediateValue *imm;
+
+ code[0] = 0x00000002;
+ code[1] = 0x78800000 | (i->subOp << 1);
+
+ emitPredicate(i);
+
+ defId(i->def(0), 2);
+ srcId(i->src(0), 10);
+
+ switch (i->src(1).getFile()) {
+ case FILE_GPR:
+ srcId(i->src(1), 23);
+ break;
+ case FILE_IMMEDIATE:
+ imm = i->getSrc(1)->asImm();
+ assert(imm && imm->reg.data.u32 < 0x20);
+ code[0] |= imm->reg.data.u32 << 23;
+ code[0] |= 1 << 31;
+ break;
+ default:
+ assert(!"invalid src1 file");
+ break;
+ }
+
+ switch (i->src(2).getFile()) {
+ case FILE_GPR:
+ srcId(i->src(2), 42);
+ break;
+ case FILE_IMMEDIATE:
+ imm = i->getSrc(2)->asImm();
+ assert(imm && imm->reg.data.u32 < 0x2000);
+ code[1] |= imm->reg.data.u32 << 5;
+ code[1] |= 1;
+ break;
+ default:
+ assert(!"invalid src2 file");
+ break;
+ }
+
+ if (!i->defExists(1))
+ code[1] |= 7 << 19;
+ else {
+ assert(i->def(1).getFile() == FILE_PREDICATE);
+ defId(i->def(1), 51);
+ }
+}
+
+void
+CodeEmitterGK110::emitVOTE(const Instruction *i)
+{
+ const ImmediateValue *imm;
+ uint32_t u32;
+
+ code[0] = 0x00000002;
+ code[1] = 0x86c00000 | (i->subOp << 19);
+
+ emitPredicate(i);
+
+ unsigned rp = 0;
+ for (int d = 0; i->defExists(d); d++) {
+ if (i->def(d).getFile() == FILE_PREDICATE) {
+ assert(!(rp & 2));
+ rp |= 2;
+ defId(i->def(d), 48);
+ } else if (i->def(d).getFile() == FILE_GPR) {
+ assert(!(rp & 1));
+ rp |= 1;
+ defId(i->def(d), 2);
+ } else {
+ assert(!"Unhandled def");
+ }
+ }
+ if (!(rp & 1))
+ code[0] |= 255 << 2;
+ if (!(rp & 2))
+ code[1] |= 7 << 16;
+
+ switch (i->src(0).getFile()) {
+ case FILE_PREDICATE:
+ if (i->src(0).mod == Modifier(NV50_IR_MOD_NOT))
+ code[0] |= 1 << 13;
+ srcId(i->src(0), 42);
+ break;
+ case FILE_IMMEDIATE:
+ imm = i->getSrc(0)->asImm();
+ assert(imm);
+ u32 = imm->reg.data.u32;
+ assert(u32 == 0 || u32 == 1);
+ code[1] |= (u32 == 1 ? 0x7 : 0xf) << 10;
+ break;
+ default:
+ assert(!"Unhandled src");
+ break;
+ }
+}
+
+void
+CodeEmitterGK110::emitSUGType(DataType ty, const int pos)
+{
+ uint8_t n = 0;
+
+ switch (ty) {
+ case TYPE_S32: n = 1; break;
+ case TYPE_U8: n = 2; break;
+ case TYPE_S8: n = 3; break;
+ default:
+ assert(ty == TYPE_U32);
+ break;
+ }
+ code[pos / 32] |= n << (pos % 32);
+}
+
+void
+CodeEmitterGK110::emitSUCachingMode(CacheMode c)
+{
+ uint8_t n = 0;
+
+ switch (c) {
+ case CACHE_CA:
+// case CACHE_WB:
+ n = 0;
+ break;
+ case CACHE_CG:
+ n = 1;
+ break;
+ case CACHE_CS:
+ n = 2;
+ break;
+ case CACHE_CV:
+// case CACHE_WT:
+ n = 3;
+ break;
+ default:
+ assert(!"invalid caching mode");
+ break;
+ }
+ code[0] |= (n & 1) << 31;
+ code[1] |= (n & 2) >> 1;
+}
+
+void
+CodeEmitterGK110::setSUConst16(const Instruction *i, const int s)
+{
+ const uint32_t offset = i->getSrc(s)->reg.data.offset;
+
+ assert(offset == (offset & 0xfffc));
+
+ code[0] |= offset << 21;
+ code[1] |= offset >> 11;
+ code[1] |= i->getSrc(s)->reg.fileIndex << 5;
+}
+
+void
+CodeEmitterGK110::emitSULDGB(const TexInstruction *i)
+{
+ code[0] = 0x00000002;
+ code[1] = 0x30000000 | (i->subOp << 14);
+
+ if (i->src(1).getFile() == FILE_MEMORY_CONST) {
+ emitLoadStoreType(i->dType, 0x38);
+ emitCachingMode(i->cache, 0x36);
+
+ // format
+ setSUConst16(i, 1);
+ } else {
+ assert(i->src(1).getFile() == FILE_GPR);
+ code[1] |= 0x49800000;
+
+ emitLoadStoreType(i->dType, 0x21);
+ emitSUCachingMode(i->cache);
+
+ srcId(i->src(1), 23);
+ }
+
+ emitSUGType(i->sType, 0x34);
+
+ emitPredicate(i);
+ defId(i->def(0), 2); // destination
+ srcId(i->src(0), 10); // address
+
+ // surface predicate
+ if (!i->srcExists(2) || (i->predSrc == 2)) {
+ code[1] |= 0x7 << 10;
+ } else {
+ if (i->src(2).mod == Modifier(NV50_IR_MOD_NOT))
+ code[1] |= 1 << 13;
+ srcId(i->src(2), 32 + 10);
+ }
+}
+
+void
+CodeEmitterGK110::emitSUSTGx(const TexInstruction *i)
+{
+ assert(i->op == OP_SUSTP);
+
+ code[0] = 0x00000002;
+ code[1] = 0x38000000;
+
+ if (i->src(1).getFile() == FILE_MEMORY_CONST) {
+ code[0] |= i->subOp << 2;
+
+ if (i->op == OP_SUSTP)
+ code[0] |= i->tex.mask << 4;
+
+ emitSUGType(i->sType, 0x8);
+ emitCachingMode(i->cache, 0x36);
+
+ // format
+ setSUConst16(i, 1);
+ } else {
+ assert(i->src(1).getFile() == FILE_GPR);
+
+ code[0] |= i->subOp << 23;
+ code[1] |= 0x41c00000;
+
+ if (i->op == OP_SUSTP)
+ code[0] |= i->tex.mask << 25;
+
+ emitSUGType(i->sType, 0x1d);
+ emitSUCachingMode(i->cache);
+
+ srcId(i->src(1), 2);
+ }
+
+ emitPredicate(i);
+ srcId(i->src(0), 10); // address
+ srcId(i->src(3), 42); // values
+
+ // surface predicate
+ if (!i->srcExists(2) || (i->predSrc == 2)) {
+ code[1] |= 0x7 << 18;
+ } else {
+ if (i->src(2).mod == Modifier(NV50_IR_MOD_NOT))
+ code[1] |= 1 << 21;
+ srcId(i->src(2), 32 + 18);
+ }
+}
+
+void
+CodeEmitterGK110::emitSUCLAMPMode(uint16_t subOp)
+{
+ uint8_t m;
+ switch (subOp & ~NV50_IR_SUBOP_SUCLAMP_2D) {
+ case NV50_IR_SUBOP_SUCLAMP_SD(0, 1): m = 0; break;
+ case NV50_IR_SUBOP_SUCLAMP_SD(1, 1): m = 1; break;
+ case NV50_IR_SUBOP_SUCLAMP_SD(2, 1): m = 2; break;
+ case NV50_IR_SUBOP_SUCLAMP_SD(3, 1): m = 3; break;
+ case NV50_IR_SUBOP_SUCLAMP_SD(4, 1): m = 4; break;
+ case NV50_IR_SUBOP_SUCLAMP_PL(0, 1): m = 5; break;
+ case NV50_IR_SUBOP_SUCLAMP_PL(1, 1): m = 6; break;
+ case NV50_IR_SUBOP_SUCLAMP_PL(2, 1): m = 7; break;
+ case NV50_IR_SUBOP_SUCLAMP_PL(3, 1): m = 8; break;
+ case NV50_IR_SUBOP_SUCLAMP_PL(4, 1): m = 9; break;
+ case NV50_IR_SUBOP_SUCLAMP_BL(0, 1): m = 10; break;
+ case NV50_IR_SUBOP_SUCLAMP_BL(1, 1): m = 11; break;
+ case NV50_IR_SUBOP_SUCLAMP_BL(2, 1): m = 12; break;
+ case NV50_IR_SUBOP_SUCLAMP_BL(3, 1): m = 13; break;
+ case NV50_IR_SUBOP_SUCLAMP_BL(4, 1): m = 14; break;
+ default:
+ return;
+ }
+ code[1] |= m << 20;
+ if (subOp & NV50_IR_SUBOP_SUCLAMP_2D)
+ code[1] |= 1 << 24;
+}
+
+void
+CodeEmitterGK110::emitSUCalc(Instruction *i)
+{
+ ImmediateValue *imm = NULL;
+ uint64_t opc1, opc2;
+
+ if (i->srcExists(2)) {
+ imm = i->getSrc(2)->asImm();
+ if (imm)
+ i->setSrc(2, NULL); // special case, make emitForm_21 not assert
+ }
+
+ switch (i->op) {
+ case OP_SUCLAMP: opc1 = 0xb00; opc2 = 0x580; break;
+ case OP_SUBFM: opc1 = 0xb68; opc2 = 0x1e8; break;
+ case OP_SUEAU: opc1 = 0xb6c; opc2 = 0x1ec; break;
+ default:
+ assert(0);
+ return;
+ }
+ emitForm_21(i, opc2, opc1);
+
+ if (i->op == OP_SUCLAMP) {
+ if (i->dType == TYPE_S32)
+ code[1] |= 1 << 19;
+ emitSUCLAMPMode(i->subOp);
+ }
+
+ if (i->op == OP_SUBFM && i->subOp == NV50_IR_SUBOP_SUBFM_3D)
+ code[1] |= 1 << 18;
+
+ if (i->op != OP_SUEAU) {
+ const uint8_t pos = i->op == OP_SUBFM ? 19 : 16;
+ if (i->def(0).getFile() == FILE_PREDICATE) { // p, #
+ code[0] |= 255 << 2;
+ code[1] |= i->getDef(1)->reg.data.id << pos;
+ } else
+ if (i->defExists(1)) { // r, p
+ assert(i->def(1).getFile() == FILE_PREDICATE);
+ code[1] |= i->getDef(1)->reg.data.id << pos;
+ } else { // r, #
+ code[1] |= 7 << pos;
+ }
+ }
+
+ if (imm) {
+ assert(i->op == OP_SUCLAMP);
+ i->setSrc(2, imm);
+ code[1] |= (imm->reg.data.u32 & 0x3f) << 10; // sint6
+ }
+}
+
+
+void
+CodeEmitterGK110::emitVectorSubOp(const Instruction *i)
+{
+ switch (NV50_IR_SUBOP_Vn(i->subOp)) {
+ case 0:
+ code[1] |= (i->subOp & 0x000f) << 7; // vsrc1
+ code[1] |= (i->subOp & 0x00e0) >> 6; // vsrc2
+ code[1] |= (i->subOp & 0x0100) << 13; // vsrc2
+ code[1] |= (i->subOp & 0x3c00) << 12; // vdst
+ break;
+ default:
+ assert(0);
+ break;
+ }
+}
+
+void
+CodeEmitterGK110::emitVSHL(const Instruction *i)
+{
+ code[0] = 0x00000002;
+ code[1] = 0xb8000000;
+
+ assert(NV50_IR_SUBOP_Vn(i->subOp) == 0);
+
+ if (isSignedType(i->dType)) code[1] |= 1 << 25;
+ if (isSignedType(i->sType)) code[1] |= 1 << 19;
+
+ emitVectorSubOp(i);
+
+ emitPredicate(i);
+ defId(i->def(0), 2);
+ srcId(i->src(0), 10);
+
+ if (i->getSrc(1)->reg.file == FILE_IMMEDIATE) {
+ ImmediateValue *imm = i->getSrc(1)->asImm();
+ assert(imm);
+ code[0] |= (imm->reg.data.u32 & 0x01ff) << 23;
+ code[1] |= (imm->reg.data.u32 & 0xfe00) >> 9;
+ } else {
+ assert(i->getSrc(1)->reg.file == FILE_GPR);
+ code[1] |= 1 << 21;
+ srcId(i->src(1), 23);
+ }
+ srcId(i->src(2), 42);
+
+ if (i->saturate)
+ code[0] |= 1 << 22;
+ if (i->flagsDef >= 0)
+ code[1] |= 1 << 18;
+}
+
+void
+CodeEmitterGK110::emitAFETCH(const Instruction *i)
+{
+ uint32_t offset = i->src(0).get()->reg.data.offset & 0x7ff;
+
+ code[0] = 0x00000002 | (offset << 23);
+ code[1] = 0x7d000000 | (offset >> 9);
+
+ if (i->getSrc(0)->reg.file == FILE_SHADER_OUTPUT)
+ code[1] |= 0x8;
+
+ emitPredicate(i);
+
+ defId(i->def(0), 2);
+ srcId(i->src(0).getIndirect(0), 10);
+}
+