public IShaderIR WalkAndGetValueTypeResult(SyntaxNode node) { var ir = WalkAndGetResult(node); // Walking the result could change the block. The load op (if required) must be emitted in the actual current block. return(mFrontEnd.GetOrGenerateValueTypeFromIR(mContext.mCurrentBlock, ir)); }
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); }
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); }
static void WriteArguments(FrontEndTranslator translator, FrontEndContext context, List <IShaderIR> valueOps, ImageIntrinsicAttributeData intrinsicData, List <IShaderIR> arguments, int startIndex) { // If there's no operands location, then just write the arguments as is. It's only if there's a mask and location that we write this (since not all image ops have a mask). if (intrinsicData.OperandsLocation == -1) { for (var i = startIndex; i < arguments.Count; ++i) { valueOps.Add(translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[i])); } } // Otherwise, add all of the given arguments, but put the operands mask in-between based upon the specified location. // This location isn't consistent for all image functions so it became an exposed value. else { for (var i = startIndex; i < intrinsicData.OperandsLocation && i < arguments.Count; ++i) { valueOps.Add(translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[i])); } valueOps.Add(translator.CreateConstantLiteral((UInt32)intrinsicData.Operands)); for (var i = intrinsicData.OperandsLocation; i < arguments.Count; ++i) { valueOps.Add(translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[i])); } } }
void AddSimpleValueTypeBinaryOp(FrontEndTranslator translator, ShaderType resultType, ShaderType lhsType, string opToken, ShaderType rhsType, OpInstructionType instructionType) { CreateBinaryOpIntrinsic(new BinaryOpKey(lhsType, opToken, rhsType), (IShaderIR lhsExpression, IShaderIR rhsExpression, FrontEndContext context) => { var lhsValueOp = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, lhsExpression); var rhsValueOp = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, rhsExpression); return(translator.CreateOp(context.mCurrentBlock, instructionType, resultType, new List <IShaderIR> { lhsValueOp, rhsValueOp })); }); }
public static void ResolveVectorSwizzleGetter(FrontEndTranslator translator, FrontEndContext context, AttributeData attribute, ISymbol returnType, List <IShaderIR> arguments) { var swizzleElements = attribute.ConstructorArguments[0].Values; var self = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[0]); var resultType = translator.mCurrentLibrary.FindType(new TypeKey(returnType)); // By default, assume the swizzle is 1 element (just a composite extract) var swizzleArgs = new List <IShaderIR>() { self }; var opType = OpInstructionType.OpCompositeExtract; // If it's multiple elements, change this to a vector shuffle if (swizzleElements.Length != 1) { swizzleArgs.Add(self); opType = OpInstructionType.OpVectorShuffle; } // Add all elements to grab for the swizzle from the attribute foreach (var element in swizzleElements) { swizzleArgs.Add(translator.CreateConstantLiteral((UInt32)element.Value)); } var op = translator.CreateOp(context.mCurrentBlock, opType, resultType, swizzleArgs); context.Push(op); }
static public void CreateArraySetType(FrontEndTranslator translator, INamedTypeSymbol typeSymbol, IMethodSymbol methodSymbol, AttributeData attribute) { // Do an access chain to get the element and then store the value inside the pointer ShaderLibrary.InstrinsicDelegate callback = (FrontEndTranslator translator, List <IShaderIR> arguments, FrontEndContext context) => { var selfOp = arguments[0]; var indexOp = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[1]); var valueOp = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[2]); var pointerType = valueOp.mResultType.FindPointerType(StorageClass.Function); var accessChainOp = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpAccessChain, pointerType, new List <IShaderIR> { selfOp, indexOp }); translator.CreateStoreOp(context.mCurrentBlock, accessChainOp, valueOp); }; translator.mCurrentLibrary.CreateIntrinsicFunction(new FunctionKey(methodSymbol), callback); }
/// <summary> /// Creates an intrinsic to retrieve an element from an array. This unfortunately has to use OpAccessChain because the other /// instruction requires an integer literal, but OpAccessChain returns a pointer (which isn't exposed). This function will return the element as a value type. /// </summary> static public void CreateArrayGetType(FrontEndTranslator translator, INamedTypeSymbol typeSymbol, IMethodSymbol methodSymbol, AttributeData attribute) { var shaderReturnType = translator.FindType(new TypeKey(methodSymbol.ReturnType)); var pointerReturnType = shaderReturnType.FindPointerType(StorageClass.Function); ShaderLibrary.InstrinsicDelegate callback = (FrontEndTranslator translator, List <IShaderIR> arguments, FrontEndContext context) => { var selfOp = arguments[0]; var indexOp = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, arguments[1]); var accessChainOp = translator.CreateOp(context.mCurrentBlock, OpInstructionType.OpAccessChain, pointerReturnType, new List <IShaderIR> { selfOp, indexOp }); // Always convert the pointer to a value type var returnOp = translator.GetOrGenerateValueTypeFromIR(context.mCurrentBlock, accessChainOp); context.Push(returnOp); }; translator.mCurrentLibrary.CreateIntrinsicFunction(new FunctionKey(methodSymbol), callback); }
void AddSimpleValueTypeUnaryOp(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); return(translator.CreateOp(context.mCurrentBlock, instructionType, resultType, new List <IShaderIR> { operandValueOp })); }); }
/// <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); }
/// <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); }
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 })); }); }
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); }
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); } }