diff --git a/.pick_status.json b/.pick_status.json index a936902fe27..fafb3da30a2 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -157,7 +157,7 @@ "description": "r600/sfn: Handle R600 scratch read", "nominated": true, "nomination_type": 1, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": "33765aa92aa5c150873fc210e9d6c1fe22cf8646" }, diff --git a/src/gallium/drivers/r600/sfn/sfn_assembler.cpp b/src/gallium/drivers/r600/sfn/sfn_assembler.cpp index cfb7d720936..00197d0153d 100644 --- a/src/gallium/drivers/r600/sfn/sfn_assembler.cpp +++ b/src/gallium/drivers/r600/sfn/sfn_assembler.cpp @@ -58,7 +58,7 @@ public: void visit(const Block& instr) override; void visit(const IfInstr& instr) override; void visit(const ControlFlowInstr& instr) override; - void visit(const WriteScratchInstr& instr) override; + void visit(const ScratchIOInstr& instr) override; void visit(const StreamOutInstr& instr) override; void visit(const MemRingOutInstr& instr) override; void visit(const EmitVertexInstr& instr) override; @@ -535,7 +535,7 @@ void AssamblerVisitor::visit(const ExportInstr& exi) } } -void AssamblerVisitor::visit(const WriteScratchInstr& instr) +void AssamblerVisitor::visit(const ScratchIOInstr& instr) { clear_states(sf_all); @@ -546,27 +546,27 @@ void AssamblerVisitor::visit(const WriteScratchInstr& instr) cf.op = CF_OP_MEM_SCRATCH; cf.elem_size = 3; cf.gpr = instr.value().sel(); - cf.mark = 1; - cf.comp_mask = instr.write_mask(); + cf.mark = !instr.is_read(); + cf.comp_mask = instr.is_read() ? 0xf : instr.write_mask(); cf.swizzle_x = 0; cf.swizzle_y = 1; cf.swizzle_z = 2; cf.swizzle_w = 3; cf.burst_count = 1; + assert(!instr.is_read() || m_bc->gfx_level < R700); + if (instr.address()) { - cf.type = 3; + cf.type = instr.is_read() || m_bc->gfx_level > R600 ? 3 : 1; cf.index_gpr = instr.address()->sel(); /* The docu seems to be wrong here: In indirect addressing the * address_base seems to be the array_size */ cf.array_size = instr.array_size(); } else { - cf.type = 2; + cf.type = instr.is_read() || m_bc->gfx_level > R600 ? 2 : 0; cf.array_base = instr.location(); } - /* This should be 0, but the address calculation is apparently wrong */ - if (r600_bytecode_add_output(m_bc, &cf)){ R600_ERR("shader_from_nir: Error creating SCRATCH_WR assembly instruction\n"); diff --git a/src/gallium/drivers/r600/sfn/sfn_instr.cpp b/src/gallium/drivers/r600/sfn/sfn_instr.cpp index 28d3d73202d..cbc3b3afaa1 100644 --- a/src/gallium/drivers/r600/sfn/sfn_instr.cpp +++ b/src/gallium/drivers/r600/sfn/sfn_instr.cpp @@ -458,7 +458,7 @@ public: DECLARE_MEMBER(Block); DECLARE_MEMBER(ControlFlowInstr); DECLARE_MEMBER(IfInstr); - DECLARE_MEMBER(WriteScratchInstr); + DECLARE_MEMBER(ScratchIOInstr); DECLARE_MEMBER(StreamOutInstr); DECLARE_MEMBER(MemRingOutInstr); DECLARE_MEMBER(EmitVertexInstr); @@ -504,7 +504,7 @@ public: m_comparer = InstrComparer(&instr); } - void visit(const WriteScratchInstr& instr) override { + void visit(const ScratchIOInstr& instr) override { m_comparer = InstrComparer(&instr); } diff --git a/src/gallium/drivers/r600/sfn/sfn_instr.h b/src/gallium/drivers/r600/sfn/sfn_instr.h index 39bd36d2574..a715305d7cf 100644 --- a/src/gallium/drivers/r600/sfn/sfn_instr.h +++ b/src/gallium/drivers/r600/sfn/sfn_instr.h @@ -45,7 +45,7 @@ class ExportInstr; class FetchInstr; class ControlFlowInstr; class IfInstr; -class WriteScratchInstr; +class ScratchIOInstr; class StreamOutInstr; class MemRingOutInstr; class EmitVertexInstr; @@ -286,7 +286,7 @@ public: virtual void visit(const Block& instr) = 0; virtual void visit(const ControlFlowInstr& instr) = 0; virtual void visit(const IfInstr& instr) = 0; - virtual void visit(const WriteScratchInstr& instr) = 0; + virtual void visit(const ScratchIOInstr& instr) = 0; virtual void visit(const StreamOutInstr& instr) = 0; virtual void visit(const MemRingOutInstr& instr) = 0; virtual void visit(const EmitVertexInstr& instr) = 0; @@ -307,7 +307,7 @@ public: virtual void visit(Block *instr) = 0; virtual void visit(ControlFlowInstr *instr) = 0; virtual void visit(IfInstr *instr) = 0; - virtual void visit(WriteScratchInstr *instr) = 0; + virtual void visit(ScratchIOInstr *instr) = 0; virtual void visit(StreamOutInstr *instr) = 0; virtual void visit(MemRingOutInstr *instr) = 0; virtual void visit(EmitVertexInstr *instr) = 0; diff --git a/src/gallium/drivers/r600/sfn/sfn_instr_alu.h b/src/gallium/drivers/r600/sfn/sfn_instr_alu.h index b1ed854c925..075c0e1647a 100644 --- a/src/gallium/drivers/r600/sfn/sfn_instr_alu.h +++ b/src/gallium/drivers/r600/sfn/sfn_instr_alu.h @@ -204,7 +204,7 @@ public: void visit(ExportInstr *instr) override {(void)instr;} void visit(FetchInstr *instr) override {(void)instr;} void visit(ControlFlowInstr *instr) override {(void)instr;} - void visit(WriteScratchInstr *instr) override {(void)instr;} + void visit(ScratchIOInstr *instr) override {(void)instr;} void visit(StreamOutInstr *instr) override {(void)instr;} void visit(MemRingOutInstr *instr) override {(void)instr;} void visit(EmitVertexInstr *instr) override {(void)instr;} diff --git a/src/gallium/drivers/r600/sfn/sfn_instr_export.cpp b/src/gallium/drivers/r600/sfn/sfn_instr_export.cpp index 3d40ea1796a..081d03f7995 100644 --- a/src/gallium/drivers/r600/sfn/sfn_instr_export.cpp +++ b/src/gallium/drivers/r600/sfn/sfn_instr_export.cpp @@ -147,40 +147,52 @@ ExportInstr::Pointer ExportInstr::from_string_impl(std::istream& is, ValueFactor return new ExportInstr( type, pos, value); } -WriteScratchInstr::WriteScratchInstr(const RegisterVec4& value, PRegister addr, - int align, int align_offset, int writemask, int array_size): +ScratchIOInstr::ScratchIOInstr(const RegisterVec4& value, PRegister addr, + int align, int align_offset, int writemask, + int array_size, bool is_read): WriteOutInstr(value), m_address(addr), m_align(align), m_align_offset(align_offset), m_writemask(writemask), - m_array_size(array_size - 1) + m_array_size(array_size - 1), + m_read(is_read) { addr->add_use(this); + if (m_read) { + for (int i = 0; i < 4; ++i) + value[i]->add_parent(this); + } } -WriteScratchInstr::WriteScratchInstr(const RegisterVec4& value, int loc, - int align, int align_offset,int writemask): +ScratchIOInstr::ScratchIOInstr(const RegisterVec4& value, int loc, + int align, int align_offset,int writemask, + bool is_read): WriteOutInstr(value), m_loc(loc), m_align(align), m_align_offset(align_offset), - m_writemask(writemask) + m_writemask(writemask), + m_read(is_read) { + if (m_read) { + for (int i = 0; i < 4; ++i) + value[i]->add_parent(this); + } } -void WriteScratchInstr::accept(ConstInstrVisitor& visitor) const +void ScratchIOInstr::accept(ConstInstrVisitor& visitor) const { visitor.visit(*this); } -void WriteScratchInstr::accept(InstrVisitor& visitor) +void ScratchIOInstr::accept(InstrVisitor& visitor) { visitor.visit(this); } -bool WriteScratchInstr::is_equal_to(const WriteScratchInstr& lhs) const +bool ScratchIOInstr::is_equal_to(const ScratchIOInstr& lhs) const { if (m_address) { if (!lhs.m_address) @@ -198,28 +210,40 @@ bool WriteScratchInstr::is_equal_to(const WriteScratchInstr& lhs) const value().sel() == lhs.value().sel(); } -bool WriteScratchInstr::do_ready() const +bool ScratchIOInstr::do_ready() const { - return value().ready(block_id(), index()) && - (!m_address || m_address->ready(block_id(), index())); + bool address_ready = !m_address || m_address->ready(block_id(), index()); + if (is_read()) + return address_ready; + else + return address_ready && value().ready(block_id(), index()); } -void WriteScratchInstr::do_print(std::ostream& os) const +void ScratchIOInstr::do_print(std::ostream& os) const { char buf[6]; - os << "WRITE_SCRATCH "; + os << (is_read() ? "READ_SCRATCH " : "WRITE_SCRATCH "); + + if (is_read()) { + os << (value()[0]->is_ssa() ? " S" : " R") + << value().sel() << "." << writemask_to_swizzle(m_writemask, buf) + << " "; + } + if (m_address) os << "@" << *m_address << "[" << m_array_size + 1<<"]"; else os << m_loc; - os << (value()[0]->is_ssa() ? " S" : " R") - << value().sel() << "." << writemask_to_swizzle(m_writemask, buf) - << " " << "AL:" << m_align << " ALO:" << m_align_offset; + if (!is_read()) + os << (value()[0]->is_ssa() ? " S" : " R") + << value().sel() << "." << writemask_to_swizzle(m_writemask, buf); + + os << " " << "AL:" << m_align << " ALO:" << m_align_offset; } -auto WriteScratchInstr::from_string(std::istream& is, ValueFactory &vf) -> Pointer +auto ScratchIOInstr::from_string(std::istream& is, ValueFactory &vf) -> Pointer { string loc_str; string value_str; @@ -261,10 +285,10 @@ auto WriteScratchInstr::from_string(std::istream& is, ValueFactory &vf) -> Point loc_ss >> array_size; loc_ss >> c; assert(c == ']'); - return new WriteScratchInstr(value, addr_reg->as_register(), align, align_offset, writemask, array_size); + return new ScratchIOInstr(value, addr_reg->as_register(), align, align_offset, writemask, array_size); } else { loc_ss >> offset; - return new WriteScratchInstr(value, offset, align, align_offset, writemask); + return new ScratchIOInstr(value, offset, align, align_offset, writemask); } } diff --git a/src/gallium/drivers/r600/sfn/sfn_instr_export.h b/src/gallium/drivers/r600/sfn/sfn_instr_export.h index c88a4e3006b..d19580a7746 100644 --- a/src/gallium/drivers/r600/sfn/sfn_instr_export.h +++ b/src/gallium/drivers/r600/sfn/sfn_instr_export.h @@ -90,23 +90,25 @@ private: bool m_is_last; }; -class WriteScratchInstr : public WriteOutInstr { +class ScratchIOInstr : public WriteOutInstr { public: - WriteScratchInstr(const RegisterVec4& value, PRegister addr, - int align, int align_offset, int writemask, int array_size); - WriteScratchInstr(const RegisterVec4& value, int addr, int align, int align_offset, - int writemask); + ScratchIOInstr(const RegisterVec4& value, PRegister addr, + int align, int align_offset, int writemask, int array_size, + bool is_read = false); + ScratchIOInstr(const RegisterVec4& value, int addr, int align, int align_offset, + int writemask, bool is_read = false); void accept(ConstInstrVisitor& visitor) const override; void accept(InstrVisitor& visitor) override; - bool is_equal_to(const WriteScratchInstr& lhs) const; + bool is_equal_to(const ScratchIOInstr& lhs) const; unsigned location() const { return m_loc;}; int write_mask() const { return m_writemask;} auto address() const { return m_address;} bool indirect() const { return !!m_address;} int array_size() const { return m_array_size;} + bool is_read() const {return m_read; } static auto from_string(std::istream& is, ValueFactory &vf) -> Pointer; private: @@ -120,6 +122,7 @@ private: unsigned m_align_offset; unsigned m_writemask; int m_array_size{0}; + bool m_read{false}; }; class StreamOutInstr: public WriteOutInstr { diff --git a/src/gallium/drivers/r600/sfn/sfn_instrfactory.cpp b/src/gallium/drivers/r600/sfn/sfn_instrfactory.cpp index d66eb7f7e0f..e28446f3c5e 100644 --- a/src/gallium/drivers/r600/sfn/sfn_instrfactory.cpp +++ b/src/gallium/drivers/r600/sfn/sfn_instrfactory.cpp @@ -92,7 +92,7 @@ PInst InstrFactory::from_string(const std::string& s, int nesting_depth) } else if (type == "IF") { result = IfInstr::from_string(is, m_value_factory); } else if (type == "WRITE_SCRATCH") { - result = WriteScratchInstr::from_string(is, m_value_factory); + result = ScratchIOInstr::from_string(is, m_value_factory); } else if (type == "MEM_RING") { result = MemRingOutInstr::from_string(is, m_value_factory); } else if (type == "EMIT_VERTEX") { diff --git a/src/gallium/drivers/r600/sfn/sfn_liverangeevaluator.cpp b/src/gallium/drivers/r600/sfn/sfn_liverangeevaluator.cpp index b62aad1f1b6..cd8b113bd53 100644 --- a/src/gallium/drivers/r600/sfn/sfn_liverangeevaluator.cpp +++ b/src/gallium/drivers/r600/sfn/sfn_liverangeevaluator.cpp @@ -53,7 +53,7 @@ public: void visit(Block *instr) override; void visit(ControlFlowInstr *instr) override; void visit(IfInstr *instr) override; - void visit(WriteScratchInstr *instr) override; + void visit(ScratchIOInstr *instr) override; void visit(StreamOutInstr *instr) override; void visit(MemRingOutInstr *instr) override; void visit(EmitVertexInstr *instr) override {(void)instr;} @@ -287,12 +287,15 @@ void LiveRangeInstrVisitor::visit(Block *instr) sfn_log << SfnLog::merge << "End block\n"; } -void LiveRangeInstrVisitor::visit(WriteScratchInstr *instr) +void LiveRangeInstrVisitor::visit(ScratchIOInstr *instr) { auto& src = instr->value(); for (int i = 0; i < 4; ++i) { if ((1 << i) & instr->write_mask()) { - record_read(src[i], LiveRangeEntry::use_unspecified); + if (instr->is_read()) + record_write(src[i]); + else + record_read(src[i], LiveRangeEntry::use_unspecified); } } diff --git a/src/gallium/drivers/r600/sfn/sfn_optimizer.cpp b/src/gallium/drivers/r600/sfn/sfn_optimizer.cpp index 18fb4e4f2d8..4325edfe3c3 100644 --- a/src/gallium/drivers/r600/sfn/sfn_optimizer.cpp +++ b/src/gallium/drivers/r600/sfn/sfn_optimizer.cpp @@ -77,7 +77,7 @@ public: void visit(ControlFlowInstr *instr) override {(void)instr;}; void visit(IfInstr *instr) override {(void)instr;}; - void visit(WriteScratchInstr *instr) override {(void)instr;}; + void visit(ScratchIOInstr *instr) override {(void)instr;}; void visit(StreamOutInstr *instr) override {(void)instr;}; void visit(MemRingOutInstr *instr) override {(void)instr;}; void visit(EmitVertexInstr *instr) override {(void)instr;}; @@ -249,7 +249,7 @@ public: void visit(Block *instr) override; void visit(ControlFlowInstr *instr) override {(void)instr;} void visit(IfInstr *instr) override {(void)instr;} - void visit(WriteScratchInstr *instr) override {(void)instr;} + void visit(ScratchIOInstr *instr) override {(void)instr;} void visit(StreamOutInstr *instr) override {(void)instr;} void visit(MemRingOutInstr *instr) override {(void)instr;} void visit(EmitVertexInstr *instr) override {(void)instr;} @@ -277,7 +277,7 @@ public: void visit(Block *instr) override; void visit(ControlFlowInstr *instr) override {(void)instr;} void visit(IfInstr *instr) override {(void)instr;} - void visit(WriteScratchInstr *instr) override {(void)instr;} + void visit(ScratchIOInstr *instr) override {(void)instr;} void visit(StreamOutInstr *instr) override {(void)instr;} void visit(MemRingOutInstr *instr) override {(void)instr;} void visit(EmitVertexInstr *instr) override {(void)instr;} @@ -493,7 +493,7 @@ public: void visit(Block *instr) override; void visit(ControlFlowInstr *instr) override; void visit(IfInstr *instr) override; - void visit(WriteScratchInstr *instr) override; + void visit(ScratchIOInstr *instr) override; void visit(StreamOutInstr *instr) override; void visit(MemRingOutInstr *instr) override; void visit(EmitVertexInstr *instr) override {(void)instr;} @@ -525,7 +525,7 @@ void SimplifySourceVecVisitor::visit(TexInstr *instr) } } -void SimplifySourceVecVisitor::visit(WriteScratchInstr *instr) +void SimplifySourceVecVisitor::visit(ScratchIOInstr *instr) { (void) instr; } diff --git a/src/gallium/drivers/r600/sfn/sfn_peephole.cpp b/src/gallium/drivers/r600/sfn/sfn_peephole.cpp index a2e5fe3bfb5..065031287dc 100644 --- a/src/gallium/drivers/r600/sfn/sfn_peephole.cpp +++ b/src/gallium/drivers/r600/sfn/sfn_peephole.cpp @@ -39,7 +39,7 @@ public: void visit(Block *instr) override; void visit(ControlFlowInstr *instr) override {(void)instr;} void visit(IfInstr *instr) override; - void visit(WriteScratchInstr *instr) override {(void)instr;} + void visit(ScratchIOInstr *instr) override {(void)instr;} void visit(StreamOutInstr *instr) override {(void)instr;} void visit(MemRingOutInstr *instr) override {(void)instr;} void visit(EmitVertexInstr *instr) override {(void)instr;} diff --git a/src/gallium/drivers/r600/sfn/sfn_scheduler.cpp b/src/gallium/drivers/r600/sfn/sfn_scheduler.cpp index a80cc924cb2..6c95c778695 100644 --- a/src/gallium/drivers/r600/sfn/sfn_scheduler.cpp +++ b/src/gallium/drivers/r600/sfn/sfn_scheduler.cpp @@ -87,7 +87,7 @@ public: m_cf_instr = instr; } - void visit(WriteScratchInstr *instr) override { + void visit(ScratchIOInstr *instr) override { mem_write_instr.push_back(instr); } diff --git a/src/gallium/drivers/r600/sfn/sfn_shader.cpp b/src/gallium/drivers/r600/sfn/sfn_shader.cpp index f477d365e40..ce2ca43012f 100644 --- a/src/gallium/drivers/r600/sfn/sfn_shader.cpp +++ b/src/gallium/drivers/r600/sfn/sfn_shader.cpp @@ -932,7 +932,7 @@ bool Shader::emit_store_scratch(nir_intrinsic_instr *intr) int align = nir_intrinsic_align_mul(intr); int align_offset = nir_intrinsic_align_offset(intr); - WriteScratchInstr *ws_ir = nullptr; + ScratchIOInstr *ws_ir = nullptr; int offset = -1; if (address->as_literal()) { @@ -946,14 +946,14 @@ bool Shader::emit_store_scratch(nir_intrinsic_instr *intr) } if (offset >= 0) { - ws_ir = new WriteScratchInstr(value, offset, align, align_offset, writemask); + ws_ir = new ScratchIOInstr(value, offset, align, align_offset, writemask); } else { auto addr_temp = vf.temp_register(0); auto load_addr = new AluInstr(op1_mov, addr_temp, address, AluInstr::last_write); load_addr->set_alu_flag(alu_no_schedule_bias); emit_instruction(load_addr); - ws_ir = new WriteScratchInstr(value, addr_temp, align, align_offset, writemask, m_scratch_size); + ws_ir = new ScratchIOInstr(value, addr_temp, align, align_offset, writemask, m_scratch_size); } emit_instruction(ws_ir); @@ -964,18 +964,48 @@ bool Shader::emit_store_scratch(nir_intrinsic_instr *intr) bool Shader::emit_load_scratch(nir_intrinsic_instr *intr) { auto addr = value_factory().src(intr->src[0], 0); - - RegisterVec4::Swizzle dest_swz = {7,7,7,7}; - - for (unsigned i = 0; i < intr->num_components; ++i) - dest_swz[i] = i; - auto dest = value_factory().dest_vec4(intr->dest, pin_group); - auto ir = new LoadFromScratch(dest, dest_swz, addr, m_scratch_size); - emit_instruction(ir); + if (chip_class() >= ISA_CC_R700) { + RegisterVec4::Swizzle dest_swz = {7,7,7,7}; + + for (unsigned i = 0; i < intr->num_components; ++i) + dest_swz[i] = i; + + auto *ir = new LoadFromScratch(dest, dest_swz, addr, m_scratch_size); + emit_instruction(ir); + chain_scratch_read(ir); + } else { + int align = nir_intrinsic_align_mul(intr); + int align_offset = nir_intrinsic_align_offset(intr); + + + int offset = -1; + if (addr->as_literal()) { + offset = addr->as_literal()->value(); + } else if (addr->as_inline_const()) { + auto il = addr->as_inline_const(); + if (il->sel() == ALU_SRC_0) + offset = 0; + else if (il->sel() == ALU_SRC_1_INT) + offset = 1; + } + + ScratchIOInstr *ir = nullptr; + if (offset >= 0) { + ir = new ScratchIOInstr(dest, offset, align, align_offset, 0xf, true); + } else { + auto addr_temp = value_factory().temp_register(0); + auto load_addr = new AluInstr(op1_mov, addr_temp, addr, AluInstr::last_write); + load_addr->set_alu_flag(alu_no_schedule_bias); + emit_instruction(load_addr); + + ir = new ScratchIOInstr(dest, addr_temp, align, align_offset, 0xf, + m_scratch_size, true); + } + emit_instruction(ir); + } - chain_scratch_read(ir); m_flags.set(sh_needs_scratch_space); @@ -1033,7 +1063,7 @@ bool Shader::emit_wait_ack() return true; } -void Shader::InstructionChain::visit(WriteScratchInstr *instr) +void Shader::InstructionChain::visit(ScratchIOInstr *instr) { apply(instr, &last_scratch_instr); } diff --git a/src/gallium/drivers/r600/sfn/sfn_shader.h b/src/gallium/drivers/r600/sfn/sfn_shader.h index 6e2e5d80132..1eaa87861b8 100644 --- a/src/gallium/drivers/r600/sfn/sfn_shader.h +++ b/src/gallium/drivers/r600/sfn/sfn_shader.h @@ -368,7 +368,7 @@ private: void visit(LDSAtomicInstr *instr) override {(void) instr;} void visit(LDSReadInstr *instr) override {(void) instr;} - void visit(WriteScratchInstr *instr) override; + void visit(ScratchIOInstr *instr) override; void visit(GDSInstr *instr) override; void visit(RatInstr *instr) override; diff --git a/src/gallium/drivers/r600/sfn/tests/sfn_instrfromstring_test.cpp b/src/gallium/drivers/r600/sfn/tests/sfn_instrfromstring_test.cpp index df6a9ace97e..4bb713edc8f 100644 --- a/src/gallium/drivers/r600/sfn/tests/sfn_instrfromstring_test.cpp +++ b/src/gallium/drivers/r600/sfn/tests/sfn_instrfromstring_test.cpp @@ -518,12 +518,12 @@ TEST_F(TestInstrFromString, test_write_scratch_to_offset) { add_dest_vec4_from_string("R1.xyzw"); string init = "WRITE_SCRATCH 20 R1.xyzw AL:4 ALO:16"; - WriteScratchInstr expect(RegisterVec4(1), 20, 4, 16, 0xf); + ScratchIOInstr expect(RegisterVec4(1), 20, 4, 16, 0xf); check(init, expect); add_dest_vec4_from_string("R2.xyzw"); string init2 = "WRITE_SCRATCH 10 R2.xy_w AL:8 ALO:8"; - WriteScratchInstr expect2(RegisterVec4(2), 10, 8, 8, 0xb); + ScratchIOInstr expect2(RegisterVec4(2), 10, 8, 8, 0xb); check(init2, expect2); } @@ -532,13 +532,13 @@ TEST_F(TestInstrFromString, test_write_scratch_to_index) add_dest_vec4_from_string("R1.xyzw"); add_dest_from_string("R3.x"); string init = "WRITE_SCRATCH @R3.x[10] R1.xyzw AL:4 ALO:16"; - WriteScratchInstr expect(RegisterVec4(1), new Register(3, 0, pin_none), 4, 16, 0xf, 10); + ScratchIOInstr expect(RegisterVec4(1), new Register(3, 0, pin_none), 4, 16, 0xf, 10); check(init, expect); add_dest_vec4_from_string("R2.xyzw"); add_dest_from_string("R4.x"); string init2 = "WRITE_SCRATCH @R4.x[20] R2.xy__ AL:4 ALO:16"; - WriteScratchInstr expect2(RegisterVec4(2), new Register(4, 0, pin_none), 4, 16, 0x3, 20); + ScratchIOInstr expect2(RegisterVec4(2), new Register(4, 0, pin_none), 4, 16, 0x3, 20); check(init2, expect2);