protected void ReturnArray(CodeGenContext context) { // Ruby.Eval.Return(array, caller); array.GenCode(context); context.ldloc(0); context.call(Runtime.Eval.Return); }
internal override void Assign(CodeGenContext context, Node rhs) { // Gen right hand sides ListGen mrhs; if (rhs is ListGen && !(rhs is MultipleRHS)) mrhs = (ListGen)rhs; else mrhs = new ARGS(null, null, rhs, null, location, true); bool created; ISimple list = mrhs.GenArgList(context, out created); list.GenSimple(context); context.callvirt(Runtime.ArgList.CheckSingleRHS); int array = context.StoreInTemp("mrhs", Runtime.ArgListRef, location); context.ReleaseLocal(list, created); // Gen assignments to left hand sides for (LVALUE l = elements; l != null; l = (LVALUE)l.nd_next) { l.Assign(context, new MultipleRHS(array, l.location)); context.pop(); } context.ldloc(array); context.callvirt(Runtime.ArgList.ToRubyArray); context.ReleaseLocal(array, true); }
internal override void GenCode0(CodeGenContext context) { // String.Concat(String.Concat(arg1, arg2), args, ...); head.GenCode0(context); if (head.nd_next != null) { int first = context.StoreInTemp("head", Runtime.StringRef, head.location); for (Node n = head.nd_next; n != null; n = n.nd_next) { n.GenCode0(context); int second = context.StoreInTemp("tail", Runtime.StringRef, n.location); context.ldloc(first); context.ldloc(second); context.callvirt(Runtime.String.Concat); context.stloc(first); context.ReleaseLocal(second, true); } context.ldloc(first); context.ReleaseLocal(first, true); } }
internal override void Defined(CodeGenContext context) { if (args != null) new AND(new ProxyNode(MethodDefined, location), new ProxyNode(((Node)args).Defined, location), location).GenCode(context); else MethodDefined(context); }
internal void GenCall(CodeGenContext context) { int result = context.CreateLocal("result", PrimitiveType.Object); PERWAPI.CILLabel endLabel = context.NewLabel(); PERWAPI.CILLabel retryLabel = context.NewLabel(); context.CodeLabel(retryLabel); context.StartBlock(Clause.Try); { // object result = Call(...) GenCall0(context); context.stloc(result); context.Goto(endLabel); } PERWAPI.TryBlock tryBlock = context.EndTryBlock(); context.StartBlock(Clause.Catch); { CatchBreakException(context, result, endLabel); } context.EndCatchBlock(Runtime.BreakExceptionRef, tryBlock); context.StartBlock(Clause.Catch); { CatchRetryException(context, retryLabel); } context.EndCatchBlock(Runtime.RetryExceptionRef, tryBlock); context.CodeLabel(endLabel); context.ldloc(result); context.ReleaseLocal(result, true); }
internal override void GenCode0(CodeGenContext context) { // hash = new Hash(); context.newobj(Runtime.Hash.ctor); int hash = context.StoreInTemp("hash", Runtime.HashRef, location); Node entry = elements; while (entry != null) { bool key_created, value_created; ISimple key = context.PreCompute0(entry, "key", out key_created); entry = entry.nd_next; ISimple value = context.PreCompute0(entry, "value", out value_created); entry = entry.nd_next; // hash.Add(key, value); context.ldloc(hash); key.GenSimple(context); value.GenSimple(context); context.callvirt(Runtime.Hash.Add); context.ReleaseLocal(key, key_created); context.ReleaseLocal(value, value_created); } context.ldloc(hash); context.ReleaseLocal(hash, true); }
protected new PERWAPI.MethodDef GenerateClassForMethod(CodeGenContext context) { // public class Eval: IEval { evalClass = context.CreateGlobalClass("_Internal", "Eval", Runtime.SystemObjectRef); evalClass.AddImplementedInterface(Runtime.IEvalRef); if (context.CurrentRubyClass == null) { context.CurrentRubyClass = CodeGenContext.AddField(evalClass, PERWAPI.FieldAttr.PublicStatic, "myRubyClass", Runtime.ClassRef); CodeGenContext cctor = context.CreateStaticConstructor(evalClass); cctor.ldsfld(Runtime.Init.rb_cObject); cctor.stsfld(context.CurrentRubyClass); cctor.ret(); cctor.Close(); } MethodDef constructor = GenConstructor(evalClass, context); GenInvokeMethod(evalClass, context); return constructor; // } }
public void GenerateWriterMethod(Type type, CodeGenContext ctx, ILGenerator il) { // arg0: Serializer, arg1: Stream, arg2: value var fields = Helpers.GetFieldInfos(type); foreach (var field in fields) { // Note: the user defined value type is not passed as reference. could cause perf problems with big structs var fieldType = field.FieldType; var data = ctx.GetTypeDataForCall(fieldType); if (data.NeedsInstanceParameter) il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); if (type.IsValueType) il.Emit(OpCodes.Ldarga_S, 2); else il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldfld, field); il.Emit(OpCodes.Call, data.WriterMethodInfo); } il.Emit(OpCodes.Ret); }
internal virtual void GenCode0(CodeGenContext context) { if (this is ISimple) ((ISimple)this).GenSimple(context); else throw new NotImplementedException(GetType().ToString()); }
public void GenerateWriterMethod(Type obtype, CodeGenContext ctx, ILGenerator il) { var getTypeIDMethodInfo = typeof(Serializer).GetMethod("GetTypeID", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(object) }, null); var map = ctx.TypeMap; // arg0: Serializer, arg1: Stream, arg2: object var idLocal = il.DeclareLocal(typeof(ushort)); // get TypeID from object's Type il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Call, getTypeIDMethodInfo); il.Emit(OpCodes.Stloc_S, idLocal); // write typeID il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc_S, idLocal); il.Emit(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(ushort))); // +1 for 0 (null) var jumpTable = new Label[map.Count + 1]; jumpTable[0] = il.DefineLabel(); foreach (var kvp in map) jumpTable[kvp.Value.TypeID] = il.DefineLabel(); il.Emit(OpCodes.Ldloc_S, idLocal); il.Emit(OpCodes.Switch, jumpTable); il.Emit(OpCodes.Newobj, Helpers.ExceptionCtorInfo); il.Emit(OpCodes.Throw); /* null case */ il.MarkLabel(jumpTable[0]); il.Emit(OpCodes.Ret); /* cases for types */ foreach (var kvp in map) { var type = kvp.Key; var data = kvp.Value; il.MarkLabel(jumpTable[data.TypeID]); if (data.NeedsInstanceParameter) il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type); il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Call, data.WriterMethodInfo); il.Emit(OpCodes.Ret); } }
internal override void GenCode0(CodeGenContext context) { bool created; ISimple list = GenArgList(context, out created); list.GenSimple(context); context.callvirt(Runtime.ArgList.ToRubyObject); context.ReleaseLocal(list, created); }
internal void GenCode(CodeGenContext context) { for (Node stmt = this; stmt != null; stmt = stmt.nd_next) { stmt.GenCode0(context); if (stmt.nd_next != null && context.Reachable()) context.pop(); } }
internal override void GenCode0(CodeGenContext context) { bool created; ISimple left = context.PreCompute(lhs, "lhs", out created); new COND((Node)left, (Node)left, rhs, location).GenCode(context); context.ReleaseLocal(left, created); }
public void GenerateReaderMethod(Type type, CodeGenContext ctx, ILGenerator il) { // arg0: Serializer, arg1: stream, arg2: out value if (type.IsClass) { // instantiate empty class il.Emit(OpCodes.Ldarg_2); var gtfh = typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Public | BindingFlags.Static); var guo = typeof(System.Runtime.Serialization.FormatterServices).GetMethod("GetUninitializedObject", BindingFlags.Public | BindingFlags.Static); il.Emit(OpCodes.Ldtoken, type); il.Emit(OpCodes.Call, gtfh); il.Emit(OpCodes.Call, guo); il.Emit(OpCodes.Castclass, type); il.Emit(OpCodes.Stind_Ref); } var fields = Helpers.GetFieldInfos(type); foreach (var field in fields) { var fieldType = field.FieldType; var data = ctx.GetTypeDataForCall(fieldType); if (data.NeedsInstanceParameter) il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); if (type.IsClass) il.Emit(OpCodes.Ldind_Ref); il.Emit(OpCodes.Ldflda, field); il.Emit(OpCodes.Call, data.ReaderMethodInfo); } if (typeof(System.Runtime.Serialization.IDeserializationCallback).IsAssignableFrom(type)) { var miOnDeserialization = typeof(System.Runtime.Serialization.IDeserializationCallback).GetMethod("OnDeserialization", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(Object) }, null); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Constrained, type); il.Emit(OpCodes.Callvirt, miOnDeserialization); } il.Emit(OpCodes.Ret); }
private ISimple PushScope(CodeGenContext context, out bool created) { if (name != null && name.scope != null) return context.PreCompute(name.scope, "scope", out created); else { created = false; if (context.CurrentRubyClass != null) return new StaticField(context.CurrentRubyClass, name.location); else return new StaticField(Runtime.Init.rb_cObject, name.location); } }
internal PERWAPI.PEFile GenerateCode(Field CurrentRubyClass) { CodeGenContext context = new CodeGenContext(); context.CurrentRubyClass = CurrentRubyClass; string name = "Eval_" + System.Guid.NewGuid().ToString("N"); context.CreateAssembly("./", name + ".dll", name, false); GenerateClassForMethod(context); return context.Assembly; }
internal override void GenCode0(CodeGenContext context) { if (args != null) { bool created; ISimple list = args.GenArgList(context, out created); list.GenSimple(context); context.callvirt(Runtime.ArgList.ToRubyArray); context.ReleaseLocal(list, created); } else context.newobj(Runtime.Array.ctor); }
internal override void GenCode0(CodeGenContext context) { PERWAPI.CILLabel elseLabel = context.NewLabel(); PERWAPI.CILLabel endLabel = context.NewLabel(); // if (Eval.Test(cond)) cond.GenCode(context); context.call(Runtime.Eval.Test); context.brfalse(elseLabel); body.GenCode(context); context.br(endLabel); context.CodeLabel(elseLabel); _else.GenCode(context); context.CodeLabel(endLabel); }
internal override void GenCode0(CodeGenContext context) { PERWAPI.CILLabel finalLabel = context.NewLabel(); int RescueTemp = context.CreateLocal("rescueTemp", PERWAPI.PrimitiveType.Object); context.ldnull(); context.stloc(RescueTemp); if (ensure != null) { context.StartBlock(Clause.Try); // outer try block with finally context.StartBlock(Clause.Try); // inner try block with catch } GenInnerBlock(context, RescueTemp); if (ensure != null) { context.Goto(finalLabel); PERWAPI.TryBlock innerTry = context.EndTryBlock(); context.StartBlock(Clause.Catch); GenRescue(context, null, 0, null); context.EndCatchBlock(Runtime.SystemExceptionRef, innerTry); PERWAPI.TryBlock outerTry = context.EndTryBlock(); // Fixme: reset labels to prevent branches out of finally block. context.StartBlock(Clause.Finally); ensure.GenCode(context); if (context.Reachable()) context.pop(); context.endfinally(); context.EndFinallyBlock(outerTry); context.CodeLabel(finalLabel); context.newEndPoint(location); } context.ldloc(RescueTemp); context.ReleaseLocal(RescueTemp, true); }
internal void CopySimple(CodeGenContext context, Scope scope) { if (block != null) { // locals.block = block; string bname = ID.ToDotNetName(block.vid); context.ldloc(0); LoadBlock(context); context.stfld(scope.GetFrameField(bname)); } for (Node f = normal; f != null; f = f.nd_next) { string fname = ID.ToDotNetName(((VAR)f).vid); // local.f = f; context.ldloc(0); context.ldarg(fname); context.stfld(scope.GetFrameField(fname)); } }
public void GenerateWriterMethod(Type type, CodeGenContext ctx, ILGenerator il) { // arg0: buffer, arg1: value var fields = Helpers.GetFieldInfos(type); foreach (var field in fields) { // Note: the user defined value type is not passed as reference. could cause perf problems with big structs il.Emit(OpCodes.Ldarg_0); if (type.IsValueType) il.Emit(OpCodes.Ldarga_S, 1); else il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldfld, field); Helpers.GenSerializerCall(ctx, il, field.FieldType); } il.Emit(OpCodes.Ret); }
public void GenSimple(CodeGenContext context) { if (value is string)// T_STRING, { context.ldstr((string)(value)); context.newobj(Runtime.String.ctor); return; } if (value is int) // T_FIXNUM { context.ldc_i4((int)(value)); context.box(PrimitiveType.Int32); return; } if (value is double)// T_FLOAT { context.ldc_r8((double)(value)); context.newobj(Runtime.Float.ctor); return; } if (value is ID) // T_SYMBOL { context.ldstr(((ID)value).ToString()); context.newobj(Runtime.Symbol.ctor); return; } if (value is BigNum) { BigNum num = (BigNum) value; context.ldc_i4(num.sign); context.ldstr(num.ToString()); context.ldc_i4(num.bas); context.newobj(Runtime.Bignum.ctor); return; } throw new System.NotImplementedException("VALUE " + value.GetType().ToString()); }
internal override void GenCode0(CodeGenContext context) { PERWAPI.CILLabel elseLabel = context.NewLabel(); PERWAPI.CILLabel endLabel = context.NewLabel(); // if (Eval.Test(cond)) context.newLine(cond.location); cond.GenCode(context); context.call(Runtime.Eval.Test); context.brfalse(elseLabel); if (body != null) { context.newStartPoint(body.location); body.GenCode(context); } else context.ldnull(); if (context.Reachable()) context.br(endLabel); context.CodeLabel(elseLabel); if (_else != null) { context.newStartPoint(_else.location); _else.GenCode(context); } else context.ldnull(); context.CodeLabel(endLabel); context.newEndPoint(location); }
public void GenerateReaderMethod(Type obtype, CodeGenContext ctx, ILGenerator il) { var map = ctx.TypeMap; // arg0: Serializer, arg1: stream, arg2: out object var idLocal = il.DeclareLocal(typeof(ushort)); // read typeID il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloca_S, idLocal); il.Emit(OpCodes.Call, ctx.GetReaderMethodInfo(typeof(ushort))); // +1 for 0 (null) var jumpTable = new Label[map.Count + 1]; jumpTable[0] = il.DefineLabel(); foreach (var kvp in map) { jumpTable[kvp.Value.TypeID] = il.DefineLabel(); } il.Emit(OpCodes.Ldloc_S, idLocal); il.Emit(OpCodes.Switch, jumpTable); il.Emit(OpCodes.Newobj, Helpers.ExceptionCtorInfo); il.Emit(OpCodes.Throw); /* null case */ il.MarkLabel(jumpTable[0]); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); /* cases for types */ foreach (var kvp in map) { var type = kvp.Key; var data = kvp.Value; il.MarkLabel(jumpTable[data.TypeID]); var local = il.DeclareLocal(type); // call deserializer for this typeID if (data.NeedsInstanceParameter) { il.Emit(OpCodes.Ldarg_0); } il.Emit(OpCodes.Ldarg_1); if (local.LocalIndex < 256) { il.Emit(OpCodes.Ldloca_S, local); } else { il.Emit(OpCodes.Ldloca, local); } il.Emit(OpCodes.Call, data.ReaderMethodInfo); // write result object to out object il.Emit(OpCodes.Ldarg_2); if (local.LocalIndex < 256) { il.Emit(OpCodes.Ldloc_S, local); } else { il.Emit(OpCodes.Ldloc, local); } if (type.IsValueType) { il.Emit(OpCodes.Box, type); } il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); } }
private static string GetExpression(CodeGenContext context, AstOperation operation) { Instruction inst = operation.Inst; InstInfo info = GetInstructionInfo(inst); if ((info.Type & InstType.Call) != 0) { bool atomic = (info.Type & InstType.Atomic) != 0; int arity = (int)(info.Type & InstType.ArityMask); string args = string.Empty; for (int argIndex = 0; argIndex < arity; argIndex++) { // For shared memory access, the second argument is unused and should be ignored. // It is there to make both storage and shared access have the same number of arguments. // For storage, both inputs are consumed when the argument index is 0, so we should skip it here. if (argIndex == 1 && (atomic || (inst & Instruction.MrMask) == Instruction.MrShared)) { continue; } if (argIndex != 0) { args += ", "; } if (argIndex == 0 && atomic) { Instruction memRegion = inst & Instruction.MrMask; switch (memRegion) { case Instruction.MrShared: args += LoadShared(context, operation); break; case Instruction.MrStorage: args += LoadStorage(context, operation); break; default: throw new InvalidOperationException($"Invalid memory region \"{memRegion}\"."); } } else { VariableType dstType = GetSrcVarType(inst, argIndex); args += GetSoureExpr(context, operation.GetSource(argIndex), dstType); } } if (inst == Instruction.Ballot) { return($"unpackUint2x32({info.OpName}({args})).x"); } else { return(info.OpName + "(" + args + ")"); } } else if ((info.Type & InstType.Op) != 0) { string op = info.OpName; // Return may optionally have a return value (and in this case it is unary). if (inst == Instruction.Return && operation.SourcesCount != 0) { return($"{op} {GetSoureExpr(context, operation.GetSource(0), context.CurrentFunction.ReturnType)}"); } int arity = (int)(info.Type & InstType.ArityMask); string[] expr = new string[arity]; for (int index = 0; index < arity; index++) { IAstNode src = operation.GetSource(index); string srcExpr = GetSoureExpr(context, src, GetSrcVarType(inst, index)); bool isLhs = arity == 2 && index == 0; expr[index] = Enclose(srcExpr, src, inst, info, isLhs); } switch (arity) { case 0: return(op); case 1: return(op + expr[0]); case 2: return($"{expr[0]} {op} {expr[1]}"); case 3: return($"{expr[0]} {op[0]} {expr[1]} {op[1]} {expr[2]}"); } } else if ((info.Type & InstType.Special) != 0) { switch (inst) { case Instruction.Call: return(Call(context, operation)); case Instruction.ImageLoad: return(ImageLoadOrStore(context, operation)); case Instruction.ImageStore: return(ImageLoadOrStore(context, operation)); case Instruction.LoadAttribute: return(LoadAttribute(context, operation)); case Instruction.LoadConstant: return(LoadConstant(context, operation)); case Instruction.LoadLocal: return(LoadLocal(context, operation)); case Instruction.LoadShared: return(LoadShared(context, operation)); case Instruction.LoadStorage: return(LoadStorage(context, operation)); case Instruction.Lod: return(Lod(context, operation)); case Instruction.PackDouble2x32: return(PackDouble2x32(context, operation)); case Instruction.PackHalf2x16: return(PackHalf2x16(context, operation)); case Instruction.StoreLocal: return(StoreLocal(context, operation)); case Instruction.StoreShared: return(StoreShared(context, operation)); case Instruction.StoreStorage: return(StoreStorage(context, operation)); case Instruction.TextureSample: return(TextureSample(context, operation)); case Instruction.TextureSize: return(TextureSize(context, operation)); case Instruction.UnpackDouble2x32: return(UnpackDouble2x32(context, operation)); case Instruction.UnpackHalf2x16: return(UnpackHalf2x16(context, operation)); } } throw new InvalidOperationException($"Unexpected instruction type \"{info.Type}\"."); }
public void GenerateWriterMethod(Type type, CodeGenContext ctx, ILGenerator il) { var elemType = type.GetElementType(); var notNullLabel = il.DefineLabel(); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Brtrue_S, notNullLabel); // if value == null, write 0 il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(uint))); il.Emit(OpCodes.Ret); il.MarkLabel(notNullLabel); // write array len + 1 il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(uint))); // declare i var idxLocal = il.DeclareLocal(typeof(int)); // i = 0 il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_S, idxLocal); var loopBodyLabel = il.DefineLabel(); var loopCheckLabel = il.DefineLabel(); il.Emit(OpCodes.Br_S, loopCheckLabel); // loop body il.MarkLabel(loopBodyLabel); var data = ctx.GetTypeDataForCall(elemType); if (data.NeedsInstanceParameter) { il.Emit(OpCodes.Ldarg_0); } // write element at index i il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldelem, elemType); il.Emit(OpCodes.Call, data.WriterMethodInfo); // i = i + 1 il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc_S, idxLocal); il.MarkLabel(loopCheckLabel); // loop condition il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); il.Emit(OpCodes.Clt); il.Emit(OpCodes.Brtrue_S, loopBodyLabel); il.Emit(OpCodes.Ret); }
public void GenerateWriterMethod(Type obtype, CodeGenContext ctx, ILGenerator il) { var getTypeIDMethodInfo = typeof(Serializer).GetMethod("GetTypeID", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(object) }, null); var map = ctx.TypeMap; // arg0: Serializer, arg1: Stream, arg2: object var idLocal = il.DeclareLocal(typeof(ushort)); // get TypeID from object's Type il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Call, getTypeIDMethodInfo); il.Emit(OpCodes.Stloc_S, idLocal); // write typeID il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc_S, idLocal); il.Emit(OpCodes.Call, ctx.GetWriterMethodInfo(typeof(ushort))); // +1 for 0 (null) var jumpTable = new Label[map.Count + 1]; jumpTable[0] = il.DefineLabel(); foreach (var kvp in map) { jumpTable[kvp.Value.TypeID] = il.DefineLabel(); } il.Emit(OpCodes.Ldloc_S, idLocal); il.Emit(OpCodes.Switch, jumpTable); il.Emit(OpCodes.Newobj, Helpers.ExceptionCtorInfo); il.Emit(OpCodes.Throw); /* null case */ il.MarkLabel(jumpTable[0]); il.Emit(OpCodes.Ret); /* cases for types */ foreach (var kvp in map) { var type = kvp.Key; var data = kvp.Value; il.MarkLabel(jumpTable[data.TypeID]); if (data.NeedsInstanceParameter) { il.Emit(OpCodes.Ldarg_0); } il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_2); il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type); il.Emit(OpCodes.Tailcall); il.Emit(OpCodes.Call, data.WriterMethodInfo); il.Emit(OpCodes.Ret); } }
public Instruction GetNextLabelAutoIncrement(CodeGenContext context) { return(GetLabel(context, _entryCount++)); }
public void GenerateReaderMethod(Type type, CodeGenContext ctx, ILGenerator il) { var elemType = type.GetElementType(); var lenLocal = il.DeclareLocal(typeof(uint)); // read array len il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloca_S, lenLocal); il.Emit(OpCodes.Call, ctx.GetReaderMethodInfo(typeof(uint))); var notNullLabel = il.DefineLabel(); /* if len == 0, return null */ il.Emit(OpCodes.Ldloc_S, lenLocal); il.Emit(OpCodes.Brtrue_S, notNullLabel); il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); il.MarkLabel(notNullLabel); var arrLocal = il.DeclareLocal(type); // create new array with len - 1 il.Emit(OpCodes.Ldloc_S, lenLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Sub); il.Emit(OpCodes.Newarr, elemType); il.Emit(OpCodes.Stloc_S, arrLocal); // declare i var idxLocal = il.DeclareLocal(typeof(int)); // i = 0 il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_S, idxLocal); var loopBodyLabel = il.DefineLabel(); var loopCheckLabel = il.DefineLabel(); il.Emit(OpCodes.Br_S, loopCheckLabel); // loop body il.MarkLabel(loopBodyLabel); // read element to arr[i] var data = ctx.GetTypeDataForCall(elemType); if (data.NeedsInstanceParameter) { il.Emit(OpCodes.Ldarg_0); } il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldelema, elemType); il.Emit(OpCodes.Call, data.ReaderMethodInfo); // i = i + 1 il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc_S, idxLocal); il.MarkLabel(loopCheckLabel); // loop condition il.Emit(OpCodes.Ldloc_S, idxLocal); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Ldlen); il.Emit(OpCodes.Conv_I4); il.Emit(OpCodes.Clt); il.Emit(OpCodes.Brtrue_S, loopBodyLabel); // store new array to the out value il.Emit(OpCodes.Ldarg_2); il.Emit(OpCodes.Ldloc_S, arrLocal); il.Emit(OpCodes.Stind_Ref); il.Emit(OpCodes.Ret); }
protected override void GenerateCodeForConditionalBranch(CodeGenContext context, BranchTargetLabel label, bool reverse) { Left.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value); Right.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value); context.GenerateBinaryCompareConditionalBranch(Op, label, reverse); }
public Instruction GetNextLabel(CodeGenContext context) { return(GetLabel(context, _entryCount)); }
public static string ImageLoadOrStore(CodeGenContext context, AstOperation operation) { AstTextureOperation texOp = (AstTextureOperation)operation; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isArray = (texOp.Type & SamplerType.Array) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; string texCall = texOp.Inst == Instruction.ImageLoad ? "imageLoad" : "imageStore"; int srcIndex = isBindless ? 1 : 0; string Src(VariableType type) { return(GetSoureExpr(context, texOp.GetSource(srcIndex++), type)); } string indexExpr = null; if (isIndexed) { indexExpr = Src(VariableType.S32); } string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr); texCall += "(" + imageName; int coordsCount = texOp.Type.GetDimensions(); int pCount = coordsCount + (isArray ? 1 : 0); void Append(string str) { texCall += ", " + str; } if (pCount > 1) { string[] elems = new string[pCount]; for (int index = 0; index < pCount; index++) { elems[index] = Src(VariableType.S32); } Append("ivec" + pCount + "(" + string.Join(", ", elems) + ")"); } else { Append(Src(VariableType.S32)); } if (texOp.Inst == Instruction.ImageStore) { VariableType type = texOp.Format.GetComponentType(); string[] cElems = new string[4]; for (int index = 0; index < 4; index++) { if (srcIndex < texOp.SourcesCount) { cElems[index] = Src(type); } else { cElems[index] = type switch { VariableType.S32 => NumberFormatter.FormatInt(0), VariableType.U32 => NumberFormatter.FormatUint(0), _ => NumberFormatter.FormatFloat(0) }; } } string prefix = type switch { VariableType.S32 => "i", VariableType.U32 => "u", _ => string.Empty }; Append(prefix + "vec4(" + string.Join(", ", cElems) + ")"); } texCall += ")" + (texOp.Inst == Instruction.ImageLoad ? GetMask(texOp.Index) : ""); return(texCall); }
public static string TextureSample(CodeGenContext context, AstOperation operation) { AstTextureOperation texOp = (AstTextureOperation)operation; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isGather = (texOp.Flags & TextureFlags.Gather) != 0; bool intCoords = (texOp.Flags & TextureFlags.IntCoords) != 0; bool hasLodBias = (texOp.Flags & TextureFlags.LodBias) != 0; bool hasLodLevel = (texOp.Flags & TextureFlags.LodLevel) != 0; bool hasOffset = (texOp.Flags & TextureFlags.Offset) != 0; bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0; bool isArray = (texOp.Type & TextureType.Array) != 0; bool isMultisample = (texOp.Type & TextureType.Multisample) != 0; bool isShadow = (texOp.Type & TextureType.Shadow) != 0; string texCall = intCoords ? "texelFetch" : "texture"; if (isGather) { texCall += "Gather"; } else if (hasLodLevel && !intCoords) { texCall += "Lod"; } if (hasOffset) { texCall += "Offset"; } else if (hasOffsets) { texCall += "Offsets"; } string samplerName = OperandManager.GetSamplerName(context.Config.Type, texOp); texCall += "(" + samplerName; int coordsCount = texOp.Type.GetCoordsCount(); int pCount = coordsCount; int arrayIndexElem = -1; if (isArray) { arrayIndexElem = pCount++; } // The sampler 1D shadow overload expects a // dummy value on the middle of the vector, who knows why... bool hasDummy1DShadowElem = texOp.Type == (TextureType.Texture1D | TextureType.Shadow); if (hasDummy1DShadowElem) { pCount++; } if (isShadow && !isGather) { pCount++; } // On textureGather*, the comparison value is // always specified as an extra argument. bool hasExtraCompareArg = isShadow && isGather; if (pCount == 5) { pCount = 4; hasExtraCompareArg = true; } int srcIndex = isBindless ? 1 : 0; string Src(VariableType type) { return(GetSoureExpr(context, texOp.GetSource(srcIndex++), type)); } void Append(string str) { texCall += ", " + str; } VariableType coordType = intCoords ? VariableType.S32 : VariableType.F32; string AssemblePVector(int count) { if (count > 1) { string[] elems = new string[count]; for (int index = 0; index < count; index++) { if (arrayIndexElem == index) { elems[index] = Src(VariableType.S32); if (!intCoords) { elems[index] = "float(" + elems[index] + ")"; } } else if (index == 1 && hasDummy1DShadowElem) { elems[index] = NumberFormatter.FormatFloat(0); } else { elems[index] = Src(coordType); } } string prefix = intCoords ? "i" : string.Empty; return(prefix + "vec" + count + "(" + string.Join(", ", elems) + ")"); } else { return(Src(coordType)); } } Append(AssemblePVector(pCount)); if (hasExtraCompareArg) { Append(Src(VariableType.F32)); } if (isMultisample) { Append(Src(VariableType.S32)); } else if (hasLodLevel) { Append(Src(coordType)); } string AssembleOffsetVector(int count) { if (count > 1) { string[] elems = new string[count]; for (int index = 0; index < count; index++) { elems[index] = Src(VariableType.S32); } return("ivec" + count + "(" + string.Join(", ", elems) + ")"); } else { return(Src(VariableType.S32)); } } if (hasOffset) { Append(AssembleOffsetVector(coordsCount)); } else if (hasOffsets) { texCall += $", ivec{coordsCount}[4]("; texCall += AssembleOffsetVector(coordsCount) + ", "; texCall += AssembleOffsetVector(coordsCount) + ", "; texCall += AssembleOffsetVector(coordsCount) + ", "; texCall += AssembleOffsetVector(coordsCount) + ")"; } if (hasLodBias) { Append(Src(VariableType.F32)); } // textureGather* optional extra component index, // not needed for shadow samplers. if (isGather && !isShadow) { Append(Src(VariableType.S32)); } texCall += ")" + (isGather || !isShadow ? GetMask(texOp.ComponentMask) : ""); return(texCall); }
protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose) { // NB: a C string's value is its address. // (There is no notion of a string's address as that would be an address of an address.) switch (purpose) { case EvaluationIntention.Value: case EvaluationIntention.ValueOrNode: // might be a case of *(p+i), which can be done as p[i]; if (Arg is AddressOfTreeNode addrOf1) { // 3404 // 3401: collapse *&(expr) on RHS and just generate code for the underlying expr context.SetPrettyPrintProlog("<skipped> "); context.PrettyPrint(Arg); return(addrOf1.Arg.GenerateCodeForValueWithPrettyPrint(context, purpose)); } else { if (Arg is AdditionTreeNode addition) { context.SetPrettyPrintProlog("<skipped> "); context.PrettyPrint(Arg); addition.Left.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value); addition.Right.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value); context.GenerateInstruction("Subscript"); } else { Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value); context.GenerateInstruction("Indirection"); } } break; case EvaluationIntention.SideEffectsOnly: Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.SideEffectsOnly); break; case EvaluationIntention.AddressOrNode: if (Arg is AddressOfTreeNode addrOf2) { // 3401: collapse *&(expr) on LHS and just generate code for the underlying expr context.SetPrettyPrintProlog("<skipped> "); context.PrettyPrint(Arg); return(addrOf2.Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.AddressOrNode)); } else { // NB: if we did ValueOrNode here, we'd have to handle Node results specially // as we cannot allow a Node from ValueOrNode unmodified as AddressOrNode Arg.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value); } break; default: throw new AssertionFailedException("unexpected evaluation intention" + purpose); } return(null); }
internal void AddScopeBody(CodeGenContext context) { returnTemp = context.CreateLocal("returnTemp", PrimitiveType.Object); context.labels = new Labels(); context.labels.Redo = context.NewLabel(); context.labels.Return = context.NewLabel(); // try { ... } context.StartBlock(Clause.Try); { if (BEGIN != null) BEGIN.GenCode(context); context.CodeLabel(context.labels.Redo); if (body != null) { body.GenCode(context); if (context.Reachable()) context.stloc(returnTemp); } context.Goto(context.labels.Return); } PERWAPI.TryBlock tryBlock = context.EndTryBlock(); CatchReturnException(context, tryBlock); // ReturnLabel: // return returnTemp; context.CodeLabel(context.labels.Return); context.newEndPoint(location); if (context.Method.GetRetType() != PERWAPI.PrimitiveType.Void) context.ldloc(returnTemp); context.ret(); context.ReleaseLocal(returnTemp, true); }
private void CreateLastClassMethod(ClassDef Class, CodeGenContext context) { CodeGenContext lastClass = context.CreateMethod(Class, PERWAPI.MethAttr.PublicVirtual, "lastClass", Runtime.ClassRef); lastClass.startMethod(this.location); int frame = lastClass.CreateLocal("frame", Runtime.FrameRef); lastClass.ldarg(0); lastClass.stloc(frame); lastClass.LastClass(this, true); lastClass.ret(); lastClass.ReleaseLocal(frame, true); lastClass.Close(); }
internal override void GenCode0(CodeGenContext context) { base.GenCode0(context); context.call(Runtime.Program.End); }
protected override void GenerateCodeForConditionalBranch(CodeGenContext context, BranchTargetLabel label, bool reverse) { Arg.GenerateCodeForConditionalBranchWithPrettyPrint(context, label, !reverse); }
public static string ImageStore(CodeGenContext context, AstOperation operation) { AstTextureOperation texOp = (AstTextureOperation)operation; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isArray = (texOp.Type & SamplerType.Array) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; string texCall = "imageStore"; int srcIndex = isBindless ? 1 : 0; string Src(VariableType type) { return(GetSoureExpr(context, texOp.GetSource(srcIndex++), type)); } string indexExpr = null; if (isIndexed) { indexExpr = Src(VariableType.S32); } string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr); texCall += "(" + imageName; int coordsCount = texOp.Type.GetDimensions(); int pCount = coordsCount; int arrayIndexElem = -1; if (isArray) { arrayIndexElem = pCount++; } void Append(string str) { texCall += ", " + str; } if (pCount > 1) { string[] elems = new string[pCount]; for (int index = 0; index < pCount; index++) { elems[index] = Src(VariableType.S32); } Append("ivec" + pCount + "(" + string.Join(", ", elems) + ")"); } else { Append(Src(VariableType.S32)); } string[] cElems = new string[4]; for (int index = 0; index < 4; index++) { if (srcIndex < texOp.SourcesCount) { cElems[index] = Src(VariableType.F32); } else { cElems[index] = NumberFormatter.FormatFloat(0); } } Append("vec4(" + string.Join(", ", cElems) + ")"); texCall += ")"; return(texCall); }
public static string StoreShared(CodeGenContext context, AstOperation operation) { return(StoreLocalOrShared(context, operation, DefaultNames.SharedMemoryName)); }
public static string LoadLocal(CodeGenContext context, AstOperation operation) { return(LoadLocalOrShared(context, operation, DefaultNames.LocalMemoryName)); }
void Test(int testNum, string exprToParse, int terminatingChar = -1) { ++_testsRun; var testName = string.Format("results-test-{0}.txt", testNum); using (var tw = File.CreateText(_testDir + testName)) { string tc = terminatingChar >= 0 ? ((char)terminatingChar).ToString() : ""; tw.WriteLine("------ Test: {0} ------\t{1}\t{2}", testNum, tc, exprToParse.Replace("\n", "\r\n")); tw.WriteLine(); var utf8Stream = CodePointStream.FromString(exprToParse); var scanner = new ScanIt(utf8Stream, testName, tw); var symbolTable = new SimpleSymbolTable(); var parser = new StatementParser(scanner, symbolTable); var result = parser.TryParse(); scanner.Message("Parse End"); tw.WriteLine(); result.Dump(tw); tw.WriteLine(); if (!result.HasErrors) { using (var context = new CodeGenContext(tw)) { try { Dump.CommentFormat(); symbolTable.GenerateVariables(context); //result.Result.PrettyPrint (); result.Result.GenerateCodeWithPrettyPrint(context); } catch (Exception ex) { System.Console.WriteLine(ex); } } } tw.WriteLine(); } using (var tr = new StreamReader(File.OpenRead(_testDir + testName))) { var trBytes = tr.ReadToEnd(); System.Console.WriteLine(); System.Console.WriteLine(); System.Console.WriteLine(trBytes); StreamReader mr = null; try { mr = new StreamReader(File.OpenRead(_masterDir + testName)); using ( mr ) { var mrBytes = mr.ReadToEnd(); int len = mrBytes.Length; if (len != trBytes.Length) { System.Console.WriteLine("Test {0} FAILURE: lengths differ!!!!", testNum); return; } for (int i = 0; i < len; i++) { if (trBytes [i] != mrBytes [i]) { System.Console.WriteLine("Test {0} FAILURE: bytes differ!!!!", testNum); return; } } } } catch (System.Exception) { System.Console.WriteLine("Test {0}: No Master!!!", testNum); return; } } System.Console.WriteLine("Test {0}: SUCCESS!!", testNum); ++_testsPassed; }
public static string TextureSample(CodeGenContext context, AstOperation operation) { AstTextureOperation texOp = (AstTextureOperation)operation; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isGather = (texOp.Flags & TextureFlags.Gather) != 0; bool hasDerivatives = (texOp.Flags & TextureFlags.Derivatives) != 0; bool intCoords = (texOp.Flags & TextureFlags.IntCoords) != 0; bool hasLodBias = (texOp.Flags & TextureFlags.LodBias) != 0; bool hasLodLevel = (texOp.Flags & TextureFlags.LodLevel) != 0; bool hasOffset = (texOp.Flags & TextureFlags.Offset) != 0; bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0; bool isArray = (texOp.Type & SamplerType.Array) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; bool isMultisample = (texOp.Type & SamplerType.Multisample) != 0; bool isShadow = (texOp.Type & SamplerType.Shadow) != 0; // This combination is valid, but not available on GLSL. // For now, ignore the LOD level and do a normal sample. // TODO: How to implement it properly? if (hasLodLevel && isArray && isShadow) { hasLodLevel = false; } string texCall = intCoords ? "texelFetch" : "texture"; if (isGather) { texCall += "Gather"; } else if (hasDerivatives) { texCall += "Grad"; } else if (hasLodLevel && !intCoords) { texCall += "Lod"; } if (hasOffset) { texCall += "Offset"; } else if (hasOffsets) { texCall += "Offsets"; } int srcIndex = isBindless ? 1 : 0; string Src(VariableType type) { return(GetSoureExpr(context, texOp.GetSource(srcIndex++), type)); } string indexExpr = null; if (isIndexed) { indexExpr = Src(VariableType.S32); } string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr); texCall += "(" + samplerName; int coordsCount = texOp.Type.GetDimensions(); int pCount = coordsCount; int arrayIndexElem = -1; if (isArray) { arrayIndexElem = pCount++; } // The sampler 1D shadow overload expects a // dummy value on the middle of the vector, who knows why... bool hasDummy1DShadowElem = texOp.Type == (SamplerType.Texture1D | SamplerType.Shadow); if (hasDummy1DShadowElem) { pCount++; } if (isShadow && !isGather) { pCount++; } // On textureGather*, the comparison value is // always specified as an extra argument. bool hasExtraCompareArg = isShadow && isGather; if (pCount == 5) { pCount = 4; hasExtraCompareArg = true; } void Append(string str) { texCall += ", " + str; } VariableType coordType = intCoords ? VariableType.S32 : VariableType.F32; string AssemblePVector(int count) { if (count > 1) { string[] elems = new string[count]; for (int index = 0; index < count; index++) { if (arrayIndexElem == index) { elems[index] = Src(VariableType.S32); if (!intCoords) { elems[index] = "float(" + elems[index] + ")"; } } else if (index == 1 && hasDummy1DShadowElem) { elems[index] = NumberFormatter.FormatFloat(0); } else { elems[index] = Src(coordType); } } string prefix = intCoords ? "i" : string.Empty; return(prefix + "vec" + count + "(" + string.Join(", ", elems) + ")"); } else { return(Src(coordType)); } } string ApplyScaling(string vector) { if (intCoords) { int index = context.FindTextureDescriptorIndex(texOp); if ((context.Config.Stage == ShaderStage.Fragment || context.Config.Stage == ShaderStage.Compute) && (texOp.Flags & TextureFlags.Bindless) == 0 && texOp.Type != SamplerType.Indexed && pCount == 2) { return("Helper_TexelFetchScale(" + vector + ", " + index + ")"); } else { // Resolution scaling cannot be applied to this texture right now. // Flag so that we know to blacklist scaling on related textures when binding them. TextureDescriptor descriptor = context.TextureDescriptors[index]; descriptor.Flags |= TextureUsageFlags.ResScaleUnsupported; context.TextureDescriptors[index] = descriptor; } } return(vector); } Append(ApplyScaling(AssemblePVector(pCount))); string AssembleDerivativesVector(int count) { if (count > 1) { string[] elems = new string[count]; for (int index = 0; index < count; index++) { elems[index] = Src(VariableType.F32); } return("vec" + count + "(" + string.Join(", ", elems) + ")"); } else { return(Src(VariableType.F32)); } } if (hasExtraCompareArg) { Append(Src(VariableType.F32)); } if (hasDerivatives) { Append(AssembleDerivativesVector(coordsCount)); // dPdx Append(AssembleDerivativesVector(coordsCount)); // dPdy } if (isMultisample) { Append(Src(VariableType.S32)); } else if (hasLodLevel) { Append(Src(coordType)); } string AssembleOffsetVector(int count) { if (count > 1) { string[] elems = new string[count]; for (int index = 0; index < count; index++) { elems[index] = Src(VariableType.S32); } return("ivec" + count + "(" + string.Join(", ", elems) + ")"); } else { return(Src(VariableType.S32)); } } if (hasOffset) { Append(AssembleOffsetVector(coordsCount)); } else if (hasOffsets) { texCall += $", ivec{coordsCount}[4]("; texCall += AssembleOffsetVector(coordsCount) + ", "; texCall += AssembleOffsetVector(coordsCount) + ", "; texCall += AssembleOffsetVector(coordsCount) + ", "; texCall += AssembleOffsetVector(coordsCount) + ")"; } if (hasLodBias) { Append(Src(VariableType.F32)); } // textureGather* optional extra component index, // not needed for shadow samplers. if (isGather && !isShadow) { Append(Src(VariableType.S32)); } texCall += ")" + (isGather || !isShadow ? GetMask(texOp.Index) : ""); return(texCall); }
private static string GetExpression(CodeGenContext context, AstOperation operation) { Instruction inst = operation.Inst; InstInfo info = GetInstructionInfo(inst); if ((info.Type & InstType.Call) != 0) { bool atomic = (info.Type & InstType.Atomic) != 0; int arity = (int)(info.Type & InstType.ArityMask); string args = string.Empty; for (int argIndex = 0; argIndex < arity; argIndex++) { if (argIndex != 0) { args += ", "; } VariableType dstType = GetSrcVarType(inst, argIndex); if (argIndex == 0 && atomic) { Instruction memRegion = inst & Instruction.MrMask; switch (memRegion) { case Instruction.MrShared: args += LoadShared(context, operation); break; case Instruction.MrStorage: args += LoadStorage(context, operation); break; default: throw new InvalidOperationException($"Invalid memory region \"{memRegion}\"."); } // We use the first 2 operands above. argIndex++; } else { args += GetSoureExpr(context, operation.GetSource(argIndex), dstType); } } if (inst == Instruction.Ballot) { return($"unpackUint2x32({info.OpName}({args})).x"); } else { return(info.OpName + "(" + args + ")"); } } else if ((info.Type & InstType.Op) != 0) { string op = info.OpName; int arity = (int)(info.Type & InstType.ArityMask); string[] expr = new string[arity]; for (int index = 0; index < arity; index++) { IAstNode src = operation.GetSource(index); string srcExpr = GetSoureExpr(context, src, GetSrcVarType(inst, index)); bool isLhs = arity == 2 && index == 0; expr[index] = Enclose(srcExpr, src, inst, info, isLhs); } switch (arity) { case 0: return(op); case 1: return(op + expr[0]); case 2: return($"{expr[0]} {op} {expr[1]}"); case 3: return($"{expr[0]} {op[0]} {expr[1]} {op[1]} {expr[2]}"); } } else if ((info.Type & InstType.Special) != 0) { switch (inst) { case Instruction.ImageLoad: return(ImageLoadOrStore(context, operation)); case Instruction.ImageStore: return(ImageLoadOrStore(context, operation)); case Instruction.LoadAttribute: return(LoadAttribute(context, operation)); case Instruction.LoadConstant: return(LoadConstant(context, operation)); case Instruction.LoadLocal: return(LoadLocal(context, operation)); case Instruction.LoadShared: return(LoadShared(context, operation)); case Instruction.LoadStorage: return(LoadStorage(context, operation)); case Instruction.Lod: return(Lod(context, operation)); case Instruction.PackDouble2x32: return(PackDouble2x32(context, operation)); case Instruction.PackHalf2x16: return(PackHalf2x16(context, operation)); case Instruction.StoreLocal: return(StoreLocal(context, operation)); case Instruction.StoreShared: return(StoreShared(context, operation)); case Instruction.StoreStorage: return(StoreStorage(context, operation)); case Instruction.TextureSample: return(TextureSample(context, operation)); case Instruction.TextureSize: return(TextureSize(context, operation)); case Instruction.UnpackDouble2x32: return(UnpackDouble2x32(context, operation)); case Instruction.UnpackHalf2x16: return(UnpackHalf2x16(context, operation)); } } throw new InvalidOperationException($"Unexpected instruction type \"{info.Type}\"."); }
public static string GetSoureExpr(CodeGenContext context, IAstNode node, VariableType dstType) { return(ReinterpretCast(context, node, OperandManager.GetNodeDestType(context, node), dstType)); }
public static string ImageLoadOrStore(CodeGenContext context, AstOperation operation) { AstTextureOperation texOp = (AstTextureOperation)operation; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; // TODO: Bindless texture support. For now we just return 0/do nothing. if (isBindless) { switch (texOp.Inst) { case Instruction.ImageStore: return "// imageStore(bindless)"; case Instruction.ImageLoad: NumberFormatter.TryFormat(0, texOp.Format.GetComponentType(), out string imageConst); return imageConst; default: return NumberFormatter.FormatInt(0); } } bool isArray = (texOp.Type & SamplerType.Array) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; string texCall; if (texOp.Inst == Instruction.ImageAtomic) { texCall = (texOp.Flags & TextureFlags.AtomicMask) switch { TextureFlags.Add => "imageAtomicAdd", TextureFlags.Minimum => "imageAtomicMin", TextureFlags.Maximum => "imageAtomicMax", TextureFlags.Increment => "imageAtomicAdd", // TODO: Clamp value. TextureFlags.Decrement => "imageAtomicAdd", // TODO: Clamp value. TextureFlags.BitwiseAnd => "imageAtomicAnd", TextureFlags.BitwiseOr => "imageAtomicOr", TextureFlags.BitwiseXor => "imageAtomicXor", TextureFlags.Swap => "imageAtomicExchange", TextureFlags.CAS => "imageAtomicCompSwap", _ => "imageAtomicAdd", }; } else { texCall = texOp.Inst == Instruction.ImageLoad ? "imageLoad" : "imageStore"; } int srcIndex = isBindless ? 1 : 0; string Src(VariableType type) { return GetSoureExpr(context, texOp.GetSource(srcIndex++), type); } string indexExpr = null; if (isIndexed) { indexExpr = Src(VariableType.S32); } string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr); texCall += "(" + imageName; int coordsCount = texOp.Type.GetDimensions(); int pCount = coordsCount + (isArray ? 1 : 0); void Append(string str) { texCall += ", " + str; } string ApplyScaling(string vector) { if (context.Config.Stage.SupportsRenderScale() && texOp.Inst == Instruction.ImageLoad && !isBindless && !isIndexed) { // Image scales start after texture ones. int scaleIndex = context.Config.GetTextureDescriptors().Length + context.Config.FindImageDescriptorIndex(texOp); if (pCount == 3 && isArray) { // The array index is not scaled, just x and y. vector = "ivec3(Helper_TexelFetchScale((" + vector + ").xy, " + scaleIndex + "), (" + vector + ").z)"; } else if (pCount == 2 && !isArray) { vector = "Helper_TexelFetchScale(" + vector + ", " + scaleIndex + ")"; } } return vector; } if (pCount > 1) { string[] elems = new string[pCount]; for (int index = 0; index < pCount; index++) { elems[index] = Src(VariableType.S32); } Append(ApplyScaling("ivec" + pCount + "(" + string.Join(", ", elems) + ")")); } else { Append(Src(VariableType.S32)); } if (texOp.Inst == Instruction.ImageStore) { VariableType type = texOp.Format.GetComponentType(); string[] cElems = new string[4]; for (int index = 0; index < 4; index++) { if (srcIndex < texOp.SourcesCount) { cElems[index] = Src(type); } else { cElems[index] = type switch { VariableType.S32 => NumberFormatter.FormatInt(0), VariableType.U32 => NumberFormatter.FormatUint(0), _ => NumberFormatter.FormatFloat(0) }; } } string prefix = type switch { VariableType.S32 => "i", VariableType.U32 => "u", _ => string.Empty }; Append(prefix + "vec4(" + string.Join(", ", cElems) + ")"); } if (texOp.Inst == Instruction.ImageAtomic) { VariableType type = texOp.Format.GetComponentType(); if ((texOp.Flags & TextureFlags.AtomicMask) == TextureFlags.CAS) { Append(Src(type)); // Compare value. } string value = (texOp.Flags & TextureFlags.AtomicMask) switch { TextureFlags.Increment => NumberFormatter.FormatInt(1, type), // TODO: Clamp value TextureFlags.Decrement => NumberFormatter.FormatInt(-1, type), // TODO: Clamp value _ => Src(type) }; Append(value); texCall += ")"; if (type != VariableType.S32) { texCall = "int(" + texCall + ")"; } } else { texCall += ")" + (texOp.Inst == Instruction.ImageLoad ? GetMask(texOp.Index) : ""); } return texCall; }
internal override void GenCode0(CodeGenContext context) { CodeGenContext Begin = context.CreateMethod(FileClass(), MethAttr.PublicStatic, "Begin" + (seq++), PrimitiveType.Object, new Param(ParamAttr.Default, "recv", PrimitiveType.Object), new Param(ParamAttr.Default, "caller", Runtime.FrameRef)); Begin.startMethod(this.location); AddScopeLocals(Begin); AddScopeBody(Begin); Begin.ReleaseLocal(0, true); Begin.Close(); // Begin(recv, caller); context.ldarg("recv"); context.ldloc(0); context.call(Begin.Method); context.pop(); }
public static string ImageLoadOrStore(CodeGenContext context, AstOperation operation) { AstTextureOperation texOp = (AstTextureOperation)operation; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; // TODO: Bindless texture support. For now we just return 0/do nothing. if (isBindless) { return(texOp.Inst == Instruction.ImageLoad ? NumberFormatter.FormatFloat(0) : "// imageStore(bindless)"); } bool isArray = (texOp.Type & SamplerType.Array) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; string texCall = texOp.Inst == Instruction.ImageLoad ? "imageLoad" : "imageStore"; int srcIndex = isBindless ? 1 : 0; string Src(VariableType type) { return(GetSoureExpr(context, texOp.GetSource(srcIndex++), type)); } string indexExpr = null; if (isIndexed) { indexExpr = Src(VariableType.S32); } string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr); texCall += "(" + imageName; int coordsCount = texOp.Type.GetDimensions(); int pCount = coordsCount + (isArray ? 1 : 0); void Append(string str) { texCall += ", " + str; } string ApplyScaling(string vector) { int index = context.FindImageDescriptorIndex(texOp); TextureUsageFlags flags = TextureUsageFlags.NeedsScaleValue; if ((context.Config.Stage == ShaderStage.Fragment || context.Config.Stage == ShaderStage.Compute) && texOp.Inst == Instruction.ImageLoad && !isBindless && !isIndexed) { // Image scales start after texture ones. int scaleIndex = context.TextureDescriptors.Count + index; if (pCount == 3 && isArray) { // The array index is not scaled, just x and y. vector = "ivec3(Helper_TexelFetchScale((" + vector + ").xy, " + scaleIndex + "), (" + vector + ").z)"; } else if (pCount == 2 && !isArray) { vector = "Helper_TexelFetchScale(" + vector + ", " + scaleIndex + ")"; } else { flags |= TextureUsageFlags.ResScaleUnsupported; } } else { flags |= TextureUsageFlags.ResScaleUnsupported; } if (!isBindless) { context.ImageDescriptors[index] = context.ImageDescriptors[index].SetFlag(flags); } return(vector); } if (pCount > 1) { string[] elems = new string[pCount]; for (int index = 0; index < pCount; index++) { elems[index] = Src(VariableType.S32); } Append(ApplyScaling("ivec" + pCount + "(" + string.Join(", ", elems) + ")")); } else { Append(Src(VariableType.S32)); } if (texOp.Inst == Instruction.ImageStore) { int texIndex = context.FindImageDescriptorIndex(texOp); context.ImageDescriptors[texIndex] = context.ImageDescriptors[texIndex].SetFlag(TextureUsageFlags.ImageStore); VariableType type = texOp.Format.GetComponentType(); string[] cElems = new string[4]; for (int index = 0; index < 4; index++) { if (srcIndex < texOp.SourcesCount) { cElems[index] = Src(type); } else { cElems[index] = type switch { VariableType.S32 => NumberFormatter.FormatInt(0), VariableType.U32 => NumberFormatter.FormatUint(0), _ => NumberFormatter.FormatFloat(0) }; } } string prefix = type switch { VariableType.S32 => "i", VariableType.U32 => "u", _ => string.Empty }; Append(prefix + "vec4(" + string.Join(", ", cElems) + ")"); } texCall += ")" + (texOp.Inst == Instruction.ImageLoad ? GetMask(texOp.Index) : ""); return(texCall); }
internal void AddScopeLocals(CodeGenContext context) { // ------------------ Start new Context ---------------------------- // [InteropMethod("MyClass")] // private class ActivationFrame: Ruby.Frame { ... } frame_def = context.CreateGlobalClass("_Internal", "Frame" + (N++), Runtime.FrameRef); Scope parentClass; for (parentClass = this; parentClass != null && !(parentClass is CLASS_OR_MODULE); parentClass = parentClass.parent_scope) ; string className = ""; if (parentClass != null) className = ((CLASS_OR_MODULE)parentClass).internal_name; ClassDef fileClass = FileClass(); string src = ""; if (fileClass != null && fileClass.Name().StartsWith("SourceFile_")) { src = fileClass.Name().Substring(11); frame_def.AddCustomAttribute(Runtime.FrameAttribute.ctor, new Constant[] { new StringConst(src), new StringConst(className) }); } foreach (string local in locals_list) CodeGenContext.AddField(frame_def, PERWAPI.FieldAttr.Public, ID.ToDotNetName(local), PrimitiveType.Object); // internal ActivationFrame(Frame caller): base(caller) { } CodeGenContext frame_ctor = context.CreateConstructor(frame_def, new Param(ParamAttr.Default, "caller", Runtime.FrameRef)); frame_ctor.ldarg(0); frame_ctor.ldarg("caller"); frame_ctor.call(Runtime.Frame.ctor); frame_ctor.ret(); frame_ctor.Close(); // internal string file() { CodeGenContext file = context.CreateMethod(frame_def, PERWAPI.MethAttr.PublicVirtual, "file", PrimitiveType.String); file.startMethod(this.location); // return "thisfile.rb" file.ldstr(this.location.file); file.ret(); file.Close(); // internal override string methodName() { CodeGenContext methodName = context.CreateMethod(frame_def, PERWAPI.MethAttr.PublicVirtual, "methodName", PrimitiveType.String); methodName.startMethod(this.location); // return "CurrentMethodName" methodName.ldstr(CurrentMethodName()); methodName.ret(); methodName.Close(); CreateNestingMethod(frame_def, context); CreateLastClassMethod(frame_def, context); // ------------------ Return to Old Context ---------------------- // ActivationFrame frame = new ActivationFrame(caller); context.ldarg("caller"); context.newobj(frame_ctor.Method); int frame = context.StoreInTemp("frame", FrameClass, location); Debug.Assert(frame == 0); // frame.block_arg = block; context.ldloc(frame); LoadBlock0(context); context.stfld(Runtime.Frame.block_arg); if (this is BLOCK) { // frame.current_block = this; context.ldloc(frame); context.ldarg(0); context.stfld(Runtime.Frame.current_block); } }
private void GenerateHelperBuildMethodFor(IManageEntityMetadata entityMetadataMgr, CodeGenContext context) { var @class = entityMetadataMgr.EntityName; var resourceNamespace = entityMetadataMgr.ResourceNamespace; if (!string.IsNullOrEmpty(resourceNamespace) && !context.NamespaceDeclaration.Usings.Contains(resourceNamespace)) context.NamespaceDeclaration.Usings.Add(resourceNamespace); var @interface = entityMetadataMgr.EntityInterface; const string methodParameters = "XElement element, INodeSearch nodeSearch"; var buildMethodName = "Build" + @class; context.ClassDeclaration .OpenMethod(new MethodDeclaration("private", @interface, buildMethodName, methodParameters)); var generateTheseMethodsRightAfterYourFinishThisMethod = new Queue<Action>(); GenerateMethodBody(entityMetadataMgr, @class, context, @interface, generateTheseMethodsRightAfterYourFinishThisMethod); context.ClassDeclaration.EndMethod(); foreach (var action in generateTheseMethodsRightAfterYourFinishThisMethod) { action(); } }
private void CreateNestingMethod(ClassDef Class, CodeGenContext context) { List<FieldDef> list = new List<FieldDef>(); for (Scope parent = this; parent != null; parent = parent.parent_scope) if (parent is CLASS_OR_MODULE) list.Add(((CLASS_OR_MODULE)parent).singletonField); // internal override Class[] nesting() { CodeGenContext nesting = context.CreateMethod(Class, PERWAPI.MethAttr.PublicVirtual, "nesting", new PERWAPI.ZeroBasedArray(Runtime.ClassRef)); nesting.startMethod(this.location); // Class[] array = new Class[list.Count]; nesting.ldc_i4(list.Count); nesting.newarr(Runtime.ClassRef); int array = nesting.CreateLocal("array", new PERWAPI.ZeroBasedArray(Runtime.ClassRef)); nesting.stloc(array); for (int i = 0; i < list.Count; i++) { // array[i] = list[i]; nesting.ldloc(array); nesting.ldc_i4(i); nesting.ldsfld(list[i]); nesting.stelem_ref(); } // return array; nesting.ldloc(array); nesting.ret(); nesting.ReleaseLocal(array, true); nesting.Close(); }
private void GenerateMethodBody(IManageEntityMetadata entityMetadataMgr, string @class, CodeGenContext context, string @interface, Queue<Action> delayedMethodGeneratorActions) { context.ClassDeclaration .WriteLine("if (element == null) return null;") .WriteLine() .WriteLine("{0} entity = new {1}();", @interface, @class) .WriteLine(); context.ClassDeclaration.WriteLine("// SingleSimpleTypedProperties"); foreach (var singleSimpleTypedProperty in entityMetadataMgr.GetSingleSimpleTypedProperties()) { if (entityMetadataMgr.IsDescriptorsExtRef()) { context.ClassDeclaration.WriteLine("var namespaceValue = element.ValueOf(\"Namespace\") ?? \"\";"); context.ClassDeclaration.WriteLine("var codeValue = element.ValueOf(\"CodeValue\") ?? \"\";"); context.ClassDeclaration.WriteLine("if( string.IsNullOrEmpty(namespaceValue) || namespaceValue.EndsWith(\"/\"))"); context.ClassDeclaration.WriteLine("{").PushIndent(); context.ClassDeclaration.WriteLine("entity.{0} = namespaceValue + codeValue;", singleSimpleTypedProperty.PropertyName); context.ClassDeclaration.PopIndent().WriteLine("}"); context.ClassDeclaration.WriteLine("else"); context.ClassDeclaration.WriteLine("{").PushIndent(); context.ClassDeclaration.WriteLine("entity.{0} = namespaceValue + \"/\" + codeValue;", singleSimpleTypedProperty.PropertyName); context.ClassDeclaration.PopIndent().WriteLine("}"); } else { context.ClassDeclaration .WriteLine("entity.{0} = {1};", singleSimpleTypedProperty.PropertyName, singleSimpleTypedProperty.GetAssignmentExpressionAsStringFor(@"element")); } } context.ClassDeclaration.WriteLine("// SingleEntityTypedProperties"); foreach (var singleEntityTypedProperty in entityMetadataMgr.GetSingleEntityTypedProperties()) { var mgr = singleEntityTypedProperty.GetMetaDataMgr(_edOrgReferenceDictionaryProvider); context.ClassDeclaration .WriteLine( @"entity.{0} = Build{1}(element.ElementOrEmpty(""{2}""), nodeSearch);", singleEntityTypedProperty.PropertyName, mgr.EntityName, singleEntityTypedProperty.ElementName); delayedMethodGeneratorActions.Enqueue(() => GenerateHelperBuildMethodFor(mgr, context)); } context.ClassDeclaration.WriteLine("// EntityTypedCollectionProperties"); foreach (var entityTypedCollectionProperty in entityMetadataMgr.GetEntityTypedCollectionProperties()) { var mgr = entityTypedCollectionProperty.GetMetaDataMgr(_edOrgReferenceDictionaryProvider); context.ClassDeclaration .WriteLine( @"entity.{0} = element.ElementsOrEmpty(""{1}"").Select(x => Build{2}(x, nodeSearch)).ToList();", entityTypedCollectionProperty.PropertyName, entityTypedCollectionProperty.ElementName, mgr.EntityName); delayedMethodGeneratorActions.Enqueue(() => GenerateHelperBuildMethodFor(mgr, context)); } context.ClassDeclaration.WriteLine("// InlineEntityCollectionProperties"); foreach (var inlineEntityProperty in entityMetadataMgr.GetInlineEntityCollectionProperties()) { var rightSideExpression = inlineEntityProperty.GetConvertExpression("x"); var assignmentString = inlineEntityProperty.IsNested ? "NestedElementsOrEmpty" : "ElementsOrEmpty"; var elementVariable = inlineEntityProperty.IsNested ? string.Format(@"new []{0}""{1}"",""{2}""{3}", "{", inlineEntityProperty.ElementNames[0], inlineEntityProperty.ElementNames[1], "}") : string.Format(@"""{0}""", inlineEntityProperty.ElementName); var inlinePropertyName = inlineEntityProperty.InlinePropertyName; if (inlineEntityProperty.ClassName == inlineEntityProperty.InlinePropertyName) { inlinePropertyName = inlinePropertyName + "X"; } context.ClassDeclaration .WriteLine(@"entity.{0} = element.{1}({2})", inlineEntityProperty.PropertyName, assignmentString, elementVariable) .PushIndent().WriteLine(".Select(x => new {0}", inlineEntityProperty.ClassName) .PushIndent().WriteLine("{") .PushIndent().WriteLine("{0} = {1}", inlinePropertyName, rightSideExpression).PopIndent() .WriteLine("})") .PopIndent().WriteLine(".Cast<{0}>()", inlineEntityProperty.InterfaceName) .WriteLine(".ToList();").PopIndent(); } context.ClassDeclaration.WriteLine("// ForeignKeyProperties"); foreach (var foreignKeyProperty in entityMetadataMgr.GetForeignKeyProperties()) { var foundElementExpression = foreignKeyProperty.GetConvertExpression("foundElement"); var possibleNamespaceElementExpression = foreignKeyProperty.GetConvertExpression("possibleNamespaceElement"); var valueReferenceMap = foreignKeyProperty.SerializedReferenceMap.Replace("\"", @""""""); string possibleNamespaceReferenceMap = null; if (valueReferenceMap.Contains("CodeValue")) { possibleNamespaceReferenceMap = valueReferenceMap.Replace("CodeValue", "Namespace"); //foundElementExpression = foreignKeyProperty.GetConvertExpression("possibleNamespaceElement") + " + " + foundElementExpression; } context.ClassDeclaration .WriteLine("{") .PushIndent() .WriteLine(@"var foundElement = nodeSearch.FindForeignKeyElement(element, @""{0}"");", valueReferenceMap); if (possibleNamespaceReferenceMap != null) context.ClassDeclaration .WriteLine( @"var possibleNamespaceElement = nodeSearch.FindForeignKeyElement(element, @""{0}"");", possibleNamespaceReferenceMap) .WriteLine( @"entity.{0} = string.IsNullOrEmpty({1}) || {1}.EndsWith(""/"")?{1}+{2}:{1}+""/""+{2};", foreignKeyProperty.PropertyName, possibleNamespaceElementExpression, foundElementExpression); else context.ClassDeclaration .WriteLine("entity.{0} = {1};", foreignKeyProperty.PropertyName, foundElementExpression); context.ClassDeclaration .PopIndent() .WriteLine("}"); } context.ClassDeclaration.WriteLine("// MultiElementEntityCollectionProperties"); foreach (var property in entityMetadataMgr.GetMultiElementEntityCollectionProperties()) { context.ClassDeclaration .WriteLine( @"entity.{0} = element.AllElementsOrEmpty(new []{1}{2}{3}).Select(x => Build{4}(x, nodeSearch)).ToList();", property.PropertyName, "{", property.ParticipatingElementsAsCommaDelimentedStringOfStrings, "}", property.EntityName); var closureSafeProperty = property; delayedMethodGeneratorActions.Enqueue(() => GenerateHelperBuildMethodFor(closureSafeProperty.GetEntityMetadataManager(), context)); } context.ClassDeclaration .WriteLine() .WriteLine("return entity;"); }
internal void CatchReturnException(CodeGenContext context, PERWAPI.TryBlock tryBlock) { // catch (Ruby.ReturnException exception) { ... } context.StartBlock(Clause.Catch); { PERWAPI.CILLabel falseLabel = context.NewLabel(); int exception = context.StoreInTemp("exception", Runtime.ReturnExceptionRef, location); // if (exception.scope == thisframe) context.ldloc(exception); context.ldfld(Runtime.ReturnException.scope); context.ldloc(0); context.bne(falseLabel); // returnTemp = exception.return_value; context.ldloc(exception); context.ldfld(Runtime.ReturnException.return_value); context.stloc(returnTemp); context.Goto(context.labels.Return); // falseLabel: context.CodeLabel(falseLabel); // throw exception context.rethrow(); context.ReleaseLocal(exception, true); } context.EndCatchBlock(Runtime.ReturnExceptionRef, tryBlock); }
private static string GetExpression(CodeGenContext context, AstOperation operation) { Instruction inst = operation.Inst; InstInfo info = GetInstructionInfo(inst); if ((info.Type & InstType.Call) != 0) { int arity = (int)(info.Type & InstType.ArityMask); string args = string.Empty; for (int argIndex = 0; argIndex < arity; argIndex++) { if (argIndex != 0) { args += ", "; } VariableType dstType = GetSrcVarType(inst, argIndex); args += GetSoureExpr(context, operation.GetSource(argIndex), dstType); } return(info.OpName + "(" + args + ")"); } else if ((info.Type & InstType.Op) != 0) { string op = info.OpName; int arity = (int)(info.Type & InstType.ArityMask); string[] expr = new string[arity]; for (int index = 0; index < arity; index++) { IAstNode src = operation.GetSource(index); string srcExpr = GetSoureExpr(context, src, GetSrcVarType(inst, index)); bool isLhs = arity == 2 && index == 0; expr[index] = Enclose(srcExpr, src, inst, info, isLhs); } switch (arity) { case 0: return(op); case 1: return(op + expr[0]); case 2: return($"{expr[0]} {op} {expr[1]}"); case 3: return($"{expr[0]} {op[0]} {expr[1]} {op[1]} {expr[2]}"); } } else if ((info.Type & InstType.Special) != 0) { switch (inst) { case Instruction.LoadConstant: return(InstGenMemory.LoadConstant(context, operation)); case Instruction.PackHalf2x16: return(InstGenPacking.PackHalf2x16(context, operation)); case Instruction.TextureSample: return(InstGenMemory.TextureSample(context, operation)); case Instruction.TextureSize: return(InstGenMemory.TextureSize(context, operation)); case Instruction.UnpackHalf2x16: return(InstGenPacking.UnpackHalf2x16(context, operation)); } } throw new InvalidOperationException($"Unexpected instruction type \"{info.Type}\"."); }