From e7ea376e006c1db9e251d18b669116fc58e45582 Mon Sep 17 00:00:00 2001 From: bo3b Date: Tue, 13 Jan 2015 22:01:09 -0800 Subject: [PATCH] One more try on the 'udiv'. Simplification. This change removes the use of src0 and src1, and instead puts the first value into uiDest, then assigns the output at the tail. This also fixes a problem where it was getting errors converting float2 to uint4. The cast operator of (uintN) is used to force the instruction to recognize the 'udiv' and not just be a regular divide. Tested on FC4 and seems to handle all cases there, including the constant l(6) as divisor, and swizzling of inputs. --- HLSLDecompiler/DecompileHLSL.cpp | 42 ++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/HLSLDecompiler/DecompileHLSL.cpp b/HLSLDecompiler/DecompileHLSL.cpp index 6beaec0ab..ae7a807ad 100644 --- a/HLSLDecompiler/DecompileHLSL.cpp +++ b/HLSLDecompiler/DecompileHLSL.cpp @@ -2761,7 +2761,7 @@ class Decompiler mOutput.pop_back(); mOutput.push_back(';'); mOutput.push_back('\n'); - const char *helperDecl = " uint4 bitmask, src0, src1, uiDest;\n float4 fDest;\n\n"; + const char *helperDecl = " uint4 bitmask, uiDest;\n float4 fDest;\n\n"; mOutput.insert(mOutput.end(), helperDecl, helperDecl + strlen(helperDecl)); } else if (!strncmp(statement, "dcl_", 4)) @@ -2881,18 +2881,24 @@ class Decompiler // UDIV instruction also could damage the original register before finishing, giving wrong results. // e.g. udiv r0.x, r1.x, r0.x, r0.y - // e.g. udiv null, r1.xy, r3.zwzz, r2.zwzz + // variant: udiv null, r1.xy, r3.zwzz, r2.zwzz // To fix this, we are using the temp variables declared at the top. + // expected output: + // uiDest.x = (uint)r0.x / (uint)r0.y; + // r1.x = (uint)r0.x % (uint)r0.y; + // r0.x = uiDest.x; + // // This will swizzle based on either op1 or op2, as long as it's not null. It's not clear whether // the swizzle is allowed to vary for each half of the instruction, like xy for /, zw for %. // To allow for that, we'll set the temp registers with full swizzle, then only use the specific // parts required for each half, as the safest approach. Might not generate udiv though. // Also removed saturate code, because udiv does not specify that. - // Need to applySwizzle to unchanged operands, as constant l values are otherwise damaged. + // Creates operand copies to applySwizzle to unchanged operands, as constant l values are otherwise damaged. case OPCODE_UDIV: { remapTarget(op1); remapTarget(op2); + char divOut[opcodeSize] = "uiDest.xyzw"; char *divSwiz = op1; char *remSwiz = op2; strcpy_s(op13, opcodeSize, op3); @@ -2900,28 +2906,28 @@ class Decompiler if (instr->asOperands[0].eType != OPERAND_TYPE_NULL) { - applySwizzle(divSwiz, fixImm(op13, instr->asOperands[2]), false); - applySwizzle(divSwiz, fixImm(op14, instr->asOperands[3]), false); + applySwizzle(divSwiz, divOut, true); + applySwizzle(divSwiz, fixImm(op13, instr->asOperands[2]), true); + applySwizzle(divSwiz, fixImm(op14, instr->asOperands[3]), true); + convertToUInt(op13); + convertToUInt(op14); - sprintf(buffer, " src0 = %s;\n", ci(op13).c_str()); - appendOutput(buffer); - sprintf(buffer, " src1 = %s;\n", ci(op14).c_str()); - appendOutput(buffer); - - sprintf(buffer, " %s = src0 / src1;\n", writeTarget(op1)); + sprintf(buffer, " %s = %s / %s;\n", divOut, ci(op13).c_str(), ci(op14).c_str()); appendOutput(buffer); } if (instr->asOperands[1].eType != OPERAND_TYPE_NULL) { - applySwizzle(remSwiz, fixImm(op3, instr->asOperands[2]), false); - applySwizzle(remSwiz, fixImm(op4, instr->asOperands[3]), false); + applySwizzle(remSwiz, fixImm(op3, instr->asOperands[2]), true); + applySwizzle(remSwiz, fixImm(op4, instr->asOperands[3]), true); + convertToUInt(op3); + convertToUInt(op4); - sprintf(buffer, " src0 = %s;\n", ci(op3).c_str()); - appendOutput(buffer); - sprintf(buffer, " src1 = %s;\n", ci(op4).c_str()); + sprintf(buffer, " %s = %s %% %s;\n", writeTarget(op2), ci(op3).c_str(), ci(op4).c_str()); appendOutput(buffer); - - sprintf(buffer, " %s = src0 %% src1;\n", writeTarget(op2)); + } + if (instr->asOperands[0].eType != OPERAND_TYPE_NULL) + { + sprintf(buffer, " %s = %s;\n", writeTarget(op1), divOut); appendOutput(buffer); } removeBoolean(op1);