/* * Copyright 2014 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Ben Skeggs */ #include "codegen/nv50_ir_target_gm107.h" namespace nv50_ir { class CodeEmitterGM107 : public CodeEmitter { public: CodeEmitterGM107(const TargetGM107 *); virtual bool emitInstruction(Instruction *); virtual uint32_t getMinEncodingSize(const Instruction *) const; virtual void prepareEmission(Program *); virtual void prepareEmission(Function *); inline void setProgramType(Program::Type pType) { progType = pType; } private: const TargetGM107 *targGM107; Program::Type progType; const Instruction *insn; const bool writeIssueDelays; uint32_t *data; private: inline void emitField(uint32_t *, int, int, uint32_t); inline void emitField(int b, int s, uint32_t v) { emitField(code, b, s, v); } inline void emitInsn(uint32_t, bool); inline void emitInsn(uint32_t o) { emitInsn(o, true); } inline void emitPred(); inline void emitGPR(int, const Value *); inline void emitGPR(int pos) { emitGPR(pos, (const Value *)NULL); } inline void emitGPR(int pos, const ValueRef &ref) { emitGPR(pos, ref.get() ? ref.rep() : (const Value *)NULL); } inline void emitGPR(int pos, const ValueRef *ref) { emitGPR(pos, ref ? ref->rep() : (const Value *)NULL); } inline void emitGPR(int pos, const ValueDef &def) { emitGPR(pos, def.get() ? def.rep() : (const Value *)NULL); } inline void emitSYS(int, const Value *); inline void emitSYS(int pos, const ValueRef &ref) { emitSYS(pos, ref.get() ? ref.rep() : (const Value *)NULL); } inline void emitPRED(int, const Value *); inline void emitPRED(int pos) { emitPRED(pos, (const Value *)NULL); } inline void emitPRED(int pos, const ValueRef &ref) { emitPRED(pos, ref.get() ? ref.rep() : (const Value *)NULL); } inline void emitPRED(int pos, const ValueDef &def) { emitPRED(pos, def.get() ? def.rep() : (const Value *)NULL); } inline void emitADDR(int, int, int, int, const ValueRef &); inline void emitCBUF(int, int, int, int, int, const ValueRef &); inline bool longIMMD(const ValueRef &); inline void emitIMMD(int, int, const ValueRef &); void emitCond3(int, CondCode); void emitCond4(int, CondCode); void emitCond5(int pos, CondCode cc) { emitCond4(pos, cc); } inline void emitO(int); inline void emitP(int); inline void emitSAT(int); inline void emitCC(int); inline void emitX(int); inline void emitABS(int, const ValueRef &); inline void emitNEG(int, const ValueRef &); inline void emitNEG2(int, const ValueRef &, const ValueRef &); inline void emitFMZ(int, int); inline void emitRND(int, RoundMode, int); inline void emitRND(int pos) { emitRND(pos, insn->rnd, -1); } inline void emitPDIV(int); inline void emitINV(int, const ValueRef &); void emitEXIT(); void emitBRA(); void emitCAL(); void emitPCNT(); void emitCONT(); void emitPBK(); void emitBRK(); void emitPRET(); void emitRET(); void emitSSY(); void emitSYNC(); void emitSAM(); void emitRAM(); void emitMOV(); void emitS2R(); void emitF2F(); void emitF2I(); void emitI2F(); void emitI2I(); void emitSEL(); void emitSHFL(); void emitDADD(); void emitDMUL(); void emitDFMA(); void emitDMNMX(); void emitDSET(); void emitDSETP(); void emitFADD(); void emitFMUL(); void emitFFMA(); void emitMUFU(); void emitFMNMX(); void emitRRO(); void emitFCMP(); void emitFSET(); void emitFSETP(); void emitFSWZADD(); void emitLOP(); void emitNOT(); void emitIADD(); void emitIMUL(); void emitIMAD(); void emitIMNMX(); void emitICMP(); void emitISET(); void emitISETP(); void emitSHL(); void emitSHR(); void emitPOPC(); void emitBFI(); void emitBFE(); void emitFLO(); void emitLDSTs(int, DataType); void emitLDSTc(int); void emitLDC(); void emitLDL(); void emitLDS(); void emitLD(); void emitSTL(); void emitSTS(); void emitST(); void emitALD(); void emitAST(); void emitISBERD(); void emitAL2P(); void emitIPA(); void emitATOM(); void emitATOMS(); void emitCCTL(); void emitPIXLD(); void emitTEXs(int); void emitTEX(); void emitTLD(); void emitTLD4(); void emitTXD(); void emitTXQ(); void emitTMML(); void emitDEPBAR(); void emitNOP(); void emitKIL(); void emitOUT(); void emitBAR(); void emitMEMBAR(); void emitVOTE(); void emitSUTarget(); void emitSUHandle(const int s); void emitSUSTx(); void emitSULDx(); void emitSUREDx(); }; /******************************************************************************* * general instruction layout/fields ******************************************************************************/ void CodeEmitterGM107::emitField(uint32_t *data, int b, int s, uint32_t v) { if (b >= 0) { uint32_t m = ((1ULL << s) - 1); uint64_t d = (uint64_t)(v & m) << b; assert(!(v & ~m) || (v & ~m) == ~m); data[1] |= d >> 32; data[0] |= d; } } void CodeEmitterGM107::emitPred() { if (insn->predSrc >= 0) { emitField(16, 3, insn->getSrc(insn->predSrc)->rep()->reg.data.id); emitField(19, 1, insn->cc == CC_NOT_P); } else { emitField(16, 3, 7); } } void CodeEmitterGM107::emitInsn(uint32_t hi, bool pred) { code[0] = 0x00000000; code[1] = hi; if (pred) emitPred(); } void CodeEmitterGM107::emitGPR(int pos, const Value *val) { emitField(pos, 8, val ? val->reg.data.id : 255); } void CodeEmitterGM107::emitSYS(int pos, const Value *val) { int id = val ? val->reg.data.id : -1; switch (id) { case SV_LANEID : id = 0x00; break; case SV_VERTEX_COUNT : id = 0x10; break; case SV_INVOCATION_ID : id = 0x11; break; case SV_THREAD_KILL : id = 0x13; break; case SV_INVOCATION_INFO: id = 0x1d; break; case SV_TID : id = 0x21 + val->reg.data.sv.index; break; case SV_CTAID : id = 0x25 + val->reg.data.sv.index; break; default: assert(!"invalid system value"); id = 0; break; } emitField(pos, 8, id); } void CodeEmitterGM107::emitPRED(int pos, const Value *val) { emitField(pos, 3, val ? val->reg.data.id : 7); } void CodeEmitterGM107::emitADDR(int gpr, int off, int len, int shr, const ValueRef &ref) { const Value *v = ref.get(); assert(!(v->reg.data.offset & ((1 << shr) - 1))); if (gpr >= 0) emitGPR(gpr, ref.getIndirect(0)); emitField(off, len, v->reg.data.offset >> shr); } void CodeEmitterGM107::emitCBUF(int buf, int gpr, int off, int len, int shr, const ValueRef &ref) { const Value *v = ref.get(); const Symbol *s = v->asSym(); assert(!(s->reg.data.offset & ((1 << shr) - 1))); emitField(buf, 5, v->reg.fileIndex); if (gpr >= 0) emitGPR(gpr, ref.getIndirect(0)); emitField(off, 16, s->reg.data.offset >> shr); } bool CodeEmitterGM107::longIMMD(const ValueRef &ref) { if (ref.getFile() == FILE_IMMEDIATE) { const ImmediateValue *imm = ref.get()->asImm(); if (isFloatType(insn->sType)) { if ((imm->reg.data.u32 & 0x00000fff) != 0x00000000) return true; } else { if ((imm->reg.data.u32 & 0xfff00000) != 0x00000000 && (imm->reg.data.u32 & 0xfff00000) != 0xfff00000) return true; } } return false; } void CodeEmitterGM107::emitIMMD(int pos, int len, const ValueRef &ref) { const ImmediateValue *imm = ref.get()->asImm(); uint32_t val = imm->reg.data.u32; if (len == 19) { if (insn->sType == TYPE_F32 || insn->sType == TYPE_F16) { assert(!(val & 0x00000fff)); val >>= 12; } else if (insn->sType == TYPE_F64) { assert(!(imm->reg.data.u64 & 0x00000fffffffffffULL)); val = imm->reg.data.u64 >> 44; } assert(!(val & 0xfff00000) || (val & 0xfff00000) == 0xfff00000); emitField( 56, 1, (val & 0x80000) >> 19); emitField(pos, len, (val & 0x7ffff)); } else { emitField(pos, len, val); } } /******************************************************************************* * modifiers ******************************************************************************/ void CodeEmitterGM107::emitCond3(int pos, CondCode code) { int data = 0; switch (code) { case CC_FL : data = 0x00; break; case CC_LTU: case CC_LT : data = 0x01; break; case CC_EQU: case CC_EQ : data = 0x02; break; case CC_LEU: case CC_LE : data = 0x03; break; case CC_GTU: case CC_GT : data = 0x04; break; case CC_NEU: case CC_NE : data = 0x05; break; case CC_GEU: case CC_GE : data = 0x06; break; case CC_TR : data = 0x07; break; default: assert(!"invalid cond3"); break; } emitField(pos, 3, data); } void CodeEmitterGM107::emitCond4(int pos, CondCode code) { int data = 0; switch (code) { case CC_FL: data = 0x00; break; case CC_LT: data = 0x01; break; case CC_EQ: data = 0x02; break; case CC_LE: data = 0x03; break; case CC_GT: data = 0x04; break; case CC_NE: data = 0x05; break; case CC_GE: data = 0x06; break; // case CC_NUM: data = 0x07; break; // case CC_NAN: data = 0x08; break; case CC_LTU: data = 0x09; break; case CC_EQU: data = 0x0a; break; case CC_LEU: data = 0x0b; break; case CC_GTU: data = 0x0c; break; case CC_NEU: data = 0x0d; break; case CC_GEU: data = 0x0e; break; case CC_TR: data = 0x0f; break; default: assert(!"invalid cond4"); break; } emitField(pos, 4, data); } void CodeEmitterGM107::emitO(int pos) { emitField(pos, 1, insn->getSrc(0)->reg.file == FILE_SHADER_OUTPUT); } void CodeEmitterGM107::emitP(int pos) { emitField(pos, 1, insn->perPatch); } void CodeEmitterGM107::emitSAT(int pos) { emitField(pos, 1, insn->saturate); } void CodeEmitterGM107::emitCC(int pos) { emitField(pos, 1, insn->flagsDef >= 0); } void CodeEmitterGM107::emitX(int pos) { emitField(pos, 1, insn->flagsSrc >= 0); } void CodeEmitterGM107::emitABS(int pos, const ValueRef &ref) { emitField(pos, 1, ref.mod.abs()); } void CodeEmitterGM107::emitNEG(int pos, const ValueRef &ref) { emitField(pos, 1, ref.mod.neg()); } void CodeEmitterGM107::emitNEG2(int pos, const ValueRef &a, const ValueRef &b) { emitField(pos, 1, a.mod.neg() ^ b.mod.neg()); } void CodeEmitterGM107::emitFMZ(int pos, int len) { emitField(pos, len, insn->dnz << 1 | insn->ftz); } void CodeEmitterGM107::emitRND(int rmp, RoundMode rnd, int rip) { int rm = 0, ri = 0; switch (rnd) { case ROUND_NI: ri = 1; case ROUND_N : rm = 0; break; case ROUND_MI: ri = 1; case ROUND_M : rm = 1; break; case ROUND_PI: ri = 1; case ROUND_P : rm = 2; break; case ROUND_ZI: ri = 1; case ROUND_Z : rm = 3; break; default: assert(!"invalid round mode"); break; } emitField(rip, 1, ri); emitField(rmp, 2, rm); } void CodeEmitterGM107::emitPDIV(int pos) { assert(insn->postFactor >= -3 && insn->postFactor <= 3); if (insn->postFactor > 0) emitField(pos, 3, 7 - insn->postFactor); else emitField(pos, 3, 0 - insn->postFactor); } void CodeEmitterGM107::emitINV(int pos, const ValueRef &ref) { emitField(pos, 1, !!(ref.mod & Modifier(NV50_IR_MOD_NOT))); } /******************************************************************************* * control flow ******************************************************************************/ void CodeEmitterGM107::emitEXIT() { emitInsn (0xe3000000); emitCond5(0x00, CC_TR); } void CodeEmitterGM107::emitBRA() { const FlowInstruction *insn = this->insn->asFlow(); int gpr = -1; if (insn->indirect) { if (insn->absolute) emitInsn(0xe2000000); // JMX else emitInsn(0xe2500000); // BRX gpr = 0x08; } else { if (insn->absolute) emitInsn(0xe2100000); // JMP else emitInsn(0xe2400000); // BRA emitField(0x07, 1, insn->allWarp); } emitField(0x06, 1, insn->limit); emitCond5(0x00, CC_TR); if (!insn->srcExists(0) || insn->src(0).getFile() != FILE_MEMORY_CONST) { int32_t pos = insn->target.bb->binPos; if (writeIssueDelays && !(pos & 0x1f)) pos += 8; if (!insn->absolute) emitField(0x14, 24, pos - (codeSize + 8)); else emitField(0x14, 32, pos); } else { emitCBUF (0x24, gpr, 20, 16, 0, insn->src(0)); emitField(0x05, 1, 1); } } void CodeEmitterGM107::emitCAL() { const FlowInstruction *insn = this->insn->asFlow(); if (insn->absolute) { emitInsn(0xe2200000, 0); // JCAL } else { emitInsn(0xe2600000, 0); // CAL } if (!insn->srcExists(0) || insn->src(0).getFile() != FILE_MEMORY_CONST) { if (!insn->absolute) emitField(0x14, 24, insn->target.bb->binPos - (codeSize + 8)); else { if (insn->builtin) { int pcAbs = targGM107->getBuiltinOffset(insn->target.builtin); addReloc(RelocEntry::TYPE_BUILTIN, 0, pcAbs, 0xfff00000, 20); addReloc(RelocEntry::TYPE_BUILTIN, 1, pcAbs, 0x000fffff, -12); } else { emitField(0x14, 32, insn->target.bb->binPos); } } } else { emitCBUF (0x24, -1, 20, 16, 0, insn->src(0)); emitField(0x05, 1, 1); } } void CodeEmitterGM107::emitPCNT() { const FlowInstruction *insn = this->insn->asFlow(); emitInsn(0xe2b00000, 0); if (!insn->srcExists(0) || insn->src(0).getFile() != FILE_MEMORY_CONST) { emitField(0x14, 24, insn->target.bb->binPos - (codeSize + 8)); } else { emitCBUF (0x24, -1, 20, 16, 0, insn->src(0)); emitField(0x05, 1, 1); } } void CodeEmitterGM107::emitCONT() { emitInsn (0xe3500000); emitCond5(0x00, CC_TR); } void CodeEmitterGM107::emitPBK() { const FlowInstruction *insn = this->insn->asFlow(); emitInsn(0xe2a00000, 0); if (!insn->srcExists(0) || insn->src(0).getFile() != FILE_MEMORY_CONST) { emitField(0x14, 24, insn->target.bb->binPos - (codeSize + 8)); } else { emitCBUF (0x24, -1, 20, 16, 0, insn->src(0)); emitField(0x05, 1, 1); } } void CodeEmitterGM107::emitBRK() { emitInsn (0xe3400000); emitCond5(0x00, CC_TR); } void CodeEmitterGM107::emitPRET() { const FlowInstruction *insn = this->insn->asFlow(); emitInsn(0xe2700000, 0); if (!insn->srcExists(0) || insn->src(0).getFile() != FILE_MEMORY_CONST) { emitField(0x14, 24, insn->target.bb->binPos - (codeSize + 8)); } else { emitCBUF (0x24, -1, 20, 16, 0, insn->src(0)); emitField(0x05, 1, 1); } } void CodeEmitterGM107::emitRET() { emitInsn (0xe3200000); emitCond5(0x00, CC_TR); } void CodeEmitterGM107::emitSSY() { const FlowInstruction *insn = this->insn->asFlow(); emitInsn(0xe2900000, 0); if (!insn->srcExists(0) || insn->src(0).getFile() != FILE_MEMORY_CONST) { emitField(0x14, 24, insn->target.bb->binPos - (codeSize + 8)); } else { emitCBUF (0x24, -1, 20, 16, 0, insn->src(0)); emitField(0x05, 1, 1); } } void CodeEmitterGM107::emitSYNC() { emitInsn (0xf0f80000); emitCond5(0x00, CC_TR); } void CodeEmitterGM107::emitSAM() { emitInsn(0xe3700000, 0); } void CodeEmitterGM107::emitRAM() { emitInsn(0xe3800000, 0); } /******************************************************************************* * predicate/cc ******************************************************************************/ /******************************************************************************* * movement / conversion ******************************************************************************/ void CodeEmitterGM107::emitMOV() { if (insn->src(0).getFile() != FILE_IMMEDIATE) { switch (insn->src(0).getFile()) { case FILE_GPR: if (insn->def(0).getFile() == FILE_PREDICATE) { emitInsn(0x5b6a0000); emitGPR (0x08); } else { emitInsn(0x5c980000); } emitGPR (0x14, insn->src(0)); break; case FILE_MEMORY_CONST: emitInsn(0x4c980000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(0)); break; case FILE_IMMEDIATE: emitInsn(0x38980000); emitIMMD(0x14, 19, insn->src(0)); break; case FILE_PREDICATE: emitInsn(0x50880000); emitPRED(0x0c, insn->src(0)); emitPRED(0x1d); emitPRED(0x27); break; default: assert(!"bad src file"); break; } if (insn->def(0).getFile() != FILE_PREDICATE && insn->src(0).getFile() != FILE_PREDICATE) emitField(0x27, 4, insn->lanes); } else { emitInsn (0x01000000); emitIMMD (0x14, 32, insn->src(0)); emitField(0x0c, 4, insn->lanes); } if (insn->def(0).getFile() == FILE_PREDICATE) { emitPRED(0x27); emitPRED(0x03, insn->def(0)); emitPRED(0x00); } else { emitGPR(0x00, insn->def(0)); } } void CodeEmitterGM107::emitS2R() { emitInsn(0xf0c80000); emitSYS (0x14, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitF2F() { RoundMode rnd = insn->rnd; switch (insn->op) { case OP_FLOOR: rnd = ROUND_MI; break; case OP_CEIL : rnd = ROUND_PI; break; case OP_TRUNC: rnd = ROUND_ZI; break; default: break; } switch (insn->src(0).getFile()) { case FILE_GPR: emitInsn(0x5ca80000); emitGPR (0x14, insn->src(0)); break; case FILE_MEMORY_CONST: emitInsn(0x4ca80000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(0)); break; case FILE_IMMEDIATE: emitInsn(0x38a80000); emitIMMD(0x14, 19, insn->src(0)); break; default: assert(!"bad src0 file"); break; } emitField(0x32, 1, (insn->op == OP_SAT) || insn->saturate); emitField(0x31, 1, (insn->op == OP_ABS) || insn->src(0).mod.abs()); emitCC (0x2f); emitField(0x2d, 1, (insn->op == OP_NEG) || insn->src(0).mod.neg()); emitFMZ (0x2c, 1); emitField(0x29, 1, insn->subOp); emitRND (0x27, rnd, 0x2a); emitField(0x0a, 2, util_logbase2(typeSizeof(insn->sType))); emitField(0x08, 2, util_logbase2(typeSizeof(insn->dType))); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitF2I() { RoundMode rnd = insn->rnd; switch (insn->op) { case OP_FLOOR: rnd = ROUND_M; break; case OP_CEIL : rnd = ROUND_P; break; case OP_TRUNC: rnd = ROUND_Z; break; default: break; } switch (insn->src(0).getFile()) { case FILE_GPR: emitInsn(0x5cb00000); emitGPR (0x14, insn->src(0)); break; case FILE_MEMORY_CONST: emitInsn(0x4cb00000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(0)); break; case FILE_IMMEDIATE: emitInsn(0x38b00000); emitIMMD(0x14, 19, insn->src(0)); break; default: assert(!"bad src0 file"); break; } emitField(0x31, 1, (insn->op == OP_ABS) || insn->src(0).mod.abs()); emitCC (0x2f); emitField(0x2d, 1, (insn->op == OP_NEG) || insn->src(0).mod.neg()); emitFMZ (0x2c, 1); emitRND (0x27, rnd, 0x2a); emitField(0x0c, 1, isSignedType(insn->dType)); emitField(0x0a, 2, util_logbase2(typeSizeof(insn->sType))); emitField(0x08, 2, util_logbase2(typeSizeof(insn->dType))); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitI2F() { RoundMode rnd = insn->rnd; switch (insn->op) { case OP_FLOOR: rnd = ROUND_M; break; case OP_CEIL : rnd = ROUND_P; break; case OP_TRUNC: rnd = ROUND_Z; break; default: break; } switch (insn->src(0).getFile()) { case FILE_GPR: emitInsn(0x5cb80000); emitGPR (0x14, insn->src(0)); break; case FILE_MEMORY_CONST: emitInsn(0x4cb80000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(0)); break; case FILE_IMMEDIATE: emitInsn(0x38b80000); emitIMMD(0x14, 19, insn->src(0)); break; default: assert(!"bad src0 file"); break; } emitField(0x31, 1, (insn->op == OP_ABS) || insn->src(0).mod.abs()); emitCC (0x2f); emitField(0x2d, 1, (insn->op == OP_NEG) || insn->src(0).mod.neg()); emitField(0x29, 2, insn->subOp); emitRND (0x27, rnd, -1); emitField(0x0d, 1, isSignedType(insn->sType)); emitField(0x0a, 2, util_logbase2(typeSizeof(insn->sType))); emitField(0x08, 2, util_logbase2(typeSizeof(insn->dType))); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitI2I() { switch (insn->src(0).getFile()) { case FILE_GPR: emitInsn(0x5ce00000); emitGPR (0x14, insn->src(0)); break; case FILE_MEMORY_CONST: emitInsn(0x4ce00000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(0)); break; case FILE_IMMEDIATE: emitInsn(0x38e00000); emitIMMD(0x14, 19, insn->src(0)); break; default: assert(!"bad src0 file"); break; } emitSAT (0x32); emitField(0x31, 1, (insn->op == OP_ABS) || insn->src(0).mod.abs()); emitCC (0x2f); emitField(0x2d, 1, (insn->op == OP_NEG) || insn->src(0).mod.neg()); emitField(0x29, 2, insn->subOp); emitField(0x0d, 1, isSignedType(insn->sType)); emitField(0x0c, 1, isSignedType(insn->dType)); emitField(0x0a, 2, util_logbase2(typeSizeof(insn->sType))); emitField(0x08, 2, util_logbase2(typeSizeof(insn->dType))); emitGPR (0x00, insn->def(0)); } static void selpFlip(const FixupEntry *entry, uint32_t *code, const FixupData& data) { int loc = entry->loc; if (data.force_persample_interp) code[loc + 1] |= 1 << 10; else code[loc + 1] &= ~(1 << 10); } void CodeEmitterGM107::emitSEL() { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5ca00000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4ca00000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38a00000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitINV (0x2a, insn->src(2)); emitPRED(0x27, insn->src(2)); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); if (insn->subOp == 1) { addInterp(0, 0, selpFlip); } } void CodeEmitterGM107::emitSHFL() { int type = 0; emitInsn (0xef100000); switch (insn->src(1).getFile()) { case FILE_GPR: emitGPR(0x14, insn->src(1)); break; case FILE_IMMEDIATE: emitIMMD(0x14, 5, insn->src(1)); type |= 1; break; default: assert(!"invalid src1 file"); break; } /*XXX: what is this arg? hardcode immediate for now */ emitField(0x22, 13, 0x1c03); type |= 2; emitPRED (0x30); emitField(0x1e, 2, insn->subOp); emitField(0x1c, 2, type); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } /******************************************************************************* * double ******************************************************************************/ void CodeEmitterGM107::emitDADD() { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c700000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c700000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38700000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitABS(0x31, insn->src(1)); emitNEG(0x30, insn->src(0)); emitCC (0x2f); emitABS(0x2e, insn->src(0)); emitNEG(0x2d, insn->src(1)); if (insn->op == OP_SUB) code[1] ^= 0x00002000; emitGPR(0x08, insn->src(0)); emitGPR(0x00, insn->def(0)); } void CodeEmitterGM107::emitDMUL() { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c800000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c800000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38800000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitNEG2(0x30, insn->src(0), insn->src(1)); emitCC (0x2f); emitRND (0x27); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitDFMA() { switch(insn->src(2).getFile()) { case FILE_GPR: switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5b700000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4b700000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x36700000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitGPR (0x27, insn->src(2)); break; case FILE_MEMORY_CONST: emitInsn(0x53700000); emitGPR (0x27, insn->src(1)); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(2)); break; default: assert(!"bad src2 file"); break; } emitRND (0x32); emitNEG (0x31, insn->src(2)); emitNEG2(0x30, insn->src(0), insn->src(1)); emitCC (0x2f); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitDMNMX() { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c500000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c500000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38500000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitABS (0x31, insn->src(1)); emitNEG (0x30, insn->src(0)); emitCC (0x2f); emitABS (0x2e, insn->src(0)); emitNEG (0x2d, insn->src(1)); emitField(0x2a, 1, insn->op == OP_MAX); emitPRED (0x27); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitDSET() { const CmpInstruction *insn = this->insn->asCmp(); switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x59000000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x49000000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x32000000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } if (insn->op != OP_SET) { switch (insn->op) { case OP_SET_AND: emitField(0x2d, 2, 0); break; case OP_SET_OR : emitField(0x2d, 2, 1); break; case OP_SET_XOR: emitField(0x2d, 2, 2); break; default: assert(!"invalid set op"); break; } emitPRED(0x27, insn->src(2)); } else { emitPRED(0x27); } emitABS (0x36, insn->src(0)); emitNEG (0x35, insn->src(1)); emitField(0x34, 1, insn->dType == TYPE_F32); emitCond4(0x30, insn->setCond); emitCC (0x2f); emitABS (0x2c, insn->src(1)); emitNEG (0x2b, insn->src(0)); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitDSETP() { const CmpInstruction *insn = this->insn->asCmp(); switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5b800000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4b800000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x36800000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } if (insn->op != OP_SET) { switch (insn->op) { case OP_SET_AND: emitField(0x2d, 2, 0); break; case OP_SET_OR : emitField(0x2d, 2, 1); break; case OP_SET_XOR: emitField(0x2d, 2, 2); break; default: assert(!"invalid set op"); break; } emitPRED(0x27, insn->src(2)); } else { emitPRED(0x27); } emitCond4(0x30, insn->setCond); emitABS (0x2c, insn->src(1)); emitNEG (0x2b, insn->src(0)); emitGPR (0x08, insn->src(0)); emitABS (0x07, insn->src(0)); emitNEG (0x06, insn->src(1)); emitPRED (0x03, insn->def(0)); if (insn->defExists(1)) emitPRED(0x00, insn->def(1)); else emitPRED(0x00); } /******************************************************************************* * float ******************************************************************************/ void CodeEmitterGM107::emitFADD() { if (!longIMMD(insn->src(1))) { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c580000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c580000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38580000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitSAT(0x32); emitABS(0x31, insn->src(1)); emitNEG(0x30, insn->src(0)); emitCC (0x2f); emitABS(0x2e, insn->src(0)); emitNEG(0x2d, insn->src(1)); emitFMZ(0x2c, 1); if (insn->op == OP_SUB) code[1] ^= 0x00002000; } else { emitInsn(0x08000000); emitABS(0x39, insn->src(1)); emitNEG(0x38, insn->src(0)); emitFMZ(0x37, 1); emitABS(0x36, insn->src(0)); emitNEG(0x35, insn->src(1)); emitCC (0x34); emitIMMD(0x14, 32, insn->src(1)); if (insn->op == OP_SUB) code[1] ^= 0x00080000; } emitGPR(0x08, insn->src(0)); emitGPR(0x00, insn->def(0)); } void CodeEmitterGM107::emitFMUL() { if (!longIMMD(insn->src(1))) { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c680000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c680000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38680000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitSAT (0x32); emitNEG2(0x30, insn->src(0), insn->src(1)); emitCC (0x2f); emitFMZ (0x2c, 2); emitPDIV(0x29); emitRND (0x27); } else { emitInsn(0x1e000000); emitSAT (0x37); emitFMZ (0x35, 2); emitCC (0x34); emitIMMD(0x14, 32, insn->src(1)); if (insn->src(0).mod.neg() ^ insn->src(1).mod.neg()) code[1] ^= 0x00080000; /* flip immd sign bit */ } emitGPR(0x08, insn->src(0)); emitGPR(0x00, insn->def(0)); } void CodeEmitterGM107::emitFFMA() { /*XXX: ffma32i exists, but not using it as third src overlaps dst */ switch(insn->src(2).getFile()) { case FILE_GPR: switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x59800000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x49800000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x32800000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitGPR (0x27, insn->src(2)); break; case FILE_MEMORY_CONST: emitInsn(0x51800000); emitGPR (0x27, insn->src(1)); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(2)); break; default: assert(!"bad src2 file"); break; } emitRND (0x33); emitSAT (0x32); emitNEG (0x31, insn->src(2)); emitNEG2(0x30, insn->src(0), insn->src(1)); emitCC (0x2f); emitFMZ(0x35, 2); emitGPR(0x08, insn->src(0)); emitGPR(0x00, insn->def(0)); } void CodeEmitterGM107::emitMUFU() { int mufu = 0; switch (insn->op) { case OP_COS: mufu = 0; break; case OP_SIN: mufu = 1; break; case OP_EX2: mufu = 2; break; case OP_LG2: mufu = 3; break; case OP_RCP: mufu = 4 + 2 * insn->subOp; break; case OP_RSQ: mufu = 5 + 2 * insn->subOp; break; default: assert(!"invalid mufu"); break; } emitInsn (0x50800000); emitSAT (0x32); emitNEG (0x30, insn->src(0)); emitABS (0x2e, insn->src(0)); emitField(0x14, 3, mufu); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitFMNMX() { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c600000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c600000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38600000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitField(0x2a, 1, insn->op == OP_MAX); emitPRED (0x27); emitABS(0x31, insn->src(1)); emitNEG(0x30, insn->src(0)); emitCC (0x2f); emitABS(0x2e, insn->src(0)); emitNEG(0x2d, insn->src(1)); emitFMZ(0x2c, 1); emitGPR(0x08, insn->src(0)); emitGPR(0x00, insn->def(0)); } void CodeEmitterGM107::emitRRO() { switch (insn->src(0).getFile()) { case FILE_GPR: emitInsn(0x5c900000); emitGPR (0x14, insn->src(0)); break; case FILE_MEMORY_CONST: emitInsn(0x4c900000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(0)); break; case FILE_IMMEDIATE: emitInsn(0x38900000); emitIMMD(0x14, 19, insn->src(0)); break; default: assert(!"bad src file"); break; } emitABS (0x31, insn->src(0)); emitNEG (0x2d, insn->src(0)); emitField(0x27, 1, insn->op == OP_PREEX2); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitFCMP() { const CmpInstruction *insn = this->insn->asCmp(); CondCode cc = insn->setCond; if (insn->src(2).mod.neg()) cc = reverseCondCode(cc); switch(insn->src(2).getFile()) { case FILE_GPR: switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5ba00000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4ba00000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x36a00000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitGPR (0x27, insn->src(2)); break; case FILE_MEMORY_CONST: emitInsn(0x53a00000); emitGPR (0x27, insn->src(1)); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(2)); break; default: assert(!"bad src2 file"); break; } emitCond4(0x30, cc); emitFMZ (0x2f, 1); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitFSET() { const CmpInstruction *insn = this->insn->asCmp(); switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x58000000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x48000000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x30000000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } if (insn->op != OP_SET) { switch (insn->op) { case OP_SET_AND: emitField(0x2d, 2, 0); break; case OP_SET_OR : emitField(0x2d, 2, 1); break; case OP_SET_XOR: emitField(0x2d, 2, 2); break; default: assert(!"invalid set op"); break; } emitPRED(0x27, insn->src(2)); } else { emitPRED(0x27); } emitFMZ (0x37, 1); emitABS (0x36, insn->src(0)); emitNEG (0x35, insn->src(1)); emitField(0x34, 1, insn->dType == TYPE_F32); emitCond4(0x30, insn->setCond); emitCC (0x2f); emitABS (0x2c, insn->src(1)); emitNEG (0x2b, insn->src(0)); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitFSETP() { const CmpInstruction *insn = this->insn->asCmp(); switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5bb00000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4bb00000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x36b00000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } if (insn->op != OP_SET) { switch (insn->op) { case OP_SET_AND: emitField(0x2d, 2, 0); break; case OP_SET_OR : emitField(0x2d, 2, 1); break; case OP_SET_XOR: emitField(0x2d, 2, 2); break; default: assert(!"invalid set op"); break; } emitPRED(0x27, insn->src(2)); } else { emitPRED(0x27); } emitCond4(0x30, insn->setCond); emitFMZ (0x2f, 1); emitABS (0x2c, insn->src(1)); emitNEG (0x2b, insn->src(0)); emitGPR (0x08, insn->src(0)); emitABS (0x07, insn->src(0)); emitNEG (0x06, insn->src(1)); emitPRED (0x03, insn->def(0)); if (insn->defExists(1)) emitPRED(0x00, insn->def(1)); else emitPRED(0x00); } void CodeEmitterGM107::emitFSWZADD() { emitInsn (0x50f80000); emitCC (0x2f); emitFMZ (0x2c, 1); emitRND (0x27); emitField(0x26, 1, insn->lanes); /* abused for .ndv */ emitField(0x1c, 8, insn->subOp); if (insn->predSrc != 1) emitGPR (0x14, insn->src(1)); else emitGPR (0x14); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } /******************************************************************************* * integer ******************************************************************************/ void CodeEmitterGM107::emitLOP() { int lop = 0; switch (insn->op) { case OP_AND: lop = 0; break; case OP_OR : lop = 1; break; case OP_XOR: lop = 2; break; default: assert(!"invalid lop"); break; } if (insn->src(1).getFile() != FILE_IMMEDIATE) { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c400000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c400000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38400000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitPRED (0x30); emitCC (0x2f); emitX (0x2b); emitField(0x29, 2, lop); emitINV (0x28, insn->src(1)); emitINV (0x27, insn->src(0)); } else { emitInsn (0x04000000); emitX (0x39); emitINV (0x38, insn->src(1)); emitINV (0x37, insn->src(0)); emitField(0x35, 2, lop); emitCC (0x34); emitIMMD (0x14, 32, insn->src(1)); } emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } /* special-case of emitLOP(): lop pass_b dst 0 ~src */ void CodeEmitterGM107::emitNOT() { if (!longIMMD(insn->src(0))) { switch (insn->src(0).getFile()) { case FILE_GPR: emitInsn(0x5c400700); emitGPR (0x14, insn->src(0)); break; case FILE_MEMORY_CONST: emitInsn(0x4c400700); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(0)); break; case FILE_IMMEDIATE: emitInsn(0x38400700); emitIMMD(0x14, 19, insn->src(0)); break; default: assert(!"bad src1 file"); break; } emitPRED (0x30); } else { emitInsn (0x05600000); emitIMMD (0x14, 32, insn->src(1)); } emitGPR(0x08); emitGPR(0x00, insn->def(0)); } void CodeEmitterGM107::emitIADD() { if (insn->src(1).getFile() != FILE_IMMEDIATE) { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c100000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c100000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38100000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitSAT(0x32); emitNEG(0x31, insn->src(0)); emitNEG(0x30, insn->src(1)); emitCC (0x2f); emitX (0x2b); } else { emitInsn(0x1c000000); emitNEG (0x38, insn->src(0)); emitSAT (0x36); emitX (0x35); emitCC (0x34); emitIMMD(0x14, 32, insn->src(1)); } if (insn->op == OP_SUB) code[1] ^= 0x00010000; emitGPR(0x08, insn->src(0)); emitGPR(0x00, insn->def(0)); } void CodeEmitterGM107::emitIMUL() { if (insn->src(1).getFile() != FILE_IMMEDIATE) { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c380000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c380000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38380000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitCC (0x2f); emitField(0x29, 1, isSignedType(insn->sType)); emitField(0x28, 1, isSignedType(insn->dType)); emitField(0x27, 1, insn->subOp == NV50_IR_SUBOP_MUL_HIGH); } else { emitInsn (0x1f000000); emitField(0x37, 1, isSignedType(insn->sType)); emitField(0x36, 1, isSignedType(insn->dType)); emitField(0x35, 1, insn->subOp == NV50_IR_SUBOP_MUL_HIGH); emitCC (0x34); emitIMMD (0x14, 32, insn->src(1)); } emitGPR(0x08, insn->src(0)); emitGPR(0x00, insn->def(0)); } void CodeEmitterGM107::emitIMAD() { /*XXX: imad32i exists, but not using it as third src overlaps dst */ switch(insn->src(2).getFile()) { case FILE_GPR: switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5a000000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4a000000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x34000000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitGPR (0x27, insn->src(2)); break; case FILE_MEMORY_CONST: emitInsn(0x52000000); emitGPR (0x27, insn->src(1)); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(2)); break; default: assert(!"bad src2 file"); break; } emitField(0x36, 1, insn->subOp == NV50_IR_SUBOP_MUL_HIGH); emitField(0x35, 1, isSignedType(insn->sType)); emitNEG (0x34, insn->src(2)); emitNEG2 (0x33, insn->src(0), insn->src(1)); emitSAT (0x32); emitX (0x31); emitField(0x30, 1, isSignedType(insn->dType)); emitCC (0x2f); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitIMNMX() { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c200000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c200000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38200000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitField(0x30, 1, isSignedType(insn->dType)); emitCC (0x2f); emitField(0x2a, 1, insn->op == OP_MAX); emitPRED (0x27); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitICMP() { const CmpInstruction *insn = this->insn->asCmp(); CondCode cc = insn->setCond; if (insn->src(2).mod.neg()) cc = reverseCondCode(cc); switch(insn->src(2).getFile()) { case FILE_GPR: switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5b400000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4b400000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x36400000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitGPR (0x27, insn->src(2)); break; case FILE_MEMORY_CONST: emitInsn(0x53400000); emitGPR (0x27, insn->src(1)); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(2)); break; default: assert(!"bad src2 file"); break; } emitCond3(0x31, cc); emitField(0x30, 1, isSignedType(insn->sType)); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitISET() { const CmpInstruction *insn = this->insn->asCmp(); switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5b500000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4b500000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x36500000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } if (insn->op != OP_SET) { switch (insn->op) { case OP_SET_AND: emitField(0x2d, 2, 0); break; case OP_SET_OR : emitField(0x2d, 2, 1); break; case OP_SET_XOR: emitField(0x2d, 2, 2); break; default: assert(!"invalid set op"); break; } emitPRED(0x27, insn->src(2)); } else { emitPRED(0x27); } emitCond3(0x31, insn->setCond); emitField(0x30, 1, isSignedType(insn->sType)); emitCC (0x2f); emitField(0x2c, 1, insn->dType == TYPE_F32); emitX (0x2b); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitISETP() { const CmpInstruction *insn = this->insn->asCmp(); switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5b600000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4b600000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x36600000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } if (insn->op != OP_SET) { switch (insn->op) { case OP_SET_AND: emitField(0x2d, 2, 0); break; case OP_SET_OR : emitField(0x2d, 2, 1); break; case OP_SET_XOR: emitField(0x2d, 2, 2); break; default: assert(!"invalid set op"); break; } emitPRED(0x27, insn->src(2)); } else { emitPRED(0x27); } emitCond3(0x31, insn->setCond); emitField(0x30, 1, isSignedType(insn->sType)); emitX (0x2b); emitGPR (0x08, insn->src(0)); emitPRED (0x03, insn->def(0)); if (insn->defExists(1)) emitPRED(0x00, insn->def(1)); else emitPRED(0x00); } void CodeEmitterGM107::emitSHL() { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c480000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c480000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38480000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitCC (0x2f); emitX (0x2b); emitField(0x27, 1, insn->subOp == NV50_IR_SUBOP_SHIFT_WRAP); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitSHR() { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c280000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c280000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38280000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitField(0x30, 1, isSignedType(insn->dType)); emitCC (0x2f); emitX (0x2c); emitField(0x27, 1, insn->subOp == NV50_IR_SUBOP_SHIFT_WRAP); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitPOPC() { switch (insn->src(0).getFile()) { case FILE_GPR: emitInsn(0x5c080000); emitGPR (0x14, insn->src(0)); break; case FILE_MEMORY_CONST: emitInsn(0x4c080000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(0)); break; case FILE_IMMEDIATE: emitInsn(0x38080000); emitIMMD(0x14, 19, insn->src(0)); break; default: assert(!"bad src1 file"); break; } emitINV(0x28, insn->src(0)); emitGPR(0x00, insn->def(0)); } void CodeEmitterGM107::emitBFI() { switch(insn->src(2).getFile()) { case FILE_GPR: switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5bf00000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4bf00000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x36f00000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitGPR (0x27, insn->src(2)); break; case FILE_MEMORY_CONST: emitInsn(0x53f00000); emitGPR (0x27, insn->src(1)); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(2)); break; default: assert(!"bad src2 file"); break; } emitCC (0x2f); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitBFE() { switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0x5c000000); emitGPR (0x14, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0x4c000000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0x38000000); emitIMMD(0x14, 19, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitField(0x30, 1, isSignedType(insn->dType)); emitCC (0x2f); emitField(0x28, 1, insn->subOp == NV50_IR_SUBOP_EXTBF_REV); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitFLO() { switch (insn->src(0).getFile()) { case FILE_GPR: emitInsn(0x5c300000); emitGPR (0x14, insn->src(0)); break; case FILE_MEMORY_CONST: emitInsn(0x4c300000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(0)); break; case FILE_IMMEDIATE: emitInsn(0x38300000); emitIMMD(0x14, 19, insn->src(0)); break; default: assert(!"bad src1 file"); break; } emitField(0x30, 1, isSignedType(insn->dType)); emitCC (0x2f); emitField(0x29, 1, insn->subOp == NV50_IR_SUBOP_BFIND_SAMT); emitINV (0x28, insn->src(0)); emitGPR (0x00, insn->def(0)); } /******************************************************************************* * memory ******************************************************************************/ void CodeEmitterGM107::emitLDSTs(int pos, DataType type) { int data = 0; switch (typeSizeof(type)) { case 1: data = isSignedType(type) ? 1 : 0; break; case 2: data = isSignedType(type) ? 3 : 2; break; case 4: data = 4; break; case 8: data = 5; break; case 16: data = 6; break; default: assert(!"bad type"); break; } emitField(pos, 3, data); } void CodeEmitterGM107::emitLDSTc(int pos) { int mode = 0; switch (insn->cache) { case CACHE_CA: mode = 0; break; case CACHE_CG: mode = 1; break; case CACHE_CS: mode = 2; break; case CACHE_CV: mode = 3; break; default: assert(!"invalid caching mode"); break; } emitField(pos, 2, mode); } void CodeEmitterGM107::emitLDC() { emitInsn (0xef900000); emitLDSTs(0x30, insn->dType); emitField(0x2c, 2, insn->subOp); emitCBUF (0x24, 0x08, 0x14, 16, 0, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitLDL() { emitInsn (0xef400000); emitLDSTs(0x30, insn->dType); emitLDSTc(0x2c); emitADDR (0x08, 0x14, 24, 0, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitLDS() { emitInsn (0xef480000); emitLDSTs(0x30, insn->dType); emitADDR (0x08, 0x14, 24, 0, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitLD() { emitInsn (0x80000000); emitPRED (0x3a); emitLDSTc(0x38); emitLDSTs(0x35, insn->dType); emitField(0x34, 1, insn->src(0).getIndirect(0)->getSize() == 8); emitADDR (0x08, 0x14, 32, 0, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitSTL() { emitInsn (0xef500000); emitLDSTs(0x30, insn->dType); emitLDSTc(0x2c); emitADDR (0x08, 0x14, 24, 0, insn->src(0)); emitGPR (0x00, insn->src(1)); } void CodeEmitterGM107::emitSTS() { emitInsn (0xef580000); emitLDSTs(0x30, insn->dType); emitADDR (0x08, 0x14, 24, 0, insn->src(0)); emitGPR (0x00, insn->src(1)); } void CodeEmitterGM107::emitST() { emitInsn (0xa0000000); emitPRED (0x3a); emitLDSTc(0x38); emitLDSTs(0x35, insn->dType); emitField(0x34, 1, insn->src(0).getIndirect(0)->getSize() == 8); emitADDR (0x08, 0x14, 32, 0, insn->src(0)); emitGPR (0x00, insn->src(1)); } void CodeEmitterGM107::emitALD() { emitInsn (0xefd80000); emitField(0x2f, 2, (insn->getDef(0)->reg.size / 4) - 1); emitGPR (0x27, insn->src(0).getIndirect(1)); emitO (0x20); emitP (0x1f); emitADDR (0x08, 20, 10, 0, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitAST() { emitInsn (0xeff00000); emitField(0x2f, 2, (typeSizeof(insn->dType) / 4) - 1); emitGPR (0x27, insn->src(0).getIndirect(1)); emitP (0x1f); emitADDR (0x08, 20, 10, 0, insn->src(0)); emitGPR (0x00, insn->src(1)); } void CodeEmitterGM107::emitISBERD() { emitInsn(0xefd00000); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitAL2P() { emitInsn (0xefa00000); emitField(0x2f, 2, (insn->getDef(0)->reg.size / 4) - 1); emitO (0x20); emitField(0x14, 11, insn->src(0).get()->reg.data.offset); emitGPR (0x08, insn->src(0).getIndirect(0)); emitGPR (0x00, insn->def(0)); } static void interpApply(const FixupEntry *entry, uint32_t *code, const FixupData& data) { int ipa = entry->ipa; int reg = entry->reg; int loc = entry->loc; if (data.flatshade && (ipa & NV50_IR_INTERP_MODE_MASK) == NV50_IR_INTERP_SC) { ipa = NV50_IR_INTERP_FLAT; reg = 0xff; } else if (data.force_persample_interp && (ipa & NV50_IR_INTERP_SAMPLE_MASK) == NV50_IR_INTERP_DEFAULT && (ipa & NV50_IR_INTERP_MODE_MASK) != NV50_IR_INTERP_FLAT) { ipa |= NV50_IR_INTERP_CENTROID; } code[loc + 1] &= ~(0xf << 0x14); code[loc + 1] |= (ipa & 0x3) << 0x16; code[loc + 1] |= (ipa & 0xc) << (0x14 - 2); code[loc + 0] &= ~(0xff << 0x14); code[loc + 0] |= reg << 0x14; } void CodeEmitterGM107::emitIPA() { int ipam = 0, ipas = 0; switch (insn->getInterpMode()) { case NV50_IR_INTERP_LINEAR : ipam = 0; break; case NV50_IR_INTERP_PERSPECTIVE: ipam = 1; break; case NV50_IR_INTERP_FLAT : ipam = 2; break; case NV50_IR_INTERP_SC : ipam = 3; break; default: assert(!"invalid ipa mode"); break; } switch (insn->getSampleMode()) { case NV50_IR_INTERP_DEFAULT : ipas = 0; break; case NV50_IR_INTERP_CENTROID: ipas = 1; break; case NV50_IR_INTERP_OFFSET : ipas = 2; break; default: assert(!"invalid ipa sample mode"); break; } emitInsn (0xe0000000); emitField(0x36, 2, ipam); emitField(0x34, 2, ipas); emitSAT (0x33); emitField(0x2f, 3, 7); emitADDR (0x08, 0x1c, 10, 0, insn->src(0)); if ((code[0] & 0x0000ff00) != 0x0000ff00) code[1] |= 0x00000040; /* .idx */ emitGPR(0x00, insn->def(0)); if (insn->op == OP_PINTERP) { emitGPR(0x14, insn->src(1)); if (insn->getSampleMode() == NV50_IR_INTERP_OFFSET) emitGPR(0x27, insn->src(2)); addInterp(insn->ipa, insn->getSrc(1)->reg.data.id, interpApply); } else { if (insn->getSampleMode() == NV50_IR_INTERP_OFFSET) emitGPR(0x27, insn->src(1)); emitGPR(0x14); addInterp(insn->ipa, 0xff, interpApply); } if (insn->getSampleMode() != NV50_IR_INTERP_OFFSET) emitGPR(0x27); } void CodeEmitterGM107::emitATOM() { unsigned dType, subOp; if (insn->subOp == NV50_IR_SUBOP_ATOM_CAS) { switch (insn->dType) { case TYPE_U32: dType = 0; break; case TYPE_U64: dType = 1; break; default: assert(!"unexpected dType"); dType = 0; break; } subOp = 15; emitInsn (0xee000000); } else { switch (insn->dType) { case TYPE_U32: dType = 0; break; case TYPE_S32: dType = 1; break; case TYPE_U64: dType = 2; break; case TYPE_F32: dType = 3; break; case TYPE_B128: dType = 4; break; case TYPE_S64: dType = 5; break; default: assert(!"unexpected dType"); dType = 0; break; } if (insn->subOp == NV50_IR_SUBOP_ATOM_EXCH) subOp = 8; else subOp = insn->subOp; emitInsn (0xed000000); } emitField(0x34, 4, subOp); emitField(0x31, 3, dType); emitField(0x30, 1, insn->src(0).getIndirect(0)->getSize() == 8); emitGPR (0x14, insn->src(1)); emitADDR (0x08, 0x1c, 20, 0, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitATOMS() { unsigned dType, subOp; if (insn->subOp == NV50_IR_SUBOP_ATOM_CAS) { switch (insn->dType) { case TYPE_U32: dType = 0; break; case TYPE_U64: dType = 1; break; default: assert(!"unexpected dType"); dType = 0; break; } subOp = 4; emitInsn (0xee000000); emitField(0x34, 1, dType); } else { switch (insn->dType) { case TYPE_U32: dType = 0; break; case TYPE_S32: dType = 1; break; case TYPE_U64: dType = 2; break; case TYPE_S64: dType = 3; break; default: assert(!"unexpected dType"); dType = 0; break; } if (insn->subOp == NV50_IR_SUBOP_ATOM_EXCH) subOp = 8; else subOp = insn->subOp; emitInsn (0xec000000); emitField(0x1c, 3, dType); } emitField(0x34, 4, subOp); emitGPR (0x14, insn->src(1)); emitADDR (0x08, 0x12, 22, 0, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitCCTL() { unsigned width; if (insn->src(0).getFile() == FILE_MEMORY_GLOBAL) { emitInsn(0xef600000); width = 30; } else { emitInsn(0xef800000); width = 22; } emitField(0x34, 1, insn->src(0).getIndirect(0)->getSize() == 8); emitADDR (0x08, 0x16, width, 2, insn->src(0)); emitField(0x00, 4, insn->subOp); } /******************************************************************************* * surface ******************************************************************************/ void CodeEmitterGM107::emitPIXLD() { emitInsn (0xefe80000); emitPRED (0x2d); emitField(0x1f, 3, insn->subOp); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } /******************************************************************************* * texture ******************************************************************************/ void CodeEmitterGM107::emitTEXs(int pos) { int src1 = insn->predSrc == 1 ? 2 : 1; if (insn->srcExists(src1)) emitGPR(pos, insn->src(src1)); else emitGPR(pos); } void CodeEmitterGM107::emitTEX() { const TexInstruction *insn = this->insn->asTex(); int lodm = 0; if (!insn->tex.levelZero) { switch (insn->op) { case OP_TEX: lodm = 0; break; case OP_TXB: lodm = 2; break; case OP_TXL: lodm = 3; break; default: assert(!"invalid tex op"); break; } } else { lodm = 1; } if (insn->tex.rIndirectSrc >= 0) { emitInsn (0xdeb80000); emitField(0x35, 2, lodm); emitField(0x24, 1, insn->tex.useOffsets == 1); } else { emitInsn (0xc0380000); emitField(0x37, 2, lodm); emitField(0x36, 1, insn->tex.useOffsets == 1); emitField(0x24, 13, insn->tex.r); } emitField(0x32, 1, insn->tex.target.isShadow()); emitField(0x31, 1, insn->tex.liveOnly); emitField(0x23, 1, insn->tex.derivAll); emitField(0x1f, 4, insn->tex.mask); emitField(0x1d, 2, insn->tex.target.isCube() ? 3 : insn->tex.target.getDim() - 1); emitField(0x1c, 1, insn->tex.target.isArray()); emitTEXs (0x14); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitTLD() { const TexInstruction *insn = this->insn->asTex(); if (insn->tex.rIndirectSrc >= 0) { emitInsn (0xdd380000); } else { emitInsn (0xdc380000); emitField(0x24, 13, insn->tex.r); } emitField(0x37, 1, insn->tex.levelZero == 0); emitField(0x32, 1, insn->tex.target.isMS()); emitField(0x31, 1, insn->tex.liveOnly); emitField(0x23, 1, insn->tex.useOffsets == 1); emitField(0x1f, 4, insn->tex.mask); emitField(0x1d, 2, insn->tex.target.isCube() ? 3 : insn->tex.target.getDim() - 1); emitField(0x1c, 1, insn->tex.target.isArray()); emitTEXs (0x14); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitTLD4() { const TexInstruction *insn = this->insn->asTex(); if (insn->tex.rIndirectSrc >= 0) { emitInsn (0xdef80000); emitField(0x26, 2, insn->tex.gatherComp); emitField(0x25, 2, insn->tex.useOffsets == 4); emitField(0x24, 2, insn->tex.useOffsets == 1); } else { emitInsn (0xc8380000); emitField(0x38, 2, insn->tex.gatherComp); emitField(0x37, 2, insn->tex.useOffsets == 4); emitField(0x36, 2, insn->tex.useOffsets == 1); emitField(0x24, 13, insn->tex.r); } emitField(0x32, 1, insn->tex.target.isShadow()); emitField(0x31, 1, insn->tex.liveOnly); emitField(0x23, 1, insn->tex.derivAll); emitField(0x1f, 4, insn->tex.mask); emitField(0x1d, 2, insn->tex.target.isCube() ? 3 : insn->tex.target.getDim() - 1); emitField(0x1c, 1, insn->tex.target.isArray()); emitTEXs (0x14); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitTXD() { const TexInstruction *insn = this->insn->asTex(); if (insn->tex.rIndirectSrc >= 0) { emitInsn (0xde780000); } else { emitInsn (0xde380000); emitField(0x24, 13, insn->tex.r); } emitField(0x31, 1, insn->tex.liveOnly); emitField(0x23, 1, insn->tex.useOffsets == 1); emitField(0x1f, 4, insn->tex.mask); emitField(0x1d, 2, insn->tex.target.isCube() ? 3 : insn->tex.target.getDim() - 1); emitField(0x1c, 1, insn->tex.target.isArray()); emitTEXs (0x14); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitTMML() { const TexInstruction *insn = this->insn->asTex(); if (insn->tex.rIndirectSrc >= 0) { emitInsn (0xdf600000); } else { emitInsn (0xdf580000); emitField(0x24, 13, insn->tex.r); } emitField(0x31, 1, insn->tex.liveOnly); emitField(0x23, 1, insn->tex.derivAll); emitField(0x1f, 4, insn->tex.mask); emitField(0x1d, 2, insn->tex.target.isCube() ? 3 : insn->tex.target.getDim() - 1); emitField(0x1c, 1, insn->tex.target.isArray()); emitTEXs (0x14); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitTXQ() { const TexInstruction *insn = this->insn->asTex(); int type = 0; switch (insn->tex.query) { case TXQ_DIMS : type = 0x01; break; case TXQ_TYPE : type = 0x02; break; case TXQ_SAMPLE_POSITION: type = 0x05; break; case TXQ_FILTER : type = 0x10; break; case TXQ_LOD : type = 0x12; break; case TXQ_WRAP : type = 0x14; break; case TXQ_BORDER_COLOUR : type = 0x16; break; default: assert(!"invalid txq query"); break; } if (insn->tex.rIndirectSrc >= 0) { emitInsn (0xdf500000); } else { emitInsn (0xdf480000); emitField(0x24, 13, insn->tex.r); } emitField(0x31, 1, insn->tex.liveOnly); emitField(0x1f, 4, insn->tex.mask); emitField(0x16, 6, type); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitDEPBAR() { emitInsn (0xf0f00000); emitField(0x1d, 1, 1); /* le */ emitField(0x1a, 3, 5); emitField(0x14, 6, insn->subOp); emitField(0x00, 6, insn->subOp); } /******************************************************************************* * misc ******************************************************************************/ void CodeEmitterGM107::emitNOP() { emitInsn(0x50b00000); } void CodeEmitterGM107::emitKIL() { emitInsn (0xe3300000); emitCond5(0x00, CC_TR); } void CodeEmitterGM107::emitOUT() { const int cut = insn->op == OP_RESTART || insn->subOp; const int emit = insn->op == OP_EMIT; switch (insn->src(1).getFile()) { case FILE_GPR: emitInsn(0xfbe00000); emitGPR (0x14, insn->src(1)); break; case FILE_IMMEDIATE: emitInsn(0xf6e00000); emitIMMD(0x14, 19, insn->src(1)); break; case FILE_MEMORY_CONST: emitInsn(0xebe00000); emitCBUF(0x22, -1, 0x14, 16, 2, insn->src(1)); break; default: assert(!"bad src1 file"); break; } emitField(0x27, 2, (cut << 1) | emit); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); } void CodeEmitterGM107::emitBAR() { uint8_t subop; emitInsn (0xf0a80000); switch (insn->subOp) { case NV50_IR_SUBOP_BAR_RED_POPC: subop = 0x02; break; case NV50_IR_SUBOP_BAR_RED_AND: subop = 0x0a; break; case NV50_IR_SUBOP_BAR_RED_OR: subop = 0x12; break; case NV50_IR_SUBOP_BAR_ARRIVE: subop = 0x81; break; default: subop = 0x80; assert(insn->subOp == NV50_IR_SUBOP_BAR_SYNC); break; } emitField(0x20, 8, subop); // barrier id if (insn->src(0).getFile() == FILE_GPR) { emitGPR(0x08, insn->src(0)); } else { ImmediateValue *imm = insn->getSrc(0)->asImm(); assert(imm); emitField(0x08, 8, imm->reg.data.u32); emitField(0x2b, 1, 1); } // thread count if (insn->src(1).getFile() == FILE_GPR) { emitGPR(0x14, insn->src(1)); } else { ImmediateValue *imm = insn->getSrc(0)->asImm(); assert(imm); emitField(0x14, 12, imm->reg.data.u32); emitField(0x2c, 1, 1); } if (insn->srcExists(2) && (insn->predSrc != 2)) { emitPRED (0x27, insn->src(2)); emitField(0x2a, 1, insn->src(2).mod == Modifier(NV50_IR_MOD_NOT)); } else { emitField(0x27, 3, 7); } } void CodeEmitterGM107::emitMEMBAR() { emitInsn (0xef980000); emitField(0x08, 2, insn->subOp >> 2); } void CodeEmitterGM107::emitVOTE() { assert(insn->src(0).getFile() == FILE_PREDICATE); int r = -1, p = -1; for (int i = 0; insn->defExists(i); i++) { if (insn->def(i).getFile() == FILE_GPR) r = i; else if (insn->def(i).getFile() == FILE_PREDICATE) p = i; } emitInsn (0x50d80000); emitField(0x30, 2, insn->subOp); if (r >= 0) emitGPR (0x00, insn->def(r)); else emitGPR (0x00); if (p >= 0) emitPRED (0x2d, insn->def(p)); else emitPRED (0x2d); emitField(0x2a, 1, insn->src(0).mod == Modifier(NV50_IR_MOD_NOT)); emitPRED (0x27, insn->src(0)); } void CodeEmitterGM107::emitSUTarget() { const TexInstruction *insn = this->insn->asTex(); int target = 0; assert(insn->op >= OP_SULDB && insn->op <= OP_SUREDP); if (insn->tex.target == TEX_TARGET_BUFFER) { target = 2; } else if (insn->tex.target == TEX_TARGET_1D_ARRAY) { target = 4; } else if (insn->tex.target == TEX_TARGET_2D || insn->tex.target == TEX_TARGET_RECT) { target = 6; } else if (insn->tex.target == TEX_TARGET_2D_ARRAY || insn->tex.target == TEX_TARGET_CUBE || insn->tex.target == TEX_TARGET_CUBE_ARRAY) { target = 8; } else if (insn->tex.target == TEX_TARGET_3D) { target = 10; } else { assert(insn->tex.target == TEX_TARGET_1D); } emitField(0x20, 4, target); } void CodeEmitterGM107::emitSUHandle(const int s) { const TexInstruction *insn = this->insn->asTex(); assert(insn->op >= OP_SULDB && insn->op <= OP_SUREDP); if (insn->src(s).getFile() == FILE_GPR) { emitGPR(0x27, insn->src(s)); } else { ImmediateValue *imm = insn->getSrc(s)->asImm(); assert(imm); emitField(0x33, 1, 1); emitField(0x24, 13, imm->reg.data.u32); } } void CodeEmitterGM107::emitSUSTx() { const TexInstruction *insn = this->insn->asTex(); emitInsn(0xeb200000); if (insn->op == OP_SUSTB) emitField(0x34, 1, 1); emitSUTarget(); emitLDSTc(0x18); emitField(0x14, 4, 0xf); // rgba emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->src(1)); emitSUHandle(2); } void CodeEmitterGM107::emitSULDx() { const TexInstruction *insn = this->insn->asTex(); int type = 0; emitInsn(0xeb000000); if (insn->op == OP_SULDB) emitField(0x34, 1, 1); emitSUTarget(); switch (insn->dType) { case TYPE_S8: type = 1; break; case TYPE_U16: type = 2; break; case TYPE_S16: type = 3; break; case TYPE_U32: type = 4; break; case TYPE_U64: type = 5; break; case TYPE_B128: type = 6; break; default: assert(insn->dType == TYPE_U8); break; } emitLDSTc(0x18); emitField(0x14, 3, type); emitGPR (0x00, insn->def(0)); emitGPR (0x08, insn->src(0)); emitSUHandle(1); } void CodeEmitterGM107::emitSUREDx() { const TexInstruction *insn = this->insn->asTex(); uint8_t type = 0, subOp; if (insn->subOp == NV50_IR_SUBOP_ATOM_CAS) emitInsn(0xeac00000); else emitInsn(0xea600000); if (insn->op == OP_SUREDB) emitField(0x34, 1, 1); emitSUTarget(); // destination type switch (insn->dType) { case TYPE_S32: type = 1; break; case TYPE_U64: type = 2; break; case TYPE_F32: type = 3; break; case TYPE_S64: type = 5; break; default: assert(insn->dType == TYPE_U32); break; } // atomic operation if (insn->subOp == NV50_IR_SUBOP_ATOM_CAS) { subOp = 0; } else if (insn->subOp == NV50_IR_SUBOP_ATOM_EXCH) { subOp = 8; } else { subOp = insn->subOp; } emitField(0x24, 3, type); emitField(0x1d, 4, subOp); emitGPR (0x14, insn->src(1)); emitGPR (0x08, insn->src(0)); emitGPR (0x00, insn->def(0)); emitSUHandle(2); } /******************************************************************************* * assembler front-end ******************************************************************************/ bool CodeEmitterGM107::emitInstruction(Instruction *i) { const unsigned int size = (writeIssueDelays && !(codeSize & 0x1f)) ? 16 : 8; bool ret = true; insn = i; if (insn->encSize != 8) { ERROR("skipping undecodable instruction: "); insn->print(); return false; } else if (codeSize + size > codeSizeLimit) { ERROR("code emitter output buffer too small\n"); return false; } if (writeIssueDelays) { int n = ((codeSize & 0x1f) / 8) - 1; if (n < 0) { data = code; data[0] = 0x00000000; data[1] = 0x00000000; code += 2; codeSize += 8; n++; } emitField(data, n * 21, 21, insn->sched); } switch (insn->op) { case OP_EXIT: emitEXIT(); break; case OP_BRA: emitBRA(); break; case OP_CALL: emitCAL(); break; case OP_PRECONT: emitPCNT(); break; case OP_CONT: emitCONT(); break; case OP_PREBREAK: emitPBK(); break; case OP_BREAK: emitBRK(); break; case OP_PRERET: emitPRET(); break; case OP_RET: emitRET(); break; case OP_JOINAT: emitSSY(); break; case OP_JOIN: emitSYNC(); break; case OP_QUADON: emitSAM(); break; case OP_QUADPOP: emitRAM(); break; case OP_MOV: emitMOV(); break; case OP_RDSV: emitS2R(); break; case OP_ABS: case OP_NEG: case OP_SAT: case OP_FLOOR: case OP_CEIL: case OP_TRUNC: case OP_CVT: if (insn->op == OP_CVT && (insn->def(0).getFile() == FILE_PREDICATE || insn->src(0).getFile() == FILE_PREDICATE)) { emitMOV(); } else if (isFloatType(insn->dType)) { if (isFloatType(insn->sType)) emitF2F(); else emitI2F(); } else { if (isFloatType(insn->sType)) emitF2I(); else emitI2I(); } break; case OP_SHFL: emitSHFL(); break; case OP_ADD: case OP_SUB: if (isFloatType(insn->dType)) { if (insn->dType == TYPE_F64) emitDADD(); else emitFADD(); } else { emitIADD(); } break; case OP_MUL: if (isFloatType(insn->dType)) { if (insn->dType == TYPE_F64) emitDMUL(); else emitFMUL(); } else { emitIMUL(); } break; case OP_MAD: case OP_FMA: if (isFloatType(insn->dType)) { if (insn->dType == TYPE_F64) emitDFMA(); else emitFFMA(); } else { emitIMAD(); } break; case OP_MIN: case OP_MAX: if (isFloatType(insn->dType)) { if (insn->dType == TYPE_F64) emitDMNMX(); else emitFMNMX(); } else { emitIMNMX(); } break; case OP_SHL: emitSHL(); break; case OP_SHR: emitSHR(); break; case OP_POPCNT: emitPOPC(); break; case OP_INSBF: emitBFI(); break; case OP_EXTBF: emitBFE(); break; case OP_BFIND: emitFLO(); break; case OP_SLCT: if (isFloatType(insn->dType)) emitFCMP(); else emitICMP(); break; case OP_SET: case OP_SET_AND: case OP_SET_OR: case OP_SET_XOR: if (insn->def(0).getFile() != FILE_PREDICATE) { if (isFloatType(insn->sType)) if (insn->sType == TYPE_F64) emitDSET(); else emitFSET(); else emitISET(); } else { if (isFloatType(insn->sType)) if (insn->sType == TYPE_F64) emitDSETP(); else emitFSETP(); else emitISETP(); } break; case OP_SELP: emitSEL(); break; case OP_PRESIN: case OP_PREEX2: emitRRO(); break; case OP_COS: case OP_SIN: case OP_EX2: case OP_LG2: case OP_RCP: case OP_RSQ: emitMUFU(); break; case OP_AND: case OP_OR: case OP_XOR: emitLOP(); break; case OP_NOT: emitNOT(); break; case OP_LOAD: switch (insn->src(0).getFile()) { case FILE_MEMORY_CONST : emitLDC(); break; case FILE_MEMORY_LOCAL : emitLDL(); break; case FILE_MEMORY_SHARED: emitLDS(); break; case FILE_MEMORY_GLOBAL: emitLD(); break; default: assert(!"invalid load"); emitNOP(); break; } break; case OP_STORE: switch (insn->src(0).getFile()) { case FILE_MEMORY_LOCAL : emitSTL(); break; case FILE_MEMORY_SHARED: emitSTS(); break; case FILE_MEMORY_GLOBAL: emitST(); break; default: assert(!"invalid store"); emitNOP(); break; } break; case OP_ATOM: if (insn->src(0).getFile() == FILE_MEMORY_SHARED) emitATOMS(); else emitATOM(); break; case OP_CCTL: emitCCTL(); break; case OP_VFETCH: emitALD(); break; case OP_EXPORT: emitAST(); break; case OP_PFETCH: emitISBERD(); break; case OP_AFETCH: emitAL2P(); break; case OP_LINTERP: case OP_PINTERP: emitIPA(); break; case OP_PIXLD: emitPIXLD(); break; case OP_TEX: case OP_TXB: case OP_TXL: emitTEX(); break; case OP_TXF: emitTLD(); break; case OP_TXG: emitTLD4(); break; case OP_TXD: emitTXD(); break; case OP_TXQ: emitTXQ(); break; case OP_TXLQ: emitTMML(); break; case OP_TEXBAR: emitDEPBAR(); break; case OP_QUADOP: emitFSWZADD(); break; case OP_NOP: emitNOP(); break; case OP_DISCARD: emitKIL(); break; case OP_EMIT: case OP_RESTART: emitOUT(); break; case OP_BAR: emitBAR(); break; case OP_MEMBAR: emitMEMBAR(); break; case OP_VOTE: emitVOTE(); break; case OP_SUSTB: case OP_SUSTP: emitSUSTx(); break; case OP_SULDB: case OP_SULDP: emitSULDx(); break; case OP_SUREDB: case OP_SUREDP: emitSUREDx(); break; default: assert(!"invalid opcode"); emitNOP(); ret = false; break; } if (insn->join) { /*XXX*/ } code += 2; codeSize += 8; return ret; } uint32_t CodeEmitterGM107::getMinEncodingSize(const Instruction *i) const { return 8; } /******************************************************************************* * sched data calculator ******************************************************************************/ class SchedDataCalculatorGM107 : public Pass { public: SchedDataCalculatorGM107(const Target *targ) : targ(targ) {} private: const Target *targ; bool visit(BasicBlock *bb); }; bool SchedDataCalculatorGM107::visit(BasicBlock *bb) { for (Instruction *insn = bb->getEntry(); insn; insn = insn->next) { /*XXX*/ insn->sched = 0x7e0; } return true; } /******************************************************************************* * main ******************************************************************************/ void CodeEmitterGM107::prepareEmission(Function *func) { SchedDataCalculatorGM107 sched(targ); CodeEmitter::prepareEmission(func); sched.run(func, true, true); } static inline uint32_t sizeToBundlesGM107(uint32_t size) { return (size + 23) / 24; } void CodeEmitterGM107::prepareEmission(Program *prog) { for (ArrayList::Iterator fi = prog->allFuncs.iterator(); !fi.end(); fi.next()) { Function *func = reinterpret_cast(fi.get()); func->binPos = prog->binSize; prepareEmission(func); // adjust sizes & positions for schedulding info: if (prog->getTarget()->hasSWSched) { uint32_t adjPos = func->binPos; BasicBlock *bb = NULL; for (int i = 0; i < func->bbCount; ++i) { bb = func->bbArray[i]; int32_t adjSize = bb->binSize; if (adjPos % 32) { adjSize -= 32 - adjPos % 32; if (adjSize < 0) adjSize = 0; } adjSize = bb->binSize + sizeToBundlesGM107(adjSize) * 8; bb->binPos = adjPos; bb->binSize = adjSize; adjPos += adjSize; } if (bb) func->binSize = adjPos - func->binPos; } prog->binSize += func->binSize; } } CodeEmitterGM107::CodeEmitterGM107(const TargetGM107 *target) : CodeEmitter(target), targGM107(target), writeIssueDelays(target->hasSWSched) { code = NULL; codeSize = codeSizeLimit = 0; relocInfo = NULL; } CodeEmitter * TargetGM107::createCodeEmitterGM107(Program::Type type) { CodeEmitterGM107 *emit = new CodeEmitterGM107(this); emit->setProgramType(type); return emit; } } // namespace nv50_ir