{ OP_MUL, 0x3, 0x0, 0x0, 0x8, 0x2, 0x2 | 0x8 },
{ OP_MAX, 0x3, 0x3, 0x0, 0x0, 0x2, 0x2 },
{ OP_MIN, 0x3, 0x3, 0x0, 0x0, 0x2, 0x2 },
- { OP_MAD, 0x7, 0x0, 0x0, 0x8, 0x6, 0x2 | 0x8 }, // special c[] constraint
+ { OP_MAD, 0x7, 0x0, 0x0, 0x8, 0x6, 0x2 }, // special c[] constraint
+ { OP_FMA, 0x7, 0x0, 0x0, 0x8, 0x6, 0x2 }, // keep the same as OP_MAD
+ { OP_SHLADD, 0x5, 0x0, 0x0, 0x0, 0x4, 0x6 },
{ OP_MADSP, 0x0, 0x0, 0x0, 0x0, 0x6, 0x2 },
{ OP_ABS, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0 },
{ OP_NEG, 0x0, 0x1, 0x0, 0x0, 0x1, 0x0 },
// saturate only:
{ OP_LINTERP, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0 },
{ OP_PINTERP, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0 },
- // nve4 ops:
+};
+
+static const struct opProperties _initPropsNVE4[] = {
{ OP_SULDB, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0 },
{ OP_SUSTB, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0 },
{ OP_SUSTP, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0 },
{ OP_SUEAU, 0x0, 0x0, 0x0, 0x0, 0x6, 0x2 }
};
+static const struct opProperties _initPropsGM107[] = {
+ { OP_SULDB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2 },
+ { OP_SULDP, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2 },
+ { OP_SUSTB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4 },
+ { OP_SUSTP, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4 },
+ { OP_SUREDB, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4 },
+ { OP_SUREDP, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4 },
+};
+
+void TargetNVC0::initProps(const struct opProperties *props, int size)
+{
+ for (int i = 0; i < size; ++i) {
+ const struct opProperties *prop = &props[i];
+
+ for (int s = 0; s < 3; ++s) {
+ if (prop->mNeg & (1 << s))
+ opInfo[prop->op].srcMods[s] |= NV50_IR_MOD_NEG;
+ if (prop->mAbs & (1 << s))
+ opInfo[prop->op].srcMods[s] |= NV50_IR_MOD_ABS;
+ if (prop->mNot & (1 << s))
+ opInfo[prop->op].srcMods[s] |= NV50_IR_MOD_NOT;
+ if (prop->fConst & (1 << s))
+ opInfo[prop->op].srcFiles[s] |= 1 << (int)FILE_MEMORY_CONST;
+ if (prop->fImmd & (1 << s))
+ opInfo[prop->op].srcFiles[s] |= 1 << (int)FILE_IMMEDIATE;
+ if (prop->fImmd & 8)
+ opInfo[prop->op].immdBits = 0xffffffff;
+ }
+ if (prop->mSat & 8)
+ opInfo[prop->op].dstMods = NV50_IR_MOD_SAT;
+ }
+}
+
void TargetNVC0::initOpInfo()
{
unsigned int i, j;
static const uint32_t commutative[(OP_LAST + 31) / 32] =
{
- // ADD, MAD, MUL, AND, OR, XOR, MAX, MIN
- 0x0670ca00, 0x0000003f, 0x00000000, 0x00000000
+ // ADD, MUL, MAD, FMA, AND, OR, XOR, MAX, MIN, SET_AND, SET_OR, SET_XOR,
+ // SET, SELP, SLCT
+ 0x0ce0ca00, 0x0000007e, 0x00000000, 0x00000000
};
static const uint32_t shortForm[(OP_LAST + 31) / 32] =
{
- // ADD, MAD, MUL, AND, OR, XOR, PRESIN, PREEX2, SFN, CVT, PINTERP, MOV
- 0x0670ca00, 0x00000000, 0x00000000, 0x00000000
+ // ADD, MUL, MAD, FMA, AND, OR, XOR, MAX, MIN
+ 0x0ce0ca00, 0x00000000, 0x00000000, 0x00000000
};
static const operation noDest[] =
for (i = 0; i < sizeof(noPred) / sizeof(noPred[0]); ++i)
opInfo[noPred[i]].predicate = 0;
- for (i = 0; i < sizeof(_initProps) / sizeof(_initProps[0]); ++i) {
- const struct opProperties *prop = &_initProps[i];
-
- for (int s = 0; s < 3; ++s) {
- if (prop->mNeg & (1 << s))
- opInfo[prop->op].srcMods[s] |= NV50_IR_MOD_NEG;
- if (prop->mAbs & (1 << s))
- opInfo[prop->op].srcMods[s] |= NV50_IR_MOD_ABS;
- if (prop->mNot & (1 << s))
- opInfo[prop->op].srcMods[s] |= NV50_IR_MOD_NOT;
- if (prop->fConst & (1 << s))
- opInfo[prop->op].srcFiles[s] |= 1 << (int)FILE_MEMORY_CONST;
- if (prop->fImmd & (1 << s))
- opInfo[prop->op].srcFiles[s] |= 1 << (int)FILE_IMMEDIATE;
- if (prop->fImmd & 8)
- opInfo[prop->op].immdBits = 0xffffffff;
- }
- if (prop->mSat & 8)
- opInfo[prop->op].dstMods = NV50_IR_MOD_SAT;
- }
+ initProps(_initProps, ARRAY_SIZE(_initProps));
+ if (chipset >= NVISA_GM107_CHIPSET)
+ initProps(_initPropsGM107, ARRAY_SIZE(_initPropsGM107));
+ else if (chipset >= NVISA_GK104_CHIPSET)
+ initProps(_initPropsNVE4, ARRAY_SIZE(_initPropsNVE4));
}
unsigned int
case SV_NTID: return kepler ? (0x00 + idx * 4) : ~0;
case SV_NCTAID: return kepler ? (0x0c + idx * 4) : ~0;
case SV_GRIDID: return kepler ? 0x18 : ~0;
+ case SV_WORK_DIM: return 0x1c;
case SV_SAMPLE_INDEX: return 0;
case SV_SAMPLE_POS: return 0;
case SV_SAMPLE_MASK: return 0;
// indirect loads can only be done by OP_LOAD/VFETCH/INTERP on nvc0
if (ld->src(0).isIndirect(0))
return false;
+ // these are implemented using shf.r and shf.l which can't load consts
+ if ((i->op == OP_SHL || i->op == OP_SHR) && typeSizeof(i->sType) == 8 &&
+ sf == FILE_MEMORY_CONST)
+ return false;
for (int k = 0; i->srcExists(k); ++k) {
if (i->src(k).getFile() == FILE_IMMEDIATE) {
if (k == 2 && i->op == OP_SUCLAMP) // special case
continue;
+ if (k == 1 && i->op == OP_SHLADD) // special case
+ continue;
if (i->getSrc(k)->reg.data.u64 != 0)
return false;
} else
if (i->src(k).getFile() != FILE_GPR &&
- i->src(k).getFile() != FILE_PREDICATE) {
+ i->src(k).getFile() != FILE_PREDICATE &&
+ i->src(k).getFile() != FILE_FLAGS) {
return false;
}
}
return false;
}
} else
- if (i->op == OP_MAD || i->op == OP_FMA) {
- // requires src == dst, cannot decide before RA
- // (except if we implement more constraints)
- if (ld->getSrc(0)->asImm()->reg.data.u32 & 0xfff)
- return false;
- } else
if (i->op == OP_ADD && i->sType == TYPE_F32) {
// add f32 LIMM cannot saturate
if (i->saturate && (reg.data.u32 & 0xfff))
{
if (ty == TYPE_NONE)
return false;
- if (file == FILE_MEMORY_CONST && getChipset() >= 0xe0) // wrong encoding ?
- return typeSizeof(ty) <= 8;
+ if (file == FILE_MEMORY_CONST) {
+ if (getChipset() >= NVISA_GM107_CHIPSET)
+ return typeSizeof(ty) <= 4;
+ else
+ if (getChipset() >= NVISA_GK104_CHIPSET) // wrong encoding ?
+ return typeSizeof(ty) <= 8;
+ }
if (ty == TYPE_B96)
return false;
return true;
if (s == 0)
return insn->src(1).mod.neg() ? false : true;
break;
+ case OP_SHLADD:
+ if (s == 1)
+ return false;
+ if (insn->src(s ? 0 : 2).mod.neg())
+ return false;
+ break;
default:
return false;
}
// not if the 2nd instruction isn't necessarily executed
if (clA == OPCLASS_TEXTURE || clA == OPCLASS_FLOW)
return false;
+
+ // Check that a and b don't write to the same sources, nor that b reads
+ // anything that a writes.
+ if (!a->canCommuteDefDef(b) || !a->canCommuteDefSrc(b))
+ return false;
+
// anything with MOV
if (a->op == OP_MOV || b->op == OP_MOV)
return true;
if (clA == clB) {
- // only F32 arith or integer additions
- if (clA != OPCLASS_ARITH)
+ switch (clA) {
+ // there might be more
+ case OPCLASS_COMPARE:
+ if ((a->op == OP_MIN || a->op == OP_MAX) &&
+ (b->op == OP_MIN || b->op == OP_MAX))
+ break;
return false;
+ case OPCLASS_ARITH:
+ break;
+ default:
+ return false;
+ }
+ // only F32 arith or integer additions
return (a->dType == TYPE_F32 || a->op == OP_ADD ||
b->dType == TYPE_F32 || b->op == OP_ADD);
}