public ShaderOp CompositeSplatConstruct(ShaderType resultType, IShaderIR value, FrontEndContext context) { var opArgs = new List <IShaderIR>(); if (resultType.mBaseType == OpType.Vector) { var vectorResultType = VectorType.Load(resultType); for (var i = 0; i < vectorResultType.GetComponentCount(); ++i) { opArgs.Add(value); } } else if (resultType.mBaseType == OpType.Matrix) { var matrixResultType = MatrixType.Load(resultType); var vectorElement = CompositeSplatConstruct(matrixResultType.GetComponentType(), value, context); for (var i = 0; i < matrixResultType.GetComponentCount(); ++i) { opArgs.Add(vectorElement); } } else { throw new Exception("invalid type"); } return(CreateOp(context.mCurrentBlock, OpInstructionType.OpCompositeConstruct, resultType, opArgs)); }
public ShaderOp GenerateFunctionCall(ShaderFunction shaderFunction, IShaderIR selfOp, List <IShaderIR> arguments, FrontEndContext context) { var argumentOps = new List <IShaderIR>(); argumentOps.Add(shaderFunction); if (!shaderFunction.IsStatic || selfOp != null) { argumentOps.Add(selfOp); } if (arguments != null) { for (var i = 0; i < arguments.Count; ++i) { var argument = arguments[i]; var paramIR = GetFunctionParameter(shaderFunction, i, argument, context); argumentOps.Add(paramIR); } } var fnShaderReturnType = shaderFunction.GetReturnType(); var functionCallOp = CreateOp(context.mCurrentBlock, OpInstructionType.OpFunctionCall, fnShaderReturnType, argumentOps); return(functionCallOp); }
void GenerateIds(IShaderIR ir) { if (ir is ShaderOp op) { GenerateIds(op); } else if (ir is ExtensionLibraryImportOp extImportOp) { GetId(extImportOp); } else if (ir is ShaderType shaderType) { GenerateIds(shaderType); } else if (ir is ShaderConstantLiteral constantLiteral) { // No op } else if (ir is ShaderBlock shaderBlock) { // Id is already assigned from the owning function } else { throw new Exception(); } }
public override void VisitFieldDeclaration(FieldDeclarationSyntax node) { mCommonPass.mFrontEnd = mFrontEnd; mCommonPass.mContext = mContext; var declaredShaderType = FindType(node.Declaration.Type); foreach (var variable in node.Declaration.Variables) { var variableSymbol = GetDeclaredSymbol(variable); if (variableSymbol.IsStatic) { GlobalShaderField shaderField; int fieldIndex; mFrontEnd.FindStaticField(mContext.mCurrentType, variable.Identifier.ToString(), out shaderField, out fieldIndex); shaderField.InitialValue = GetInitialValue(variable, shaderField); } else { ShaderField shaderField; int fieldIndex; mFrontEnd.FindField(mContext.mCurrentType, variable.Identifier.ToString(), out shaderField, out fieldIndex); // If there is an initial value op then store it into the field IShaderIR initialValueOp = GetInitialValue(variable, shaderField); if (initialValueOp != null) { var variableOp = mFrontEnd.GenerateAccessChain(mContext.mThisOp, shaderField.mType, (uint)fieldIndex, mContext); mFrontEnd.CreateStoreOp(mContext.mCurrentBlock, variableOp, initialValueOp); } } } }
public void Visit(IShaderIR ir) { if (ir is ShaderType shaderType) { Visit(shaderType); } else if (ir is ShaderFunction shaderFunction) { Visit(shaderFunction); } else if (ir is ShaderConstantLiteral constantLiteral) { Visit(constantLiteral); } else if (ir is ShaderOp shaderOp) { Visit(shaderOp); } else if (ir is ExtensionLibraryImportOp extLibraryImportOp) { Visit(extLibraryImportOp); } else if (ir is ShaderBlock shaderBlock) { // Skip blocks as an ir. This is a target of some other op (like a branch) and it's body will be visited elsewhere (typically on the function) } else { throw new Exception(); } }
public ShaderOp CastBoolToFloat(ShaderType resultType, IShaderIR expressionOp, FrontEndContext context) { var constantOp0 = CreateConstantOp <float>(0.0f); var constantOp1 = CreateConstantOp <float>(1.0f); return(CastFromBool(resultType, expressionOp, constantOp0, constantOp1, context)); }
public ShaderOp TryGenerateFunctionCall(ShaderFunction shaderFunction, IShaderIR selfOp, List <IShaderIR> arguments, FrontEndContext context) { if (shaderFunction == null) { return(null); } return(GenerateFunctionCall(shaderFunction, selfOp, arguments, context)); }
public ShaderOp CreateStoreOp(ShaderBlock block, IShaderIR variable, IShaderIR result) { var valueResult = GetOrGenerateValueTypeFromIR(block, result); return(CreateOp(block, OpInstructionType.OpStore, null, new List <IShaderIR> { variable, valueResult })); }
UInt32 GetId(IShaderIR ir) { if (!mIdMap.ContainsKey(ir)) { mIdMap.Add(ir, mId); ++mId; } return(mIdMap[ir]); }
public static void AddDecorationDescriptorSet(FrontEndTranslator translator, IShaderIR ir, int descriptorSetId, ShaderBlock decorationsBlock) { var decorationBindingLiteral = translator.CreateConstantLiteral((int)Spv.Decoration.DecorationDescriptorSet); var descriptorSetIdLiteral = translator.CreateConstantLiteral(descriptorSetId); translator.CreateOp(decorationsBlock, OpInstructionType.OpDecorate, null, new List <IShaderIR>() { ir, decorationBindingLiteral, descriptorSetIdLiteral }); }
public ShaderOp GenerateAccessChain(IShaderIR selfIR, string fieldName, FrontEndContext context) { var selfOp = selfIR as ShaderOp; var selfType = selfOp.mResultType.GetDereferenceType(); ShaderField shaderField; int fieldIndex; FindField(selfType, fieldName, out shaderField, out fieldIndex); return(GenerateAccessChain(selfIR, shaderField.mType, (uint)fieldIndex, context)); }
public ShaderOp GenerateAccessChain(IShaderIR selfIR, ShaderType resultType, uint fieldIndex, FrontEndContext context) { var selfOp = selfIR as ShaderOp; var constantLiteral = CreateConstantLiteral(fieldIndex); var memberIndexConstant = CreateConstantOp(FindType(typeof(uint)), constantLiteral); resultType = FindOrCreatePointerType(resultType.GetDereferenceType(), selfOp.mResultType.mStorageClass); var memberVariableOp = CreateOp(context.mCurrentBlock, OpInstructionType.OpAccessChain, resultType, new List <IShaderIR> { selfOp, memberIndexConstant }); return(memberVariableOp); }
public bool TryCallSetterFunction(FunctionKey functionKey, IShaderIR selfInstanceIR, IShaderIR rhsIR) { var setterShaderFunction = mFrontEnd.mCurrentLibrary.FindFunction(functionKey); if (setterShaderFunction == null) { return(false); } GenerateFunctionCall(setterShaderFunction, selfInstanceIR, new List <IShaderIR>() { rhsIR }); return(true); }
void WriteIR(IShaderIR ir) { if (ir is ShaderOp op) { WriteOp(op); } else if (ir is ShaderConstantLiteral constantLiteral) { WriteConstantLiteral(constantLiteral); } else { throw new Exception(); } }
void WriteDebugName(IShaderIR ir, string debugName) { if (string.IsNullOrEmpty(debugName)) { return; } var id = GetId(ir); var wordCount = mWriter.GetPaddedWordCount(debugName); var instructionSize = (UInt16)(2 + wordCount); mWriter.WriteInstruction(instructionSize, Spv.Op.OpName); mWriter.Write(id); mWriter.Write(debugName); }
public bool TryCallIntrinsicsSetterFunction(FunctionKey functionKey, IShaderIR setter, IShaderIR argumentIR) { var instrinsicDelegate = mFrontEnd.mCurrentLibrary.FindIntrinsicSetterFunction(functionKey); if (instrinsicDelegate == null) { return(false); } // Build the arguments up var argumentIRs = new List <IShaderIR>(); instrinsicDelegate(mFrontEnd, setter, argumentIR, mContext); return(true); }
///////////////////////////////////////////////////////////////Conversions public ShaderOp CastFromBool(ShaderType resultType, IShaderIR expressionOp, IShaderIR zeroScalar, IShaderIR oneScalar, FrontEndContext context) { var zeroExpression = zeroScalar; var oneExpression = oneScalar; if (resultType.mBaseType == OpType.Vector) { zeroExpression = CompositeSplatConstruct(resultType, zeroScalar, context); oneExpression = CompositeSplatConstruct(resultType, oneScalar, context); } var castOp = CreateOp(context.mCurrentBlock, OpInstructionType.OpSelect, resultType, new List <IShaderIR> { expressionOp, zeroScalar, oneScalar }); context.Push(castOp); return(castOp); }
public ShaderOp GenerateCompositeExtract(IShaderIR selfIR, string fieldName, FrontEndContext context) { var selfOp = selfIR as ShaderOp; var selfType = selfOp.mResultType.GetDereferenceType(); ShaderField shaderField; int fieldIndex; FindField(selfType, fieldName, out shaderField, out fieldIndex); var resultType = shaderField.mType.GetDereferenceType(); var constantLiteral = CreateConstantLiteral <uint>((uint)fieldIndex); var memberVariableOp = CreateOp(context.mCurrentBlock, OpInstructionType.OpCompositeExtract, resultType, new List <IShaderIR> { selfOp, constantLiteral }); return(memberVariableOp); }
void IncDecOp(FrontEndTranslator translator, ShaderType resultType, string opToken, ShaderType operandType, OpInstructionType instructionType) { CreateUnaryOpIntrinsic(new UnaryOpKey(opToken, operandType), (IShaderIR operandIR, FrontEndContext context) => { var operandValueOp = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, operandIR); IShaderIR oneConstantOp = null; if (resultType.mBaseType == OpType.Int) { oneConstantOp = translator.CreateConstantOp(operandType, 1); } else if (resultType.mBaseType == OpType.Float) { oneConstantOp = translator.CreateConstantOp(operandType, 1.0f); } return(translator.CreateOp(context.mCurrentBlock, instructionType, resultType, new List <IShaderIR> { operandValueOp, oneConstantOp })); }); }
public void GenerateFunctionCall(ShaderFunction shaderFunction, IShaderIR selfOp, List <CSharpSyntaxNode> arguments) { var argumentOps = new List <IShaderIR>(); argumentOps.Add(shaderFunction); if (!shaderFunction.IsStatic) { argumentOps.Add(selfOp); } for (var i = 0; i < arguments.Count; ++i) { var argument = arguments[i]; var paramIR = GetFunctionParameter(shaderFunction, i, argument); argumentOps.Add(paramIR); } var fnShaderReturnType = shaderFunction.GetReturnType(); var functionCallOp = mFrontEnd.CreateOp(mContext.mCurrentBlock, OpInstructionType.OpFunctionCall, fnShaderReturnType, argumentOps); mContext.Push(functionCallOp); }
public void GenerateLoopConditionBlock(SyntaxNode conditionalNode, ShaderBlock conditionBlock, ShaderBlock branchTrueBlock, ShaderBlock branchFalseBlock, FrontEndContext context) { // The condition builds the conditional and then jumps either to the body of the loop or to the end context.mCurrentBlock = conditionBlock; // If the conditional node exists if (conditionalNode != null) { //ExtractDebugInfo(conditionalNode->Condition, context->mDebugInfo); // Get the conditional value (must be a bool via how zilch works) IShaderIR conditional = WalkAndGetValueTypeResult(context.mCurrentBlock, conditionalNode); // Branch to either the true or false branch mFrontEnd.CreateOp(context.mCurrentBlock, OpInstructionType.OpBranchConditional, null, new List <IShaderIR> { conditional, branchTrueBlock, branchFalseBlock }); } // Otherwise there is no conditional (e.g. loop) so unconditionally branch to the true block else { mFrontEnd.CreateOp(context.mCurrentBlock, OpInstructionType.OpBranch, null, new List <IShaderIR> { branchTrueBlock }); } }
public ShaderOp GetOrGenerateValueTypeFromIR(ShaderBlock block, IShaderIR ir) { var op = ir as ShaderOp; if (op == null) { return(null); } var opResultType = GetOpResultType(op); if (opResultType.mBaseType != OpType.Pointer) { return(op); } var opValueType = GetValueType(opResultType); var valueOp = CreateOp(block, OpInstructionType.OpLoad, opValueType, new List <IShaderIR> { op }); return(valueOp); }
public override void VisitAssignmentExpression(AssignmentExpressionSyntax node) { // Always get the right IR but not always the left. In some cases with setters we don't need the left. This avoids loading the left twice. IShaderIR leftIR = null; IShaderIR rightIR = WalkAndGetResult(node.Right); // If the token isn't the assignment op, then this must be a compound assignment (e.g. '+='). var token = node.OperatorToken.Text; if (token != "=") { // To do the compound we have to load the left now. leftIR = WalkAndGetResult(node.Left); var lhsType = GetSymbolType(node.Left); var rhsType = GetSymbolType(node.Right); // Generate the token for the binary op in the compound (just strip the '=' off) and then visit the binary expression. var binaryOp = token.Substring(0, token.Length - 1); VisitBinaryExpression(node, lhsType, leftIR, rhsType, rightIR, binaryOp); // Do whatever remaining logic for the assignment with the result of the binary expression. rightIR = mContext.Pop(); } // If the left side is actually a setter, then we have to flip the assignment around to call the setter var leftSymbol = GetSymbol(node.Left); // One complicated case is if the left is actually a member access (e.g. Vec3.XY = rhs). // In this case, we need to call the setter on Vec3 (the expression of the member access) if (node.Left is MemberAccessExpressionSyntax memberAccessNode && leftSymbol.IsStatic == false) { FunctionKey functionKey = null; // Try and get the function key for this symbol depending on if it's a field, property, etc... if (leftSymbol is IPropertySymbol propertySymbol && !propertySymbol.IsReadOnly) { functionKey = new FunctionKey(propertySymbol.SetMethod); }
public void AddIRForSymbol(ISymbol symbol, IShaderIR ir) { mContext.mSymbolToIRMap.Add(symbol, ir); }
public override void Visit(IShaderIR shaderIR) { GetId(shaderIR); base.Visit(shaderIR); }
public void GenerateFunctionCall(ShaderFunction shaderFunction, IShaderIR selfOp, List <IShaderIR> arguments) { mFrontEnd.GenerateFunctionCall(shaderFunction, selfOp, arguments, mContext); }
public IShaderIR GetFunctionParameter(ShaderFunction shaderFunction, int paramIndex, IShaderIR argumentOp) { return(mFrontEnd.GetFunctionParameter(shaderFunction, paramIndex, argumentOp, mContext)); }
public void ExtractDebugInfo(IShaderIR ir, ISymbol symbol, SyntaxNode node) { ir.DebugInfo.Name = symbol.Name; ir.DebugInfo.Location = node.GetLocation(); }
public static void ResolveVectorSwizzleSetter(FrontEndTranslator translator, FrontEndContext context, AttributeData attribute, ISymbol returnType, IShaderIR selfInstance, IShaderIR rhsIR) { var swizzleElements = attribute.ConstructorArguments[0].Values; var selfValue = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, selfInstance); var selfValueType = selfValue.mResultType.GetDereferenceType(); var componentCount = (UInt32)(selfValueType.mParameters[1] as ShaderConstantLiteral).mValue; var rhs = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, rhsIR); // If we're setting just a single element, then do an access chain and to set that element if (swizzleElements.Length == 1) { // Find what element we're setting var constantLiteral = translator.CreateConstantLiteral((UInt32)swizzleElements[0].Value); var memberIndexConstant = translator.CreateConstantOp(translator.FindType(typeof(uint)), constantLiteral); // Lookup the result type var resultType = translator.mCurrentLibrary.FindType(new TypeKey(returnType)); resultType = resultType.FindPointerType(selfValue.mResultType.mStorageClass); // Build the access chain to the element var memberVariableOp = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpAccessChain, resultType, new List <IShaderIR> { selfInstance, memberIndexConstant }); // Then set this back to the lhs side translator.CreateStoreOp(context.mCurrentBlock, memberVariableOp, rhs); } // Otherwise construct a new vector and set it over else { var swizzleArgs = new List <IShaderIR>() { selfValue, rhs }; // Build up a set of what element indices were in the swizzle var elementSet = new HashSet <UInt32>(); foreach (var element in swizzleElements) { elementSet.Add((UInt32)element.Value); } // Foreach element in the new vector, choose if we take it from the rhs or the lhs. If the element index is in the swizzle ops, // then take the next element from rhs, otherwise take the same index from lhs. var rhsElementIndex = 0u; for (uint element = 0; element < componentCount; ++element) { if (elementSet.Contains(element)) { swizzleArgs.Add(translator.CreateConstantLiteral(componentCount + rhsElementIndex)); ++rhsElementIndex; } else { swizzleArgs.Add(translator.CreateConstantLiteral(element)); } } // To build the setter, first create the new vector from components in the lhs/rhs as appropriate. var op = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpVectorShuffle, selfValueType, swizzleArgs); // Then set this back to the lhs side translator.CreateStoreOp(context.mCurrentBlock, selfInstance, op); } }
public void ExtractDebugInfo(IShaderIR ir, SyntaxNode node) { ir.DebugInfo.Location = node.GetLocation(); }