AST -> SPV: Add basic atomic_uint and atomic*() built-in function functionality.

This commit is contained in:
John Kessenich 2015-07-23 10:22:48 -06:00
parent 917ec4ac8c
commit 426394d0c8
6 changed files with 311 additions and 23 deletions

View file

@ -99,6 +99,7 @@ protected:
spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat);
spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);
spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);
spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);
spv::Id createNoArgOperation(glslang::TOperator op);
spv::Id getSymbolId(const glslang::TIntermSymbol* node);
@ -718,6 +719,16 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);
return false;
case glslang::EOpAtomicCounterIncrement:
case glslang::EOpAtomicCounterDecrement:
case glslang::EOpAtomicCounter:
{
// Handle all of the atomics in one place, in createAtomicOperation()
std::vector<spv::Id> operands;
operands.push_back(operand);
result = createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
return false;
}
default:
spv::MissingFunctionality("glslang unary");
break;
@ -733,6 +744,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
bool reduceComparison = true;
bool isMatrix = false;
bool noReturnValue = false;
bool atomic = false;
assert(node->getOp());
@ -952,6 +964,17 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
// These all have 0 operands and will naturally finish up in the code below for 0 operands
break;
case glslang::EOpAtomicAdd:
case glslang::EOpAtomicMin:
case glslang::EOpAtomicMax:
case glslang::EOpAtomicAnd:
case glslang::EOpAtomicOr:
case glslang::EOpAtomicXor:
case glslang::EOpAtomicExchange:
case glslang::EOpAtomicCompSwap:
atomic = true;
break;
default:
break;
}
@ -959,7 +982,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
//
// See if it maps to a regular operation.
//
if (binOp != glslang::EOpNull) {
glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();
glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();
@ -987,6 +1009,9 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
return false;
}
//
// Create the list of operands.
//
glslang::TIntermSequence& glslangOperands = node->getSequence();
std::vector<spv::Id> operands;
for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {
@ -1012,16 +1037,23 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
else
operands.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangOperands[arg]->getAsTyped()->getType())));
}
switch (glslangOperands.size()) {
case 0:
result = createNoArgOperation(node->getOp());
break;
case 1:
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);
break;
default:
result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
break;
if (atomic) {
// Handle all atomics
result = createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
} else {
// Pass through to generic operations.
switch (glslangOperands.size()) {
case 0:
result = createNoArgOperation(node->getOp());
break;
case 1:
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);
break;
default:
result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
break;
}
}
if (noReturnValue)
@ -1272,6 +1304,10 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
case glslang::EbtUint:
spvType = builder.makeUintType(32);
break;
case glslang::EbtAtomicUint:
spv::TbdFunctionality("Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?");
spvType = builder.makeUintType(32);
break;
case glslang::EbtSampler:
{
const glslang::TSampler& sampler = type.getSampler();
@ -2245,6 +2281,67 @@ spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vector
return builder.makeCompositeConstant(vectorTypeId, components);
}
// For glslang ops that map to SPV atomic opCodes
spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)
{
spv::Op opCode = spv::OpNop;
switch (op) {
case glslang::EOpAtomicAdd:
opCode = spv::OpAtomicIAdd;
break;
case glslang::EOpAtomicMin:
opCode = spv::OpAtomicIMin;
break;
case glslang::EOpAtomicMax:
opCode = spv::OpAtomicIMax;
break;
case glslang::EOpAtomicAnd:
opCode = spv::OpAtomicAnd;
break;
case glslang::EOpAtomicOr:
opCode = spv::OpAtomicOr;
break;
case glslang::EOpAtomicXor:
opCode = spv::OpAtomicXor;
break;
case glslang::EOpAtomicExchange:
opCode = spv::OpAtomicExchange;
break;
case glslang::EOpAtomicCompSwap:
opCode = spv::OpAtomicCompareExchange;
break;
case glslang::EOpAtomicCounterIncrement:
opCode = spv::OpAtomicIIncrement;
break;
case glslang::EOpAtomicCounterDecrement:
opCode = spv::OpAtomicIDecrement;
break;
case glslang::EOpAtomicCounter:
opCode = spv::OpAtomicLoad;
break;
default:
spv::MissingFunctionality("missing nested atomic");
break;
}
// Sort out the operands
// - mapping from glslang -> SPV
// - there are extra SPV operands with no glslang source
std::vector<spv::Id> spvAtomicOperands; // hold the spv operands
auto opIt = operands.begin(); // walk the glslang operands
spvAtomicOperands.push_back(*(opIt++));
spvAtomicOperands.push_back(spv::ExecutionScopeDevice); // TBD: what is the correct scope?
spvAtomicOperands.push_back( spv::MemorySemanticsMaskNone); // TBD: what are the correct memory semantics?
// Add the rest of the operands, skipping the first one, which was dealt with above.
// For some ops, there are none, for some 1, for compare-exchange, 2.
for (; opIt != operands.end(); ++opIt)
spvAtomicOperands.push_back(*opIt);
return builder.createOp(opCode, typeId, spvAtomicOperands);
}
spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)
{
spv::Op opCode = spv::OpNop;
@ -2298,6 +2395,7 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
case glslang::EOpRefract:
libCall = GLSL_STD_450::Refract;
break;
default:
return 0;
}
@ -2319,7 +2417,7 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
break;
case 3:
id = builder.createTernaryOp(opCode, typeId, operands[0], operands[1], operands[2]);
id = builder.createTriOp(opCode, typeId, operands[0], operands[1], operands[2]);
break;
default:
// These do not exist yet

View file

@ -45,6 +45,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <unordered_set>
#include "SpvBuilder.h"
#ifndef _WIN32
@ -989,12 +991,11 @@ Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
return op->getResultId();
}
Id Builder::createTernaryOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
Id Builder::createOp(Op opCode, Id typeId, std::vector<Id>& operands)
{
Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
op->addIdOperand(op1);
op->addIdOperand(op2);
op->addIdOperand(op3);
for (auto operand : operands)
op->addIdOperand(operand);
buildPoint->addInstruction(op);
return op->getResultId();
@ -2172,17 +2173,22 @@ void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector
}
}
void TbdFunctionality(const char* tbd)
{
static std::unordered_set<const char*> issued;
if (issued.find(tbd) == issued.end()) {
printf("TBD functionality: %s\n", tbd);
issued.insert(tbd);
}
}
void MissingFunctionality(const char* fun)
{
printf("Missing functionality: %s\n", fun);
exit(1);
}
void ValidationError(const char* error)
{
printf("Validation Error: %s\n", error);
}
Builder::Loop::Loop(Builder& builder, bool testFirstArg)
: function(&builder.getBuildPoint()->getParent()),
header(new Block(builder.getUniqueId(), *function)),

View file

@ -238,7 +238,7 @@ public:
Id createUnaryOp(Op, Id typeId, Id operand);
Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
Id createTernaryOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
Id createOp(Op, Id typeId, std::vector<Id>& operands);
Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
// Take an rvalue (source) and a set of channels to extract from it to
@ -564,8 +564,11 @@ protected:
std::stack<Loop> loops;
}; // end Builder class
// Use for non-fatal notes about what's not complete
void TbdFunctionality(const char*);
// Use for fatal missing functionality
void MissingFunctionality(const char*);
void ValidationError(const char* error);
}; // end spv namespace