shader: Constant propagation and global memory to storage buffer
This commit is contained in:
parent
d24a16045f
commit
e81739493a
17 changed files with 652 additions and 63 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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{};
|
||||
};
|
||||
|
|
|
@ -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, )
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -25,7 +25,6 @@ enum class Type {
|
|||
U16 = 1 << 7,
|
||||
U32 = 1 << 8,
|
||||
U64 = 1 << 9,
|
||||
ZSCO = 1 << 10,
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(Type)
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue