public StateData(int memVarsCount) { if (memVarsCount < 0) throw new ArgumentOutOfRangeException("memVarsCount"); _registers = new CompilerVar[RegisterCount]; MemVarsData = new CompilerVar[memVarsCount]; }
public CompilerHint(Compiler compiler, CompilerVar varData, VariableHintKind hintKind, int hintValue) : base(compiler) { if (varData == null) throw new ArgumentNullException("varData"); Contract.Requires(compiler != null); Contract.EndContractBlock(); _varData = varData; _hintKind = hintKind; _hintValue = hintValue; }
public StateData(StateData other, int memVarsCount) { if (other == null) throw new ArgumentNullException("other"); if (memVarsCount < 0) throw new ArgumentOutOfRangeException("memVarsCount"); _registers = (CompilerVar[])other._registers.Clone(); Contract.Assume(_registers.Length == other._registers.Length); UsedGP = other.UsedGP; UsedMM = other.UsedMM; UsedXMM = other.UsedXMM; ChangedGP = other.ChangedGP; ChangedMM = other.ChangedMM; ChangedXMM = other.ChangedXMM; MemVarsData = new CompilerVar[memVarsCount]; }
// TODO: Find code which uses this and improve. internal void NewRegisterHomeMask(CompilerVar var, RegisterMask mask) { Contract.Requires(var != null); var.PreferredRegisterMask |= mask; }
// TODO: Find code which uses this and improve. internal void NewRegisterHomeIndex(CompilerVar var, RegIndex idx) { Contract.Requires(var != null); if (var.HomeRegisterIndex == RegIndex.Invalid) var.HomeRegisterIndex = idx; var.PreferredRegisterMask |= RegisterMask.FromIndex(idx); }
private void MoveSrcVariableToRegister(CompilerContext cc, CompilerVar vdata, FunctionDeclaration.Argument argType) { Contract.Requires(cc != null); Contract.Requires(vdata != null); Contract.Requires(argType != null); RegIndex dst = argType._registerIndex; RegIndex src = vdata.RegisterIndex; Compiler compiler = cc.Compiler; if (src != RegIndex.Invalid) { switch (argType._variableType) { case VariableType.GPD: switch (vdata.Type) { case VariableType.GPD: compiler.Emit(InstructionCode.Mov, Register.gpd(dst), Register.gpd(src)); return; case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); compiler.Emit(InstructionCode.Mov, Register.gpq(dst), Register.gpq(src)); return; case VariableType.MM: compiler.Emit(InstructionCode.Movd, Register.gpd(dst), Register.mm(src)); return; } break; case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); switch (vdata.Type) { case VariableType.GPD: compiler.Emit(InstructionCode.Mov, Register.gpd(dst), Register.gpd(src)); return; case VariableType.GPQ: compiler.Emit(InstructionCode.Mov, Register.gpq(dst), Register.gpq(src)); return; case VariableType.MM: compiler.Emit(InstructionCode.Movq, Register.gpq(dst), Register.mm(src)); return; } break; case VariableType.MM: switch (vdata.Type) { case VariableType.GPD: compiler.Emit(InstructionCode.Movd, Register.gpd(dst), Register.gpd(src)); return; case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); compiler.Emit(InstructionCode.Movq, Register.gpq(dst), Register.gpq(src)); return; case VariableType.MM: compiler.Emit(InstructionCode.Movq, Register.mm(dst), Register.mm(src)); return; } break; case VariableType.XMM: case VariableType.XMM_4F: case VariableType.XMM_2D: switch (vdata.Type) { case VariableType.GPD: compiler.Emit(InstructionCode.Movd, Register.xmm(dst), Register.gpd(src)); return; case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); compiler.Emit(InstructionCode.Movq, Register.xmm(dst), Register.gpq(src)); return; case VariableType.MM: compiler.Emit(InstructionCode.Movq, Register.xmm(dst), Register.mm(src)); return; case VariableType.XMM: case VariableType.XMM_1F: case VariableType.XMM_4F: case VariableType.XMM_1D: case VariableType.XMM_2D: compiler.Emit(InstructionCode.Movdqa, Register.xmm(dst), Register.xmm(src)); return; } break; case VariableType.XMM_1F: switch (vdata.Type) { case VariableType.MM: compiler.Emit(InstructionCode.Movq, Register.xmm(dst), Register.mm(src)); return; case VariableType.XMM: compiler.Emit(InstructionCode.Movdqa, Register.xmm(dst), Register.xmm(src)); return; case VariableType.XMM_1F: case VariableType.XMM_4F: compiler.Emit(InstructionCode.Movss, Register.xmm(dst), Register.xmm(src)); return; case VariableType.XMM_1D: case VariableType.XMM_2D: compiler.Emit(InstructionCode.Cvtsd2ss, Register.xmm(dst), Register.xmm(src)); return; } break; case VariableType.XMM_1D: switch (vdata.Type) { case VariableType.MM: compiler.Emit(InstructionCode.Movq, Register.xmm(dst), Register.mm(src)); return; case VariableType.XMM: compiler.Emit(InstructionCode.Movdqa, Register.xmm(dst), Register.xmm(src)); return; case VariableType.XMM_1F: case VariableType.XMM_4F: compiler.Emit(InstructionCode.Cvtss2sd, Register.xmm(dst), Register.xmm(src)); return; case VariableType.XMM_1D: case VariableType.XMM_2D: compiler.Emit(InstructionCode.Movsd, Register.xmm(dst), Register.xmm(src)); return; } break; } } else { Mem mem = cc.GetVarMem(vdata); switch (argType._variableType) { case VariableType.GPD: switch (vdata.Type) { case VariableType.GPD: compiler.Emit(InstructionCode.Mov, Register.gpd(dst), mem); return; case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); compiler.Emit(InstructionCode.Mov, Register.gpq(dst), mem); return; case VariableType.MM: compiler.Emit(InstructionCode.Movd, Register.gpd(dst), mem); return; } break; case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); switch (vdata.Type) { case VariableType.GPD: compiler.Emit(InstructionCode.Mov, Register.gpd(dst), mem); return; case VariableType.GPQ: compiler.Emit(InstructionCode.Mov, Register.gpq(dst), mem); return; case VariableType.MM: compiler.Emit(InstructionCode.Movq, Register.gpq(dst), mem); return; } break; case VariableType.MM: switch (vdata.Type) { case VariableType.GPD: compiler.Emit(InstructionCode.Movd, Register.gpd(dst), mem); return; case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); compiler.Emit(InstructionCode.Movq, Register.gpq(dst), mem); return; case VariableType.MM: compiler.Emit(InstructionCode.Movq, Register.mm(dst), mem); return; } break; case VariableType.XMM: case VariableType.XMM_4F: case VariableType.XMM_2D: switch (vdata.Type) { case VariableType.GPD: compiler.Emit(InstructionCode.Movd, Register.xmm(dst), mem); return; case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); compiler.Emit(InstructionCode.Movq, Register.xmm(dst), mem); return; case VariableType.MM: compiler.Emit(InstructionCode.Movq, Register.xmm(dst), mem); return; case VariableType.XMM: case VariableType.XMM_1F: case VariableType.XMM_4F: case VariableType.XMM_1D: case VariableType.XMM_2D: compiler.Emit(InstructionCode.Movdqa, Register.xmm(dst), mem); return; } break; case VariableType.XMM_1F: switch (vdata.Type) { case VariableType.MM: compiler.Emit(InstructionCode.Movq, Register.xmm(dst), mem); return; case VariableType.XMM: compiler.Emit(InstructionCode.Movdqa, Register.xmm(dst), mem); return; case VariableType.XMM_1F: case VariableType.XMM_4F: compiler.Emit(InstructionCode.Movss, Register.xmm(dst), mem); return; case VariableType.XMM_1D: case VariableType.XMM_2D: compiler.Emit(InstructionCode.Cvtsd2ss, Register.xmm(dst), mem); return; } break; case VariableType.XMM_1D: switch (vdata.Type) { case VariableType.MM: compiler.Emit(InstructionCode.Movq, Register.xmm(dst), mem); return; case VariableType.XMM: compiler.Emit(InstructionCode.Movdqa, Register.xmm(dst), mem); return; case VariableType.XMM_1F: case VariableType.XMM_4F: compiler.Emit(InstructionCode.Cvtss2sd, Register.xmm(dst), mem); return; case VariableType.XMM_1D: case VariableType.XMM_2D: compiler.Emit(InstructionCode.Movsd, Register.xmm(dst), mem); return; } break; } } throw new ArgumentException("Incompatible argument."); }
protected virtual bool TryUnuseVarImpl(CompilerVar v) { Contract.Requires(v != null); return false; }
public void SaveVar(CompilerVar var) { Contract.Requires(var != null); if (var == null) throw new ArgumentNullException("var"); if (var.State != VariableState.Register || var.RegisterIndex == RegIndex.Invalid) throw new ArgumentException("Can't save a variable that isn't allocated."); switch (var.Type) { case VariableType.GPD: case VariableType.GPQ: if (var.Type == VariableType.GPQ && !Util.IsX64) throw new NotSupportedException(); break; case VariableType.X87: case VariableType.X87_1F: case VariableType.X87_1D: // TODO: X87 VARIABLES NOT IMPLEMENTED. throw new NotImplementedException("X87 variables are not yet implemented."); case VariableType.MM: break; case VariableType.XMM: case VariableType.XMM_1F: case VariableType.XMM_4F: case VariableType.XMM_1D: case VariableType.XMM_2D: break; default: throw new ArgumentException("The variable type is not supported."); } RegIndex idx = var.RegisterIndex; EmitSaveVar(var, idx); // Update VarData. var.Changed = false; }
public void EmitMoveVar(CompilerVar var, RegIndex regIndex, VariableAlloc vflags) { Contract.Requires(var != null); if (var.RegisterIndex == RegIndex.Invalid) throw new ArgumentException("Caller must ensure that variable is allocated."); if ((vflags & VariableAlloc.Read) == 0) return; switch (var.Type) { case VariableType.GPD: _compiler.Emit(InstructionCode.Mov, Register.gpd(regIndex), Register.gpd(var.RegisterIndex)); break; case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); _compiler.Emit(InstructionCode.Mov, Register.gpq(regIndex), Register.gpq(var.RegisterIndex)); break; case VariableType.X87: case VariableType.X87_1F: case VariableType.X87_1D: // TODO: X87 VARIABLES NOT IMPLEMENTED. throw new NotImplementedException("X87 variables are not yet implemented."); case VariableType.MM: _compiler.Emit(InstructionCode.Movq, Register.mm(regIndex), Register.mm(var.RegisterIndex)); break; case VariableType.XMM: _compiler.Emit(InstructionCode.Movdqa, Register.xmm(regIndex), Register.xmm(var.RegisterIndex)); break; case VariableType.XMM_1F: _compiler.Emit(InstructionCode.Movss, Register.xmm(regIndex), Register.xmm(var.RegisterIndex)); break; case VariableType.XMM_1D: _compiler.Emit(InstructionCode.Movsd, Register.xmm(regIndex), Register.xmm(var.RegisterIndex)); break; case VariableType.XMM_4F: _compiler.Emit(InstructionCode.Movaps, Register.xmm(regIndex), Register.xmm(var.RegisterIndex)); break; case VariableType.XMM_2D: _compiler.Emit(InstructionCode.Movapd, Register.xmm(regIndex), Register.xmm(var.RegisterIndex)); break; default: throw new CompilerException("Invalid variable type."); } }
public void AllocXMMVar(CompilerVar var, RegisterMask regMask, VariableAlloc vflags) { Contract.Requires(var != null); Contract.Requires(Function != null); AllocNonGPVar(var, regMask, vflags, RegNum.XMM, var.Scope.Declaration.PreservedXMM, _state.UsedXMM, _state.XMM, AllocatedXMMRegister, SpillXMMVar, FreedXMMRegister); }
internal void AllocatedVariable(CompilerVar var) { Contract.Requires(var != null); RegIndex idx = var.RegisterIndex; switch (var.Type) { case VariableType.GPD: case VariableType.GPQ: _state.GP[(int)idx] = var; AllocatedGPRegister(idx); break; case VariableType.MM: _state.MM[(int)idx] = var; AllocatedMMRegister(idx); break; case VariableType.XMM: case VariableType.XMM_1F: case VariableType.XMM_4F: case VariableType.XMM_1D: case VariableType.XMM_2D: _state.XMM[(int)idx] = var; AllocatedXMMRegister(idx); break; default: throw new CompilerException("Invalid variable type."); } }
internal void AddActive(CompilerVar var) { Contract.Requires(var != null); if (var.NextActive != null) throw new ArgumentException(); if (var.PreviousActive != null) throw new ArgumentException(); if (_active == null) { var.NextActive = var; var.PreviousActive = var; _active = var; } else { CompilerVar vlast = _active.PreviousActive; vlast.NextActive = var; _active.PreviousActive = var; var.NextActive = _active; var.PreviousActive = vlast; } }
public void UnuseVarOnEndOfScope(CompilerItem e, CompilerVar vdata) { Contract.Requires(e != null); Contract.Requires(vdata != null); if (vdata.LastItem == e) UnuseVar(vdata, VariableState.Unused); }
public void UnuseVar(CompilerVar var, VariableState toState) { Contract.Requires(var != null); if (toState == VariableState.Register) throw new ArgumentException(); if (var.State == VariableState.Register) { RegIndex registerIndex = var.RegisterIndex; switch (var.Type) { case VariableType.GPD: case VariableType.GPQ: if (var.Type == VariableType.GPQ && !Util.IsX64) throw new NotSupportedException(); _state.GP[(int)registerIndex] = null; FreedGPRegister(registerIndex); break; case VariableType.X87: case VariableType.X87_1F: case VariableType.X87_1D: // TODO: X87 VARIABLES NOT IMPLEMENTED. break; case VariableType.MM: _state.MM[(int)registerIndex] = null; FreedMMRegister(registerIndex); break; case VariableType.XMM: case VariableType.XMM_1F: case VariableType.XMM_4F: case VariableType.XMM_1D: case VariableType.XMM_2D: _state.XMM[(int)registerIndex] = null; FreedXMMRegister(registerIndex); break; default: throw new CompilerException("Invalid variable type."); } } var.State = toState; var.Changed = false; var.RegisterIndex = RegIndex.Invalid; }
public void SpillXMMVar(CompilerVar var) { Contract.Requires(var != null); SpillVar(var, _state.XMM, FreedXMMRegister); }
public void SpillVar(CompilerVar var) { Contract.Requires(var != null); switch (var.Type) { case VariableType.GPD: case VariableType.GPQ: if (var.Type == VariableType.GPQ && !Util.IsX64) throw new NotSupportedException(); SpillGPVar(var); break; case VariableType.X87: case VariableType.X87_1F: case VariableType.X87_1D: // TODO: X87 VARIABLES NOT IMPLEMENTED. throw new NotImplementedException("X87 variables are not yet implemented."); case VariableType.MM: SpillMMVar(var); break; case VariableType.XMM: case VariableType.XMM_1F: case VariableType.XMM_4F: case VariableType.XMM_1D: case VariableType.XMM_2D: SpillXMMVar(var); break; default: throw new CompilerException("Invalid variable type."); } }
public void SpillGPVar(CompilerVar var) { Contract.Requires(var != null); Contract.Requires(var.State == VariableState.Register); Contract.Requires(var.RegisterIndex != RegIndex.Invalid); SpillVar(var, _state.GP, FreedGPRegister); }
public void AllocGPVar(CompilerVar var, RegisterMask regMask, VariableAlloc variableAlloc) { Contract.Requires(var != null); Contract.Requires(Function != null); RegisterMask fullMask = RegisterMask.MaskToIndex(RegNum.GP) & ~RegisterMask.FromIndex(RegIndex.Esp); if (!_allocableEBP) fullMask &= ~RegisterMask.FromIndex(RegIndex.Ebp); // Fix the regMask (0 or full bit-array means that any register may be used). if (regMask == RegisterMask.Zero) regMask = RegisterMask.MaskToIndex(RegNum.GP); regMask &= fullMask; int i; RegisterMask mask; // Last register code (aka home). RegIndex home = var.HomeRegisterIndex; // New register code. RegIndex idx = RegIndex.Invalid; // Preserved GP variables. RegisterMask preservedGP = var.Scope.Declaration.PreservedGP; // Spill candidate. CompilerVar spillCandidate = null; // spill caused by direct jump to L_Spill bool doSpill = false; // Whether to alloc the non-preserved variables first. bool nonPreservedFirst = true; if (Function.IsCaller) { nonPreservedFirst = var.FirstCallable == null || var.FirstCallable.Offset >= var.LastItem.Offset; } // -------------------------------------------------------------------------- // [Already Allocated] // -------------------------------------------------------------------------- // Go away if variable is already allocated. if (var.State == VariableState.Register) { RegIndex oldIndex = var.RegisterIndex; // Already allocated in the right register. if ((RegisterMask.FromIndex(oldIndex) & regMask) != RegisterMask.Zero) return; // Try to find unallocated register first. mask = regMask & ~_state.UsedGP; if (mask != RegisterMask.Zero) { idx = ((nonPreservedFirst && (mask & ~preservedGP) != RegisterMask.Zero) ? mask & ~preservedGP : mask).FirstRegister; } // Then find the allocated and exchange later. else { idx = (regMask & _state.UsedGP).FirstRegister; } Contract.Assert(idx != RegIndex.Invalid); CompilerVar other = _state.GP[(int)idx]; EmitExchangeVar(var, idx, variableAlloc, other); _state.GP[(int)oldIndex] = other; _state.GP[(int)idx] = var; if (other != null) other.RegisterIndex = oldIndex; else FreedGPRegister(oldIndex); // Update VarData. var.State = VariableState.Register; var.RegisterIndex = idx; var.HomeRegisterIndex = idx; AllocatedGPRegister(idx); return; } // -------------------------------------------------------------------------- // [Find Unused GP] // -------------------------------------------------------------------------- // Home register code. if (idx == RegIndex.Invalid && home != RegIndex.Invalid && (regMask & RegisterMask.FromIndex(home)) != RegisterMask.Zero && (State.UsedGP & RegisterMask.FromIndex(home)) == RegisterMask.Zero) { idx = home; goto _Alloc; } // We start from 1, because EAX/RAX register is sometimes explicitly // needed. So we trying to prevent reallocation in near future. if (idx == RegIndex.Invalid) { for (i = 1, mask = RegisterMask.FromIndex((RegIndex)i); i < (int)RegNum.GP; i++, mask = RegisterMask.FromIndex((RegIndex)i)) { if ((regMask & mask) != RegisterMask.Zero && (_state.UsedGP & mask) == RegisterMask.Zero) { // Convenience to alloc non-preserved first or non-preserved last. if (nonPreservedFirst) { if (idx != RegIndex.Invalid && (preservedGP & mask) != RegisterMask.Zero) continue; idx = (RegIndex)i; // If current register is preserved, we should try to find different // one that is not. This can save one push / pop in prolog / epilog. if ((preservedGP & mask) == RegisterMask.Zero) break; } else { if (idx != RegIndex.Invalid && (preservedGP & mask) == RegisterMask.Zero) continue; idx = (RegIndex)i; // The opposite. if ((preservedGP & mask) != RegisterMask.Zero) break; } } } } // If not found, try EAX/RAX. if (idx == RegIndex.Invalid && (regMask & RegisterMask.FromIndex(RegIndex.Eax)) != RegisterMask.Zero && (_state.UsedGP & RegisterMask.FromIndex(RegIndex.Eax)) == RegisterMask.Zero) { idx = RegIndex.Eax; goto _Alloc; } // If regMask contains restricted registers which may be used then everything // is handled inside this block. if (idx == RegIndex.Invalid && regMask != fullMask) { // Try to find unallocated register first. mask = regMask & ~_state.UsedGP; if (mask != RegisterMask.Zero) { idx = ((nonPreservedFirst && (mask & ~preservedGP) != RegisterMask.Zero) ? (mask & ~preservedGP) : mask).FirstRegister; Contract.Assert(idx != RegIndex.Invalid); } // Then find the allocated and spill later. else { idx = (regMask & _state.UsedGP).FirstRegister; Contract.Assert(idx != RegIndex.Invalid); // Spill register we need. spillCandidate = _state.GP[(int)idx]; // Jump to spill part of allocation. doSpill = true; goto L_Spill; } } // -------------------------------------------------------------------------- // [Spill] // -------------------------------------------------------------------------- // If register is still not found, spill other variable. if (idx == RegIndex.Invalid) { if (spillCandidate == null) { spillCandidate = GetSpillCandidateGP(); } // Spill candidate not found? if (spillCandidate == null) { throw new CompilerException("Not enough registers."); } } L_Spill: if (idx == RegIndex.Invalid || doSpill) { // Prevented variables can't be spilled. _getSpillCandidate() never returns // prevented variables, but when jumping to L_Spill it can happen. if (spillCandidate.WorkOffset == _currentOffset) { throw new CompilerException("Registers overlap."); } idx = spillCandidate.RegisterIndex; SpillGPVar(spillCandidate); } // -------------------------------------------------------------------------- // [Alloc] // -------------------------------------------------------------------------- _Alloc: if (var.State == VariableState.Memory && (variableAlloc & VariableAlloc.Read) != 0) { EmitLoadVar(var, idx); } // Update VarData. var.State = VariableState.Register; var.RegisterIndex = idx; var.HomeRegisterIndex = idx; // Update StateData. AllocatedVariable(var); }
public void AllocVar(CompilerVar var, RegisterMask regMask, VariableAlloc variableAlloc) { Contract.Requires(var != null); switch (var.Type) { case VariableType.GPD: case VariableType.GPQ: if (var.Type == VariableType.GPQ && !Util.IsX64) throw new NotSupportedException(); AllocGPVar(var, regMask, variableAlloc); break; case VariableType.X87: case VariableType.X87_1F: case VariableType.X87_1D: // TODO: X87 VARIABLES NOT IMPLEMENTED. break; case VariableType.MM: AllocMMVar(var, regMask, variableAlloc); break; case VariableType.XMM: case VariableType.XMM_1F: case VariableType.XMM_4F: case VariableType.XMM_1D: case VariableType.XMM_2D: AllocXMMVar(var, regMask, variableAlloc); break; } PostAlloc(var, variableAlloc); }
internal void Clear() { Contract.Ensures(Function == null); //_zone.clear(); _function = null; _start = null; _stop = null; _state.Clear(); _active = null; _forwardJumps = null; _currentOffset = 0; //_unreachable = 0; _modifiedGPRegisters = RegisterMask.Zero; _modifiedMMRegisters = RegisterMask.Zero; _modifiedXMMRegisters = RegisterMask.Zero; _allocableEBP = false; _adjustESP = 0; _argumentsBaseReg = RegIndex.Invalid; _argumentsBaseOffset = 0; _argumentsActualDisp = 0; _variablesBaseReg = RegIndex.Invalid; _variablesBaseOffset = 0; _variablesActualDisp = 0; _memUsed = null; _memFree = null; _mem4BlocksCount = 0; _mem8BlocksCount = 0; _mem16BlocksCount = 0; _memBytesTotal = 0; _backCode.Clear(); _backPos = 0; }
public void EmitExchangeVar(CompilerVar var, RegIndex regIndex, VariableAlloc vflags, CompilerVar other) { Contract.Requires(var != null); Contract.Requires(other != null); if (var.RegisterIndex == RegIndex.Invalid) throw new CompilerException("Caller must ensure that variable is allocated."); // If other is not valid then we can just emit MOV (or other similar instruction). if (other == null) { EmitMoveVar(var, regIndex, vflags); return; } // If we need to alloc for write-only operation then we can move other // variable away instead of exchanging them. if ((vflags & VariableAlloc.Read) == 0) { EmitMoveVar(other, var.RegisterIndex, VariableAlloc.Read); return; } switch (var.Type) { case VariableType.GPD: _compiler.Emit(InstructionCode.Xchg, Register.gpd(regIndex), Register.gpd(var.RegisterIndex)); break; case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); _compiler.Emit(InstructionCode.Xchg, Register.gpq(regIndex), Register.gpq(var.RegisterIndex)); break; case VariableType.X87: case VariableType.X87_1F: case VariableType.X87_1D: // TODO: X87 VARIABLES NOT IMPLEMENTED. break; // NOTE: MM and XMM registers shoudln't be exchanged using this way, it's // correct, but it sucks. case VariableType.MM: { MMReg a = Register.mm(regIndex); MMReg b = Register.mm(var.RegisterIndex); _compiler.Emit(InstructionCode.Pxor, a, b); _compiler.Emit(InstructionCode.Pxor, b, a); _compiler.Emit(InstructionCode.Pxor, a, b); break; } case VariableType.XMM_1F: case VariableType.XMM_4F: { XMMReg a = Register.xmm(regIndex); XMMReg b = Register.xmm(var.RegisterIndex); _compiler.Emit(InstructionCode.Xorps, a, b); _compiler.Emit(InstructionCode.Xorps, b, a); _compiler.Emit(InstructionCode.Xorps, a, b); break; } case VariableType.XMM_1D: case VariableType.XMM_2D: { XMMReg a = Register.xmm(regIndex); XMMReg b = Register.xmm(var.RegisterIndex); _compiler.Emit(InstructionCode.Xorpd, a, b); _compiler.Emit(InstructionCode.Xorpd, b, a); _compiler.Emit(InstructionCode.Xorpd, a, b); break; } case VariableType.XMM: { XMMReg a = Register.xmm(regIndex); XMMReg b = Register.xmm(var.RegisterIndex); _compiler.Emit(InstructionCode.Pxor, a, b); _compiler.Emit(InstructionCode.Pxor, b, a); _compiler.Emit(InstructionCode.Pxor, a, b); break; } } }
internal void FreeActive(CompilerVar var) { Contract.Requires(var != null); CompilerVar next = var.NextActive; CompilerVar prev = var.PreviousActive; if (prev == next) { _active = null; } else { if (_active == var) _active = next; prev.NextActive = next; next.PreviousActive = prev; } var.NextActive = null; var.PreviousActive = null; }
public void EmitSaveVar(CompilerVar var, RegIndex regIndex) { Contract.Requires(var != null); if (var == null) throw new ArgumentNullException("var"); if (regIndex == RegIndex.Invalid) throw new ArgumentException("Caller must ensure that variable is allocated."); Mem m = GetVarMem(var); switch (var.Type) { case VariableType.GPD: _compiler.Emit(InstructionCode.Mov, m, Register.gpd(regIndex)); if (_emitComments) goto addComment; break; case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); _compiler.Emit(InstructionCode.Mov, m, Register.gpq(regIndex)); if (_emitComments) goto addComment; break; case VariableType.X87: case VariableType.X87_1F: case VariableType.X87_1D: // TODO: X87 VARIABLES NOT IMPLEMENTED. break; case VariableType.MM: _compiler.Emit(InstructionCode.Movq, m, Register.mm(regIndex)); if (_emitComments) goto addComment; break; case VariableType.XMM: _compiler.Emit(InstructionCode.Movdqa, m, Register.xmm(regIndex)); if (_emitComments) goto addComment; break; case VariableType.XMM_1F: _compiler.Emit(InstructionCode.Movss, m, Register.xmm(regIndex)); if (_emitComments) goto addComment; break; case VariableType.XMM_1D: _compiler.Emit(InstructionCode.Movsd, m, Register.xmm(regIndex)); if (_emitComments) goto addComment; break; case VariableType.XMM_4F: _compiler.Emit(InstructionCode.Movaps, m, Register.xmm(regIndex)); if (_emitComments) goto addComment; break; case VariableType.XMM_2D: _compiler.Emit(InstructionCode.Movapd, m, Register.xmm(regIndex)); if (_emitComments) goto addComment; break; default: throw new CompilerException("Invalid variable type."); } return; addComment: _compiler.CurrentItem.Comment = string.Format("Spill {0}", var.Name); }
internal Mem GetVarMem(CompilerVar var) { Contract.Requires(var != null); Contract.Ensures(Contract.Result<Mem>() != null); Mem m = new Mem(var.Id); if (!var.IsMemArgument) m.Displacement = (IntPtr)_adjustESP; MarkMemoryUsed(var); return m; }
/// <summary> /// Try to unuse the variable <paramref name="v"/>. /// </summary> /// <param name="v"></param> /// <returns> /// @c true only if the variable will be unused by the instruction, /// otherwise @c false is returned. /// </returns> public bool TryUnuseVar(CompilerVar v) { Contract.Requires(v != null); return TryUnuseVarImpl(v); }
protected override bool TryUnuseVarImpl(CompilerVar v) { for (uint i = 0; i < _variables.Length; i++) { if (_variables[i].VarData == v) { _variables[i].VarFlags |= VariableAlloc.UnuseAfterUse; return true; } } return false; }
internal bool IsActive(CompilerVar var) { Contract.Requires(var != null); return var.NextActive != null; }
private void MoveSpilledVariableToStack(CompilerContext cc, CompilerVar vdata, FunctionDeclaration.Argument argType, RegIndex temporaryGpReg, RegIndex temporaryXmmReg) { Contract.Requires(cc != null); Contract.Requires(vdata != null); Contract.Requires(argType != null); if (argType._registerIndex != RegIndex.Invalid) throw new ArgumentException(); if (vdata.RegisterIndex != RegIndex.Invalid) throw new ArgumentException(); Compiler compiler = cc.Compiler; Mem src = cc.GetVarMem(vdata); Mem dst = Mem.ptr(Register.nsp, -IntPtr.Size + argType._stackOffset); switch (vdata.Type) { case VariableType.GPD: switch (argType._variableType) { case VariableType.GPD: compiler.Emit(InstructionCode.Mov, Register.gpd(temporaryGpReg), src); compiler.Emit(InstructionCode.Mov, dst, Register.gpd(temporaryGpReg)); return; case VariableType.GPQ: case VariableType.MM: if (!Util.IsX64) throw new NotSupportedException(); compiler.Emit(InstructionCode.Mov, Register.gpd(temporaryGpReg), src); compiler.Emit(InstructionCode.Mov, dst, Register.gpq(temporaryGpReg)); return; default: throw new CompilerException(); } case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); switch (argType._variableType) { case VariableType.GPD: compiler.Emit(InstructionCode.Mov, Register.gpd(temporaryGpReg), src); compiler.Emit(InstructionCode.Mov, dst, Register.gpd(temporaryGpReg)); return; case VariableType.GPQ: case VariableType.MM: compiler.Emit(InstructionCode.Mov, Register.gpq(temporaryGpReg), src); compiler.Emit(InstructionCode.Mov, dst, Register.gpq(temporaryGpReg)); return; default: throw new CompilerException(); } case VariableType.MM: switch (argType._variableType) { case VariableType.GPD: case VariableType.X87_1F: case VariableType.XMM_1F: compiler.Emit(InstructionCode.Mov, Register.gpd(temporaryGpReg), src); compiler.Emit(InstructionCode.Mov, dst, Register.gpd(temporaryGpReg)); return; case VariableType.GPQ: case VariableType.MM: case VariableType.X87_1D: case VariableType.XMM_1D: // TODO return; default: throw new CompilerException(); } // We allow incompatible types here, because the called can convert them // to correct format before function is called. case VariableType.XMM: case VariableType.XMM_4F: case VariableType.XMM_2D: switch (argType._variableType) { case VariableType.XMM: compiler.Emit(InstructionCode.Movdqu, Register.xmm(temporaryXmmReg), src); compiler.Emit(InstructionCode.Movdqu, dst, Register.xmm(temporaryXmmReg)); return; case VariableType.XMM_1F: case VariableType.XMM_4F: compiler.Emit(InstructionCode.Movups, Register.xmm(temporaryXmmReg), src); compiler.Emit(InstructionCode.Movups, dst, Register.xmm(temporaryXmmReg)); return; case VariableType.XMM_1D: case VariableType.XMM_2D: compiler.Emit(InstructionCode.Movupd, Register.xmm(temporaryXmmReg), src); compiler.Emit(InstructionCode.Movupd, dst, Register.xmm(temporaryXmmReg)); return; default: throw new CompilerException(); } case VariableType.XMM_1F: switch (argType._variableType) { case VariableType.X87_1F: case VariableType.XMM: case VariableType.XMM_1F: case VariableType.XMM_4F: case VariableType.XMM_1D: case VariableType.XMM_2D: compiler.Emit(InstructionCode.Movss, Register.xmm(temporaryXmmReg), src); compiler.Emit(InstructionCode.Movss, dst, Register.xmm(temporaryXmmReg)); return; default: throw new CompilerException(); } case VariableType.XMM_1D: switch (argType._variableType) { case VariableType.X87_1D: case VariableType.XMM: case VariableType.XMM_1F: case VariableType.XMM_4F: case VariableType.XMM_1D: case VariableType.XMM_2D: compiler.Emit(InstructionCode.Movsd, Register.xmm(temporaryXmmReg), src); compiler.Emit(InstructionCode.Movsd, dst, Register.xmm(temporaryXmmReg)); return; default: throw new CompilerException(); } default: throw new CompilerException("Incompatible argument."); } }
public static GPVar FromData(CompilerVar vdata) { Contract.Requires(vdata != null); return new GPVar(vdata.Id, vdata.Size, VariableInfo.GetVariableInfo(vdata.Type).RegisterType, vdata.Type); }
internal void MarkMemoryUsed(CompilerVar var) { Contract.Requires(var != null); if (var.HomeMemoryData != null) return; VarMemBlock mem = AllocMemBlock(var.Size); if (mem == null) return; var.HomeMemoryData = mem; }