}
bool
-NVC0LoweringPass::handleSUQ(Instruction *suq)
+NVC0LoweringPass::handleBUFQ(Instruction *bufq)
{
- suq->op = OP_MOV;
- suq->setSrc(0, loadResLength32(suq->getIndirect(0, 1),
- suq->getSrc(0)->reg.fileIndex * 16));
- suq->setIndirect(0, 0, NULL);
- suq->setIndirect(0, 1, NULL);
+ bufq->op = OP_MOV;
+ bufq->setSrc(0, loadBufLength32(bufq->getIndirect(0, 1),
+ bufq->getSrc(0)->reg.fileIndex * 16));
+ bufq->setIndirect(0, 0, NULL);
+ bufq->setIndirect(0, 1, NULL);
return true;
}
+void
+NVC0LoweringPass::handleSharedATOMNVE4(Instruction *atom)
+{
+ assert(atom->src(0).getFile() == FILE_MEMORY_SHARED);
+
+ BasicBlock *currBB = atom->bb;
+ BasicBlock *tryLockBB = atom->bb->splitBefore(atom, false);
+ BasicBlock *joinBB = atom->bb->splitAfter(atom);
+ BasicBlock *setAndUnlockBB = new BasicBlock(func);
+ BasicBlock *failLockBB = new BasicBlock(func);
+
+ bld.setPosition(currBB, true);
+ assert(!currBB->joinAt);
+ currBB->joinAt = bld.mkFlow(OP_JOINAT, joinBB, CC_ALWAYS, NULL);
+
+ CmpInstruction *pred =
+ bld.mkCmp(OP_SET, CC_EQ, TYPE_U32, bld.getSSA(1, FILE_PREDICATE),
+ TYPE_U32, bld.mkImm(0), bld.mkImm(1));
+
+ bld.mkFlow(OP_BRA, tryLockBB, CC_ALWAYS, NULL);
+ currBB->cfg.attach(&tryLockBB->cfg, Graph::Edge::TREE);
+
+ bld.setPosition(tryLockBB, true);
+
+ Instruction *ld =
+ bld.mkLoad(TYPE_U32, atom->getDef(0),
+ bld.mkSymbol(FILE_MEMORY_SHARED, 0, TYPE_U32, 0), NULL);
+ ld->setDef(1, bld.getSSA(1, FILE_PREDICATE));
+ ld->subOp = NV50_IR_SUBOP_LOAD_LOCKED;
+
+ bld.mkFlow(OP_BRA, setAndUnlockBB, CC_P, ld->getDef(1));
+ bld.mkFlow(OP_BRA, failLockBB, CC_ALWAYS, NULL);
+ tryLockBB->cfg.attach(&failLockBB->cfg, Graph::Edge::CROSS);
+ tryLockBB->cfg.attach(&setAndUnlockBB->cfg, Graph::Edge::TREE);
+
+ tryLockBB->cfg.detach(&joinBB->cfg);
+ bld.remove(atom);
+
+ bld.setPosition(setAndUnlockBB, true);
+ Value *stVal;
+ if (atom->subOp == NV50_IR_SUBOP_ATOM_EXCH) {
+ // Read the old value, and write the new one.
+ stVal = atom->getSrc(1);
+ } else if (atom->subOp == NV50_IR_SUBOP_ATOM_CAS) {
+ CmpInstruction *set =
+ bld.mkCmp(OP_SET, CC_EQ, TYPE_U32, bld.getSSA(),
+ TYPE_U32, ld->getDef(0), atom->getSrc(1));
+
+ bld.mkCmp(OP_SLCT, CC_NE, TYPE_U32, (stVal = bld.getSSA()),
+ TYPE_U32, atom->getSrc(2), ld->getDef(0), set->getDef(0));
+ } else {
+ operation op;
+
+ switch (atom->subOp) {
+ case NV50_IR_SUBOP_ATOM_ADD:
+ op = OP_ADD;
+ break;
+ case NV50_IR_SUBOP_ATOM_AND:
+ op = OP_AND;
+ break;
+ case NV50_IR_SUBOP_ATOM_OR:
+ op = OP_OR;
+ break;
+ case NV50_IR_SUBOP_ATOM_XOR:
+ op = OP_XOR;
+ break;
+ case NV50_IR_SUBOP_ATOM_MIN:
+ op = OP_MIN;
+ break;
+ case NV50_IR_SUBOP_ATOM_MAX:
+ op = OP_MAX;
+ break;
+ default:
+ assert(0);
+ return;
+ }
+
+ stVal = bld.mkOp2v(op, atom->dType, bld.getSSA(), ld->getDef(0),
+ atom->getSrc(1));
+ }
+
+ Instruction *st =
+ bld.mkStore(OP_STORE, TYPE_U32,
+ bld.mkSymbol(FILE_MEMORY_SHARED, 0, TYPE_U32, 0),
+ NULL, stVal);
+ st->setDef(0, pred->getDef(0));
+ st->subOp = NV50_IR_SUBOP_STORE_UNLOCKED;
+
+ bld.mkFlow(OP_BRA, failLockBB, CC_ALWAYS, NULL);
+ setAndUnlockBB->cfg.attach(&failLockBB->cfg, Graph::Edge::TREE);
+
+ // Lock until the store has not been performed.
+ bld.setPosition(failLockBB, true);
+ bld.mkFlow(OP_BRA, tryLockBB, CC_NOT_P, pred->getDef(0));
+ bld.mkFlow(OP_BRA, joinBB, CC_ALWAYS, NULL);
+ failLockBB->cfg.attach(&tryLockBB->cfg, Graph::Edge::BACK);
+ failLockBB->cfg.attach(&joinBB->cfg, Graph::Edge::TREE);
+
+ bld.setPosition(joinBB, false);
+ bld.mkFlow(OP_JOIN, NULL, CC_ALWAYS, NULL)->fixed = 1;
+}
+
void
NVC0LoweringPass::handleSharedATOM(Instruction *atom)
{
sv = SV_LBASE;
break;
case FILE_MEMORY_SHARED:
- handleSharedATOM(atom);
+ // For Fermi/Kepler, we have to use ld lock/st unlock to perform atomic
+ // operations on shared memory. For Maxwell, ATOMS is enough.
+ if (targ->getChipset() < NVISA_GK104_CHIPSET)
+ handleSharedATOM(atom);
+ else if (targ->getChipset() < NVISA_GM107_CHIPSET)
+ handleSharedATOMNVE4(atom);
return true;
default:
- assert(atom->src(0).getFile() == FILE_MEMORY_GLOBAL);
- base = loadResInfo64(ind, atom->getSrc(0)->reg.fileIndex * 16);
+ assert(atom->src(0).getFile() == FILE_MEMORY_BUFFER);
+ base = loadBufInfo64(ind, atom->getSrc(0)->reg.fileIndex * 16);
assert(base->reg.size == 8);
if (ptr)
base = bld.mkOp2v(OP_ADD, TYPE_U64, base, base, ptr);
assert(base->reg.size == 8);
atom->setIndirect(0, 0, base);
+ atom->getSrc(0)->reg.file = FILE_MEMORY_GLOBAL;
return true;
}
base =
bool
NVC0LoweringPass::handleCasExch(Instruction *cas, bool needCctl)
{
- if (cas->src(0).getFile() == FILE_MEMORY_SHARED) {
- // ATOM_CAS and ATOM_EXCH are handled in handleSharedATOM().
- return false;
+ if (targ->getChipset() < NVISA_GM107_CHIPSET) {
+ if (cas->src(0).getFile() == FILE_MEMORY_SHARED) {
+ // ATOM_CAS and ATOM_EXCH are handled in handleSharedATOM().
+ return false;
+ }
}
if (cas->subOp != NV50_IR_SUBOP_ATOM_CAS &&
}
inline Value *
-NVC0LoweringPass::loadResInfo32(Value *ptr, uint32_t off)
+NVC0LoweringPass::loadResInfo32(Value *ptr, uint32_t off, uint16_t base)
{
uint8_t b = prog->driver->io.auxCBSlot;
- off += prog->driver->io.suInfoBase;
+ off += base;
+
return bld.
mkLoadv(TYPE_U32, bld.mkSymbol(FILE_MEMORY_CONST, b, TYPE_U32, off), ptr);
}
inline Value *
-NVC0LoweringPass::loadResInfo64(Value *ptr, uint32_t off)
+NVC0LoweringPass::loadResInfo64(Value *ptr, uint32_t off, uint16_t base)
{
uint8_t b = prog->driver->io.auxCBSlot;
- off += prog->driver->io.suInfoBase;
+ off += base;
if (ptr)
ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getScratch(), ptr, bld.mkImm(4));
}
inline Value *
-NVC0LoweringPass::loadResLength32(Value *ptr, uint32_t off)
+NVC0LoweringPass::loadResLength32(Value *ptr, uint32_t off, uint16_t base)
{
uint8_t b = prog->driver->io.auxCBSlot;
- off += prog->driver->io.suInfoBase;
+ off += base;
if (ptr)
ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getScratch(), ptr, bld.mkImm(4));
mkLoadv(TYPE_U32, bld.mkSymbol(FILE_MEMORY_CONST, b, TYPE_U64, off + 8), ptr);
}
+inline Value *
+NVC0LoweringPass::loadSuInfo32(Value *ptr, uint32_t off)
+{
+ return loadResInfo32(ptr, off, prog->driver->io.suInfoBase);
+}
+
+inline Value *
+NVC0LoweringPass::loadSuInfo64(Value *ptr, uint32_t off)
+{
+ return loadResInfo64(ptr, off, prog->driver->io.suInfoBase);
+}
+
+inline Value *
+NVC0LoweringPass::loadSuLength32(Value *ptr, uint32_t off)
+{
+ return loadResLength32(ptr, off, prog->driver->io.suInfoBase);
+}
+
+inline Value *
+NVC0LoweringPass::loadBufInfo32(Value *ptr, uint32_t off)
+{
+ return loadResInfo32(ptr, off, prog->driver->io.bufInfoBase);
+}
+
+inline Value *
+NVC0LoweringPass::loadBufInfo64(Value *ptr, uint32_t off)
+{
+ return loadResInfo64(ptr, off, prog->driver->io.bufInfoBase);
+}
+
+inline Value *
+NVC0LoweringPass::loadBufLength32(Value *ptr, uint32_t off)
+{
+ return loadResLength32(ptr, off, prog->driver->io.bufInfoBase);
+}
+
+inline Value *
+NVC0LoweringPass::loadUboInfo32(Value *ptr, uint32_t off)
+{
+ return loadResInfo32(ptr, off, prog->driver->io.uboInfoBase);
+}
+
+inline Value *
+NVC0LoweringPass::loadUboInfo64(Value *ptr, uint32_t off)
+{
+ return loadResInfo64(ptr, off, prog->driver->io.uboInfoBase);
+}
+
+inline Value *
+NVC0LoweringPass::loadUboLength32(Value *ptr, uint32_t off)
+{
+ return loadResLength32(ptr, off, prog->driver->io.uboInfoBase);
+}
+
inline Value *
NVC0LoweringPass::loadMsInfo32(Value *ptr, uint32_t off)
{
}
}
+bool
+NVC0LoweringPass::handleSUQ(TexInstruction *suq)
+{
+ int dim = suq->tex.target.getDim();
+ int arg = dim + (suq->tex.target.isArray() || suq->tex.target.isCube());
+ uint8_t s = prog->driver->io.auxCBSlot;
+ Value *ind = suq->getIndirectR();
+ uint32_t base;
+ int c;
+
+ base = prog->driver->io.suInfoBase + suq->tex.r * NVE4_SU_INFO__STRIDE;
+
+ if (ind)
+ ind = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getScratch(),
+ ind, bld.mkImm(6));
+
+ for (c = 0; c < arg; ++c) {
+ if (suq->defExists(c)) {
+ int offset;
+
+ if (c == 1 && suq->tex.target == TEX_TARGET_1D_ARRAY) {
+ offset = base + NVE4_SU_INFO_SIZE(2);
+ } else {
+ offset = base + NVE4_SU_INFO_SIZE(c);
+ }
+ bld.mkLoad(TYPE_U32, suq->getDef(c),
+ bld.mkSymbol(FILE_MEMORY_CONST, s, TYPE_U32, offset), ind);
+ }
+ }
+
+ if (suq->tex.target.isCube()) {
+ if (suq->defExists(2)) {
+ bld.mkOp2(OP_DIV, TYPE_U32, suq->getDef(2), suq->getDef(2),
+ bld.loadImm(NULL, 6));
+ }
+ }
+
+ if (suq->defExists(3)) {
+ // .w contains the number of samples for multi-sampled images but we
+ // don't support them for now.
+ bld.mkMov(suq->getDef(3), bld.loadImm(NULL, 1));
+ }
+
+ bld.remove(suq);
+ return true;
+}
+
void
NVC0LoweringPass::adjustCoordinatesMS(TexInstruction *tex)
{
Value *tx = bld.getSSA(), *ty = bld.getSSA(), *ts = bld.getSSA();
- Value *ms_x = loadResInfo32(NULL, base + NVE4_SU_INFO_MS(0));
- Value *ms_y = loadResInfo32(NULL, base + NVE4_SU_INFO_MS(1));
+ Value *ms_x = loadSuInfo32(NULL, base + NVE4_SU_INFO_MS(0));
+ Value *ms_y = loadSuInfo32(NULL, base + NVE4_SU_INFO_MS(1));
bld.mkOp2(OP_SHL, TYPE_U32, tx, x, ms_x);
bld.mkOp2(OP_SHL, TYPE_U32, ty, y, ms_y);
su->op == OP_SULDB || su->op == OP_SUSTB || su->op == OP_SUREDB;
const int idx = su->tex.r;
const int dim = su->tex.target.getDim();
- const int arg = dim + (su->tex.target.isArray() ? 1 : 0);
+ const int arg = dim + (su->tex.target.isArray() || su->tex.target.isCube());
const uint16_t base = idx * NVE4_SU_INFO__STRIDE;
int c;
Value *zero = bld.mkImm(0);
// calculate clamped coordinates
for (c = 0; c < arg; ++c) {
+ int dimc = c;
+
+ if (c == 1 && su->tex.target == TEX_TARGET_1D_ARRAY) {
+ // The array index is stored in the Z component for 1D arrays.
+ dimc = 2;
+ }
+
src[c] = bld.getScratch();
if (c == 0 && raw)
- v = loadResInfo32(NULL, base + NVE4_SU_INFO_RAW_X);
+ v = loadSuInfo32(NULL, base + NVE4_SU_INFO_RAW_X);
else
- v = loadResInfo32(NULL, base + NVE4_SU_INFO_DIM(c));
+ v = loadSuInfo32(NULL, base + NVE4_SU_INFO_DIM(dimc));
bld.mkOp3(OP_SUCLAMP, TYPE_S32, src[c], su->getSrc(c), v, zero)
- ->subOp = getSuClampSubOp(su, c);
+ ->subOp = getSuClampSubOp(su, dimc);
}
for (; c < 3; ++c)
src[c] = zero;
if (su->tex.target == TEX_TARGET_BUFFER) {
src[0]->getInsn()->setFlagsDef(1, pred);
} else
- if (su->tex.target.isArray()) {
+ if (su->tex.target.isArray() || su->tex.target.isCube()) {
p1 = bld.getSSA(1, FILE_PREDICATE);
src[dim]->getInsn()->setFlagsDef(1, p1);
}
bld.mkOp2(OP_AND, TYPE_U32, off, src[0], bld.loadImm(NULL, 0xffff));
} else
if (dim == 3) {
- v = loadResInfo32(NULL, base + NVE4_SU_INFO_UNK1C);
+ v = loadSuInfo32(NULL, base + NVE4_SU_INFO_UNK1C);
bld.mkOp3(OP_MADSP, TYPE_U32, off, src[2], v, src[1])
->subOp = NV50_IR_SUBOP_MADSP(4,2,8); // u16l u16l u16l
- v = loadResInfo32(NULL, base + NVE4_SU_INFO_PITCH);
+ v = loadSuInfo32(NULL, base + NVE4_SU_INFO_PITCH);
bld.mkOp3(OP_MADSP, TYPE_U32, off, off, v, src[0])
->subOp = NV50_IR_SUBOP_MADSP(0,2,8); // u32 u16l u16l
} else {
assert(dim == 2);
- v = loadResInfo32(NULL, base + NVE4_SU_INFO_PITCH);
+ v = loadSuInfo32(NULL, base + NVE4_SU_INFO_PITCH);
bld.mkOp3(OP_MADSP, TYPE_U32, off, src[1], v, src[0])
- ->subOp = su->tex.target.isArray() ?
+ ->subOp = (su->tex.target.isArray() || su->tex.target.isCube()) ?
NV50_IR_SUBOP_MADSP_SD : NV50_IR_SUBOP_MADSP(4,2,8); // u16l u16l u16l
}
if (raw) {
bf = src[0];
} else {
- v = loadResInfo32(NULL, base + NVE4_SU_INFO_FMT);
+ v = loadSuInfo32(NULL, base + NVE4_SU_INFO_FMT);
bld.mkOp3(OP_VSHL, TYPE_U32, bf, src[0], v, zero)
->subOp = NV50_IR_SUBOP_V1(7,6,8|2);
}
break;
case 2:
z = off;
- if (!su->tex.target.isArray()) {
- z = loadResInfo32(NULL, base + NVE4_SU_INFO_UNK1C);
+ if (!su->tex.target.isArray() && !su->tex.target.isCube()) {
+ z = loadSuInfo32(NULL, base + NVE4_SU_INFO_UNK1C);
subOp = NV50_IR_SUBOP_SUBFM_3D;
}
break;
}
// part 2
- v = loadResInfo32(NULL, base + NVE4_SU_INFO_ADDR);
+ v = loadSuInfo32(NULL, base + NVE4_SU_INFO_ADDR);
if (su->tex.target == TEX_TARGET_BUFFER) {
eau = v;
eau = bld.mkOp3v(OP_SUEAU, TYPE_U32, bld.getScratch(4), off, bf, v);
}
// add array layer offset
- if (su->tex.target.isArray()) {
- v = loadResInfo32(NULL, base + NVE4_SU_INFO_ARRAY);
+ if (su->tex.target.isArray() || su->tex.target.isCube()) {
+ v = loadSuInfo32(NULL, base + NVE4_SU_INFO_ARRAY);
if (dim == 1)
bld.mkOp3(OP_MADSP, TYPE_U32, eau, src[1], v, eau)
->subOp = NV50_IR_SUBOP_MADSP(4,0,0); // u16 u24 u32
// let's just set it 0 for raw access and hope it works
v = raw ?
- bld.mkImm(0) : loadResInfo32(NULL, base + NVE4_SU_INFO_FMT);
+ bld.mkImm(0) : loadSuInfo32(NULL, base + NVE4_SU_INFO_FMT);
// get rid of old coordinate sources, make space for fmt info and predicate
su->moveSources(arg, 3 - arg);
su->setSrc(2, pred);
}
+static DataType
+getSrcType(const TexInstruction::ImgFormatDesc *t, int c)
+{
+ switch (t->type) {
+ case FLOAT: return t->bits[c] == 16 ? TYPE_F16 : TYPE_F32;
+ case UNORM: return t->bits[c] == 8 ? TYPE_U8 : TYPE_U16;
+ case SNORM: return t->bits[c] == 8 ? TYPE_S8 : TYPE_S16;
+ case UINT:
+ return (t->bits[c] == 8 ? TYPE_U8 :
+ (t->bits[c] == 16 ? TYPE_U16 : TYPE_U32));
+ case SINT:
+ return (t->bits[c] == 8 ? TYPE_S8 :
+ (t->bits[c] == 16 ? TYPE_S16 : TYPE_S32));
+ }
+ return TYPE_NONE;
+}
+
+static DataType
+getDestType(const ImgType type) {
+ switch (type) {
+ case FLOAT:
+ case UNORM:
+ case SNORM:
+ return TYPE_F32;
+ case UINT:
+ return TYPE_U32;
+ case SINT:
+ return TYPE_S32;
+ default:
+ assert(!"Impossible type");
+ return TYPE_NONE;
+ }
+}
+
void
-NVC0LoweringPass::handleSurfaceOpNVE4(TexInstruction *su)
+NVC0LoweringPass::convertSurfaceFormat(TexInstruction *su)
{
- processSurfaceCoordsNVE4(su);
+ const TexInstruction::ImgFormatDesc *format = su->tex.format;
+ int width = format->bits[0] + format->bits[1] +
+ format->bits[2] + format->bits[3];
+ Value *untypedDst[4] = {};
+ Value *typedDst[4] = {};
+
+ // We must convert this to a generic load.
+ su->op = OP_SULDB;
+
+ su->dType = typeOfSize(width / 8);
+ su->sType = TYPE_U8;
- // Who do we hate more ? The person who decided that nvc0's SULD doesn't
- // have to support conversion or the person who decided that, in OpenCL,
- // you don't have to specify the format here like you do in OpenGL ?
-
- if (su->op == OP_SULDP) {
- // We don't patch shaders. Ever.
- // You get an indirect call to our library blob here.
- // But at least it's uniform.
- FlowInstruction *call;
- LValue *p[3];
- LValue *r[5];
- uint16_t base = su->tex.r * NVE4_SU_INFO__STRIDE + NVE4_SU_INFO_CALL;
-
- for (int i = 0; i < 4; ++i)
- (r[i] = bld.getScratch(4, FILE_GPR))->reg.data.id = i;
- for (int i = 0; i < 3; ++i)
- (p[i] = bld.getScratch(1, FILE_PREDICATE))->reg.data.id = i;
- (r[4] = bld.getScratch(8, FILE_GPR))->reg.data.id = 4;
-
- bld.mkMov(p[1], bld.mkImm((su->cache == CACHE_CA) ? 1 : 0), TYPE_U8);
- bld.mkMov(p[2], bld.mkImm((su->cache == CACHE_CG) ? 1 : 0), TYPE_U8);
- bld.mkMov(p[0], su->getSrc(2), TYPE_U8);
- bld.mkMov(r[4], su->getSrc(0), TYPE_U64);
- bld.mkMov(r[2], su->getSrc(1), TYPE_U32);
-
- call = bld.mkFlow(OP_CALL, NULL, su->cc, su->getPredicate());
-
- call->indirect = 1;
- call->absolute = 1;
- call->setSrc(0, bld.mkSymbol(FILE_MEMORY_CONST,
- prog->driver->io.auxCBSlot, TYPE_U32,
- prog->driver->io.suInfoBase + base));
- call->setSrc(1, r[2]);
- call->setSrc(2, r[4]);
- for (int i = 0; i < 3; ++i)
- call->setSrc(3 + i, p[i]);
- for (int i = 0; i < 4; ++i) {
- call->setDef(i, r[i]);
- bld.mkMov(su->getDef(i), r[i]);
+ for (int i = 0; i < width / 32; i++)
+ untypedDst[i] = bld.getSSA();
+ if (width < 32)
+ untypedDst[0] = bld.getSSA();
+
+ for (int i = 0; i < 4; i++) {
+ typedDst[i] = su->getDef(i);
+ }
+
+ // Set the untyped dsts as the su's destinations
+ for (int i = 0; i < 4; i++)
+ su->setDef(i, untypedDst[i]);
+
+ bld.setPosition(su, true);
+
+ // Unpack each component into the typed dsts
+ int bits = 0;
+ for (int i = 0; i < 4; bits += format->bits[i], i++) {
+ if (!typedDst[i])
+ continue;
+ if (i >= format->components) {
+ if (format->type == FLOAT ||
+ format->type == UNORM ||
+ format->type == SNORM)
+ bld.loadImm(typedDst[i], i == 3 ? 1.0f : 0.0f);
+ else
+ bld.loadImm(typedDst[i], i == 3 ? 1 : 0);
+ continue;
+ }
+
+ // Get just that component's data into the relevant place
+ if (format->bits[i] == 32)
+ bld.mkMov(typedDst[i], untypedDst[i]);
+ else if (format->bits[i] == 16)
+ bld.mkCvt(OP_CVT, getDestType(format->type), typedDst[i],
+ getSrcType(format, i), untypedDst[i / 2])
+ ->subOp = (i & 1) << (format->type == FLOAT ? 0 : 1);
+ else if (format->bits[i] == 8)
+ bld.mkCvt(OP_CVT, getDestType(format->type), typedDst[i],
+ getSrcType(format, i), untypedDst[0])->subOp = i;
+ else {
+ bld.mkOp2(OP_EXTBF, TYPE_U32, typedDst[i], untypedDst[bits / 32],
+ bld.mkImm((bits % 32) | (format->bits[i] << 8)));
+ if (format->type == UNORM || format->type == SNORM)
+ bld.mkCvt(OP_CVT, TYPE_F32, typedDst[i], getSrcType(format, i), typedDst[i]);
+ }
+
+ // Normalize / convert as necessary
+ if (format->type == UNORM)
+ bld.mkOp2(OP_MUL, TYPE_F32, typedDst[i], typedDst[i], bld.loadImm(NULL, 1.0f / ((1 << format->bits[i]) - 1)));
+ else if (format->type == SNORM)
+ bld.mkOp2(OP_MUL, TYPE_F32, typedDst[i], typedDst[i], bld.loadImm(NULL, 1.0f / ((1 << (format->bits[i] - 1)) - 1)));
+ else if (format->type == FLOAT && format->bits[i] < 16) {
+ bld.mkOp2(OP_SHL, TYPE_U32, typedDst[i], typedDst[i], bld.loadImm(NULL, 15 - format->bits[i]));
+ bld.mkCvt(OP_CVT, TYPE_F32, typedDst[i], TYPE_F16, typedDst[i]);
}
- call->setDef(4, p[1]);
- delete_Instruction(bld.getProgram(), su);
}
+}
+
+void
+NVC0LoweringPass::handleSurfaceOpNVE4(TexInstruction *su)
+{
+ processSurfaceCoordsNVE4(su);
+
+ if (su->op == OP_SULDP)
+ convertSurfaceFormat(su);
if (su->op == OP_SUREDB || su->op == OP_SUREDP) {
// FIXME: for out of bounds access, destination value will be undefined !
red->setPredicate(cc, pred);
delete_Instruction(bld.getProgram(), su);
handleCasExch(red, true);
- } else {
- su->sType = (su->tex.target == TEX_TARGET_BUFFER) ? TYPE_U32 : TYPE_U8;
}
+
+ if (su->op == OP_SUSTB || su->op == OP_SUSTP)
+ su->sType = (su->tex.target == TEX_TARGET_BUFFER) ? TYPE_U32 : TYPE_U8;
}
bool
return true;
}
+void
+NVC0LoweringPass::handleLDST(Instruction *i)
+{
+ if (i->src(0).getFile() == FILE_SHADER_INPUT) {
+ if (prog->getType() == Program::TYPE_COMPUTE) {
+ i->getSrc(0)->reg.file = FILE_MEMORY_CONST;
+ i->getSrc(0)->reg.fileIndex = 0;
+ } else
+ if (prog->getType() == Program::TYPE_GEOMETRY &&
+ i->src(0).isIndirect(0)) {
+ // XXX: this assumes vec4 units
+ Value *ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(),
+ i->getIndirect(0, 0), bld.mkImm(4));
+ i->setIndirect(0, 0, ptr);
+ i->op = OP_VFETCH;
+ } else {
+ i->op = OP_VFETCH;
+ assert(prog->getType() != Program::TYPE_FRAGMENT); // INTERP
+ }
+ } else if (i->src(0).getFile() == FILE_MEMORY_CONST) {
+ if (targ->getChipset() >= NVISA_GK104_CHIPSET &&
+ prog->getType() == Program::TYPE_COMPUTE) {
+ // The launch descriptor only allows to set up 8 CBs, but OpenGL
+ // requires at least 12 UBOs. To bypass this limitation, we store the
+ // addrs into the driver constbuf and we directly load from the global
+ // memory.
+ int8_t fileIndex = i->getSrc(0)->reg.fileIndex - 1;
+ Value *ind = i->getIndirect(0, 1);
+ Value *ptr = loadUboInfo64(ind, fileIndex * 16);
+
+ // TODO: clamp the offset to the maximum number of const buf.
+ if (i->src(0).isIndirect(1)) {
+ Value *offset = bld.loadImm(NULL, i->getSrc(0)->reg.data.offset + typeSizeof(i->sType));
+ Value *length = loadUboLength32(ind, fileIndex * 16);
+ Value *pred = new_LValue(func, FILE_PREDICATE);
+ if (i->src(0).isIndirect(0)) {
+ bld.mkOp2(OP_ADD, TYPE_U64, ptr, ptr, i->getIndirect(0, 0));
+ bld.mkOp2(OP_ADD, TYPE_U32, offset, offset, i->getIndirect(0, 0));
+ }
+ i->getSrc(0)->reg.file = FILE_MEMORY_GLOBAL;
+ i->setIndirect(0, 1, NULL);
+ i->setIndirect(0, 0, ptr);
+ bld.mkCmp(OP_SET, CC_GT, TYPE_U32, pred, TYPE_U32, offset, length);
+ i->setPredicate(CC_NOT_P, pred);
+ if (i->defExists(0)) {
+ bld.mkMov(i->getDef(0), bld.mkImm(0));
+ }
+ } else if (fileIndex >= 0) {
+ if (i->src(0).isIndirect(0)) {
+ bld.mkOp2(OP_ADD, TYPE_U64, ptr, ptr, i->getIndirect(0, 0));
+ }
+ i->getSrc(0)->reg.file = FILE_MEMORY_GLOBAL;
+ i->setIndirect(0, 1, NULL);
+ i->setIndirect(0, 0, ptr);
+ }
+ } else if (i->src(0).isIndirect(1)) {
+ Value *ptr;
+ if (i->src(0).isIndirect(0))
+ ptr = bld.mkOp3v(OP_INSBF, TYPE_U32, bld.getSSA(),
+ i->getIndirect(0, 1), bld.mkImm(0x1010),
+ i->getIndirect(0, 0));
+ else
+ ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(),
+ i->getIndirect(0, 1), bld.mkImm(16));
+ i->setIndirect(0, 1, NULL);
+ i->setIndirect(0, 0, ptr);
+ i->subOp = NV50_IR_SUBOP_LDC_IS;
+ }
+ } else if (i->src(0).getFile() == FILE_SHADER_OUTPUT) {
+ assert(prog->getType() == Program::TYPE_TESSELLATION_CONTROL);
+ i->op = OP_VFETCH;
+ } else if (i->src(0).getFile() == FILE_MEMORY_BUFFER) {
+ Value *ind = i->getIndirect(0, 1);
+ Value *ptr = loadBufInfo64(ind, i->getSrc(0)->reg.fileIndex * 16);
+ // XXX come up with a way not to do this for EVERY little access but
+ // rather to batch these up somehow. Unfortunately we've lost the
+ // information about the field width by the time we get here.
+ Value *offset = bld.loadImm(NULL, i->getSrc(0)->reg.data.offset + typeSizeof(i->sType));
+ Value *length = loadBufLength32(ind, i->getSrc(0)->reg.fileIndex * 16);
+ Value *pred = new_LValue(func, FILE_PREDICATE);
+ if (i->src(0).isIndirect(0)) {
+ bld.mkOp2(OP_ADD, TYPE_U64, ptr, ptr, i->getIndirect(0, 0));
+ bld.mkOp2(OP_ADD, TYPE_U32, offset, offset, i->getIndirect(0, 0));
+ }
+ i->setIndirect(0, 1, NULL);
+ i->setIndirect(0, 0, ptr);
+ i->getSrc(0)->reg.file = FILE_MEMORY_GLOBAL;
+ bld.mkCmp(OP_SET, CC_GT, TYPE_U32, pred, TYPE_U32, offset, length);
+ i->setPredicate(CC_NOT_P, pred);
+ if (i->defExists(0)) {
+ bld.mkMov(i->getDef(0), bld.mkImm(0));
+ }
+ }
+}
+
void
NVC0LoweringPass::readTessCoord(LValue *dst, int c)
{
return handleWRSV(i);
case OP_STORE:
case OP_LOAD:
- if (i->src(0).getFile() == FILE_SHADER_INPUT) {
- if (prog->getType() == Program::TYPE_COMPUTE) {
- i->getSrc(0)->reg.file = FILE_MEMORY_CONST;
- i->getSrc(0)->reg.fileIndex = 0;
- } else
- if (prog->getType() == Program::TYPE_GEOMETRY &&
- i->src(0).isIndirect(0)) {
- // XXX: this assumes vec4 units
- Value *ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(),
- i->getIndirect(0, 0), bld.mkImm(4));
- i->setIndirect(0, 0, ptr);
- i->op = OP_VFETCH;
- } else {
- i->op = OP_VFETCH;
- assert(prog->getType() != Program::TYPE_FRAGMENT); // INTERP
- }
- } else if (i->src(0).getFile() == FILE_MEMORY_CONST) {
- if (i->src(0).isIndirect(1)) {
- Value *ptr;
- if (i->src(0).isIndirect(0))
- ptr = bld.mkOp3v(OP_INSBF, TYPE_U32, bld.getSSA(),
- i->getIndirect(0, 1), bld.mkImm(0x1010),
- i->getIndirect(0, 0));
- else
- ptr = bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(),
- i->getIndirect(0, 1), bld.mkImm(16));
- i->setIndirect(0, 1, NULL);
- i->setIndirect(0, 0, ptr);
- i->subOp = NV50_IR_SUBOP_LDC_IS;
- }
- } else if (i->src(0).getFile() == FILE_SHADER_OUTPUT) {
- assert(prog->getType() == Program::TYPE_TESSELLATION_CONTROL);
- i->op = OP_VFETCH;
- } else if (i->src(0).getFile() == FILE_MEMORY_GLOBAL) {
- Value *ind = i->getIndirect(0, 1);
- Value *ptr = loadResInfo64(ind, i->getSrc(0)->reg.fileIndex * 16);
- // XXX come up with a way not to do this for EVERY little access but
- // rather to batch these up somehow. Unfortunately we've lost the
- // information about the field width by the time we get here.
- Value *offset = bld.loadImm(NULL, i->getSrc(0)->reg.data.offset + typeSizeof(i->sType));
- Value *length = loadResLength32(ind, i->getSrc(0)->reg.fileIndex * 16);
- Value *pred = new_LValue(func, FILE_PREDICATE);
- if (i->src(0).isIndirect(0)) {
- bld.mkOp2(OP_ADD, TYPE_U64, ptr, ptr, i->getIndirect(0, 0));
- bld.mkOp2(OP_ADD, TYPE_U32, offset, offset, i->getIndirect(0, 0));
- }
- i->setIndirect(0, 1, NULL);
- i->setIndirect(0, 0, ptr);
- bld.mkCmp(OP_SET, CC_GT, TYPE_U32, pred, TYPE_U32, offset, length);
- i->setPredicate(CC_NOT_P, pred);
- if (i->defExists(0)) {
- bld.mkMov(i->getDef(0), bld.mkImm(0));
- }
- }
+ handleLDST(i);
break;
case OP_ATOM:
{
- const bool cctl = i->src(0).getFile() == FILE_MEMORY_GLOBAL;
+ const bool cctl = i->src(0).getFile() == FILE_MEMORY_BUFFER;
handleATOM(i);
handleCasExch(i, cctl);
}
handleSurfaceOpNVE4(i->asTex());
break;
case OP_SUQ:
- handleSUQ(i);
+ handleSUQ(i->asTex());
+ break;
+ case OP_BUFQ:
+ handleBUFQ(i);
break;
default:
break;