Merge pull request #468 from Subv/compound_preds

Shader: Implemented compound predicates in the fset and fsetp instructions
This commit is contained in:
bunnei 2018-05-25 22:28:47 -04:00 committed by GitHub
commit aee356bd10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -597,6 +597,46 @@ private:
return variable; return variable;
} }
/**
* Returns the comparison string to use to compare two values in the 'set' family of
* instructions.
* @params condition The condition used in the 'set'-family instruction.
* @returns String corresponding to the GLSL operator that matches the desired comparison.
*/
std::string GetPredicateComparison(Tegra::Shader::PredCondition condition) const {
using Tegra::Shader::PredCondition;
static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = {
{PredCondition::LessThan, "<"},
{PredCondition::Equal, "=="},
{PredCondition::LessEqual, "<="},
{PredCondition::GreaterThan, ">"},
};
auto comparison = PredicateComparisonStrings.find(condition);
ASSERT_MSG(comparison != PredicateComparisonStrings.end(),
"Unknown predicate comparison operation");
return comparison->second;
}
/**
* Returns the operator string to use to combine two predicates in the 'setp' family of
* instructions.
* @params operation The operator used in the 'setp'-family instruction.
* @returns String corresponding to the GLSL operator that matches the desired operator.
*/
std::string GetPredicateCombiner(Tegra::Shader::PredOperation operation) const {
using Tegra::Shader::PredOperation;
static const std::unordered_map<PredOperation, const char*> PredicateOperationStrings = {
{PredOperation::And, "&&"},
{PredOperation::Or, "||"},
{PredOperation::Xor, "^^"},
};
auto op = PredicateOperationStrings.find(operation);
ASSERT_MSG(op != PredicateOperationStrings.end(), "Unknown predicate operation");
return op->second;
}
/* /*
* Returns whether the instruction at the specified offset is a 'sched' instruction. * Returns whether the instruction at the specified offset is a 'sched' instruction.
* Sched instructions always appear before a sequence of 3 instructions. * Sched instructions always appear before a sequence of 3 instructions.
@ -888,28 +928,25 @@ private:
} }
using Tegra::Shader::Pred; using Tegra::Shader::Pred;
ASSERT_MSG(instr.fsetp.pred0 == static_cast<u64>(Pred::UnusedIndex) &&
instr.fsetp.pred39 == static_cast<u64>(Pred::UnusedIndex),
"Compound predicates are not implemented");
// We can't use the constant predicate as destination. // We can't use the constant predicate as destination.
ASSERT(instr.fsetp.pred3 != static_cast<u64>(Pred::UnusedIndex)); ASSERT(instr.fsetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
using Tegra::Shader::PredCondition; std::string second_pred =
switch (instr.fsetp.cond) { GetPredicateCondition(instr.fsetp.pred39, instr.fsetp.neg_pred != 0);
case PredCondition::LessThan:
SetPredicate(instr.fsetp.pred3, '(' + op_a + ") < (" + op_b + ')'); std::string comparator = GetPredicateComparison(instr.fsetp.cond);
break; std::string combiner = GetPredicateCombiner(instr.fsetp.op);
case PredCondition::Equal:
SetPredicate(instr.fsetp.pred3, '(' + op_a + ") == (" + op_b + ')'); std::string predicate = '(' + op_a + ") " + comparator + " (" + op_b + ')';
break; // Set the primary predicate to the result of Predicate OP SecondPredicate
case PredCondition::LessEqual: SetPredicate(instr.fsetp.pred3,
SetPredicate(instr.fsetp.pred3, '(' + op_a + ") <= (" + op_b + ')'); '(' + predicate + ") " + combiner + " (" + second_pred + ')');
break;
default: if (instr.fsetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})", // Set the secondary predicate to the result of !Predicate OP SecondPredicate, if
static_cast<unsigned>(instr.fsetp.cond.Value()), op_a, op_b); // enabled
UNREACHABLE(); SetPredicate(instr.fsetp.pred0,
"!(" + predicate + ") " + combiner + " (" + second_pred + ')');
} }
break; break;
} }
@ -941,35 +978,18 @@ private:
op_b = "abs(" + op_b + ')'; op_b = "abs(" + op_b + ')';
} }
using Tegra::Shader::Pred;
ASSERT_MSG(instr.fset.pred39 == static_cast<u64>(Pred::UnusedIndex),
"Compound predicates are not implemented");
// The fset instruction sets a register to 1.0 if the condition is true, and to 0 // The fset instruction sets a register to 1.0 if the condition is true, and to 0
// otherwise. // otherwise.
using Tegra::Shader::PredCondition; std::string second_pred =
switch (instr.fset.cond) { GetPredicateCondition(instr.fset.pred39, instr.fset.neg_pred != 0);
case PredCondition::LessThan:
regs.SetRegisterToFloat(instr.gpr0, 0, std::string comparator = GetPredicateComparison(instr.fset.cond);
"((" + op_a + ") < (" + op_b + ")) ? 1.0 : 0", 1, 1); std::string combiner = GetPredicateCombiner(instr.fset.op);
break;
case PredCondition::Equal: std::string predicate = "(((" + op_a + ") " + comparator + " (" + op_b + ")) " +
regs.SetRegisterToFloat(instr.gpr0, 0, combiner + " (" + second_pred + "))";
"((" + op_a + ") == (" + op_b + ")) ? 1.0 : 0", 1, 1);
break; regs.SetRegisterToFloat(instr.gpr0, 0, predicate + " ? 1.0 : 0.0", 1, 1);
case PredCondition::LessEqual:
regs.SetRegisterToFloat(instr.gpr0, 0,
"((" + op_a + ") <= (" + op_b + ")) ? 1.0 : 0", 1, 1);
break;
case PredCondition::GreaterThan:
regs.SetRegisterToFloat(instr.gpr0, 0,
"((" + op_a + ") > (" + op_b + ")) ? 1.0 : 0", 1, 1);
break;
default:
NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})",
static_cast<unsigned>(instr.fset.cond.Value()), op_a, op_b);
UNREACHABLE();
}
break; break;
} }
default: { default: {