Merge pull request #4490 from karanvora2599/perf/shader-minmax-floor-denormal-free
perf(shader): treat f32 min, max, med3, floor and ceil results as denormal-free
This commit is contained in:
commit
520ee1a2e8
|
|
@ -150,6 +150,66 @@ int main() {
|
|||
return b.eliminate() == 1u && !clamped.HasUses() && product.HasUses();
|
||||
});
|
||||
|
||||
passed &= run("a min, max, min3, max3 or med3 of flushed values needs no flush, one with an unknown operand does", [] {
|
||||
Builder b;
|
||||
const auto value = [&](IrValue& bits) -> IrValue& { return b.emit(IrOpcode::BitCastF32U32, IrType::F32, {&bits}); };
|
||||
const auto flushedResult = [&](IrOpcode opcode, std::initializer_list<IrValue*> arguments) -> IrValue& {
|
||||
return b.flush(b.emit(IrOpcode::BitCastU32F32, IrType::U32, {&b.emit(opcode, IrType::F32, arguments)}));
|
||||
};
|
||||
auto& x = value(b.flush(b.unknown()));
|
||||
auto& y = value(b.flush(b.unknown()));
|
||||
auto& z = value(b.flush(b.unknown()));
|
||||
auto& raw = value(b.unknown());
|
||||
IrValue* removed[] = {
|
||||
&flushedResult(IrOpcode::FPMin32, {&x, &y}),
|
||||
&flushedResult(IrOpcode::FPMax32, {&y, &x}),
|
||||
&flushedResult(IrOpcode::FPMinTri32, {&x, &y, &z}),
|
||||
&flushedResult(IrOpcode::FPMaxTri32, {&z, &y, &x}),
|
||||
&flushedResult(IrOpcode::FPMedTri32, {&x, &z, &y}),
|
||||
};
|
||||
auto& mixedPair = flushedResult(IrOpcode::FPMax32, {&x, &raw});
|
||||
auto& mixedMedian = flushedResult(IrOpcode::FPMedTri32, {&x, &y, &raw});
|
||||
for (auto* flushed : removed) b.keep(*flushed);
|
||||
b.keep(mixedPair);
|
||||
b.keep(mixedMedian);
|
||||
const bool counted = b.eliminate() == 5u;
|
||||
bool kept = false;
|
||||
for (auto* flushed : removed) kept |= flushed->HasUses();
|
||||
return counted && !kept && mixedPair.HasUses() && mixedMedian.HasUses();
|
||||
});
|
||||
|
||||
passed &= run("a floor or ceil needs no flush, even of an unknown value", [] {
|
||||
Builder b;
|
||||
auto& raw = b.emit(IrOpcode::BitCastF32U32, IrType::F32, {&b.unknown()});
|
||||
auto& floored = b.flush(b.emit(IrOpcode::BitCastU32F32, IrType::U32, {&b.emit(IrOpcode::FPFloor32, IrType::F32, {&raw})}));
|
||||
auto& ceiled = b.flush(b.emit(IrOpcode::BitCastU32F32, IrType::U32, {&b.emit(IrOpcode::FPCeil32, IrType::F32, {&raw})}));
|
||||
b.keep(floored);
|
||||
b.keep(ceiled);
|
||||
return b.eliminate() == 2u && !floored.HasUses() && !ceiled.HasUses();
|
||||
});
|
||||
|
||||
passed &= run("a max carried around a loop without a flush keeps its flush and the search ends", [] {
|
||||
Builder b;
|
||||
IrBlock& head = *b.block;
|
||||
IrBlock& body = b.newBlock();
|
||||
IrBlock& exit = b.newBlock();
|
||||
head.AddBranch(&body);
|
||||
body.AddBranch(&body);
|
||||
body.AddBranch(&exit);
|
||||
auto& initial = b.flush(b.unknown());
|
||||
b.block = &body;
|
||||
auto& carried = b.program.CreateValue(IrOpcode::Phi, IrType::U32);
|
||||
body.AppendInstruction(&carried);
|
||||
auto& step = b.emit(IrOpcode::BitCastF32U32, IrType::F32, {&b.flush(b.unknown())});
|
||||
auto& maximum = b.emit(IrOpcode::BitCastU32F32, IrType::U32, {&b.emit(IrOpcode::FPMax32, IrType::F32, {&b.emit(IrOpcode::BitCastF32U32, IrType::F32, {&carried}), &step})});
|
||||
carried.AddPhiOperand(&head, &initial);
|
||||
carried.AddPhiOperand(&body, &maximum);
|
||||
auto& flushed = b.flush(maximum);
|
||||
b.block = &exit;
|
||||
b.keep(flushed);
|
||||
return b.eliminate() == 0u && flushed.HasUses();
|
||||
});
|
||||
|
||||
passed &= run("a phi of flushed values needs no flush", [] {
|
||||
Builder b;
|
||||
IrBlock& head = *b.block;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ private:
|
|||
case IrOpcode::ConvertF32S32:
|
||||
case IrOpcode::ConvertF32U32:
|
||||
case IrOpcode::ConvertF32F16:
|
||||
case IrOpcode::FPFloor32:
|
||||
case IrOpcode::FPCeil32:
|
||||
return true;
|
||||
case IrOpcode::BitCastU32F32:
|
||||
case IrOpcode::BitCastF32U32:
|
||||
|
|
@ -67,6 +69,11 @@ private:
|
|||
case IrOpcode::SelectU32:
|
||||
case IrOpcode::SelectF32:
|
||||
return Contains(value.Argument(1)) && Contains(value.Argument(2));
|
||||
case IrOpcode::FPMin32:
|
||||
case IrOpcode::FPMax32:
|
||||
case IrOpcode::FPMinTri32:
|
||||
case IrOpcode::FPMaxTri32:
|
||||
case IrOpcode::FPMedTri32:
|
||||
case IrOpcode::Phi:
|
||||
for (std::size_t index = 0; index < value.ArgumentCount(); ++index) {
|
||||
if (!Contains(value.Argument(index))) return false;
|
||||
|
|
|
|||
Loading…
Reference in New Issue