private void Alloc(RegisterClass @class) { if (Done.Get(@class) == Count.Get(@class)) { return; } var list = VaList[(int)@class]; var count = Count.Get(@class); var state = VariableContext.State; // var sVars = state.GetListByClass(@class); bool didWork; do { didWork = false; int i; for (i = 0; i < count; i++) { var aVa = list[i]; var aVd = aVa.VariableData; if ((aVa.Flags & (VariableFlags.RReg | VariableFlags.AllocRDone)) != VariableFlags.RReg) { continue; } var aIndex = aVd.RegisterIndex; var bIndex = aVa.InRegIndex; // Shouldn't be the same. if (aIndex == bIndex) { throw new ArgumentException(); } var bVd = state.GetListByClass(@class)[bIndex]; if (bVd != null) { var bVa = bVd.Attributes; // Gp registers only - Swap two registers if we can solve two // allocation tasks by a single 'xchg' instruction, swapping // two registers required by the instruction/node or one register // required with another non-required. if (@class != RegisterClass.Gp) { continue; } Translator.SwapGp(aVd, bVd); aVa.Flags |= VariableFlags.AllocRDone; Done.Add(@class); // Doublehit, two registers allocated by a single swap. if (bVa != null && bVa.InRegIndex == aIndex) { bVa.Flags |= VariableFlags.AllocRDone; Done.Add(@class); } didWork = true; } else if (aIndex != RegisterIndex.Invalid) { Translator.Move(aVd, @class, bIndex); VariableContext.ClobberedRegs.Or(@class, Utils.Mask(bIndex)); aVa.Flags |= VariableFlags.AllocRDone; Done.Add(@class); didWork = true; } else { Translator.Alloc(aVd, @class, bIndex); VariableContext.ClobberedRegs.Or(@class, Utils.Mask(bIndex)); aVa.Flags |= VariableFlags.AllocRDone; Done.Add(@class); didWork = true; } } }while (didWork); }
private void Plan(RegisterClass @class) { if (Done.Get(@class) == Count.Get(@class)) { return; } int i; int willAlloc = _willAlloc.Get(@class); int willFree = 0; var list = VaList[(int)@class]; var count = Count.Get(@class); var state = VariableContext.State; // Calculate 'willAlloc' and 'willFree' masks based on mandatory masks. for (i = 0; i < count; i++) { var va = list[i]; var vd = va.VariableData; var vaFlags = va.Flags; var regIndex = vd.RegisterIndex; var regMask = (regIndex != RegisterIndex.Invalid) ? Utils.Mask(regIndex) : 0; if ((vaFlags & VariableFlags.XReg) != 0) { // Planning register allocation. First check whether the variable is // already allocated in register and if it can stay allocated there. // // The following conditions may happen: // // a) Allocated register is one of the mandatoryRegs. // b) Allocated register is one of the allocableRegs. var mandatoryRegs = va.InRegs; var allocableRegs = va.AllocableRegs; if (regMask != 0) { // Special path for planning output-only registers. if ((vaFlags & VariableFlags.XReg) == VariableFlags.WReg) { var outRegIndex = va.OutRegIndex; mandatoryRegs = (outRegIndex != RegisterIndex.Invalid) ? Utils.Mask(outRegIndex) : 0; if ((mandatoryRegs | allocableRegs).IsSet(regMask)) { va.OutRegIndex = regIndex; va.Flags |= VariableFlags.AllocWDone; if (mandatoryRegs.IsSet(regMask)) { // Case 'a' - 'willAlloc' contains initially all inRegs from all VarAttr's. if (!((willAlloc & regMask) != 0)) { throw new ArgumentException(); } } else { // Case 'b'. va.OutRegIndex = regIndex; willAlloc |= regMask; } Done.Add(@class); continue; } } else { if ((mandatoryRegs | allocableRegs).IsSet(regMask)) { va.InRegIndex = regIndex; va.Flags |= VariableFlags.AllocRDone; if (mandatoryRegs.IsSet(regMask)) { // Case 'a' - 'willAlloc' contains initially all inRegs from all VarAttr's. if (!((willAlloc & regMask) != 0)) { throw new ArgumentException(); } } else { // Case 'b'. va.InRegs |= regMask; willAlloc |= regMask; } Done.Add(@class); continue; } } } // Variable is not allocated or allocated in register that doesn't // match inRegs or allocableRegs. The next step is to pick the best // register for this variable. If `inRegs` contains any register the // decision is simple - we have to follow, in other case will use // the advantage of `guessAlloc()` to find a register (or registers) // by looking ahead. But the best way to find a good register is not // here since now we have no information about the registers that // will be freed. So instead of finding register here, we just mark // the current register (if variable is allocated) as `willFree` so // the planner can use this information in the second step to plan the // allocation as a whole. willFree |= regMask; } else { // Memory access - if variable is allocated it has to be freed. if (regMask != 0) { willFree |= regMask; } else { va.Flags |= VariableFlags.AllocRDone; Done.Add(@class); } } } // Occupied registers without 'willFree' registers; contains basically // all the registers we can use to allocate variables without inRegs // speficied. var occupied = state.Occupied.Get(@class) & ~willFree; var willSpill = 0; // Find the best registers for variables that are not allocated yet. for (i = 0; i < count; i++) { var va = list[i]; var vd = va.VariableData; var vaFlags = va.Flags; if ((vaFlags & VariableFlags.XReg) != 0) { if ((vaFlags & VariableFlags.XReg) == VariableFlags.WReg) { if (vaFlags.IsSet(VariableFlags.AllocWDone)) { continue; } // Skip all registers that have assigned outRegIndex. Spill if occupied. if (va.OutRegIndex != RegisterIndex.Invalid) { var outRegs = Utils.Mask(va.OutRegIndex); willSpill |= occupied & outRegs; continue; } } else { if (vaFlags.IsSet(VariableFlags.AllocRDone)) { continue; } // We skip all registers that have assigned inRegIndex, indicates that // the register to allocate in is known. if (va.InRegIndex != RegisterIndex.Invalid) { var inRegs = va.InRegs; willSpill |= occupied & inRegs; continue; } } var m = va.InRegs; if (va.OutRegIndex != RegisterIndex.Invalid) { m |= Utils.Mask(va.OutRegIndex); } m = va.AllocableRegs & ~(willAlloc ^ m); m = GuessAlloc(vd, m, @class); if (!(m != 0)) { throw new ArgumentException(); } var candidateRegs = m & ~occupied; var homeMask = vd.HomeMask; if (candidateRegs == 0) { candidateRegs = m & occupied & ~state.Modified.Get(@class); if (candidateRegs == 0) { candidateRegs = m; } } // printf("CANDIDATE: %s %08X\n", vd->getName(), homeMask); if (candidateRegs.IsSet(homeMask)) { candidateRegs &= homeMask; } var regIndex = candidateRegs.FindFirstBit(); var regMask = Utils.Mask(regIndex); if ((vaFlags & VariableFlags.XReg) == VariableFlags.WReg) { va.OutRegIndex = regIndex; } else { va.InRegIndex = regIndex; va.InRegs = regMask; } willAlloc |= regMask; willSpill |= regMask & occupied; willFree &= ~regMask; occupied |= regMask; } else if ((vaFlags & VariableFlags.XMem) != 0) { var regIndex = vd.RegisterIndex; if (regIndex != RegisterIndex.Invalid && (vaFlags & VariableFlags.XMem) != VariableFlags.WMem) { willSpill |= Utils.Mask(regIndex); } } } _willSpill.Set(@class, willSpill); _willAlloc.Set(@class, willAlloc); }