shader: Implement BAR and fix memory barriers
This commit is contained in:
		| @@ -28,6 +28,7 @@ void EmitSelectionMerge(EmitContext& ctx, Id merge_label); | ||||
| void EmitReturn(EmitContext& ctx); | ||||
| void EmitUnreachable(EmitContext& ctx); | ||||
| void EmitDemoteToHelperInvocation(EmitContext& ctx, Id continue_label); | ||||
| void EmitBarrier(EmitContext& ctx); | ||||
| void EmitMemoryBarrierWorkgroupLevel(EmitContext& ctx); | ||||
| void EmitMemoryBarrierDeviceLevel(EmitContext& ctx); | ||||
| void EmitMemoryBarrierSystemLevel(EmitContext& ctx); | ||||
|   | ||||
| @@ -8,16 +8,25 @@ | ||||
| namespace Shader::Backend::SPIRV { | ||||
| namespace { | ||||
| void EmitMemoryBarrierImpl(EmitContext& ctx, spv::Scope scope) { | ||||
|     const auto semantics = | ||||
|     const auto semantics{ | ||||
|         spv::MemorySemanticsMask::AcquireRelease | spv::MemorySemanticsMask::UniformMemory | | ||||
|         spv::MemorySemanticsMask::WorkgroupMemory | spv::MemorySemanticsMask::AtomicCounterMemory | | ||||
|         spv::MemorySemanticsMask::ImageMemory; | ||||
|         spv::MemorySemanticsMask::ImageMemory}; | ||||
|     ctx.OpMemoryBarrier(ctx.Constant(ctx.U32[1], static_cast<u32>(scope)), | ||||
|                         ctx.Constant(ctx.U32[1], static_cast<u32>(semantics))); | ||||
| } | ||||
|  | ||||
| } // Anonymous namespace | ||||
|  | ||||
| void EmitBarrier(EmitContext& ctx) { | ||||
|     const auto execution{spv::Scope::Workgroup}; | ||||
|     const auto memory{spv::Scope::Workgroup}; | ||||
|     const auto memory_semantics{spv::MemorySemanticsMask::AcquireRelease | | ||||
|                                 spv::MemorySemanticsMask::WorkgroupMemory}; | ||||
|     ctx.OpControlBarrier(ctx.Constant(ctx.U32[1], static_cast<u32>(execution)), | ||||
|                          ctx.Constant(ctx.U32[1], static_cast<u32>(memory)), | ||||
|                          ctx.Constant(ctx.U32[1], static_cast<u32>(memory_semantics))); | ||||
| } | ||||
|  | ||||
| void EmitMemoryBarrierWorkgroupLevel(EmitContext& ctx) { | ||||
|     EmitMemoryBarrierImpl(ctx, spv::Scope::Workgroup); | ||||
| } | ||||
|   | ||||
| @@ -82,6 +82,10 @@ void IREmitter::SelectionMerge(Block* merge_block) { | ||||
|     Inst(Opcode::SelectionMerge, merge_block); | ||||
| } | ||||
|  | ||||
| void IREmitter::Barrier() { | ||||
|     Inst(Opcode::Barrier); | ||||
| } | ||||
|  | ||||
| void IREmitter::MemoryBarrier(MemoryScope scope) { | ||||
|     switch (scope) { | ||||
|     case MemoryScope::Workgroup: | ||||
|   | ||||
| @@ -128,6 +128,7 @@ public: | ||||
|     [[nodiscard]] Value Select(const U1& condition, const Value& true_value, | ||||
|                                const Value& false_value); | ||||
|  | ||||
|     [[nodiscard]] void Barrier(); | ||||
|     [[nodiscard]] void MemoryBarrier(MemoryScope scope); | ||||
|  | ||||
|     template <typename Dest, typename Source> | ||||
|   | ||||
| @@ -57,6 +57,10 @@ bool Inst::MayHaveSideEffects() const noexcept { | ||||
|     case Opcode::Return: | ||||
|     case Opcode::Unreachable: | ||||
|     case Opcode::DemoteToHelperInvocation: | ||||
|     case Opcode::Barrier: | ||||
|     case Opcode::MemoryBarrierWorkgroupLevel: | ||||
|     case Opcode::MemoryBarrierDeviceLevel: | ||||
|     case Opcode::MemoryBarrierSystemLevel: | ||||
|     case Opcode::Prologue: | ||||
|     case Opcode::Epilogue: | ||||
|     case Opcode::SetAttribute: | ||||
|   | ||||
| @@ -17,6 +17,7 @@ OPCODE(Unreachable,                                         Void, | ||||
| OPCODE(DemoteToHelperInvocation,                            Void,           Label,                                                                          ) | ||||
|  | ||||
| // Barriers | ||||
| OPCODE(Barrier,                                             Void,                                                                                           ) | ||||
| OPCODE(MemoryBarrierWorkgroupLevel,                         Void,                                                                                           ) | ||||
| OPCODE(MemoryBarrierDeviceLevel,                            Void,                                                                                           ) | ||||
| OPCODE(MemoryBarrierSystemLevel,                            Void,                                                                                           ) | ||||
|   | ||||
| @@ -38,6 +38,7 @@ void TranslatorVisitor::MEMBAR(u64 inst) { | ||||
|         u64 raw; | ||||
|         BitField<8, 2, LocalScope> scope; | ||||
|     } membar{inst}; | ||||
|  | ||||
|     ir.MemoryBarrier(LocalScopeToMemoryScope(membar.scope)); | ||||
| } | ||||
|  | ||||
| @@ -45,8 +46,61 @@ void TranslatorVisitor::DEPBAR() { | ||||
|     // DEPBAR is a no-op | ||||
| } | ||||
|  | ||||
| void TranslatorVisitor::BAR(u64) { | ||||
|     throw NotImplementedException("Instruction {} is not implemented", Opcode::BAR); | ||||
| void TranslatorVisitor::BAR(u64 insn) { | ||||
|     enum class Mode { | ||||
|         RedPopc, | ||||
|         Scan, | ||||
|         RedAnd, | ||||
|         RedOr, | ||||
|         Sync, | ||||
|         Arrive, | ||||
|     }; | ||||
|     union { | ||||
|         u64 raw; | ||||
|         BitField<43, 1, u64> is_a_imm; | ||||
|         BitField<44, 1, u64> is_b_imm; | ||||
|         BitField<8, 8, u64> imm_a; | ||||
|         BitField<20, 12, u64> imm_b; | ||||
|         BitField<42, 1, u64> neg_pred; | ||||
|         BitField<39, 3, IR::Pred> pred; | ||||
|     } const bar{insn}; | ||||
|  | ||||
|     const Mode mode{[insn] { | ||||
|         switch (insn & 0x0000009B00000000ULL) { | ||||
|         case 0x0000000200000000ULL: | ||||
|             return Mode::RedPopc; | ||||
|         case 0x0000000300000000ULL: | ||||
|             return Mode::Scan; | ||||
|         case 0x0000000A00000000ULL: | ||||
|             return Mode::RedAnd; | ||||
|         case 0x0000001200000000ULL: | ||||
|             return Mode::RedOr; | ||||
|         case 0x0000008000000000ULL: | ||||
|             return Mode::Sync; | ||||
|         case 0x0000008100000000ULL: | ||||
|             return Mode::Arrive; | ||||
|         } | ||||
|         throw NotImplementedException("Invalid encoding"); | ||||
|     }()}; | ||||
|     if (mode != Mode::Sync) { | ||||
|         throw NotImplementedException("BAR mode {}", mode); | ||||
|     } | ||||
|     if (bar.is_a_imm == 0) { | ||||
|         throw NotImplementedException("Non-immediate input A"); | ||||
|     } | ||||
|     if (bar.imm_a != 0) { | ||||
|         throw NotImplementedException("Non-zero input A"); | ||||
|     } | ||||
|     if (bar.is_b_imm == 0) { | ||||
|         throw NotImplementedException("Non-immediate input B"); | ||||
|     } | ||||
|     if (bar.imm_b != 0) { | ||||
|         throw NotImplementedException("Non-zero input B"); | ||||
|     } | ||||
|     if (bar.pred != IR::Pred::PT && bar.neg_pred != 0) { | ||||
|         throw NotImplementedException("Non-true input predicate"); | ||||
|     } | ||||
|     ir.Barrier(); | ||||
| } | ||||
|  | ||||
| } // namespace Shader::Maxwell | ||||
|   | ||||
		Reference in New Issue
	
	Block a user