This will be useful in several places. The only externally visible difference (other than non-VGRF files being supported now) is that the region sizes are now passed in byte units instead of in GRF units because the loss of precision would have become a problem in the SIMD lowering pass. Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>tags/12.0-branchpoint
| @@ -757,14 +757,6 @@ can_propagate_from(fs_inst *inst) | |||
| !inst->is_partial_write()); | |||
| } | |||
| inline bool | |||
| regions_overlap(const fs_reg &r, unsigned n, const fs_reg &s, unsigned m) | |||
| { | |||
| return r.file == s.file && r.nr == s.nr && | |||
| !(r.reg_offset + n <= s.reg_offset || | |||
| s.reg_offset + m <= r.reg_offset); | |||
| } | |||
| /* Walks a basic block and does copy propagation on it using the acp | |||
| * list. | |||
| */ | |||
| @@ -791,8 +783,8 @@ fs_visitor::opt_copy_propagate_local(void *copy_prop_ctx, bblock_t *block, | |||
| /* kill the destination from the ACP */ | |||
| if (inst->dst.file == VGRF) { | |||
| foreach_in_list_safe(acp_entry, entry, &acp[inst->dst.nr % ACP_HASH_SIZE]) { | |||
| if (regions_overlap(entry->dst, entry->regs_written, | |||
| inst->dst, inst->regs_written)) | |||
| if (regions_overlap(entry->dst, entry->regs_written * REG_SIZE, | |||
| inst->dst, inst->regs_written * REG_SIZE)) | |||
| entry->remove(); | |||
| } | |||
| @@ -804,8 +796,8 @@ fs_visitor::opt_copy_propagate_local(void *copy_prop_ctx, bblock_t *block, | |||
| /* Make sure we kill the entry if this instruction overwrites | |||
| * _any_ of the registers that it reads | |||
| */ | |||
| if (regions_overlap(entry->src, entry->regs_read, | |||
| inst->dst, inst->regs_written)) | |||
| if (regions_overlap(entry->src, entry->regs_read * REG_SIZE, | |||
| inst->dst, inst->regs_written * REG_SIZE)) | |||
| entry->remove(); | |||
| } | |||
| } | |||
| @@ -171,6 +171,44 @@ component(fs_reg reg, unsigned idx) | |||
| return reg; | |||
| } | |||
| /** | |||
| * Return an integer identifying the discrete address space a register is | |||
| * contained in. A register is by definition fully contained in the single | |||
| * reg_space it belongs to, so two registers with different reg_space ids are | |||
| * guaranteed not to overlap. Most register files are a single reg_space of | |||
| * its own, only the VGRF file is composed of multiple discrete address | |||
| * spaces, one for each VGRF allocation. | |||
| */ | |||
| static inline uint32_t | |||
| reg_space(const fs_reg &r) | |||
| { | |||
| return r.file << 16 | (r.file == VGRF ? r.nr : 0); | |||
| } | |||
| /** | |||
| * Return the base offset in bytes of a register relative to the start of its | |||
| * reg_space(). | |||
| */ | |||
| static inline unsigned | |||
| reg_offset(const fs_reg &r) | |||
| { | |||
| return ((r.file == VGRF || r.file == IMM ? 0 : r.nr) + r.reg_offset) * | |||
| (r.file == UNIFORM ? 4 : REG_SIZE) + r.subreg_offset; | |||
| } | |||
| /** | |||
| * Return whether the register region starting at \p r and spanning \p dr | |||
| * bytes could potentially overlap the register region starting at \p s and | |||
| * spanning \p ds bytes. | |||
| */ | |||
| static inline bool | |||
| regions_overlap(const fs_reg &r, unsigned dr, const fs_reg &s, unsigned ds) | |||
| { | |||
| return reg_space(r) == reg_space(s) && | |||
| !(reg_offset(r) + dr <= reg_offset(s) || | |||
| reg_offset(s) + ds <= reg_offset(r)); | |||
| } | |||
| /** | |||
| * Return whether the given register region is n-periodic, i.e. whether the | |||
| * original region remains invariant after shifting it by \p n scalar | |||