void emitUADD(const Instruction *);
void emitAADD(const Instruction *);
void emitFADD(const Instruction *);
+ void emitDADD(const Instruction *);
void emitIMUL(const Instruction *);
void emitFMUL(const Instruction *);
+ void emitDMUL(const Instruction *);
void emitFMAD(const Instruction *);
+ void emitDMAD(const Instruction *);
void emitIMAD(const Instruction *);
void emitISAD(const Instruction *);
mode |= 3 << (s * 2);
break;
default:
- ERROR("invalid file on source %i: %u\n", s, i->src(s).getFile());
+ ERROR("invalid file on source %i: %u\n", s, i->src(s).getFile());
assert(0);
break;
}
return;
if ((mode & 3) == 1) {
- const int pos = i->src(1).getFile() == FILE_IMMEDIATE ? 13 : 14;
+ const int pos = ((mode >> 2) & 3) == 3 ? 13 : 14;
- switch (i->getSrc(0)->reg.type) {
+ switch (i->sType) {
case TYPE_U8:
break;
case TYPE_U16:
setSrc(i, 2, 2);
if (i->getIndirect(0, 0)) {
- assert(!i->getIndirect(1, 0));
+ assert(!i->srcExists(1) || !i->getIndirect(1, 0));
+ assert(!i->srcExists(2) || !i->getIndirect(2, 0));
setAReg16(i, 0);
- } else {
+ } else if (i->srcExists(1) && i->getIndirect(1, 0)) {
+ assert(!i->srcExists(2) || !i->getIndirect(2, 0));
setAReg16(i, 1);
+ } else {
+ setAReg16(i, 2);
}
}
}
// usual immediate form
-// - 1 to 3 sources where last is immediate (rir, gir)
+// - 1 to 3 sources where second is immediate (rir, gir)
// - no address or predicate possible
void
CodeEmitterNV50::emitForm_IMM(const Instruction *i)
if (Target::operationSrcNr[i->op] > 1) {
setSrc(i, 0, 0);
setImmediate(i, 1);
- setSrc(i, 2, 1);
+ // If there is another source, it has to be the same as the dest reg.
} else {
setImmediate(i, 0);
}
assert(sf == FILE_GPR || df == FILE_GPR);
if (sf == FILE_FLAGS) {
+ assert(i->flagsSrc >= 0);
code[0] = 0x00000001;
code[1] = 0x20000000;
defId(i->def(0), 2);
- srcId(i->src(0), 12);
emitFlagsRd(i);
} else
if (sf == FILE_ADDRESS) {
emitFlagsRd(i);
} else
if (df == FILE_FLAGS) {
+ assert(i->flagsDef >= 0);
code[0] = 0x00000001;
code[1] = 0xa0000000;
- defId(i->def(0), 4);
srcId(i->src(0), 9);
emitFlagsRd(i);
+ emitFlagsWr(i);
} else
if (sf == FILE_IMMEDIATE) {
code[0] = 0x10008001;
emitFlagsRd(i);
}
+static void
+interpApply(const InterpEntry *entry, uint32_t *code,
+ bool force_persample_interp, bool flatshade)
+{
+ int ipa = entry->ipa;
+ int encSize = entry->reg;
+ int loc = entry->loc;
+
+ if ((ipa & NV50_IR_INTERP_SAMPLE_MASK) == NV50_IR_INTERP_DEFAULT &&
+ (ipa & NV50_IR_INTERP_MODE_MASK) != NV50_IR_INTERP_FLAT) {
+ if (force_persample_interp) {
+ if (encSize == 8)
+ code[loc + 1] |= 1 << 16;
+ else
+ code[loc + 0] |= 1 << 24;
+ } else {
+ if (encSize == 8)
+ code[loc + 1] &= ~(1 << 16);
+ else
+ code[loc + 0] &= ~(1 << 24);
+ }
+ }
+}
+
void
CodeEmitterNV50::emitINTERP(const Instruction *i)
{
defId(i->def(0), 2);
srcAddr8(i->src(0), 16);
- if (i->getInterpMode() == NV50_IR_INTERP_FLAT) {
+ if (i->encSize != 8 && i->getInterpMode() == NV50_IR_INTERP_FLAT) {
code[0] |= 1 << 8;
} else {
if (i->op == OP_PINTERP) {
}
if (i->encSize == 8) {
- code[1] =
- (code[0] & (3 << 24)) >> (24 - 16) |
- (code[0] & (1 << 8)) << (18 - 8);
- code[0] &= ~0x03000100;
+ if (i->getInterpMode() == NV50_IR_INTERP_FLAT)
+ code[1] = 4 << 16;
+ else
+ code[1] = (code[0] & (3 << 24)) >> (24 - 16);
+ code[0] &= ~0x03000000;
code[0] |= 1;
emitFlagsRd(i);
}
+
+ addInterp(i->ipa, i->encSize, interpApply);
}
void
assert(0);
break;
}
- code[1] |= i->src(0).mod.abs() << 20;
- code[1] |= i->src(0).mod.neg() << 26;
- code[1] |= i->src(1).mod.abs() << 19;
- code[1] |= i->src(1).mod.neg() << 27;
}
+
+ code[1] |= i->src(0).mod.abs() << 20;
+ code[1] |= i->src(0).mod.neg() << 26;
+ code[1] |= i->src(1).mod.abs() << 19;
+ code[1] |= i->src(1).mod.neg() << 27;
+
emitForm_MAD(i);
}
code[0] = 0xe0000000;
+ if (i->src(1).getFile() == FILE_IMMEDIATE) {
+ code[1] = 0;
+ emitForm_IMM(i);
+ code[0] |= neg_mul << 15;
+ code[0] |= neg_add << 22;
+ if (i->saturate)
+ code[0] |= 1 << 8;
+ } else
if (i->encSize == 4) {
emitForm_MUL(i);
- assert(!neg_mul && !neg_add);
+ code[0] |= neg_mul << 15;
+ code[0] |= neg_add << 22;
+ if (i->saturate)
+ code[0] |= 1 << 8;
} else {
code[1] = neg_mul << 26;
code[1] |= neg_add << 27;
}
}
+void
+CodeEmitterNV50::emitDMAD(const Instruction *i)
+{
+ const int neg_mul = i->src(0).mod.neg() ^ i->src(1).mod.neg();
+ const int neg_add = i->src(2).mod.neg();
+
+ assert(i->encSize == 8);
+ assert(!i->saturate);
+
+ code[1] = 0x40000000;
+ code[0] = 0xe0000000;
+
+ code[1] |= neg_mul << 26;
+ code[1] |= neg_add << 27;
+
+ roundMode_MAD(i);
+
+ emitForm_MAD(i);
+}
+
void
CodeEmitterNV50::emitFADD(const Instruction *i)
{
}
}
+void
+CodeEmitterNV50::emitDADD(const Instruction *i)
+{
+ const int neg0 = i->src(0).mod.neg();
+ const int neg1 = i->src(1).mod.neg() ^ ((i->op == OP_SUB) ? 1 : 0);
+
+ assert(!(i->src(0).mod | i->src(1).mod).abs());
+ assert(!i->saturate);
+ assert(i->encSize == 8);
+
+ code[1] = 0x60000000;
+ code[0] = 0xe0000000;
+
+ emitForm_ADD(i);
+
+ code[1] |= neg0 << 26;
+ code[1] |= neg1 << 27;
+}
+
void
CodeEmitterNV50::emitUADD(const Instruction *i)
{
{
code[0] = 0x40000000;
+ if (i->src(1).getFile() == FILE_IMMEDIATE) {
+ if (i->sType == TYPE_S16)
+ code[0] |= 0x8100;
+ code[1] = 0;
+ emitForm_IMM(i);
+ } else
if (i->encSize == 8) {
code[1] = (i->sType == TYPE_S16) ? (0x8000 | 0x4000) : 0x0000;
emitForm_MAD(i);
emitForm_IMM(i);
if (neg)
code[0] |= 0x8000;
+ if (i->saturate)
+ code[0] |= 1 << 8;
} else
if (i->encSize == 8) {
code[1] = i->rnd == ROUND_Z ? 0x0000c000 : 0;
if (neg)
code[1] |= 0x08000000;
+ if (i->saturate)
+ code[1] |= 1 << 20;
emitForm_MAD(i);
} else {
emitForm_MUL(i);
if (neg)
code[0] |= 0x8000;
+ if (i->saturate)
+ code[0] |= 1 << 8;
}
}
void
-CodeEmitterNV50::emitIMAD(const Instruction *i)
+CodeEmitterNV50::emitDMUL(const Instruction *i)
{
- code[0] = 0x60000000;
- if (isSignedType(i->sType))
- code[1] = i->saturate ? 0x40000000 : 0x20000000;
- else
- code[1] = 0x00000000;
+ const int neg = (i->src(0).mod ^ i->src(1).mod).neg();
- int neg1 = i->src(0).mod.neg() ^ i->src(1).mod.neg();
- int neg2 = i->src(2).mod.neg();
+ assert(!i->saturate);
+ assert(i->encSize == 8);
- assert(!(neg1 & neg2));
- code[1] |= neg1 << 27;
- code[1] |= neg2 << 26;
+ code[1] = 0x80000000;
+ code[0] = 0xe0000000;
+
+ if (neg)
+ code[1] |= 0x08000000;
+
+ roundMode_CVT(i->rnd);
emitForm_MAD(i);
+}
- if (i->flagsSrc >= 0) {
- // add with carry from $cX
- assert(!(code[1] & 0x0c000000) && !i->getPredicate());
- code[1] |= 0xc << 24;
- srcId(i->src(i->flagsSrc), 32 + 12);
+void
+CodeEmitterNV50::emitIMAD(const Instruction *i)
+{
+ int mode;
+ code[0] = 0x60000000;
+
+ assert(!i->src(0).mod && !i->src(1).mod && !i->src(2).mod);
+ if (!isSignedType(i->sType))
+ mode = 0;
+ else if (i->saturate)
+ mode = 2;
+ else
+ mode = 1;
+
+ if (i->src(1).getFile() == FILE_IMMEDIATE) {
+ code[1] = 0;
+ emitForm_IMM(i);
+ code[0] |= (mode & 1) << 8 | (mode & 2) << 14;
+ if (i->flagsSrc >= 0) {
+ assert(!(code[0] & 0x10400000));
+ assert(SDATA(i->src(i->flagsSrc)).id == 0);
+ code[0] |= 0x10400000;
+ }
+ } else
+ if (i->encSize == 4) {
+ emitForm_MUL(i);
+ code[0] |= (mode & 1) << 8 | (mode & 2) << 14;
+ if (i->flagsSrc >= 0) {
+ assert(!(code[0] & 0x10400000));
+ assert(SDATA(i->src(i->flagsSrc)).id == 0);
+ code[0] |= 0x10400000;
+ }
+ } else {
+ code[1] = mode << 29;
+ emitForm_MAD(i);
+
+ if (i->flagsSrc >= 0) {
+ // add with carry from $cX
+ assert(!(code[1] & 0x0c000000) && !i->getPredicate());
+ code[1] |= 0xc << 24;
+ srcId(i->src(i->flagsSrc), 32 + 12);
+ }
}
}
code[0] = 0x30000000;
code[1] = 0x60000000;
- emitCondCode(i->asCmp()->setCond, i->sType, 32 + 14);
-
switch (i->sType) {
+ case TYPE_F64:
+ code[0] = 0xe0000000;
+ code[1] = 0xe0000000;
+ break;
case TYPE_F32: code[0] |= 0x80000000; break;
case TYPE_S32: code[1] |= 0x0c000000; break;
case TYPE_U32: code[1] |= 0x04000000; break;
assert(0);
break;
}
+
+ emitCondCode(i->asCmp()->setCond, i->sType, 32 + 14);
+
if (i->src(0).mod.neg()) code[1] |= 0x04000000;
if (i->src(1).mod.neg()) code[1] |= 0x08000000;
if (i->src(0).mod.abs()) code[1] |= 0x00100000;
if (i->encSize == 4) {
assert(i->op == OP_RCP);
+ assert(!i->saturate);
code[0] |= i->src(0).mod.abs() << 15;
code[0] |= i->src(0).mod.neg() << 22;
emitForm_MUL(i);
code[1] = subOp << 29;
code[1] |= i->src(0).mod.abs() << 20;
code[1] |= i->src(0).mod.neg() << 26;
+ if (i->saturate) {
+ assert(subOp == 6 && i->op == OP_EX2);
+ code[1] |= 1 << 27;
+ }
emitForm_MAD(i);
}
}
break;
case OP_ADD:
case OP_SUB:
- if (isFloatType(insn->dType))
+ if (insn->dType == TYPE_F64)
+ emitDADD(insn);
+ else if (isFloatType(insn->dType))
emitFADD(insn);
else if (insn->getDef(0)->reg.file == FILE_ADDRESS)
emitAADD(insn);
emitUADD(insn);
break;
case OP_MUL:
- if (isFloatType(insn->dType))
+ if (insn->dType == TYPE_F64)
+ emitDMUL(insn);
+ else if (isFloatType(insn->dType))
emitFMUL(insn);
else
emitIMUL(insn);
break;
case OP_MAD:
case OP_FMA:
- if (isFloatType(insn->dType))
+ if (insn->dType == TYPE_F64)
+ emitDMAD(insn);
+ else if (isFloatType(insn->dType))
emitFMAD(insn);
else
emitIMAD(insn);
{
const Target::OpInfo &info = targ->getOpInfo(i);
- if (info.minEncSize > 4)
+ if (info.minEncSize > 4 || i->dType == TYPE_F64)
return 8;
// check constraints on dst and src operands
// check constraints on short MAD
if (info.srcNr >= 2 && i->srcExists(2)) {
- if (i->saturate || i->src(2).mod)
- return 8;
- if ((i->src(0).mod ^ i->src(1).mod) ||
- (i->src(0).mod | i->src(1).mod).abs())
- return 8;
if (!i->defExists(0) ||
- i->def(0).rep()->reg.data.id != i->src(2).rep()->reg.data.id)
+ (i->flagsSrc >= 0 && SDATA(i->src(i->flagsSrc)).id > 0) ||
+ DDATA(i->def(0)).id != SDATA(i->src(2)).id)
return 8;
}