summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-check-expr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-check-expr.cpp')
-rw-r--r--source/slang/slang-check-expr.cpp125
1 files changed, 97 insertions, 28 deletions
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index 5266f02f6..43db85e3b 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -3898,44 +3898,114 @@ namespace Slang
Expr* SemanticsExprVisitor::visitSPIRVAsmExpr(SPIRVAsmExpr* expr)
{
+ //
+ // Firstly, get the info for this op, the opcode has already been
+ // discovered by the parser
+ //
+ const auto& spirvInfo = getSession()->spirvCoreGrammarInfo;
+
// We will iterate over all the operands in all the insts and check
// them
+ bool failed = false;
for(auto& inst : expr->insts)
{
+ // It's not automatically a failure to not have info, we just won't
+ // be able to deduce types for operands
+ const auto opInfo = spirvInfo->opInfos.lookup(SpvOp(inst.opcode.knownValue));
+
+ if(opInfo->numOperandTypes == 0 && inst.operands.getCount())
+ {
+ failed = true;
+ getSink()->diagnose(inst.opcode.token, Diagnostics::spirvInstructionWithTooManyOperands, inst.opcode.token, 0);
+ continue;
+ }
+
const bool isLast = &inst == &expr->insts.getLast();
- for(auto& operand : inst.operands)
+ for(Index operandIndex = 0; operandIndex < inst.operands.getCount(); ++operandIndex)
{
- if(operand.flavor == SPIRVAsmOperand::SlangType)
- {
- // This is a $$type operand, fill in the TypeExp member of the operand
- TypeExp& typeExpr = operand.type;
- typeExpr.exp = operand.expr;
- typeExpr = CheckProperType(typeExpr);
- operand.expr = typeExpr.exp;
- }
- else if(operand.flavor == SPIRVAsmOperand::SlangValue
- || operand.flavor == SPIRVAsmOperand::SlangValueAddr)
- {
- // This is a $expr operand, check the expr
- operand.expr = dispatch(operand.expr);
- }
- else if(operand.flavor == SPIRVAsmOperand::NamedValue
- && operand.token.getContent() == "result")
- {
- // This is the <result-id> marker, check that it only
- // appears in the last instruction.
+ // Clamp to the end of the type info array, because the last one will be any variable operands
+ const auto operandType
+ = opInfo->operandTypes[std::min(operandIndex, Index(opInfo->numOperandTypes)-1)];
+ const auto baseOperandType
+ = spirvInfo->operandKindUnderneathIds.lookup(operandType).value_or(operandType);
+ const auto needsIdWrapper = baseOperandType != operandType;
- // TODO: We could consider relaxing this, because SPIR-V
- // does have forward references for decorations and such
- if (!isLast)
+ const auto check = [&](const auto& go, auto& operand) -> void {
+ if(operand.flavor == SPIRVAsmOperand::SlangType)
{
- getSink()->diagnose(operand.token, Diagnostics::misplacedResultIdMarker);
- getSink()->diagnoseWithoutSourceView(expr, Diagnostics::considerOpCopyObject);
+ // This is a $$type operand, fill in the TypeExp member of the operand
+ TypeExp& typeExpr = operand.type;
+ typeExpr.exp = operand.expr;
+ typeExpr = CheckProperType(typeExpr);
+ operand.expr = typeExpr.exp;
}
- }
+ else if(operand.flavor == SPIRVAsmOperand::SlangValue
+ || operand.flavor == SPIRVAsmOperand::SlangValueAddr)
+ {
+ // This is a $expr operand, check the expr
+ operand.expr = dispatch(operand.expr);
+ }
+ else if(operand.flavor == SPIRVAsmOperand::ResultMarker)
+ {
+ // This is the <result-id> marker, check that it only
+ // appears in the last instruction.
+
+ // TODO: We could consider relaxing this, because SPIR-V
+ // does have forward references for decorations and such
+ if (!isLast)
+ {
+ getSink()->diagnose(operand.token, Diagnostics::misplacedResultIdMarker);
+ getSink()->diagnoseWithoutSourceView(expr, Diagnostics::considerOpCopyObject);
+ }
+ }
+ else if(operand.flavor == SPIRVAsmOperand::NamedValue)
+ {
+ // First try and look it up with the knowledge of this operand's type
+ auto enumValue
+ = spirvInfo->allEnums.lookup({baseOperandType, operand.token.getContent()});
+ // Then fall back to with the type prefix
+ if(!enumValue)
+ enumValue = spirvInfo->allEnumsWithTypePrefix.lookup(operand.token.getContent());
+ // Then see if it's an opcode (for OpSpecialize)
+ if(!enumValue)
+ enumValue = spirvInfo->opcodes.lookup(operand.token.getContent());
+
+ if(!enumValue)
+ {
+ failed = true;
+ getSink()->diagnose(operand.token, Diagnostics::spirvUnableToResolveName, operand.token.getContent());
+ return;
+ }
+
+ operand.knownValue = *enumValue;
+ operand.wrapInId = needsIdWrapper;
+ }
+ if(operand.bitwiseOrWith.getCount()
+ && operand.flavor != SPIRVAsmOperand::Literal
+ && operand.flavor != SPIRVAsmOperand::NamedValue)
+ {
+ failed = true;
+ getSink()->diagnose(operand.token, Diagnostics::spirvNonConstantBitwiseOr);
+ }
+ for(auto& o : operand.bitwiseOrWith)
+ {
+ if(o.flavor != SPIRVAsmOperand::Literal && o.flavor != SPIRVAsmOperand::NamedValue)
+ {
+ failed = true;
+ getSink()->diagnose(operand.token, Diagnostics::spirvNonConstantBitwiseOr);
+ }
+ go(go, o);
+ operand.knownValue |= o.knownValue;
+ }
+ };
+
+ check(check, inst.operands[operandIndex]);
}
}
+ if(failed)
+ return CreateErrorExpr(expr);
+
// Assign the type of this expression from the type of the last
// instruction, otherwise void
if(expr->insts.getCount())
@@ -3944,8 +4014,7 @@ namespace Slang
const auto lastOperands = expr->insts.getLast().operands;
if(lastOperands.getCount() >= 2
&& lastOperands[0].flavor == SPIRVAsmOperand::SlangType
- && lastOperands[1].flavor == SPIRVAsmOperand::NamedValue
- && lastOperands[1].token.getContent() == "result")
+ && lastOperands[1].flavor == SPIRVAsmOperand::ResultMarker)
{
expr->type = lastOperands[0].type.type;
}