summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp235
1 files changed, 122 insertions, 113 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 76d9b3538..a1cef99ae 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -347,6 +347,15 @@ public:
347 BuildInputList(); 347 BuildInputList();
348 } 348 }
349 349
350 void SetConditionalCodesFromExpression(const std::string& expresion) {
351 SetInternalFlag(InternalFlag::ZeroFlag, "(" + expresion + ") == 0");
352 LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete.");
353 }
354
355 void SetConditionalCodesFromRegister(const Register& reg, u64 dest_elem = 0) {
356 SetConditionalCodesFromExpression(GetRegister(reg, static_cast<u32>(dest_elem)));
357 }
358
350 /** 359 /**
351 * Returns code that does an integer size conversion for the specified size. 360 * Returns code that does an integer size conversion for the specified size.
352 * @param value Value to perform integer size conversion on. 361 * @param value Value to perform integer size conversion on.
@@ -401,14 +410,24 @@ public:
401 * @param dest_num_components Number of components in the destination. 410 * @param dest_num_components Number of components in the destination.
402 * @param value_num_components Number of components in the value. 411 * @param value_num_components Number of components in the value.
403 * @param is_saturated Optional, when True, saturates the provided value. 412 * @param is_saturated Optional, when True, saturates the provided value.
413 * @param sets_cc Optional, when True, sets the corresponding values to the implemented
414 * condition flags.
404 * @param dest_elem Optional, the destination element to use for the operation. 415 * @param dest_elem Optional, the destination element to use for the operation.
405 */ 416 */
406 void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value, 417 void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value,
407 u64 dest_num_components, u64 value_num_components, 418 u64 dest_num_components, u64 value_num_components,
408 bool is_saturated = false, u64 dest_elem = 0, bool precise = false) { 419 bool is_saturated = false, bool sets_cc = false, u64 dest_elem = 0,
409 420 bool precise = false) {
410 SetRegister(reg, elem, is_saturated ? "clamp(" + value + ", 0.0, 1.0)" : value, 421 const std::string clamped_value = is_saturated ? "clamp(" + value + ", 0.0, 1.0)" : value;
411 dest_num_components, value_num_components, dest_elem, precise); 422 SetRegister(reg, elem, clamped_value, dest_num_components, value_num_components, dest_elem,
423 precise);
424 if (sets_cc) {
425 if (reg == Register::ZeroIndex) {
426 SetConditionalCodesFromExpression(clamped_value);
427 } else {
428 SetConditionalCodesFromRegister(reg, dest_elem);
429 }
430 }
412 } 431 }
413 432
414 /** 433 /**
@@ -419,25 +438,29 @@ public:
419 * @param dest_num_components Number of components in the destination. 438 * @param dest_num_components Number of components in the destination.
420 * @param value_num_components Number of components in the value. 439 * @param value_num_components Number of components in the value.
421 * @param is_saturated Optional, when True, saturates the provided value. 440 * @param is_saturated Optional, when True, saturates the provided value.
441 * @param sets_cc Optional, when True, sets the corresponding values to the implemented
442 * condition flags.
422 * @param dest_elem Optional, the destination element to use for the operation. 443 * @param dest_elem Optional, the destination element to use for the operation.
423 * @param size Register size to use for conversion instructions. 444 * @param size Register size to use for conversion instructions.
424 */ 445 */
425 void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem, 446 void SetRegisterToInteger(const Register& reg, bool is_signed, u64 elem,
426 const std::string& value, u64 dest_num_components, 447 const std::string& value, u64 dest_num_components,
427 u64 value_num_components, bool is_saturated = false, 448 u64 value_num_components, bool is_saturated = false,
428 u64 dest_elem = 0, Register::Size size = Register::Size::Word, 449 bool sets_cc = false, u64 dest_elem = 0,
429 bool sets_cc = false) { 450 Register::Size size = Register::Size::Word) {
430 UNIMPLEMENTED_IF(is_saturated); 451 UNIMPLEMENTED_IF(is_saturated);
431 452 const std::string final_value = ConvertIntegerSize(value, size);
432 const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"}; 453 const std::string func{is_signed ? "intBitsToFloat" : "uintBitsToFloat"};
433 454
434 SetRegister(reg, elem, func + '(' + ConvertIntegerSize(value, size) + ')', 455 SetRegister(reg, elem, func + '(' + final_value + ')', dest_num_components,
435 dest_num_components, value_num_components, dest_elem, false); 456 value_num_components, dest_elem, false);
436 457
437 if (sets_cc) { 458 if (sets_cc) {
438 const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; 459 if (reg == Register::ZeroIndex) {
439 SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); 460 SetConditionalCodesFromExpression(final_value);
440 LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete."); 461 } else {
462 SetConditionalCodesFromRegister(reg, dest_elem);
463 }
441 } 464 }
442 } 465 }
443 466
@@ -1275,7 +1298,7 @@ private:
1275 void WriteLogicOperation(Register dest, LogicOperation logic_op, const std::string& op_a, 1298 void WriteLogicOperation(Register dest, LogicOperation logic_op, const std::string& op_a,
1276 const std::string& op_b, 1299 const std::string& op_b,
1277 Tegra::Shader::PredicateResultMode predicate_mode, 1300 Tegra::Shader::PredicateResultMode predicate_mode,
1278 Tegra::Shader::Pred predicate) { 1301 Tegra::Shader::Pred predicate, const bool set_cc) {
1279 std::string result{}; 1302 std::string result{};
1280 switch (logic_op) { 1303 switch (logic_op) {
1281 case LogicOperation::And: { 1304 case LogicOperation::And: {
@@ -1299,7 +1322,7 @@ private:
1299 } 1322 }
1300 1323
1301 if (dest != Tegra::Shader::Register::ZeroIndex) { 1324 if (dest != Tegra::Shader::Register::ZeroIndex) {
1302 regs.SetRegisterToInteger(dest, true, 0, result, 1, 1); 1325 regs.SetRegisterToInteger(dest, true, 0, result, 1, 1, false, set_cc);
1303 } 1326 }
1304 1327
1305 using Tegra::Shader::PredicateResultMode; 1328 using Tegra::Shader::PredicateResultMode;
@@ -1319,7 +1342,8 @@ private:
1319 } 1342 }
1320 1343
1321 void WriteLop3Instruction(Register dest, const std::string& op_a, const std::string& op_b, 1344 void WriteLop3Instruction(Register dest, const std::string& op_a, const std::string& op_b,
1322 const std::string& op_c, const std::string& imm_lut) { 1345 const std::string& op_c, const std::string& imm_lut,
1346 const bool set_cc) {
1323 if (dest == Tegra::Shader::Register::ZeroIndex) { 1347 if (dest == Tegra::Shader::Register::ZeroIndex) {
1324 return; 1348 return;
1325 } 1349 }
@@ -1342,7 +1366,7 @@ private:
1342 1366
1343 result += ')'; 1367 result += ')';
1344 1368
1345 regs.SetRegisterToInteger(dest, true, 0, result, 1, 1); 1369 regs.SetRegisterToInteger(dest, true, 0, result, 1, 1, false, set_cc);
1346 } 1370 }
1347 1371
1348 void WriteTexsInstructionFloat(const Instruction& instr, const std::string& texture) { 1372 void WriteTexsInstructionFloat(const Instruction& instr, const std::string& texture) {
@@ -1357,12 +1381,12 @@ private:
1357 1381
1358 if (written_components < 2) { 1382 if (written_components < 2) {
1359 // Write the first two swizzle components to gpr0 and gpr0+1 1383 // Write the first two swizzle components to gpr0 and gpr0+1
1360 regs.SetRegisterToFloat(instr.gpr0, component, texture, 1, 4, false, 1384 regs.SetRegisterToFloat(instr.gpr0, component, texture, 1, 4, false, false,
1361 written_components % 2); 1385 written_components % 2);
1362 } else { 1386 } else {
1363 ASSERT(instr.texs.HasTwoDestinations()); 1387 ASSERT(instr.texs.HasTwoDestinations());
1364 // Write the rest of the swizzle components to gpr28 and gpr28+1 1388 // Write the rest of the swizzle components to gpr28 and gpr28+1
1365 regs.SetRegisterToFloat(instr.gpr28, component, texture, 1, 4, false, 1389 regs.SetRegisterToFloat(instr.gpr28, component, texture, 1, 4, false, false,
1366 written_components % 2); 1390 written_components % 2);
1367 } 1391 }
1368 1392
@@ -1871,8 +1895,6 @@ private:
1871 instr.fmul.tab5c68_0 != 1, "FMUL tab5cb8_0({}) is not implemented", 1895 instr.fmul.tab5c68_0 != 1, "FMUL tab5cb8_0({}) is not implemented",
1872 instr.fmul.tab5c68_0 1896 instr.fmul.tab5c68_0
1873 .Value()); // SMO typical sends 1 here which seems to be the default 1897 .Value()); // SMO typical sends 1 here which seems to be the default
1874 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1875 "Condition codes generation in FMUL is not implemented");
1876 1898
1877 op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b); 1899 op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b);
1878 1900
@@ -1896,20 +1918,17 @@ private:
1896 } 1918 }
1897 1919
1898 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + postfactor_op, 1, 1, 1920 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + postfactor_op, 1, 1,
1899 instr.alu.saturate_d, 0, true); 1921 instr.alu.saturate_d, instr.generates_cc, 0, true);
1900 break; 1922 break;
1901 } 1923 }
1902 case OpCode::Id::FADD_C: 1924 case OpCode::Id::FADD_C:
1903 case OpCode::Id::FADD_R: 1925 case OpCode::Id::FADD_R:
1904 case OpCode::Id::FADD_IMM: { 1926 case OpCode::Id::FADD_IMM: {
1905 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
1906 "Condition codes generation in FADD is not implemented");
1907
1908 op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); 1927 op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a);
1909 op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); 1928 op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b);
1910 1929
1911 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, 1930 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1,
1912 instr.alu.saturate_d, 0, true); 1931 instr.alu.saturate_d, instr.generates_cc, 0, true);
1913 break; 1932 break;
1914 } 1933 }
1915 case OpCode::Id::MUFU: { 1934 case OpCode::Id::MUFU: {
@@ -1917,31 +1936,31 @@ private:
1917 switch (instr.sub_op) { 1936 switch (instr.sub_op) {
1918 case SubOp::Cos: 1937 case SubOp::Cos:
1919 regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1, 1938 regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1,
1920 instr.alu.saturate_d, 0, true); 1939 instr.alu.saturate_d, false, 0, true);
1921 break; 1940 break;
1922 case SubOp::Sin: 1941 case SubOp::Sin:
1923 regs.SetRegisterToFloat(instr.gpr0, 0, "sin(" + op_a + ')', 1, 1, 1942 regs.SetRegisterToFloat(instr.gpr0, 0, "sin(" + op_a + ')', 1, 1,
1924 instr.alu.saturate_d, 0, true); 1943 instr.alu.saturate_d, false, 0, true);
1925 break; 1944 break;
1926 case SubOp::Ex2: 1945 case SubOp::Ex2:
1927 regs.SetRegisterToFloat(instr.gpr0, 0, "exp2(" + op_a + ')', 1, 1, 1946 regs.SetRegisterToFloat(instr.gpr0, 0, "exp2(" + op_a + ')', 1, 1,
1928 instr.alu.saturate_d, 0, true); 1947 instr.alu.saturate_d, false, 0, true);
1929 break; 1948 break;
1930 case SubOp::Lg2: 1949 case SubOp::Lg2:
1931 regs.SetRegisterToFloat(instr.gpr0, 0, "log2(" + op_a + ')', 1, 1, 1950 regs.SetRegisterToFloat(instr.gpr0, 0, "log2(" + op_a + ')', 1, 1,
1932 instr.alu.saturate_d, 0, true); 1951 instr.alu.saturate_d, false, 0, true);
1933 break; 1952 break;
1934 case SubOp::Rcp: 1953 case SubOp::Rcp:
1935 regs.SetRegisterToFloat(instr.gpr0, 0, "1.0 / " + op_a, 1, 1, 1954 regs.SetRegisterToFloat(instr.gpr0, 0, "1.0 / " + op_a, 1, 1,
1936 instr.alu.saturate_d, 0, true); 1955 instr.alu.saturate_d, false, 0, true);
1937 break; 1956 break;
1938 case SubOp::Rsq: 1957 case SubOp::Rsq:
1939 regs.SetRegisterToFloat(instr.gpr0, 0, "inversesqrt(" + op_a + ')', 1, 1, 1958 regs.SetRegisterToFloat(instr.gpr0, 0, "inversesqrt(" + op_a + ')', 1, 1,
1940 instr.alu.saturate_d, 0, true); 1959 instr.alu.saturate_d, false, 0, true);
1941 break; 1960 break;
1942 case SubOp::Sqrt: 1961 case SubOp::Sqrt:
1943 regs.SetRegisterToFloat(instr.gpr0, 0, "sqrt(" + op_a + ')', 1, 1, 1962 regs.SetRegisterToFloat(instr.gpr0, 0, "sqrt(" + op_a + ')', 1, 1,
1944 instr.alu.saturate_d, 0, true); 1963 instr.alu.saturate_d, false, 0, true);
1945 break; 1964 break;
1946 default: 1965 default:
1947 UNIMPLEMENTED_MSG("Unhandled MUFU sub op={0:x}", 1966 UNIMPLEMENTED_MSG("Unhandled MUFU sub op={0:x}",
@@ -1952,8 +1971,9 @@ private:
1952 case OpCode::Id::FMNMX_C: 1971 case OpCode::Id::FMNMX_C:
1953 case OpCode::Id::FMNMX_R: 1972 case OpCode::Id::FMNMX_R:
1954 case OpCode::Id::FMNMX_IMM: { 1973 case OpCode::Id::FMNMX_IMM: {
1955 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 1974 UNIMPLEMENTED_IF_MSG(
1956 "Condition codes generation in FMNMX is not implemented"); 1975 instr.generates_cc,
1976 "Condition codes generation in FMNMX is partially implemented");
1957 1977
1958 op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); 1978 op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a);
1959 op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); 1979 op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b);
@@ -1964,7 +1984,7 @@ private:
1964 regs.SetRegisterToFloat(instr.gpr0, 0, 1984 regs.SetRegisterToFloat(instr.gpr0, 0,
1965 '(' + condition + ") ? min(" + parameters + ") : max(" + 1985 '(' + condition + ") ? min(" + parameters + ") : max(" +
1966 parameters + ')', 1986 parameters + ')',
1967 1, 1, false, 0, true); 1987 1, 1, false, instr.generates_cc, 0, true);
1968 break; 1988 break;
1969 } 1989 }
1970 case OpCode::Id::RRO_C: 1990 case OpCode::Id::RRO_C:
@@ -1989,18 +2009,16 @@ private:
1989 break; 2009 break;
1990 } 2010 }
1991 case OpCode::Id::FMUL32_IMM: { 2011 case OpCode::Id::FMUL32_IMM: {
1992 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, 2012 regs.SetRegisterToFloat(
1993 "Condition codes generation in FMUL32 is not implemented"); 2013 instr.gpr0, 0,
1994 2014 regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1,
1995 regs.SetRegisterToFloat(instr.gpr0, 0, 2015 instr.fmul32.saturate, instr.op_32.generates_cc, 0, true);
1996 regs.GetRegisterAsFloat(instr.gpr8) + " * " +
1997 GetImmediate32(instr),
1998 1, 1, instr.fmul32.saturate, 0, true);
1999 break; 2016 break;
2000 } 2017 }
2001 case OpCode::Id::FADD32I: { 2018 case OpCode::Id::FADD32I: {
2002 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, 2019 UNIMPLEMENTED_IF_MSG(
2003 "Condition codes generation in FADD32I is not implemented"); 2020 instr.op_32.generates_cc,
2021 "Condition codes generation in FADD32I is partially implemented");
2004 2022
2005 std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 2023 std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
2006 std::string op_b = GetImmediate32(instr); 2024 std::string op_b = GetImmediate32(instr);
@@ -2021,7 +2039,8 @@ private:
2021 op_b = "-(" + op_b + ')'; 2039 op_b = "-(" + op_b + ')';
2022 } 2040 }
2023 2041
2024 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true); 2042 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false,
2043 instr.op_32.generates_cc, 0, true);
2025 break; 2044 break;
2026 } 2045 }
2027 } 2046 }
@@ -2035,16 +2054,14 @@ private:
2035 2054
2036 switch (opcode->get().GetId()) { 2055 switch (opcode->get().GetId()) {
2037 case OpCode::Id::BFE_IMM: { 2056 case OpCode::Id::BFE_IMM: {
2038 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2039 "Condition codes generation in BFE is not implemented");
2040
2041 std::string inner_shift = 2057 std::string inner_shift =
2042 '(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')'; 2058 '(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')';
2043 std::string outer_shift = 2059 std::string outer_shift =
2044 '(' + inner_shift + " >> " + 2060 '(' + inner_shift + " >> " +
2045 std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')'; 2061 std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')';
2046 2062
2047 regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1); 2063 regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1, false,
2064 instr.generates_cc);
2048 break; 2065 break;
2049 } 2066 }
2050 default: { 2067 default: {
@@ -2055,8 +2072,6 @@ private:
2055 break; 2072 break;
2056 } 2073 }
2057 case OpCode::Type::Bfi: { 2074 case OpCode::Type::Bfi: {
2058 UNIMPLEMENTED_IF(instr.generates_cc);
2059
2060 const auto [base, packed_shift] = [&]() -> std::tuple<std::string, std::string> { 2075 const auto [base, packed_shift] = [&]() -> std::tuple<std::string, std::string> {
2061 switch (opcode->get().GetId()) { 2076 switch (opcode->get().GetId()) {
2062 case OpCode::Id::BFI_IMM_R: 2077 case OpCode::Id::BFI_IMM_R:
@@ -2071,9 +2086,10 @@ private:
2071 const std::string offset = '(' + packed_shift + " & 0xff)"; 2086 const std::string offset = '(' + packed_shift + " & 0xff)";
2072 const std::string bits = "((" + packed_shift + " >> 8) & 0xff)"; 2087 const std::string bits = "((" + packed_shift + " >> 8) & 0xff)";
2073 const std::string insert = regs.GetRegisterAsInteger(instr.gpr8, 0, false); 2088 const std::string insert = regs.GetRegisterAsInteger(instr.gpr8, 0, false);
2074 regs.SetRegisterToInteger( 2089 regs.SetRegisterToInteger(instr.gpr0, false, 0,
2075 instr.gpr0, false, 0, 2090 "bitfieldInsert(" + base + ", " + insert + ", " + offset +
2076 "bitfieldInsert(" + base + ", " + insert + ", " + offset + ", " + bits + ')', 1, 1); 2091 ", " + bits + ')',
2092 1, 1, false, instr.generates_cc);
2077 break; 2093 break;
2078 } 2094 }
2079 case OpCode::Type::Shift: { 2095 case OpCode::Type::Shift: {
@@ -2095,9 +2111,6 @@ private:
2095 case OpCode::Id::SHR_C: 2111 case OpCode::Id::SHR_C:
2096 case OpCode::Id::SHR_R: 2112 case OpCode::Id::SHR_R:
2097 case OpCode::Id::SHR_IMM: { 2113 case OpCode::Id::SHR_IMM: {
2098 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2099 "Condition codes generation in SHR is not implemented");
2100
2101 if (!instr.shift.is_signed) { 2114 if (!instr.shift.is_signed) {
2102 // Logical shift right 2115 // Logical shift right
2103 op_a = "uint(" + op_a + ')'; 2116 op_a = "uint(" + op_a + ')';
@@ -2105,7 +2118,7 @@ private:
2105 2118
2106 // Cast to int is superfluous for arithmetic shift, it's only for a logical shift 2119 // Cast to int is superfluous for arithmetic shift, it's only for a logical shift
2107 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')', 2120 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')',
2108 1, 1); 2121 1, 1, false, instr.generates_cc);
2109 break; 2122 break;
2110 } 2123 }
2111 case OpCode::Id::SHL_C: 2124 case OpCode::Id::SHL_C:
@@ -2113,7 +2126,8 @@ private:
2113 case OpCode::Id::SHL_IMM: 2126 case OpCode::Id::SHL_IMM:
2114 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 2127 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2115 "Condition codes generation in SHL is not implemented"); 2128 "Condition codes generation in SHL is not implemented");
2116 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1); 2129 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1, false,
2130 instr.generates_cc);
2117 break; 2131 break;
2118 default: { 2132 default: {
2119 UNIMPLEMENTED_MSG("Unhandled shift instruction: {}", opcode->get().GetName()); 2133 UNIMPLEMENTED_MSG("Unhandled shift instruction: {}", opcode->get().GetName());
@@ -2127,18 +2141,17 @@ private:
2127 2141
2128 switch (opcode->get().GetId()) { 2142 switch (opcode->get().GetId()) {
2129 case OpCode::Id::IADD32I: 2143 case OpCode::Id::IADD32I:
2130 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, 2144 UNIMPLEMENTED_IF_MSG(
2131 "Condition codes generation in IADD32I is not implemented"); 2145 instr.op_32.generates_cc,
2146 "Condition codes generation in IADD32I is partially implemented");
2132 2147
2133 if (instr.iadd32i.negate_a) 2148 if (instr.iadd32i.negate_a)
2134 op_a = "-(" + op_a + ')'; 2149 op_a = "-(" + op_a + ')';
2135 2150
2136 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, 2151 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
2137 instr.iadd32i.saturate != 0); 2152 instr.iadd32i.saturate, instr.op_32.generates_cc);
2138 break; 2153 break;
2139 case OpCode::Id::LOP32I: { 2154 case OpCode::Id::LOP32I: {
2140 UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc,
2141 "Condition codes generation in LOP32I is not implemented");
2142 2155
2143 if (instr.alu.lop32i.invert_a) 2156 if (instr.alu.lop32i.invert_a)
2144 op_a = "~(" + op_a + ')'; 2157 op_a = "~(" + op_a + ')';
@@ -2148,7 +2161,7 @@ private:
2148 2161
2149 WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b, 2162 WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b,
2150 Tegra::Shader::PredicateResultMode::None, 2163 Tegra::Shader::PredicateResultMode::None,
2151 Tegra::Shader::Pred::UnusedIndex); 2164 Tegra::Shader::Pred::UnusedIndex, instr.op_32.generates_cc);
2152 break; 2165 break;
2153 } 2166 }
2154 default: { 2167 default: {
@@ -2177,7 +2190,7 @@ private:
2177 case OpCode::Id::IADD_R: 2190 case OpCode::Id::IADD_R:
2178 case OpCode::Id::IADD_IMM: { 2191 case OpCode::Id::IADD_IMM: {
2179 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 2192 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2180 "Condition codes generation in IADD is not implemented"); 2193 "Condition codes generation in IADD is partially implemented");
2181 2194
2182 if (instr.alu_integer.negate_a) 2195 if (instr.alu_integer.negate_a)
2183 op_a = "-(" + op_a + ')'; 2196 op_a = "-(" + op_a + ')';
@@ -2186,14 +2199,15 @@ private:
2186 op_b = "-(" + op_b + ')'; 2199 op_b = "-(" + op_b + ')';
2187 2200
2188 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, 2201 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
2189 instr.alu.saturate_d); 2202 instr.alu.saturate_d, instr.generates_cc);
2190 break; 2203 break;
2191 } 2204 }
2192 case OpCode::Id::IADD3_C: 2205 case OpCode::Id::IADD3_C:
2193 case OpCode::Id::IADD3_R: 2206 case OpCode::Id::IADD3_R:
2194 case OpCode::Id::IADD3_IMM: { 2207 case OpCode::Id::IADD3_IMM: {
2195 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 2208 UNIMPLEMENTED_IF_MSG(
2196 "Condition codes generation in IADD3 is not implemented"); 2209 instr.generates_cc,
2210 "Condition codes generation in IADD3 is partially implemented");
2197 2211
2198 std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); 2212 std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
2199 2213
@@ -2249,14 +2263,16 @@ private:
2249 result = '(' + op_a + " + " + op_b + " + " + op_c + ')'; 2263 result = '(' + op_a + " + " + op_b + " + " + op_c + ')';
2250 } 2264 }
2251 2265
2252 regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1); 2266 regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1, false,
2267 instr.generates_cc);
2253 break; 2268 break;
2254 } 2269 }
2255 case OpCode::Id::ISCADD_C: 2270 case OpCode::Id::ISCADD_C:
2256 case OpCode::Id::ISCADD_R: 2271 case OpCode::Id::ISCADD_R:
2257 case OpCode::Id::ISCADD_IMM: { 2272 case OpCode::Id::ISCADD_IMM: {
2258 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 2273 UNIMPLEMENTED_IF_MSG(
2259 "Condition codes generation in ISCADD is not implemented"); 2274 instr.generates_cc,
2275 "Condition codes generation in ISCADD is partially implemented");
2260 2276
2261 if (instr.alu_integer.negate_a) 2277 if (instr.alu_integer.negate_a)
2262 op_a = "-(" + op_a + ')'; 2278 op_a = "-(" + op_a + ')';
@@ -2267,7 +2283,8 @@ private:
2267 const std::string shift = std::to_string(instr.alu_integer.shift_amount.Value()); 2283 const std::string shift = std::to_string(instr.alu_integer.shift_amount.Value());
2268 2284
2269 regs.SetRegisterToInteger(instr.gpr0, true, 0, 2285 regs.SetRegisterToInteger(instr.gpr0, true, 0,
2270 "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); 2286 "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1,
2287 false, instr.generates_cc);
2271 break; 2288 break;
2272 } 2289 }
2273 case OpCode::Id::POPC_C: 2290 case OpCode::Id::POPC_C:
@@ -2291,8 +2308,6 @@ private:
2291 case OpCode::Id::LOP_C: 2308 case OpCode::Id::LOP_C:
2292 case OpCode::Id::LOP_R: 2309 case OpCode::Id::LOP_R:
2293 case OpCode::Id::LOP_IMM: { 2310 case OpCode::Id::LOP_IMM: {
2294 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2295 "Condition codes generation in LOP is not implemented");
2296 2311
2297 if (instr.alu.lop.invert_a) 2312 if (instr.alu.lop.invert_a)
2298 op_a = "~(" + op_a + ')'; 2313 op_a = "~(" + op_a + ')';
@@ -2301,15 +2316,13 @@ private:
2301 op_b = "~(" + op_b + ')'; 2316 op_b = "~(" + op_b + ')';
2302 2317
2303 WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b, 2318 WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b,
2304 instr.alu.lop.pred_result_mode, instr.alu.lop.pred48); 2319 instr.alu.lop.pred_result_mode, instr.alu.lop.pred48,
2320 instr.generates_cc);
2305 break; 2321 break;
2306 } 2322 }
2307 case OpCode::Id::LOP3_C: 2323 case OpCode::Id::LOP3_C:
2308 case OpCode::Id::LOP3_R: 2324 case OpCode::Id::LOP3_R:
2309 case OpCode::Id::LOP3_IMM: { 2325 case OpCode::Id::LOP3_IMM: {
2310 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2311 "Condition codes generation in LOP3 is not implemented");
2312
2313 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); 2326 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
2314 std::string lut; 2327 std::string lut;
2315 2328
@@ -2319,15 +2332,16 @@ private:
2319 lut = '(' + std::to_string(instr.alu.lop3.GetImmLut48()) + ')'; 2332 lut = '(' + std::to_string(instr.alu.lop3.GetImmLut48()) + ')';
2320 } 2333 }
2321 2334
2322 WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut); 2335 WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut, instr.generates_cc);
2323 break; 2336 break;
2324 } 2337 }
2325 case OpCode::Id::IMNMX_C: 2338 case OpCode::Id::IMNMX_C:
2326 case OpCode::Id::IMNMX_R: 2339 case OpCode::Id::IMNMX_R:
2327 case OpCode::Id::IMNMX_IMM: { 2340 case OpCode::Id::IMNMX_IMM: {
2328 UNIMPLEMENTED_IF(instr.imnmx.exchange != Tegra::Shader::IMinMaxExchange::None); 2341 UNIMPLEMENTED_IF(instr.imnmx.exchange != Tegra::Shader::IMinMaxExchange::None);
2329 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 2342 UNIMPLEMENTED_IF_MSG(
2330 "Condition codes generation in IMNMX is not implemented"); 2343 instr.generates_cc,
2344 "Condition codes generation in IMNMX is partially implemented");
2331 2345
2332 const std::string condition = 2346 const std::string condition =
2333 GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0); 2347 GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0);
@@ -2335,7 +2349,7 @@ private:
2335 regs.SetRegisterToInteger(instr.gpr0, instr.imnmx.is_signed, 0, 2349 regs.SetRegisterToInteger(instr.gpr0, instr.imnmx.is_signed, 0,
2336 '(' + condition + ") ? min(" + parameters + ") : max(" + 2350 '(' + condition + ") ? min(" + parameters + ") : max(" +
2337 parameters + ')', 2351 parameters + ')',
2338 1, 1); 2352 1, 1, false, instr.generates_cc);
2339 break; 2353 break;
2340 } 2354 }
2341 case OpCode::Id::LEA_R2: 2355 case OpCode::Id::LEA_R2:
@@ -2396,7 +2410,8 @@ private:
2396 UNIMPLEMENTED_IF_MSG(instr.lea.pred48 != static_cast<u64>(Pred::UnusedIndex), 2410 UNIMPLEMENTED_IF_MSG(instr.lea.pred48 != static_cast<u64>(Pred::UnusedIndex),
2397 "Unhandled LEA Predicate"); 2411 "Unhandled LEA Predicate");
2398 const std::string value = '(' + op_a + " + (" + op_b + "*(1 << " + op_c + ")))"; 2412 const std::string value = '(' + op_a + " + (" + op_b + "*(1 << " + op_c + ")))";
2399 regs.SetRegisterToInteger(instr.gpr0, true, 0, value, 1, 1); 2413 regs.SetRegisterToInteger(instr.gpr0, true, 0, value, 1, 1, false,
2414 instr.generates_cc);
2400 2415
2401 break; 2416 break;
2402 } 2417 }
@@ -2501,7 +2516,7 @@ private:
2501 UNIMPLEMENTED_IF_MSG(instr.ffma.tab5980_1 != 0, "FFMA tab5980_1({}) not implemented", 2516 UNIMPLEMENTED_IF_MSG(instr.ffma.tab5980_1 != 0, "FFMA tab5980_1({}) not implemented",
2502 instr.ffma.tab5980_1.Value()); 2517 instr.ffma.tab5980_1.Value());
2503 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 2518 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2504 "Condition codes generation in FFMA is not implemented"); 2519 "Condition codes generation in FFMA is partially implemented");
2505 2520
2506 switch (opcode->get().GetId()) { 2521 switch (opcode->get().GetId()) {
2507 case OpCode::Id::FFMA_CR: { 2522 case OpCode::Id::FFMA_CR: {
@@ -2532,7 +2547,7 @@ private:
2532 } 2547 }
2533 2548
2534 regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')', 2549 regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')',
2535 1, 1, instr.alu.saturate_d, 0, true); 2550 1, 1, instr.alu.saturate_d, instr.generates_cc, 0, true);
2536 break; 2551 break;
2537 } 2552 }
2538 case OpCode::Type::Hfma2: { 2553 case OpCode::Type::Hfma2: {
@@ -2603,16 +2618,14 @@ private:
2603 } 2618 }
2604 2619
2605 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, 2620 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
2606 1, instr.alu.saturate_d, 0, instr.conversion.dest_size, 2621 1, instr.alu.saturate_d, instr.generates_cc, 0,
2607 instr.generates_cc.Value() != 0); 2622 instr.conversion.dest_size);
2608 break; 2623 break;
2609 } 2624 }
2610 case OpCode::Id::I2F_R: 2625 case OpCode::Id::I2F_R:
2611 case OpCode::Id::I2F_C: { 2626 case OpCode::Id::I2F_C: {
2612 UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word); 2627 UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
2613 UNIMPLEMENTED_IF(instr.conversion.selector); 2628 UNIMPLEMENTED_IF(instr.conversion.selector);
2614 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2615 "Condition codes generation in I2F is not implemented");
2616 std::string op_a; 2629 std::string op_a;
2617 2630
2618 if (instr.is_b_gpr) { 2631 if (instr.is_b_gpr) {
@@ -2635,14 +2648,12 @@ private:
2635 op_a = "-(" + op_a + ')'; 2648 op_a = "-(" + op_a + ')';
2636 } 2649 }
2637 2650
2638 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); 2651 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, false, instr.generates_cc);
2639 break; 2652 break;
2640 } 2653 }
2641 case OpCode::Id::F2F_R: { 2654 case OpCode::Id::F2F_R: {
2642 UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word); 2655 UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
2643 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); 2656 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
2644 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2645 "Condition codes generation in F2F is not implemented");
2646 std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); 2657 std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
2647 2658
2648 if (instr.conversion.abs_a) { 2659 if (instr.conversion.abs_a) {
@@ -2674,14 +2685,13 @@ private:
2674 break; 2685 break;
2675 } 2686 }
2676 2687
2677 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d); 2688 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d,
2689 instr.generates_cc);
2678 break; 2690 break;
2679 } 2691 }
2680 case OpCode::Id::F2I_R: 2692 case OpCode::Id::F2I_R:
2681 case OpCode::Id::F2I_C: { 2693 case OpCode::Id::F2I_C: {
2682 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); 2694 UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
2683 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2684 "Condition codes generation in F2I is not implemented");
2685 std::string op_a{}; 2695 std::string op_a{};
2686 2696
2687 if (instr.is_b_gpr) { 2697 if (instr.is_b_gpr) {
@@ -2724,7 +2734,8 @@ private:
2724 } 2734 }
2725 2735
2726 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, 2736 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
2727 1, false, 0, instr.conversion.dest_size); 2737 1, false, instr.generates_cc, 0,
2738 instr.conversion.dest_size);
2728 break; 2739 break;
2729 } 2740 }
2730 default: { 2741 default: {
@@ -2887,7 +2898,7 @@ private:
2887 shader.AddLine(coord); 2898 shader.AddLine(coord);
2888 2899
2889 if (depth_compare) { 2900 if (depth_compare) {
2890 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); 2901 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1);
2891 } else { 2902 } else {
2892 shader.AddLine("vec4 texture_tmp = " + texture + ';'); 2903 shader.AddLine("vec4 texture_tmp = " + texture + ';');
2893 std::size_t dest_elem{}; 2904 std::size_t dest_elem{};
@@ -2896,7 +2907,7 @@ private:
2896 // Skip disabled components 2907 // Skip disabled components
2897 continue; 2908 continue;
2898 } 2909 }
2899 regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, 2910 regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, false,
2900 dest_elem); 2911 dest_elem);
2901 ++dest_elem; 2912 ++dest_elem;
2902 } 2913 }
@@ -2982,7 +2993,7 @@ private:
2982 // Skip disabled components 2993 // Skip disabled components
2983 continue; 2994 continue;
2984 } 2995 }
2985 regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, 2996 regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, false,
2986 dest_elem); 2997 dest_elem);
2987 ++dest_elem; 2998 ++dest_elem;
2988 } 2999 }
@@ -3231,7 +3242,7 @@ private:
3231 } 3242 }
3232 case OpCode::Type::PredicateSetRegister: { 3243 case OpCode::Type::PredicateSetRegister: {
3233 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 3244 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
3234 "Condition codes generation in PSET is not implemented"); 3245 "Condition codes generation in PSET is partially implemented");
3235 3246
3236 const std::string op_a = 3247 const std::string op_a =
3237 GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0); 3248 GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0);
@@ -3248,10 +3259,11 @@ private:
3248 const std::string result = '(' + predicate + ") " + combiner + " (" + second_pred + ')'; 3259 const std::string result = '(' + predicate + ") " + combiner + " (" + second_pred + ')';
3249 if (instr.pset.bf == 0) { 3260 if (instr.pset.bf == 0) {
3250 const std::string value = '(' + result + ") ? 0xFFFFFFFF : 0"; 3261 const std::string value = '(' + result + ") ? 0xFFFFFFFF : 0";
3251 regs.SetRegisterToInteger(instr.gpr0, false, 0, value, 1, 1); 3262 regs.SetRegisterToInteger(instr.gpr0, false, 0, value, 1, 1, false,
3263 instr.generates_cc);
3252 } else { 3264 } else {
3253 const std::string value = '(' + result + ") ? 1.0 : 0.0"; 3265 const std::string value = '(' + result + ") ? 1.0 : 0.0";
3254 regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1); 3266 regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1, false, instr.generates_cc);
3255 } 3267 }
3256 break; 3268 break;
3257 } 3269 }
@@ -3368,14 +3380,11 @@ private:
3368 ") " + combiner + " (" + second_pred + "))"; 3380 ") " + combiner + " (" + second_pred + "))";
3369 3381
3370 if (instr.fset.bf) { 3382 if (instr.fset.bf) {
3371 regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1); 3383 regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1, false,
3384 instr.generates_cc);
3372 } else { 3385 } else {
3373 regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1, 3386 regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1,
3374 1); 3387 1, false, instr.generates_cc);
3375 }
3376 if (instr.generates_cc.Value() != 0) {
3377 regs.SetInternalFlag(InternalFlag::ZeroFlag, predicate);
3378 LOG_WARNING(HW_GPU, "FSET Condition Code is incomplete");
3379 } 3388 }
3380 break; 3389 break;
3381 } 3390 }
@@ -3462,7 +3471,7 @@ private:
3462 UNIMPLEMENTED_IF(instr.xmad.sign_a); 3471 UNIMPLEMENTED_IF(instr.xmad.sign_a);
3463 UNIMPLEMENTED_IF(instr.xmad.sign_b); 3472 UNIMPLEMENTED_IF(instr.xmad.sign_b);
3464 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 3473 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
3465 "Condition codes generation in XMAD is not implemented"); 3474 "Condition codes generation in XMAD is partially implemented");
3466 3475
3467 std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)}; 3476 std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)};
3468 std::string op_b; 3477 std::string op_b;
@@ -3548,7 +3557,8 @@ private:
3548 sum = "((" + sum + " & 0xFFFF) | (" + src2 + "<< 16))"; 3557 sum = "((" + sum + " & 0xFFFF) | (" + src2 + "<< 16))";
3549 } 3558 }
3550 3559
3551 regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1); 3560 regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1, false,
3561 instr.generates_cc);
3552 break; 3562 break;
3553 } 3563 }
3554 default: { 3564 default: {
@@ -3752,8 +3762,7 @@ private:
3752 } 3762 }
3753 3763
3754 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1, 3764 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
3755 instr.vmad.saturate == 1, 0, Register::Size::Word, 3765 instr.vmad.saturate, instr.vmad.cc);
3756 instr.vmad.cc);
3757 break; 3766 break;
3758 } 3767 }
3759 case OpCode::Id::VSETP: { 3768 case OpCode::Id::VSETP: {