package codegen import ( "slices" "git.urbach.dev/cli/q/src/ssa" "git.urbach.dev/cli/q/src/token" ) // fixRegisterConflicts checks for conflicts where 2 values that are live at the same time use the same register. // It then assigns a new register to the value that was defined earlier. func (f *Function) fixRegisterConflicts() { for _, step := range f.Steps { switch instr := step.Value.(type) { case *ssa.BinaryOp: if instr.Op == token.Shl || instr.Op == token.Shr { if slices.Contains(f.CPU.ShiftRestricted, step.Register) { f.assignFreeRegister(step) } } if step.Register != -1 { right := f.ValueToStep[instr.Right] if step.Register == right.Register { f.assignFreeRegister(right) } left := f.ValueToStep[instr.Left] if instr.Op == token.Mod && step.Register == left.Register { f.assignFreeRegister(left) } } case *ssa.Register: if f.arch.conflictsWithStackPointer(step.Register) { f.assignFreeRegister(step) } } clobbered := f.clobberedRegisters(step) for i, live := range step.Live { if live.Register == -1 { continue } if live.Value != step.Value { if slices.Contains(clobbered, live.Register) { f.assignFreeRegister(live) continue } field, isField := live.Value.(*ssa.Field) if isField { _, isFieldFromCall := field.Tuple.(*ssa.Call) if isFieldFromCall && live.Index > step.Index && step.Register == f.CPU.Call.Out[field.Index] { f.assignFreeRegister(step) break } } } for _, previous := range step.Live[:i] { if previous.Register == -1 { continue } if previous.Register != live.Register { continue } if previous.Index < live.Index { f.assignFreeRegister(previous) } else { f.assignFreeRegister(live) break } } } } }