public CompilerFunctionCall(Compiler compiler, CompilerFunction caller, Operand target, CallingConvention callingConvention, VariableType[] arguments, VariableType returnValue) : base(compiler) { Contract.Requires(arguments != null); _caller = caller; _target = target; _functionPrototype = new FunctionDeclaration(callingConvention, arguments, returnValue); if (arguments != null && arguments.Length > 0) _args = new Operand[arguments.Length]; }
public CompilerFunctionCall(Compiler compiler, CompilerFunction caller, Operand target, CallingConvention callingConvention, Type delegateType) : base(compiler) { Contract.Requires(compiler != null); Contract.Requires(caller != null); _caller = caller; _target = target; _functionPrototype = new FunctionDeclaration(callingConvention, delegateType); if (_functionPrototype.Arguments != null && _functionPrototype.Arguments.Length > 0) _args = new Operand[_functionPrototype.Arguments.Length]; }
private CompilerFunction(Compiler compiler, FunctionDeclaration prototype) : base(compiler) { Contract.Requires(compiler != null); Contract.Requires(prototype != null); _functionPrototype = prototype; _entryLabel = compiler.DefineLabel(); _exitLabel = compiler.DefineLabel(); _entryTarget = compiler.GetTarget(_entryLabel.Id); _exitTarget = compiler.GetTarget(_exitLabel.Id); _end = new CompilerFunctionEnd(compiler, this); }
public static FunctionDeclaration GetFunctionPrototype(CallingConvention callingConvention, VariableType[] arguments, VariableType returnValue) { if (arguments == null) throw new ArgumentNullException("arguments"); Contract.Ensures(Contract.Result<FunctionDeclaration>() != null); Contract.EndContractBlock(); bool isAction = returnValue == VariableType.Invalid; Type delegateType; if (isAction) { delegateType = Expression.GetActionType(Array.ConvertAll(arguments, i => Compiler.IdToType(i))); } else { List<Type> typeArgs = arguments.Select(i => Compiler.IdToType(i)).ToList(); typeArgs.Add(Compiler.IdToType(returnValue)); delegateType = Expression.GetFuncType(typeArgs.ToArray()); } List<FunctionDeclaration> prototypes = _prototypes.GetOrAdd(delegateType, key => new List<FunctionDeclaration>()); lock (prototypes) { FunctionDeclaration prototype = prototypes.FirstOrDefault(i => i.CallingConvention == callingConvention); if (prototype == null) { prototype = new FunctionDeclaration(callingConvention, arguments, returnValue); prototypes.Add(prototype); } return prototype; } }
public static FunctionDeclaration GetFunctionPrototype(CallingConvention callingConvention, Type delegateType) { if (delegateType == null) throw new ArgumentNullException("delegateType"); Contract.Ensures(Contract.Result<FunctionDeclaration>() != null); Contract.EndContractBlock(); List<FunctionDeclaration> prototypes = _prototypes.GetOrAdd(delegateType, key => new List<FunctionDeclaration>()); lock (prototypes) { FunctionDeclaration prototype = prototypes.FirstOrDefault(i => i.CallingConvention == callingConvention); if (prototype == null) { prototype = new FunctionDeclaration(callingConvention, delegateType); prototypes.Add(prototype); } return prototype; } }
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."); }
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."); } }
private void MoveAllocatedVariableToStack(CompilerContext cc, CompilerVar vdata, FunctionDeclaration.Argument argType) { 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; RegIndex src = vdata.RegisterIndex; 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, dst, Register.gpd(src)); return; case VariableType.GPQ: case VariableType.MM: if (!Util.IsX64) throw new NotSupportedException(); compiler.Emit(InstructionCode.Mov, dst, Register.gpq(src)); return; } break; case VariableType.GPQ: if (!Util.IsX64) throw new NotSupportedException(); switch (argType._variableType) { case VariableType.GPD: compiler.Emit(InstructionCode.Mov, dst, Register.gpd(src)); return; case VariableType.GPQ: compiler.Emit(InstructionCode.Mov, dst, Register.gpq(src)); return; case VariableType.MM: compiler.Emit(InstructionCode.Movq, dst, Register.gpq(src)); return; } break; case VariableType.MM: switch (argType._variableType) { case VariableType.GPD: case VariableType.X87_1F: case VariableType.XMM_1F: compiler.Emit(InstructionCode.Movd, dst, Register.mm(src)); return; case VariableType.GPQ: case VariableType.MM: case VariableType.X87_1D: case VariableType.XMM_1D: compiler.Emit(InstructionCode.Movq, dst, Register.mm(src)); return; } break; // 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, dst, Register.xmm(src)); return; case VariableType.XMM_1F: case VariableType.XMM_4F: compiler.Emit(InstructionCode.Movups, dst, Register.xmm(src)); return; case VariableType.XMM_1D: case VariableType.XMM_2D: compiler.Emit(InstructionCode.Movupd, dst, Register.xmm(src)); return; } break; 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, dst, Register.xmm(src)); return; } break; 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, dst, Register.xmm(src)); return; } break; } throw new ArgumentException("Incompatible argument."); }
private CompilerVar GetOverlappingVariable(CompilerContext cc, FunctionDeclaration.Argument argType) { Contract.Requires(cc != null); Contract.Requires(argType != null); if (argType._variableType == VariableType.Invalid) throw new ArgumentException(); switch (argType._variableType) { case VariableType.GPD: case VariableType.GPQ: return cc.State.GP[(int)argType._registerIndex]; case VariableType.MM: return cc.State.MM[(int)argType._registerIndex]; case VariableType.XMM: case VariableType.XMM_1F: case VariableType.XMM_1D: case VariableType.XMM_4F: case VariableType.XMM_2D: return cc.State.XMM[(int)argType._registerIndex]; default: throw new CompilerException(); } }