ConstantFolding.cs
1 using Ryujinx.Common.Utilities; 2 using Ryujinx.Graphics.Shader.IntermediateRepresentation; 3 using System; 4 using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; 5 6 namespace Ryujinx.Graphics.Shader.Translation.Optimizations 7 { 8 static class ConstantFolding 9 { 10 public static void RunPass(ResourceManager resourceManager, Operation operation) 11 { 12 if (!AreAllSourcesConstant(operation)) 13 { 14 return; 15 } 16 17 switch (operation.Inst) 18 { 19 case Instruction.Add: 20 EvaluateBinary(operation, (x, y) => x + y); 21 break; 22 23 case Instruction.BitCount: 24 EvaluateUnary(operation, (x) => BitCount(x)); 25 break; 26 27 case Instruction.BitwiseAnd: 28 EvaluateBinary(operation, (x, y) => x & y); 29 break; 30 31 case Instruction.BitwiseExclusiveOr: 32 EvaluateBinary(operation, (x, y) => x ^ y); 33 break; 34 35 case Instruction.BitwiseNot: 36 EvaluateUnary(operation, (x) => ~x); 37 break; 38 39 case Instruction.BitwiseOr: 40 EvaluateBinary(operation, (x, y) => x | y); 41 break; 42 43 case Instruction.BitfieldExtractS32: 44 BitfieldExtractS32(operation); 45 break; 46 47 case Instruction.BitfieldExtractU32: 48 BitfieldExtractU32(operation); 49 break; 50 51 case Instruction.Clamp: 52 EvaluateTernary(operation, (x, y, z) => Math.Clamp(x, y, z)); 53 break; 54 55 case Instruction.ClampU32: 56 EvaluateTernary(operation, (x, y, z) => (int)Math.Clamp((uint)x, (uint)y, (uint)z)); 57 break; 58 59 case Instruction.CompareEqual: 60 EvaluateBinary(operation, (x, y) => x == y); 61 break; 62 63 case Instruction.CompareGreater: 64 EvaluateBinary(operation, (x, y) => x > y); 65 break; 66 67 case Instruction.CompareGreaterOrEqual: 68 EvaluateBinary(operation, (x, y) => x >= y); 69 break; 70 71 case Instruction.CompareGreaterOrEqualU32: 72 EvaluateBinary(operation, (x, y) => (uint)x >= (uint)y); 73 break; 74 75 case Instruction.CompareGreaterU32: 76 EvaluateBinary(operation, (x, y) => (uint)x > (uint)y); 77 break; 78 79 case Instruction.CompareLess: 80 EvaluateBinary(operation, (x, y) => x < y); 81 break; 82 83 case Instruction.CompareLessOrEqual: 84 EvaluateBinary(operation, (x, y) => x <= y); 85 break; 86 87 case Instruction.CompareLessOrEqualU32: 88 EvaluateBinary(operation, (x, y) => (uint)x <= (uint)y); 89 break; 90 91 case Instruction.CompareLessU32: 92 EvaluateBinary(operation, (x, y) => (uint)x < (uint)y); 93 break; 94 95 case Instruction.CompareNotEqual: 96 EvaluateBinary(operation, (x, y) => x != y); 97 break; 98 99 case Instruction.Divide: 100 EvaluateBinary(operation, (x, y) => y != 0 ? x / y : 0); 101 break; 102 103 case Instruction.FP32 | Instruction.Add: 104 EvaluateFPBinary(operation, (x, y) => x + y); 105 break; 106 107 case Instruction.FP32 | Instruction.Clamp: 108 EvaluateFPTernary(operation, (x, y, z) => Math.Clamp(x, y, z)); 109 break; 110 111 case Instruction.FP32 | Instruction.CompareEqual: 112 EvaluateFPBinary(operation, (x, y) => x == y); 113 break; 114 115 case Instruction.FP32 | Instruction.CompareGreater: 116 EvaluateFPBinary(operation, (x, y) => x > y); 117 break; 118 119 case Instruction.FP32 | Instruction.CompareGreaterOrEqual: 120 EvaluateFPBinary(operation, (x, y) => x >= y); 121 break; 122 123 case Instruction.FP32 | Instruction.CompareLess: 124 EvaluateFPBinary(operation, (x, y) => x < y); 125 break; 126 127 case Instruction.FP32 | Instruction.CompareLessOrEqual: 128 EvaluateFPBinary(operation, (x, y) => x <= y); 129 break; 130 131 case Instruction.FP32 | Instruction.CompareNotEqual: 132 EvaluateFPBinary(operation, (x, y) => x != y); 133 break; 134 135 case Instruction.FP32 | Instruction.Divide: 136 EvaluateFPBinary(operation, (x, y) => x / y); 137 break; 138 139 case Instruction.FP32 | Instruction.Multiply: 140 EvaluateFPBinary(operation, (x, y) => x * y); 141 break; 142 143 case Instruction.FP32 | Instruction.Negate: 144 EvaluateFPUnary(operation, (x) => -x); 145 break; 146 147 case Instruction.FP32 | Instruction.Subtract: 148 EvaluateFPBinary(operation, (x, y) => x - y); 149 break; 150 151 case Instruction.IsNan: 152 EvaluateFPUnary(operation, (x) => float.IsNaN(x)); 153 break; 154 155 case Instruction.Load: 156 if (operation.StorageKind == StorageKind.ConstantBuffer && operation.SourcesCount == 4) 157 { 158 int binding = operation.GetSource(0).Value; 159 int fieldIndex = operation.GetSource(1).Value; 160 161 if (resourceManager.TryGetConstantBufferSlot(binding, out int cbufSlot) && fieldIndex == 0) 162 { 163 int vecIndex = operation.GetSource(2).Value; 164 int elemIndex = operation.GetSource(3).Value; 165 int cbufOffset = vecIndex * 4 + elemIndex; 166 167 operation.TurnIntoCopy(Cbuf(cbufSlot, cbufOffset)); 168 } 169 } 170 break; 171 172 case Instruction.Maximum: 173 EvaluateBinary(operation, (x, y) => Math.Max(x, y)); 174 break; 175 176 case Instruction.MaximumU32: 177 EvaluateBinary(operation, (x, y) => (int)Math.Max((uint)x, (uint)y)); 178 break; 179 180 case Instruction.Minimum: 181 EvaluateBinary(operation, (x, y) => Math.Min(x, y)); 182 break; 183 184 case Instruction.MinimumU32: 185 EvaluateBinary(operation, (x, y) => (int)Math.Min((uint)x, (uint)y)); 186 break; 187 188 case Instruction.Multiply: 189 EvaluateBinary(operation, (x, y) => x * y); 190 break; 191 192 case Instruction.Negate: 193 EvaluateUnary(operation, (x) => -x); 194 break; 195 196 case Instruction.ShiftLeft: 197 EvaluateBinary(operation, (x, y) => x << y); 198 break; 199 200 case Instruction.ShiftRightS32: 201 EvaluateBinary(operation, (x, y) => x >> y); 202 break; 203 204 case Instruction.ShiftRightU32: 205 EvaluateBinary(operation, (x, y) => (int)((uint)x >> y)); 206 break; 207 208 case Instruction.Subtract: 209 EvaluateBinary(operation, (x, y) => x - y); 210 break; 211 212 case Instruction.UnpackHalf2x16: 213 UnpackHalf2x16(operation); 214 break; 215 } 216 } 217 218 private static bool AreAllSourcesConstant(Operation operation) 219 { 220 for (int index = 0; index < operation.SourcesCount; index++) 221 { 222 if (operation.GetSource(index).Type != OperandType.Constant) 223 { 224 return false; 225 } 226 } 227 228 return true; 229 } 230 231 private static int BitCount(int value) 232 { 233 int count = 0; 234 235 for (int bit = 0; bit < 32; bit++) 236 { 237 if (value.Extract(bit)) 238 { 239 count++; 240 } 241 } 242 243 return count; 244 } 245 246 private static void BitfieldExtractS32(Operation operation) 247 { 248 int value = GetBitfieldExtractValue(operation); 249 250 int shift = 32 - operation.GetSource(2).Value; 251 252 value = (value << shift) >> shift; 253 254 operation.TurnIntoCopy(Const(value)); 255 } 256 257 private static void BitfieldExtractU32(Operation operation) 258 { 259 operation.TurnIntoCopy(Const(GetBitfieldExtractValue(operation))); 260 } 261 262 private static int GetBitfieldExtractValue(Operation operation) 263 { 264 int value = operation.GetSource(0).Value; 265 int lsb = operation.GetSource(1).Value; 266 int length = operation.GetSource(2).Value; 267 268 return value.Extract(lsb, length); 269 } 270 271 private static void UnpackHalf2x16(Operation operation) 272 { 273 int value = operation.GetSource(0).Value; 274 275 value = (value >> operation.Index * 16) & 0xffff; 276 277 operation.TurnIntoCopy(ConstF((float)BitConverter.UInt16BitsToHalf((ushort)value))); 278 } 279 280 private static void EvaluateUnary(Operation operation, Func<int, int> op) 281 { 282 int x = operation.GetSource(0).Value; 283 284 operation.TurnIntoCopy(Const(op(x))); 285 } 286 287 private static void EvaluateFPUnary(Operation operation, Func<float, float> op) 288 { 289 float x = operation.GetSource(0).AsFloat(); 290 291 operation.TurnIntoCopy(ConstF(op(x))); 292 } 293 294 private static void EvaluateFPUnary(Operation operation, Func<float, bool> op) 295 { 296 float x = operation.GetSource(0).AsFloat(); 297 298 operation.TurnIntoCopy(Const(op(x) ? IrConsts.True : IrConsts.False)); 299 } 300 301 private static void EvaluateBinary(Operation operation, Func<int, int, int> op) 302 { 303 int x = operation.GetSource(0).Value; 304 int y = operation.GetSource(1).Value; 305 306 operation.TurnIntoCopy(Const(op(x, y))); 307 } 308 309 private static void EvaluateBinary(Operation operation, Func<int, int, bool> op) 310 { 311 int x = operation.GetSource(0).Value; 312 int y = operation.GetSource(1).Value; 313 314 operation.TurnIntoCopy(Const(op(x, y) ? IrConsts.True : IrConsts.False)); 315 } 316 317 private static void EvaluateFPBinary(Operation operation, Func<float, float, float> op) 318 { 319 float x = operation.GetSource(0).AsFloat(); 320 float y = operation.GetSource(1).AsFloat(); 321 322 operation.TurnIntoCopy(ConstF(op(x, y))); 323 } 324 325 private static void EvaluateFPBinary(Operation operation, Func<float, float, bool> op) 326 { 327 float x = operation.GetSource(0).AsFloat(); 328 float y = operation.GetSource(1).AsFloat(); 329 330 operation.TurnIntoCopy(Const(op(x, y) ? IrConsts.True : IrConsts.False)); 331 } 332 333 private static void EvaluateTernary(Operation operation, Func<int, int, int, int> op) 334 { 335 int x = operation.GetSource(0).Value; 336 int y = operation.GetSource(1).Value; 337 int z = operation.GetSource(2).Value; 338 339 operation.TurnIntoCopy(Const(op(x, y, z))); 340 } 341 342 private static void EvaluateFPTernary(Operation operation, Func<float, float, float, float> op) 343 { 344 float x = operation.GetSource(0).AsFloat(); 345 float y = operation.GetSource(1).AsFloat(); 346 float z = operation.GetSource(2).AsFloat(); 347 348 operation.TurnIntoCopy(ConstF(op(x, y, z))); 349 } 350 } 351 }