in benchmarks/JetStream2/WSL/SPIR-V.js [29:249]
function SPIRV(json) {
let result = {
ops: {},
kinds: {}
}
let composites = new Map();
let ids = new Map();
for (let kind of json.operand_kinds) {
switch (kind.category) {
case "BitEnum":
case "ValueEnum":
let enumerants = { category: kind.category };
for (let enumerant of kind.enumerants) {
enumerants[enumerant.enumerant] = enumerant;
}
result.kinds[kind.kind] = enumerants;
break;
case "Composite":
composites.set(kind.kind, kind);
break;
case "Id":
ids.set(kind.kind, kind);
break;
}
}
function matchType(operandInfoKind, operand) {
switch (operandInfoKind) {
// FIXME: I'm not actually sure that Ids should be unsigned.
case "IdResultType":
case "IdResult":
case "IdRef":
case "IdScope":
case "IdMemorySemantics":
case "LiteralExtInstInteger":
if (typeof operand != "number")
throw new Error("Operand needs to be a number");
if ((operand >>> 0) != operand)
throw new Error("Operand needs to fit in an unsigned int");
return;
case "LiteralInteger":
if (typeof operand != "number")
throw new Error("Operand needs to be a number");
if ((operand | 0) != operand)
throw new Error("Operand needs to fit in an int");
return;
case "LiteralString":
if (typeof operand != "string")
throw new Error("Operand needs to be a string");
return;
case "LiteralContextDependentNumber":
case "LiteralSpecConstantOpInteger":
if (typeof operand != "number")
throw new Error("Operand needs to be a number");
if ((operand >>> 0) != operand && (operand | 0) != operand)
throw new Error("Operand needs to fit in an unsigned int or an int.");
return;
}
let kind = result.kinds[operandInfoKind];
if (kind) {
if (operand instanceof Array) {
if (kind.category != "BitEnum")
throw new Error("Passing an array to a " + kind.category + " operand");
for (let operandItem of operand) {
if (kind[operandItem.enumerant] != operandItem)
throw new Error("" + operandItem.enumerant + " is not a member of " + operandInfoKind);
}
return;
}
if (kind[operand.enumerant] != operand)
throw new Error("" + operand.enumerant + " is not a member of " + operandInfoKind);
return;
}
throw new Error("Unknown type: " + operandInfoKind);
}
class OperandChecker {
constructor(operandInfos)
{
this._operandInfos = operandInfos || [];
this._operandIndex = 0;
this._operandInfoIndex = 0;
this._parameters = [];
}
_isStar(operandInfo)
{
switch (operandInfo.kind) {
case "LiteralContextDependentNumber":
case "LiteralSpecConstantOpInteger":
// These types can be any width.
return true;
}
return operandInfo.quantifier && operandInfo.quantifier == "*";
}
nextComparisonType(operand)
{
if (this._operandInfoIndex >= this._operandInfos.length)
throw new Error("Specified operand does not correspond to any that the instruction expects.");
let operandInfo = this._operandInfos[this._operandInfoIndex];
let isStar = this._isStar(operandInfo);
if (this._parameters.length != 0) {
let result = this._parameters[0];
this._parameters.splice(0, 1);
// FIXME: Handle parameters that require their own parameters
++this._operandIndex;
if (this._parameters.length == 0 && !isStar)
++this._operandInfoIndex;
return result;
}
let composite = composites.get(operandInfo.kind);
if (composite) {
for (let base of composite.bases)
this._parameters.push(base);
nextComparisonType(operand);
return;
}
let kind = result.kinds[operandInfo.kind];
if (kind) {
let enumerant = kind[operand.enumerant];
if (enumerant) {
let parameters = enumerant.parameters;
if (parameters) {
for (let parameter of parameters) {
this._parameters.push(parameter.kind);
}
++this._operandIndex;
return operandInfo.kind;
}
}
}
++this._operandIndex;
if (!isStar)
++this._operandInfoIndex;
return operandInfo.kind;
}
check(operand)
{
matchType(this.nextComparisonType(operand), operand);
}
finalize()
{
if (this._parameters.length != 0)
throw new Error("Operand not specified for parameter.");
for (let i = this._operandInfoIndex; i < this._operandInfos.length; ++i) {
let operandInfo = this._operandInfos[i];
let quantifier = operandInfo.quantifier;
if (quantifier != "?" && !this._isStar(operandInfo))
throw new Error("Did not specify operand " + i + " to instruction.");
}
}
}
for (let instruction of json.instructions) {
if (!instruction.opname.startsWith("Op"))
continue;
let attributeName = instruction.opname.substring(2);
result.ops[attributeName] = class {
constructor(...operands)
{
let operandChecker = new OperandChecker(instruction.operands);
for (let operand of operands)
operandChecker.check(operand);
operandChecker.finalize();
this._operands = operands;
}
get operands()
{
return this._operands;
}
get opname()
{
return instruction.opname;
}
get opcode()
{
return instruction.opcode;
}
get operandInfo()
{
return instruction.operands;
}
get storageSize()
{
let result = 1;
for (let operand of this.operands) {
if (typeof operand == "number")
++result;
else if (typeof operand == "string")
result += (((operand.length + 1) + 3) / 4) | 0;
else
++result;
}
return result;
}
get largestId()
{
let maximumId = 0;
let operandChecker = new OperandChecker(this.operandInfo);
for (let operand of this.operands) {
let type = operandChecker.nextComparisonType(operand);
let idType = ids.get(type);
if (idType)
maximumId = Math.max(maximumId, operand);
}
return maximumId;
}
}
}
return result;
}