aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGen.cs
blob: 3bf31c16393397b79b46e39f8e027ff8465004a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
using Ryujinx.Graphics.Shader.StructuredIr;
using System;

using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;

namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
{
    static class InstGen
    {
        public static string GetExpression(CodeGenContext context, IAstNode node)
        {
            if (node is AstOperation operation)
            {
                return GetExpression(context, operation);
            }
            else if (node is AstOperand operand)
            {
                return context.OperandManager.GetExpression(operand, context.Config.Stage);
            }

            throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\".");
        }

        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.ImageStore:
                        return InstGenMemory.ImageStore(context, operation);

                    case Instruction.LoadAttribute:
                        return InstGenMemory.LoadAttribute(context, operation);

                    case Instruction.LoadConstant:
                        return InstGenMemory.LoadConstant(context, operation);

                    case Instruction.LoadLocal:
                        return InstGenMemory.LoadLocal(context, operation);

                    case Instruction.LoadStorage:
                        return InstGenMemory.LoadStorage(context, operation);

                    case Instruction.PackHalf2x16:
                        return InstGenPacking.PackHalf2x16(context, operation);

                    case Instruction.StoreLocal:
                        return InstGenMemory.StoreLocal(context, operation);

                    case Instruction.StoreStorage:
                        return InstGenMemory.StoreStorage(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);
                }
            }

            return "0";

            throw new InvalidOperationException($"Unexpected instruction type \"{info.Type}\".");
        }
    }
}