diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 235 |
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: { |