+ @cached_property
+ def copies(self):
+ # type: () -> FMap[SSAValSubReg, SSAValSubReg]
+ """ map from SSAValSubRegs to the original SSAValSubRegs that they are
+ a copy of, looking through all layers of copies. The map excludes all
+ SSAValSubRegs that aren't copies of other SSAValSubRegs.
+ """
+ retval = {} # type: dict[SSAValSubReg, SSAValSubReg]
+ for op in self.op_indexes.keys():
+ if not op.properties.is_copy:
+ continue
+ copy_reg_len = op.properties.copy_reg_len
+ copy_inputs = [] # type: list[SSAValSubReg]
+ for inp in op.input_vals[:op.properties.copy_inputs_len]:
+ for inp_sub_reg in inp.ssa_val_sub_regs:
+ # propagate copies of copies
+ inp_sub_reg = retval.get(inp_sub_reg, inp_sub_reg)
+ copy_inputs.append(inp_sub_reg)
+ assert len(copy_inputs) == copy_reg_len, "logic error"
+ copy_outputs = [] # type: list[SSAValSubReg]
+ for out in op.outputs[:op.properties.copy_outputs_len]:
+ copy_outputs.extend(out.ssa_val_sub_regs)
+ assert len(copy_outputs) == copy_reg_len, "logic error"
+ for inp, out in zip(copy_inputs, copy_outputs):
+ retval[out] = inp
+ return FMap(retval)
+
+ @cached_property
+ def const_ssa_vals(self):
+ # type: () -> FMap[SSAVal, tuple[int, ...]]
+ state = ConstPropagationState(
+ ssa_vals={}, memory={}, skipped_ops=OSet())
+ self.fn.sim(state)
+ return FMap(state.ssa_vals)
+
+ @cached_property
+ def const_ssa_val_sub_regs(self):
+ # type: () -> FMap[SSAValSubReg, int]
+ retval = {} # type: dict[SSAValSubReg, int]
+ for ssa_val, const_val in self.const_ssa_vals.items():
+ assert ssa_val.ty.reg_len == len(const_val), "logic error"
+ for reg_idx, v in enumerate(const_val):
+ retval[SSAValSubReg(ssa_val, reg_idx)] = v
+ return FMap(retval)
+
+ def are_always_equal(self, a, b):
+ # type: (SSAValSubReg, SSAValSubReg) -> bool
+ """check if a and b are known to be always equal to each other.
+ This means they can be allocated to the same location if other
+ constraints don't prevent that.
+
+ this can happen for a number of reasons, such as:
+ * a and b are copies of the same thing
+ * a and b are known to be constants and they have the same value
+ """
+ if a.ssa_val.base_ty != b.ssa_val.base_ty:
+ return False # can't be equal, they have different types
+ # look through copies
+ a = self.copies.get(a, a)
+ b = self.copies.get(b, b)
+ if a == b:
+ return True
+ # check if they have the same constant value
+ try:
+ a_const_val = self.const_ssa_val_sub_regs[a]
+ b_const_val = self.const_ssa_val_sub_regs[b]
+ if a_const_val == b_const_val:
+ return True
+ except KeyError:
+ pass
+ return False
+