using Ryujinx.Graphics.Shader.Decoders; using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.Translation; using System.Collections.Generic; using System.Linq; using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; namespace Ryujinx.Graphics.Shader.Instructions { static partial class InstEmit { public static void Bra(EmitterContext context) { EmitBranch(context, context.CurrBlock.Branch.Address); } public static void Exit(EmitterContext context) { OpCodeExit op = (OpCodeExit)context.CurrOp; // TODO: Figure out how this is supposed to work in the // presence of other condition codes. if (op.Condition == Condition.Always) { context.Return(); } } public static void Kil(EmitterContext context) { context.Discard(); } public static void Ssy(EmitterContext context) { OpCodeSsy op = (OpCodeSsy)context.CurrOp; foreach (KeyValuePair kv in op.Syncs) { OpCodeSync opSync = kv.Key; Operand local = kv.Value; int ssyIndex = opSync.Targets[op]; context.Copy(local, Const(ssyIndex)); } } public static void Sync(EmitterContext context) { OpCodeSync op = (OpCodeSync)context.CurrOp; if (op.Targets.Count == 1) { // If we have only one target, then the SSY is basically // a branch, we can produce better codegen for this case. OpCodeSsy opSsy = op.Targets.Keys.First(); EmitBranch(context, opSsy.GetAbsoluteAddress()); } else { foreach (KeyValuePair kv in op.Targets) { OpCodeSsy opSsy = kv.Key; Operand label = context.GetLabel(opSsy.GetAbsoluteAddress()); Operand local = opSsy.Syncs[op]; int ssyIndex = kv.Value; context.BranchIfTrue(label, context.ICompareEqual(local, Const(ssyIndex))); } } } private static void EmitBranch(EmitterContext context, ulong address) { // If we're branching to the next instruction, then the branch // is useless and we can ignore it. if (address == context.CurrOp.Address + 8) { return; } Operand label = context.GetLabel(address); Operand pred = Register(context.CurrOp.Predicate); if (context.CurrOp.Predicate.IsPT) { context.Branch(label); } else if (context.CurrOp.InvertPredicate) { context.BranchIfFalse(label, pred); } else { context.BranchIfTrue(label, pred); } } } }