github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/isa/arm64/machine_regalloc.go (about)

     1  package arm64
     2  
     3  // This file implements the interfaces required for register allocations. See backend.RegAllocFunctionMachine.
     4  
     5  import (
     6  	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend"
     7  	"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
     8  	"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
     9  )
    10  
    11  // ClobberedRegisters implements backend.RegAllocFunctionMachine.
    12  func (m *machine) ClobberedRegisters(regs []regalloc.VReg) {
    13  	m.clobberedRegs = append(m.clobberedRegs[:0], regs...)
    14  }
    15  
    16  // Swap implements backend.RegAllocFunctionMachine.
    17  func (m *machine) Swap(cur *instruction, x1, x2, tmp regalloc.VReg) {
    18  	prevNext := cur.next
    19  	var mov1, mov2, mov3 *instruction
    20  	if x1.RegType() == regalloc.RegTypeInt {
    21  		if !tmp.Valid() {
    22  			tmp = tmpRegVReg
    23  		}
    24  		mov1 = m.allocateInstr().asMove64(tmp, x1)
    25  		mov2 = m.allocateInstr().asMove64(x1, x2)
    26  		mov3 = m.allocateInstr().asMove64(x2, tmp)
    27  		cur = linkInstr(cur, mov1)
    28  		cur = linkInstr(cur, mov2)
    29  		cur = linkInstr(cur, mov3)
    30  		linkInstr(cur, prevNext)
    31  	} else {
    32  		if !tmp.Valid() {
    33  			r2 := x2.RealReg()
    34  			// Temporarily spill x1 to stack.
    35  			cur = m.InsertStoreRegisterAt(x1, cur, true).prev
    36  			// Then move x2 to x1.
    37  			cur = linkInstr(cur, m.allocateInstr().asFpuMov128(x1, x2))
    38  			linkInstr(cur, prevNext)
    39  			// Then reload the original value on x1 from stack to r2.
    40  			m.InsertReloadRegisterAt(x1.SetRealReg(r2), cur, true)
    41  		} else {
    42  			mov1 = m.allocateInstr().asFpuMov128(tmp, x1)
    43  			mov2 = m.allocateInstr().asFpuMov128(x1, x2)
    44  			mov3 = m.allocateInstr().asFpuMov128(x2, tmp)
    45  			cur = linkInstr(cur, mov1)
    46  			cur = linkInstr(cur, mov2)
    47  			cur = linkInstr(cur, mov3)
    48  			linkInstr(cur, prevNext)
    49  		}
    50  	}
    51  }
    52  
    53  // InsertMoveBefore implements backend.RegAllocFunctionMachine.
    54  func (m *machine) InsertMoveBefore(dst, src regalloc.VReg, instr *instruction) {
    55  	typ := src.RegType()
    56  	if typ != dst.RegType() {
    57  		panic("BUG: src and dst must have the same type")
    58  	}
    59  
    60  	mov := m.allocateInstr()
    61  	if typ == regalloc.RegTypeInt {
    62  		mov.asMove64(dst, src)
    63  	} else {
    64  		mov.asFpuMov128(dst, src)
    65  	}
    66  
    67  	cur := instr.prev
    68  	prevNext := cur.next
    69  	cur = linkInstr(cur, mov)
    70  	linkInstr(cur, prevNext)
    71  }
    72  
    73  // SSABlockLabel implements backend.RegAllocFunctionMachine.
    74  func (m *machine) SSABlockLabel(id ssa.BasicBlockID) backend.Label {
    75  	return m.executableContext.SsaBlockIDToLabels[id]
    76  }
    77  
    78  // InsertStoreRegisterAt implements backend.RegAllocFunctionMachine.
    79  func (m *machine) InsertStoreRegisterAt(v regalloc.VReg, instr *instruction, after bool) *instruction {
    80  	if !v.IsRealReg() {
    81  		panic("BUG: VReg must be backed by real reg to be stored")
    82  	}
    83  
    84  	typ := m.compiler.TypeOf(v)
    85  
    86  	var prevNext, cur *instruction
    87  	if after {
    88  		cur, prevNext = instr, instr.next
    89  	} else {
    90  		cur, prevNext = instr.prev, instr
    91  	}
    92  
    93  	offsetFromSP := m.getVRegSpillSlotOffsetFromSP(v.ID(), typ.Size())
    94  	var amode addressMode
    95  	cur, amode = m.resolveAddressModeForOffsetAndInsert(cur, offsetFromSP, typ.Bits(), spVReg, true)
    96  	store := m.allocateInstr()
    97  	store.asStore(operandNR(v), amode, typ.Bits())
    98  
    99  	cur = linkInstr(cur, store)
   100  	return linkInstr(cur, prevNext)
   101  }
   102  
   103  // InsertReloadRegisterAt implements backend.RegAllocFunctionMachine.
   104  func (m *machine) InsertReloadRegisterAt(v regalloc.VReg, instr *instruction, after bool) *instruction {
   105  	if !v.IsRealReg() {
   106  		panic("BUG: VReg must be backed by real reg to be stored")
   107  	}
   108  
   109  	typ := m.compiler.TypeOf(v)
   110  
   111  	var prevNext, cur *instruction
   112  	if after {
   113  		cur, prevNext = instr, instr.next
   114  	} else {
   115  		cur, prevNext = instr.prev, instr
   116  	}
   117  
   118  	offsetFromSP := m.getVRegSpillSlotOffsetFromSP(v.ID(), typ.Size())
   119  	var amode addressMode
   120  	cur, amode = m.resolveAddressModeForOffsetAndInsert(cur, offsetFromSP, typ.Bits(), spVReg, true)
   121  	load := m.allocateInstr()
   122  	switch typ {
   123  	case ssa.TypeI32, ssa.TypeI64:
   124  		load.asULoad(operandNR(v), amode, typ.Bits())
   125  	case ssa.TypeF32, ssa.TypeF64:
   126  		load.asFpuLoad(operandNR(v), amode, typ.Bits())
   127  	case ssa.TypeV128:
   128  		load.asFpuLoad(operandNR(v), amode, 128)
   129  	default:
   130  		panic("TODO")
   131  	}
   132  
   133  	cur = linkInstr(cur, load)
   134  	return linkInstr(cur, prevNext)
   135  }
   136  
   137  // LastInstrForInsertion implements backend.RegAllocFunctionMachine.
   138  func (m *machine) LastInstrForInsertion(begin, end *instruction) *instruction {
   139  	cur := end
   140  	for cur.kind == nop0 {
   141  		cur = cur.prev
   142  		if cur == begin {
   143  			return end
   144  		}
   145  	}
   146  	switch cur.kind {
   147  	case br:
   148  		return cur
   149  	default:
   150  		return end
   151  	}
   152  }