/// <summary> /// Does a simple intrinsic (one where all ops are value types). /// </summary> static void SimpleValueTypeIntrinsic(FrontEndTranslator translator, FrontEndContext context, OpInstructionType opType, ShaderType returnType, List <IShaderIR> arguments) { var valueOps = new List <IShaderIR>(); foreach (var argument in arguments) { valueOps.Add(translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, argument)); } var op = translator.CreateOp(context.mCurrentBlock, opType, returnType, valueOps); context.Push(op); }
public void Translate(FrontEndTranslator translator, CSharpCompilation compilation, List <SyntaxTree> trees) { FrontEndContext context = new FrontEndContext(); context.mFrontEnd = translator; foreach (var pass in mPasses) { pass.Visit(translator, compilation, trees, context); } // Validation passes }
public static ShaderEntryPointInfo GeneratePixel(FrontEndTranslator translator, ShaderType shaderType, ShaderFunction function) { var entryPoint = new ShaderEntryPointInfo(); var context = new FrontEndContext(); context.mCurrentType = shaderType; var interfaceInfo = new EntryPointInterfaceInfo(); EntryPointGenerationShared.CollectInterface(translator, shaderType, interfaceInfo); // Build inputs block EntryPointGenerationShared.GenerateHardwareBuiltIns(translator, interfaceInfo.HardwareBuiltInInputs, StorageClass.Input, entryPoint.mInterfaceVariables, entryPoint.mDecorations); InputDeclarations.GenerateInputStruct(translator, shaderType, interfaceInfo.StageInputs, entryPoint.mInterfaceVariables, entryPoint.mDecorations); EntryPointGenerationShared.GenerateHardwareBuiltIns(translator, interfaceInfo.HardwareBuiltInOutputs, StorageClass.Output, entryPoint.mInterfaceVariables, entryPoint.mDecorations); OutputDeclarations.GenerateOutputFields(translator, shaderType, interfaceInfo.StageOutputs, entryPoint.mInterfaceVariables, entryPoint.mDecorations); UniformDeclarations.DeclareUniformBuffers(translator, interfaceInfo.UniformBuffers, entryPoint.mInterfaceVariables, entryPoint.mDecorations); UniformDeclarations.DeclareUniformConstants(translator, interfaceInfo.ConstantUniforms, entryPoint.mDecorations); // Create the functions required to run an entry point string entryPointName = EntryPointGenerationShared.GenerateEntryPointFunctionName(translator, shaderType, function); CreateGlobalVariableInitializeFunction(translator, shaderType, entryPoint, interfaceInfo, context); InputDeclarations.GenerateCopyInputsFunction(translator, shaderType, entryPoint, interfaceInfo); OutputDeclarations.GenerateCopyOutputsFunction(translator, shaderType, entryPoint, interfaceInfo); var entryPointFunction = GenerateSpirVEntryPointFunction(translator, shaderType, entryPointName); // Generate the entry point function body translator.TryGenerateFunctionCall(entryPoint.mGlobalsInitializationFunction, null, null, entryPointFunction.Context); EntryPointGenerationShared.ConstructShaderType(translator, shaderType, entryPointFunction.Context); var entryPointThisOp = entryPointFunction.Context.mThisOp; translator.TryGenerateFunctionCall(interfaceInfo.CopyInputsFunction.ShaderFunction, entryPointThisOp, null, entryPointFunction.Context); translator.TryGenerateFunctionCall(function, entryPointThisOp, null, entryPointFunction.Context); translator.TryGenerateFunctionCall(interfaceInfo.CopyOutputsFunction.ShaderFunction, entryPointThisOp, null, entryPointFunction.Context); translator.FixupBlockTerminators(entryPointFunction.ShaderFunction); // Make sure all global variables are added to the interface of the entry point AddGlobalVariables(translator, entryPoint, interfaceInfo); entryPoint.mEntryPointFunction = entryPointFunction.ShaderFunction; entryPoint.mStageType = shaderType.mFragmentType; shaderType.mEntryPoints.Add(entryPoint); EntryPointGenerationShared.AddExecutionMode(translator, entryPoint, entryPoint.mEntryPointFunction, Spv.ExecutionMode.ExecutionModeOriginUpperLeft); return(entryPoint); }
public static EntryPointFunction GenerateEntryPointCopyFunction(FrontEndTranslator translator, ShaderType shaderType, string functionName) { ShaderOp thisOp = null; var shaderFunction = GenerateFunction_ShaderTypeParam(translator, shaderType, functionName, out thisOp); var context = new FrontEndContext(); context.mCurrentBlock = shaderFunction.mBlocks[0]; context.mCurrentFunction = shaderFunction; var entryPointFunction = new EntryPointFunction(); entryPointFunction.Context = context; entryPointFunction.ShaderFunction = shaderFunction; entryPointFunction.ShaderTypeInstanceOp = thisOp; return(entryPointFunction); }
/// <summary> /// Does a simple extension intrinsic (one where all ops are value types). /// </summary> static void ResolveSimpleExtensionIntrinsic(FrontEndTranslator translator, FrontEndContext context, string extensionName, int extOpType, ShaderType returnType, List <IShaderIR> arguments) { var extensionImportOp = translator.mCurrentLibrary.GetOrCreateExtensionLibraryImport(extensionName); var extOpTypeOp = translator.CreateConstantLiteral(extOpType); var valueOps = new List <IShaderIR>(); valueOps.Add(extensionImportOp); valueOps.Add(extOpTypeOp); foreach (var argument in arguments) { valueOps.Add(translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, argument)); } var op = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpExtInst, returnType, valueOps); context.Push(op); }
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); }
public ShaderOp ConstructAndInitializeOpVariable(ShaderType shaderType, FrontEndContext context) { // Create the variable var voidType = mCurrentLibrary.FindType(new TypeKey(typeof(void))); var varOp = CreateOpVariable(shaderType, context); // Either call the constructor or implicitly construct the type if needed. if (shaderType.mImplicitConstructor != null) { var fnParamOps = new List <IShaderIR>(); fnParamOps.Add(shaderType.mImplicitConstructor); fnParamOps.Add(varOp); CreateOp(context.mCurrentBlock, OpInstructionType.OpFunctionCall, voidType, fnParamOps); } else if (shaderType.mPreConstructor != null) { var fnParamOps = new List <IShaderIR>(); fnParamOps.Add(shaderType.mPreConstructor); fnParamOps.Add(varOp); CreateOp(context.mCurrentBlock, OpInstructionType.OpFunctionCall, voidType, fnParamOps); } return(varOp); }
public void CreateDummyEntryPoint(TypeDependencyCollector typeCollector, ShaderLibrary library, FrontEndTranslator frontEnd, ShaderType shaderType) { var context = new FrontEndContext(); context.mCurrentType = shaderType; if (shaderType.mEntryPoints.Count != 0) { return; } ShaderEntryPointInfo entryPoint = null; if (shaderType.mFragmentType == FragmentType.Pixel || shaderType.mFragmentType == FragmentType.None) { entryPoint = EntryPointGeneration.GeneratePixel(frontEnd, shaderType, null); } else if (shaderType.mFragmentType == FragmentType.Vertex) { entryPoint = EntryPointGeneration.GenerateVertex(frontEnd, shaderType, null); } typeCollector.Visit(entryPoint); }
public virtual void Visit(FrontEndTranslator translator, CSharpCompilation compilation, List <SyntaxTree> trees, FrontEndContext context) { mFrontEnd = translator; mContext = context; mContext.mCurrentPass = this; VisitTrees(compilation, trees); }
public ShaderOp CastUnsignedConvert(ShaderType resultType, IShaderIR expressionOp, FrontEndContext context) { return(SimpleCast(resultType, OpInstructionType.OpUConvert, expressionOp, context)); }
static void ProcessCompositeConstructIntrinsic(FrontEndTranslator translator, ShaderType returnType, List <IShaderIR> arguments, FrontEndContext context) { // Extract how many elements this composite is made up of var compositeCountLiteral = returnType.mParameters[1] as ShaderConstantLiteral; var compositeCount = (uint)compositeCountLiteral.mValue; var valueOps = new List <IShaderIR>(); // If this is a splat constructor (only 1 arg) then splat the argument for each composite element if (arguments.Count == 1) { var splatArgument = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[0]); for (uint i = 0; i < compositeCount; ++i) { valueOps.Add(splatArgument); } } // Otherwise, just copy all args over (@JoshD: Needs validation) else { foreach (var argument in arguments) { valueOps.Add(translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, argument)); } } var op = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpCompositeConstruct, returnType, valueOps); context.Push(op); }
public ShaderOp CastUIntToInt(ShaderType resultType, IShaderIR expressionOp, FrontEndContext context) { return(SimpleCast(resultType, OpInstructionType.OpBitcast, expressionOp, context)); }
public static void CopyInterfaceFields(FrontEndTranslator translator, ShaderOp thisOp, ShaderInterfaceSet interfaceSet, InterfaceFieldCopyMode copyMode, FrontEndContext context) { foreach (var interfaceField in interfaceSet) { var interfaceInstance = interfaceSet.GetFieldInstance(translator, interfaceField, context); if (interfaceInstance == null) { continue; } var shaderFieldInstance = translator.GenerateAccessChain(thisOp, interfaceField.ShaderField.mMeta.mName, context); if (copyMode == InterfaceFieldCopyMode.Input) { translator.CreateStoreOp(context.mCurrentBlock, shaderFieldInstance, interfaceInstance); } else { translator.CreateStoreOp(context.mCurrentBlock, interfaceInstance, shaderFieldInstance); } } }
public static void CreateGlobalVariableInitializeFunction(FrontEndTranslator translator, ShaderType shaderType, ShaderEntryPointInfo entryPoint, EntryPointInterfaceInfo interfaceInfo, FrontEndContext context) { // First check if any global variables that need the variable initialization function exist. If not then don't emit anything. bool globalVariablesExist = false; foreach (var globalField in interfaceInfo.GlobalFields) { if (globalField.InitialValue != null) { globalVariablesExist = true; } } if (!globalVariablesExist) { return; } var library = translator.mCurrentLibrary; var voidType = library.FindType(new TypeKey(typeof(void))); var initGlobalFunction = translator.CreateFunctionAndType(shaderType, voidType, "InitGlobals", null, null); initGlobalFunction.mBlocks.Add(new ShaderBlock()); entryPoint.mGlobalsInitializationFunction = initGlobalFunction; // Add the store op for each global variable context.mCurrentFunction = initGlobalFunction; context.mCurrentBlock = initGlobalFunction.mBlocks[0]; foreach (var globalField in interfaceInfo.GlobalFields) { if (globalField.InitialValue != null) { translator.CreateStoreOp(context.mCurrentBlock, globalField.InstanceOp, globalField.InitialValue); } } translator.FixupBlockTerminators(context.mCurrentFunction); }
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 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 GenerateLoopContinueBlock(IEnumerable <SyntaxNode> iteratorNodes, ShaderBlock continueBlock, ShaderBlock headerBlock, FrontEndContext context) { // Mark the continue block as the active block context.mCurrentBlock = continueBlock; // If it exists, walk the iterator statement if (iteratorNodes != null) { foreach (var iteratorNode in iteratorNodes) { Visit(iteratorNode); } } // Always jump back to the header block mFrontEnd.CreateOp(continueBlock, OpInstructionType.OpBranch, null, new List <IShaderIR> { headerBlock }); }
public ShaderOp CastFloatToUInt(ShaderType resultType, IShaderIR expressionOp, FrontEndContext context) { return(SimpleCast(resultType, OpInstructionType.OpConvertFToU, expressionOp, context)); }
public ShaderOp GetOwnerInstance(FrontEndTranslator translator, ShaderOp ownerOp, FrontEndContext context) { if (GetOwnerDelegate == null) { return(ownerOp); } return(GetOwnerDelegate(translator, this, ownerOp, context)); }
static void CombinedSampledImageValueTypeIntrinsic(FrontEndTranslator translator, FrontEndContext context, ImageIntrinsicAttributeData intrinsicData, ShaderType returnType, List <IShaderIR> arguments) { var valueOps = new List <IShaderIR>(); var sampledImageParam = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[0]); var sampledImageType = sampledImageParam.mResultType; var imageType = sampledImageType.mParameters[0] as ShaderType; // Pull the image out of the sampled image. var imageOp = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpImage, imageType, new List <IShaderIR>() { sampledImageParam }); valueOps.Add(imageOp); WriteArguments(translator, context, valueOps, intrinsicData, arguments, 1); var op = translator.CreateOp(context.mCurrentBlock, intrinsicData.OpType, returnType, valueOps); context.Push(op); }
/////////////////////////////////////////////////////////////// Loops public void GenerateGenericLoop(IEnumerable <SyntaxNode> initializerNodes, IEnumerable <SyntaxNode> iteratorNodes, SyntaxNode conditionalNode, StatementSyntax loopScopeNode, FrontEndContext context) { // Always walk the initializer node statements first if they exists. The contents of this go before any loop block. if (initializerNodes != null) { foreach (var initializerNode in initializerNodes) { WalkAndGetResult(initializerNode); } } // A basic while looks like a header block that always jumps to a condition block. // The condition block will choose to jump either to the loop block or to the merge point. // The loop block will always branch to the continue target unless a break happens which // will branch to the merge block (after the loop). // The continue block will always jump back to the header block. var headerBlock = mFrontEnd.CreateBlock("headerBlock"); var conditionBlock = mFrontEnd.CreateBlock("conditionBlock"); var loopTrueBlock = mFrontEnd.CreateBlock("loop-body"); var continueBlock = mFrontEnd.CreateBlock("continueBlock"); var mergeBlock = mFrontEnd.CreateBlock("after-loop"); // Always jump to the header block mFrontEnd.CreateOp(context.mCurrentBlock, OpInstructionType.OpBranch, null, new List <IShaderIR> { headerBlock }); // The header always jumps to the conditional context.mCurrentFunction.mBlocks.Add(headerBlock); GenerateLoopHeaderBlock(headerBlock, conditionBlock, mergeBlock, continueBlock, context); // The conditional will jump to either the loop body or the merge point (after the loop) context.mCurrentFunction.mBlocks.Add(conditionBlock); GenerateLoopConditionBlock(conditionalNode, conditionBlock, loopTrueBlock, mergeBlock, context); // Walk all of the statements in the loop body and jump to either the merge or continue block context.mCurrentFunction.mBlocks.Add(loopTrueBlock); GenerateLoopStatements(loopScopeNode, loopTrueBlock, mergeBlock, continueBlock, context); // The continue block always just jumps to the header block context.mCurrentFunction.mBlocks.Add(continueBlock); GenerateLoopContinueBlock(iteratorNodes, continueBlock, headerBlock, context); // Afterwards the active block is always the merge point context.mCurrentFunction.mBlocks.Add(mergeBlock); context.mCurrentBlock = mergeBlock; }
public ShaderOp CastFloatToBool(ShaderType resultType, IShaderIR expressionOp, FrontEndContext context) { var constantOp = CreateConstantOp <float>(0.0f); return(SimpleCompareCast(resultType, OpInstructionType.OpFOrdNotEqual, expressionOp, constantOp, context)); }
public void GenerateLoopHeaderBlock(ShaderBlock headerBlock, ShaderBlock branchTarget, ShaderBlock mergeBlock, ShaderBlock continueBlock, FrontEndContext context) { // Mark the header block as a loop block (so we emit the LoopMerge instruction) headerBlock.mBlockType = BlockType.Loop; // Being a LoopMerge requires setting the merge and continue points headerBlock.mMergePoint = mergeBlock; headerBlock.mContinuePoint = continueBlock; var loopControlMask = mFrontEnd.CreateConstantLiteral <uint>((uint)Spv.LoopControlMask.LoopControlMaskNone); mFrontEnd.CreateOp(headerBlock, OpInstructionType.OpLoopMerge, null, new List <IShaderIR> { mergeBlock, continueBlock, loopControlMask }); // The header always jumps to the branch target (typically a continue) mFrontEnd.CreateOp(headerBlock, OpInstructionType.OpBranch, null, new List <IShaderIR> { branchTarget }); }
public static void ConstructShaderType(FrontEndTranslator translator, ShaderType shaderType, FrontEndContext context) { var selfOp = translator.ConstructAndInitializeOpVariable(shaderType, context); selfOp.DebugInfo.Name = "self"; context.mThisOp = selfOp; }
public void GenerateLoopStatements(StatementSyntax loopScopeNode, ShaderBlock loopBlock, ShaderBlock mergeBlock, ShaderBlock continueBlock, FrontEndContext context) { context.mCurrentBlock = loopBlock; // Set the continue and merge points for this block (mainly needed for nested loops) loopBlock.mContinuePoint = continueBlock; loopBlock.mMergePoint = mergeBlock; context.PushMergePoint(continueBlock, mergeBlock); // Iterate over all of the statements in the loop body Visit(loopScopeNode); // Write out a jump back to the continue block of the loop. Only write this to the active block // which will either be the end of the loop block or something like an after if if (context.mCurrentBlock.mTerminatorOp == null) { var currentBlockContinue = mFrontEnd.CreateOp(context.mCurrentBlock, OpInstructionType.OpBranch, null, new List <IShaderIR> { continueBlock }); } context.PopMergePoint(); }
public ShaderOp GetFieldInstance(FrontEndTranslator translator, ShaderInterfaceField interfaceField, FrontEndContext context) { if (interfaceField.GetInstance == null) { return(null); } return(interfaceField.GetInstance(translator, interfaceField, context)); }
public static void ResolveMatrixDefaultConstructor(FrontEndTranslator translator, FrontEndContext context, ShaderType vectorType) { var componentType = vectorType.mParameters[0] as ShaderType; var componentCount = (UInt32)(vectorType.mParameters[1] as ShaderConstantLiteral).mValue; // This direct call to the vector resolver is less than ideal, but works for now VectorResolvers.ResolveVectorDefaultConstructor(translator, context, componentType); var zeroConstant = context.Pop(); var constructorArgs = new List <IShaderIR>(); for (var i = 0; i < componentCount; ++i) { constructorArgs.Add(zeroConstant); } var op = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpCompositeConstruct, vectorType, constructorArgs); context.Push(op); }
void LogicalOrAnd(SyntaxNode lhsExpression, SyntaxNode rhsExpression, FrontEndContext context, bool isOr) { var translator = context.mFrontEnd; var boolType = translator.FindType(typeof(bool)); // Walk the left hand operator (this can change the current block) var leftIR = context.mCurrentPass.WalkAndGetResult(lhsExpression); // In the current block, get the value type result of the left hand side var leftOp = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, leftIR); // Logical ors/ands have to generate conditionals due to short circuit evaluation. To store the temporary // result we have to either generate a temporary variable or use an OpPhi instruction. For convenience generate a temporary. var temp = translator.CreateOpVariable(boolType.FindPointerType(StorageClass.Function), context); if (isOr) { temp.DebugInfo.Name = "tempOr"; } else { temp.DebugInfo.Name = "tempAnd"; } // If statements always have 3 new blocks var ifTrue = translator.CreateBlock("ifTrue"); var ifFalse = translator.CreateBlock("ifFalse"); var mergePoint = translator.CreateBlock("mergePoint"); // Mark the current block as a selection that merges at the merge block var currentBlock = context.mCurrentBlock; currentBlock.mBlockType = BlockType.Selection; currentBlock.mMergePoint = mergePoint; // Branch to the true or false block depending on the value of the left op. // Logical Or/And are the same except for which branch they short-circuit on so // simply flip the true/false blocks to differentiate between them. var selectControlMask = translator.CreateConstantLiteral <uint>((uint)Spv.SelectionControlMask.SelectionControlMaskNone); translator.CreateOp(currentBlock, OpInstructionType.OpSelectionMerge, null, new List <IShaderIR> { mergePoint, selectControlMask }); if (isOr) { translator.CreateOp(currentBlock, OpInstructionType.OpBranchConditional, null, new List <IShaderIR> { leftOp, ifTrue, ifFalse }); } else { translator.CreateOp(currentBlock, OpInstructionType.OpBranchConditional, null, new List <IShaderIR> { leftOp, ifFalse, ifTrue }); } // In the true condition of a LogicalOr, we don't have to walk the left // hand side so simply store the result into the temp variable and branch to the merge point. context.mCurrentBlock = ifTrue; context.mCurrentFunction.mBlocks.Add(ifTrue); translator.CreateStoreOp(ifTrue, temp, leftOp); translator.CreateOp(ifTrue, OpInstructionType.OpBranch, null, new List <IShaderIR> { mergePoint }); // In the false block we have to evaluate the right hand side. If there are nested Ors/Ands they will each // generate an if/else chain that has to be evaluated but without actually evaluating a side that needs to be short circuited. context.mCurrentBlock = ifFalse; context.mCurrentFunction.mBlocks.Add(ifFalse); var rightIR = context.mCurrentPass.WalkAndGetResult(rhsExpression); // Walking the right hand side can change the current block currentBlock = context.mCurrentBlock; // Always store the result of the right hand side into our temp translator.CreateStoreOp(currentBlock, temp, rightIR); // And always branch to the merge point translator.CreateOp(currentBlock, OpInstructionType.OpBranch, null, new List <IShaderIR> { mergePoint }); // Now continue control flow from the merge point with the result of this expression as our temporary result context.mCurrentBlock = mergePoint; context.mCurrentFunction.mBlocks.Add(mergePoint); context.Push(temp); }
public static void ResolveVectorDefaultConstructor(FrontEndTranslator translator, FrontEndContext context, ShaderType vectorType) { var componentType = vectorType.mParameters[0] as ShaderType; var componentCount = (UInt32)(vectorType.mParameters[1] as ShaderConstantLiteral).mValue; var zeroConstantLiteral = translator.CreateConstantLiteralZero(componentType); var zeroConstant = translator.CreateConstantOp(componentType, zeroConstantLiteral); var constructorArgs = new List <IShaderIR>(); for (var i = 0; i < componentCount; ++i) { constructorArgs.Add(zeroConstant); } var op = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpCompositeConstruct, vectorType, constructorArgs); context.Push(op); }
static void SplitSampledImageValueTypeIntrinsic(FrontEndTranslator translator, FrontEndContext context, ImageIntrinsicAttributeData intrinsicData, ShaderType returnType, List <IShaderIR> arguments) { var valueOps = new List <IShaderIR>(); var imageParam = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[0]); var samplerParam = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[1]); // Try and generate a sampled image type for this image. If we do create a new type that wasn't necessary that's fine because it'll be de-duped in the binary backend. var sampledImageTypeStr = new TypeName { Name = "GeneratedSampledImage_" + imageParam.mResultType.ToString() }; var sampledImageType = translator.FindType(new TypeKey(sampledImageTypeStr)); if (sampledImageType == null) { sampledImageType = translator.CreateType(new TypeKey(sampledImageTypeStr), sampledImageTypeStr, OpType.SampledImage, null); sampledImageType.mParameters.Add(imageParam.mResultType.GetDereferenceType()); } // Combine the image and sampler together into a sampled image. This is a bit annoying, but a sampled image // can't be stored into a variable so this has to be a temporary. Use this combined sampled image in place of the first two args to the intrinsics. var sampledImageOp = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpSampledImage, sampledImageType, new List <IShaderIR>() { imageParam, samplerParam }); valueOps.Add(sampledImageOp); WriteArguments(translator, context, valueOps, intrinsicData, arguments, 2); var op = translator.CreateOp(context.mCurrentBlock, intrinsicData.OpType, returnType, valueOps); context.Push(op); }