shader: Constant propagation and global memory to storage buffer

This commit is contained in:
ReinUsesLisp 2021-02-05 05:58:02 -03:00 committed by ameerj
parent d24a16045f
commit e81739493a
17 changed files with 652 additions and 63 deletions

View file

@ -504,6 +504,20 @@ U32U64 IREmitter::IAdd(const U32U64& a, const U32U64& b) {
}
}
U32U64 IREmitter::ISub(const U32U64& a, const U32U64& b) {
if (a.Type() != b.Type()) {
throw InvalidArgument("Mismatching types {} and {}", a.Type(), b.Type());
}
switch (a.Type()) {
case Type::U32:
return Inst<U32>(Opcode::ISub32, a, b);
case Type::U64:
return Inst<U64>(Opcode::ISub64, a, b);
default:
ThrowInvalidType(a.Type());
}
}
U32 IREmitter::IMul(const U32& a, const U32& b) {
return Inst<U32>(Opcode::IMul32, a, b);
}
@ -679,8 +693,8 @@ U32U64 IREmitter::ConvertFToI(size_t bitsize, bool is_signed, const U16U32U64& v
}
}
U32U64 IREmitter::ConvertU(size_t bitsize, const U32U64& value) {
switch (bitsize) {
U32U64 IREmitter::ConvertU(size_t result_bitsize, const U32U64& value) {
switch (result_bitsize) {
case 32:
switch (value.Type()) {
case Type::U32:
@ -703,7 +717,7 @@ U32U64 IREmitter::ConvertU(size_t bitsize, const U32U64& value) {
break;
}
}
throw NotImplementedException("Conversion from {} to {} bits", value.Type(), bitsize);
throw NotImplementedException("Conversion from {} to {} bits", value.Type(), result_bitsize);
}
} // namespace Shader::IR

View file

@ -17,6 +17,8 @@ namespace Shader::IR {
class IREmitter {
public:
explicit IREmitter(Block& block_) : block{block_}, insertion_point{block.end()} {}
explicit IREmitter(Block& block_, Block::iterator insertion_point_)
: block{block_}, insertion_point{insertion_point_} {}
Block& block;
@ -125,6 +127,7 @@ public:
[[nodiscard]] U16U32U64 FPTrunc(const U16U32U64& value);
[[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b);
[[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b);
[[nodiscard]] U32 IMul(const U32& a, const U32& b);
[[nodiscard]] U32 INeg(const U32& value);
[[nodiscard]] U32 IAbs(const U32& value);
@ -155,7 +158,7 @@ public:
[[nodiscard]] U32U64 ConvertFToU(size_t bitsize, const U16U32U64& value);
[[nodiscard]] U32U64 ConvertFToI(size_t bitsize, bool is_signed, const U16U32U64& value);
[[nodiscard]] U32U64 ConvertU(size_t bitsize, const U32U64& value);
[[nodiscard]] U32U64 ConvertU(size_t result_bitsize, const U32U64& value);
private:
IR::Block::iterator insertion_point;

View file

@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include "shader_recompiler/exception.h"
#include "shader_recompiler/frontend/ir/microinstruction.h"
#include "shader_recompiler/frontend/ir/type.h"
@ -44,6 +46,13 @@ bool Inst::MayHaveSideEffects() const noexcept {
case Opcode::WriteGlobal32:
case Opcode::WriteGlobal64:
case Opcode::WriteGlobal128:
case Opcode::WriteStorageU8:
case Opcode::WriteStorageS8:
case Opcode::WriteStorageU16:
case Opcode::WriteStorageS16:
case Opcode::WriteStorage32:
case Opcode::WriteStorage64:
case Opcode::WriteStorage128:
return true;
default:
return false;
@ -56,15 +65,19 @@ bool Inst::IsPseudoInstruction() const noexcept {
case Opcode::GetSignFromOp:
case Opcode::GetCarryFromOp:
case Opcode::GetOverflowFromOp:
case Opcode::GetZSCOFromOp:
return true;
default:
return false;
}
}
bool Inst::AreAllArgsImmediates() const noexcept {
return std::all_of(args.begin(), args.begin() + NumArgs(),
[](const IR::Value& value) { return value.IsImmediate(); });
}
bool Inst::HasAssociatedPseudoOperation() const noexcept {
return zero_inst || sign_inst || carry_inst || overflow_inst || zsco_inst;
return zero_inst || sign_inst || carry_inst || overflow_inst;
}
Inst* Inst::GetAssociatedPseudoOperation(IR::Opcode opcode) {
@ -82,9 +95,6 @@ Inst* Inst::GetAssociatedPseudoOperation(IR::Opcode opcode) {
case Opcode::GetOverflowFromOp:
CheckPseudoInstruction(overflow_inst, Opcode::GetOverflowFromOp);
return overflow_inst;
case Opcode::GetZSCOFromOp:
CheckPseudoInstruction(zsco_inst, Opcode::GetZSCOFromOp);
return zsco_inst;
default:
throw InvalidArgument("{} is not a pseudo-instruction", opcode);
}
@ -176,9 +186,6 @@ void Inst::Use(const Value& value) {
case Opcode::GetOverflowFromOp:
SetPseudoInstruction(value.Inst()->overflow_inst, this);
break;
case Opcode::GetZSCOFromOp:
SetPseudoInstruction(value.Inst()->zsco_inst, this);
break;
default:
break;
}
@ -200,9 +207,6 @@ void Inst::UndoUse(const Value& value) {
case Opcode::GetOverflowFromOp:
RemovePseudoInstruction(value.Inst()->overflow_inst, Opcode::GetOverflowFromOp);
break;
case Opcode::GetZSCOFromOp:
RemovePseudoInstruction(value.Inst()->zsco_inst, Opcode::GetZSCOFromOp);
break;
default:
break;
}

View file

@ -49,6 +49,9 @@ public:
/// Pseudo-instructions depend on their parent instructions for their semantics.
[[nodiscard]] bool IsPseudoInstruction() const noexcept;
/// Determines if all arguments of this instruction are immediates.
[[nodiscard]] bool AreAllArgsImmediates() const noexcept;
/// Determines if there is a pseudo-operation associated with this instruction.
[[nodiscard]] bool HasAssociatedPseudoOperation() const noexcept;
/// Gets a pseudo-operation associated with this instruction
@ -94,7 +97,6 @@ private:
Inst* sign_inst{};
Inst* carry_inst{};
Inst* overflow_inst{};
Inst* zsco_inst{};
std::vector<std::pair<Block*, Value>> phi_operands;
u64 flags{};
};

View file

@ -24,9 +24,6 @@ OPCODE(GetAttribute, U32, Attr
OPCODE(SetAttribute, U32, Attribute, )
OPCODE(GetAttributeIndexed, U32, U32, )
OPCODE(SetAttributeIndexed, U32, U32, )
OPCODE(GetZSCORaw, U32, )
OPCODE(SetZSCORaw, Void, U32, )
OPCODE(SetZSCO, Void, ZSCO, )
OPCODE(GetZFlag, U1, Void, )
OPCODE(GetSFlag, U1, Void, )
OPCODE(GetCFlag, U1, Void, )
@ -65,6 +62,22 @@ OPCODE(WriteGlobal32, Void, U64,
OPCODE(WriteGlobal64, Void, U64, Opaque, )
OPCODE(WriteGlobal128, Void, U64, Opaque, )
// Storage buffer operations
OPCODE(LoadStorageU8, U32, U32, U32, )
OPCODE(LoadStorageS8, U32, U32, U32, )
OPCODE(LoadStorageU16, U32, U32, U32, )
OPCODE(LoadStorageS16, U32, U32, U32, )
OPCODE(LoadStorage32, U32, U32, U32, )
OPCODE(LoadStorage64, Opaque, U32, U32, )
OPCODE(LoadStorage128, Opaque, U32, U32, )
OPCODE(WriteStorageU8, Void, U32, U32, U32, )
OPCODE(WriteStorageS8, Void, U32, U32, U32, )
OPCODE(WriteStorageU16, Void, U32, U32, U32, )
OPCODE(WriteStorageS16, Void, U32, U32, U32, )
OPCODE(WriteStorage32, Void, U32, U32, U32, )
OPCODE(WriteStorage64, Void, U32, U32, Opaque, )
OPCODE(WriteStorage128, Void, U32, U32, Opaque, )
// Vector utility
OPCODE(CompositeConstruct2, Opaque, Opaque, Opaque, )
OPCODE(CompositeConstruct3, Opaque, Opaque, Opaque, Opaque, )
@ -90,7 +103,6 @@ OPCODE(GetZeroFromOp, U1, Opaq
OPCODE(GetSignFromOp, U1, Opaque, )
OPCODE(GetCarryFromOp, U1, Opaque, )
OPCODE(GetOverflowFromOp, U1, Opaque, )
OPCODE(GetZSCOFromOp, ZSCO, Opaque, )
// Floating-point operations
OPCODE(FPAbs16, U16, U16, )
@ -143,6 +155,8 @@ OPCODE(FPTrunc64, U64, U64,
// Integer operations
OPCODE(IAdd32, U32, U32, U32, )
OPCODE(IAdd64, U64, U64, U64, )
OPCODE(ISub32, U32, U32, U32, )
OPCODE(ISub64, U64, U64, U64, )
OPCODE(IMul32, U32, U32, U32, )
OPCODE(INeg32, U32, U32, )
OPCODE(IAbs32, U32, U32, )

View file

@ -11,7 +11,7 @@ namespace Shader::IR {
std::string NameOf(Type type) {
static constexpr std::array names{
"Opaque", "Label", "Reg", "Pred", "Attribute", "U1", "U8", "U16", "U32", "U64", "ZSCO",
"Opaque", "Label", "Reg", "Pred", "Attribute", "U1", "U8", "U16", "U32", "U64",
};
const size_t bits{static_cast<size_t>(type)};
if (bits == 0) {

View file

@ -25,7 +25,6 @@ enum class Type {
U16 = 1 << 7,
U32 = 1 << 8,
U64 = 1 << 9,
ZSCO = 1 << 10,
};
DECLARE_ENUM_FLAG_OPERATORS(Type)

View file

@ -91,26 +91,41 @@ IR::Attribute Value::Attribute() const {
}
bool Value::U1() const {
if (IsIdentity()) {
return inst->Arg(0).U1();
}
ValidateAccess(Type::U1);
return imm_u1;
}
u8 Value::U8() const {
if (IsIdentity()) {
return inst->Arg(0).U8();
}
ValidateAccess(Type::U8);
return imm_u8;
}
u16 Value::U16() const {
if (IsIdentity()) {
return inst->Arg(0).U16();
}
ValidateAccess(Type::U16);
return imm_u16;
}
u32 Value::U32() const {
if (IsIdentity()) {
return inst->Arg(0).U32();
}
ValidateAccess(Type::U32);
return imm_u32;
}
u64 Value::U64() const {
if (IsIdentity()) {
return inst->Arg(0).U64();
}
ValidateAccess(Type::U64);
return imm_u64;
}
@ -142,8 +157,6 @@ bool Value::operator==(const Value& other) const {
return imm_u32 == other.imm_u32;
case Type::U64:
return imm_u64 == other.imm_u64;
case Type::ZSCO:
throw NotImplementedException("ZSCO comparison");
}
throw LogicError("Invalid type {}", type);
}

View file

@ -96,6 +96,5 @@ using U64 = TypedValue<Type::U64>;
using U32U64 = TypedValue<Type::U32 | Type::U64>;
using U16U32U64 = TypedValue<Type::U16 | Type::U32 | Type::U64>;
using UAny = TypedValue<Type::U8 | Type::U16 | Type::U32 | Type::U64>;
using ZSCO = TypedValue<Type::ZSCO>;
} // namespace Shader::IR