public CompilerFunctionReturn(Compiler compiler, CompilerFunction function, Operand first, Operand second) : base(compiler) { Contract.Requires(compiler != null); Contract.Requires(function != null); _function = function; _first = first; _second = second; }
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]; }
public CompilerJmpInstruction(Compiler compiler, InstructionCode code, Operand[] operands) : base(compiler, code, operands) { if (code < InstructionDescription.JumpBegin || code > InstructionDescription.JumpEnd) throw new ArgumentException("The specified instruction code is not a valid jump."); Contract.Requires(compiler != null); Contract.Requires(operands != null); Contract.EndContractBlock(); _jumpTarget = compiler.GetTarget(Operands[0].Id); _jumpTarget.JumpsCount++; _jumpNext = _jumpTarget.From; _jumpTarget.From = this; _isTaken = Code == InstructionCode.Jmp || (Operands.Length > 1 && Operands[1].IsImm && ((Imm)Operands[1]).Value == (IntPtr)Hint.Taken); }
public CompilerInstruction(Compiler compiler, InstructionCode code, Operand[] operands) : base(compiler) { Contract.Requires(compiler != null); Contract.Requires(operands != null); _code = code; _emitOptions = compiler.EmitOptions; // Each created instruction takes emit options and clears it. compiler.EmitOptions = EmitOptions.None; _operands = operands; _memoryOperand = null; _variables = null; for (int i = 0; i < operands.Length; i++) { if (operands[i].IsMem) { _memoryOperand = (Mem)operands[i]; break; } } InstructionDescription id = InstructionDescription.FromInstruction(_code); _isSpecial = id.IsSpecial; _isFPU = id.IsFPU; _isGPBHiUsed = false; _isGPBLoUsed = false; if (_isSpecial) { // ${SPECIAL_INSTRUCTION_HANDLING_BEGIN} switch (_code) { case InstructionCode.Cpuid: // Special... break; case InstructionCode.Cbw: case InstructionCode.Cdqe: case InstructionCode.Cwde: // Special... break; case InstructionCode.Cdq: case InstructionCode.Cqo: case InstructionCode.Cwd: // Special... break; case InstructionCode.Cmpxchg: case InstructionCode.Cmpxchg8b: case InstructionCode.Cmpxchg16b: // Special... if (_code == InstructionCode.Cmpxchg16b && !Util.IsX64) throw new NotSupportedException(string.Format("The '{0}' instruction is only supported on X64.", _code)); break; case InstructionCode.Daa: case InstructionCode.Das: // Special... if (!Util.IsX86) throw new NotSupportedException(string.Format("The '{0}' instruction is only supported on X86.", _code)); break; case InstructionCode.Imul: switch (operands.Length) { case 2: // IMUL dst, src is not special instruction. _isSpecial = false; break; case 3: if (!(_operands[0].IsVar && _operands[1].IsVar && _operands[2].IsVarMem)) { // Only IMUL dst_hi, dst_lo, reg/mem is special, all others don't. _isSpecial = false; } break; } break; case InstructionCode.Mul: case InstructionCode.Idiv: case InstructionCode.Div: // Special... break; case InstructionCode.MovPtr: // Special... break; case InstructionCode.Lahf: case InstructionCode.Sahf: // Special... break; case InstructionCode.Maskmovdqu: case InstructionCode.Maskmovq: // Special... break; case InstructionCode.Enter: case InstructionCode.Leave: // Special... break; case InstructionCode.Ret: // Special... break; case InstructionCode.Monitor: case InstructionCode.Mwait: // Special... break; case InstructionCode.Pop: case InstructionCode.Popad: case InstructionCode.Popfd: case InstructionCode.Popfq: // Special... break; case InstructionCode.Push: case InstructionCode.Pushad: case InstructionCode.Pushfd: case InstructionCode.Pushfq: // Special... break; case InstructionCode.Rcl: case InstructionCode.Rcr: case InstructionCode.Rol: case InstructionCode.Ror: case InstructionCode.Sal: case InstructionCode.Sar: case InstructionCode.Shl: case InstructionCode.Shr: // Rot instruction is special only if last operand is variable (register). _isSpecial = _operands[1].IsVar; break; case InstructionCode.Shld: case InstructionCode.Shrd: // Shld/Shrd instruction is special only if last operand is variable (register). _isSpecial = _operands[2].IsVar; break; case InstructionCode.Rdtsc: case InstructionCode.Rdtscp: // Special... break; case InstructionCode.RepLodsb: case InstructionCode.RepLodsd: case InstructionCode.RepLodsq: case InstructionCode.RepLodsw: case InstructionCode.RepMovsb: case InstructionCode.RepMovsd: case InstructionCode.RepMovsq: case InstructionCode.RepMovsw: case InstructionCode.RepStosb: case InstructionCode.RepStosd: case InstructionCode.RepStosq: case InstructionCode.RepStosw: case InstructionCode.RepeCmpsb: case InstructionCode.RepeCmpsd: case InstructionCode.RepeCmpsq: case InstructionCode.RepeCmpsw: case InstructionCode.RepeScasb: case InstructionCode.RepeScasd: case InstructionCode.RepeScasq: case InstructionCode.RepeScasw: case InstructionCode.RepneCmpsb: case InstructionCode.RepneCmpsd: case InstructionCode.RepneCmpsq: case InstructionCode.RepneCmpsw: case InstructionCode.RepneScasb: case InstructionCode.RepneScasd: case InstructionCode.RepneScasq: case InstructionCode.RepneScasw: // Special... break; default: throw new CompilerException("Instruction is marked as special but handling for it is not present."); } // ${SPECIAL_INSTRUCTION_HANDLING_END} } }
public void TranslateOperands(Operand[] operands) { Contract.Requires(operands != null); int i; int count = operands.Length; // Translate variables to registers. for (i = 0; i < count; i++) { Operand o = operands[i]; if (o.IsVar) { CompilerVar vdata = _compiler.GetVarData(o.Id); Contract.Assert(vdata != null); operands[i] = new GPReg(((BaseVar)o).RegisterType, vdata.RegisterIndex); } else if (o.IsMem) { Mem mem = (Mem)o; if ((o.Id & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar) { // Memory access. We just increment here actual displacement. CompilerVar vdata = _compiler.GetVarData(o.Id); Contract.Assert(vdata != null); mem.Displacement += vdata.IsMemArgument ? _argumentsActualDisp : _variablesActualDisp; // NOTE: This is not enough, variable position will be patched later // by CompilerContext::_patchMemoryOperands(). } else if (((int)mem.Base & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar) { CompilerVar vdata = _compiler.GetVarData((int)mem.Base); Contract.Assert(vdata != null); mem.Base = vdata.RegisterIndex; } if (((int)mem.Index & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar) { CompilerVar vdata = _compiler.GetVarData((int)mem.Index); Contract.Assert(vdata != null); mem.Index = vdata.RegisterIndex; } } } }
protected override CompilerItem TranslateImpl(CompilerContext cc) { RegisterMask preserved; RegIndex temporaryGpReg; RegIndex temporaryXmmReg; int offset = cc.CurrentOffset; Compiler compiler = cc.Compiler; // Constants. FunctionDeclaration.Argument[] targs = Declaration.Arguments; int argumentsCount = Declaration.Arguments.Length; int variablesCount = _variables.Length; // Processed arguments. bool[] processed = new bool[FUNC_MAX_ARGS]; compiler.Comment("Call"); // These variables are used by the instruction so we set current offset // to their work offsets -> The SpillCandidate method never returns // the variable used by this instruction. for (int i = 0; i < variablesCount; i++) { _variables[i].vdata.WorkOffset = offset; // Init back-reference to VarCallRecord. _variables[i].vdata.Temp = _variables[i]; } // -------------------------------------------------------------------------- // STEP 1: // // Spill variables which are not used by the function call and have to // be destroyed. These registers may be used by callee. // -------------------------------------------------------------------------- preserved = Declaration.PreservedGP; for (int i = 0; i < RegNum.GP; i++) { RegisterMask mask = RegisterMask.FromIndex((RegIndex)i); CompilerVar vdata = cc.State.GP[i]; if (vdata != null && vdata.WorkOffset != offset && (preserved & mask) == RegisterMask.Zero) cc.SpillGPVar(vdata); } preserved = Declaration.PreservedMM; for (int i = 0; i < RegNum.MM; i++) { RegisterMask mask = RegisterMask.FromIndex((RegIndex)i); CompilerVar vdata = cc.State.MM[i]; if (vdata != null && vdata.WorkOffset != offset && (preserved & mask) == RegisterMask.Zero) cc.SpillMMVar(vdata); } preserved = Declaration.PreservedXMM; for (int i = 0; i < RegNum.XMM; i++) { RegisterMask mask = RegisterMask.FromIndex((RegIndex)i); CompilerVar vdata = cc.State.XMM[i]; if (vdata != null && vdata.WorkOffset != offset && (preserved & mask) == RegisterMask.Zero) cc.SpillXMMVar(vdata); } // -------------------------------------------------------------------------- // STEP 2: // // Move all arguments to the stack which are already in registers. // -------------------------------------------------------------------------- for (int i = 0; i < argumentsCount; i++) { if (processed[i]) continue; FunctionDeclaration.Argument argType = targs[i]; if (argType._registerIndex != RegIndex.Invalid) continue; Operand operand = _args[i]; if (operand.IsVar) { VarCallRecord rec = _argumentToVarRecord[i]; CompilerVar vdata = compiler.GetVarData(operand.Id); Contract.Assert(vdata != null); if (vdata.RegisterIndex != RegIndex.Invalid) { MoveAllocatedVariableToStack(cc, vdata, argType); rec.InDone++; processed[i] = true; } } } // -------------------------------------------------------------------------- // STEP 3: // // Spill all non-preserved variables we moved to stack in STEP #2. // -------------------------------------------------------------------------- for (int i = 0; i < argumentsCount; i++) { VarCallRecord rec = _argumentToVarRecord[i]; if (rec == null || processed[i]) continue; if (rec.InDone >= rec.InCount) { CompilerVar vdata = rec.vdata; if (vdata.RegisterIndex == RegIndex.Invalid) continue; if (rec.OutCount != 0) { // Variable will be rewritten by function return value, it's not needed // to spill it. It will be allocated again by ECall. cc.UnuseVar(rec.vdata, VariableState.Unused); } else { switch (vdata.Type) { case VariableType.GPD: case VariableType.GPQ: if ((Declaration.PreservedGP & RegisterMask.FromIndex(vdata.RegisterIndex)) == RegisterMask.Zero) cc.SpillGPVar(vdata); break; case VariableType.MM: if ((Declaration.PreservedMM & RegisterMask.FromIndex(vdata.RegisterIndex)) == RegisterMask.Zero) cc.SpillMMVar(vdata); break; case VariableType.XMM: case VariableType.XMM_1F: case VariableType.XMM_1D: case VariableType.XMM_4F: case VariableType.XMM_2D: if ((Declaration.PreservedXMM & RegisterMask.FromIndex(vdata.RegisterIndex)) == RegisterMask.Zero) cc.SpillXMMVar(vdata); break; default: throw new CompilerException(); } } } } // -------------------------------------------------------------------------- // STEP 4: // // Get temporary register that we can use to pass input function arguments. // Now it's safe to do, because the non-needed variables should be spilled. // -------------------------------------------------------------------------- temporaryGpReg = FindTemporaryGpRegister(cc, true); temporaryXmmReg = FindTemporaryXmmRegister(cc); // If failed to get temporary register then we need just to pick one. if (temporaryGpReg == RegIndex.Invalid) { throw new NotImplementedException(); } if (temporaryXmmReg == RegIndex.Invalid) { // TODO. throw new NotImplementedException(); } // -------------------------------------------------------------------------- // STEP 5: // // Move all remaining arguments to the stack (we can use temporary register). // or allocate it to the primary register. Also move immediates. // -------------------------------------------------------------------------- for (int i = 0; i < argumentsCount; i++) { if (processed[i]) continue; FunctionDeclaration.Argument argType = targs[i]; if (argType._registerIndex != RegIndex.Invalid) continue; Operand operand = _args[i]; if (operand.IsVar) { VarCallRecord rec = _argumentToVarRecord[i]; CompilerVar vdata = compiler.GetVarData(operand.Id); Contract.Assert(vdata != null); MoveSpilledVariableToStack(cc, vdata, argType, temporaryGpReg, temporaryXmmReg); rec.InDone++; processed[i] = true; } else if (operand.IsImm) { Mem dst; switch (argType._variableType) { case VariableType.GPD: dst = Mem.dword_ptr(Register.nsp, -IntPtr.Size + argType._stackOffset); break; case VariableType.GPQ: dst = Mem.qword_ptr(Register.nsp, -IntPtr.Size + argType._stackOffset); break; case VariableType.X87: case VariableType.X87_1D: case VariableType.X87_1F: throw new NotImplementedException(); case VariableType.MM: dst = Mem.mmword_ptr(Register.nsp, -IntPtr.Size + argType._stackOffset); break; case VariableType.XMM: case VariableType.XMM_1D: case VariableType.XMM_1F: case VariableType.XMM_2D: case VariableType.XMM_4F: dst = Mem.xmmword_ptr(Register.nsp, -IntPtr.Size + argType._stackOffset); break; default: throw new NotImplementedException(); } compiler.Mov(dst, (Imm)operand); } } // -------------------------------------------------------------------------- // STEP 6: // // Allocate arguments to registers. // -------------------------------------------------------------------------- bool didWork; do { didWork = false; for (int i = 0; i < argumentsCount; i++) { if (processed[i]) continue; VarCallRecord rsrc = _argumentToVarRecord[i]; Operand osrc = _args[i]; if (!osrc.IsVar) throw new CompilerException(); CompilerVar vsrc = compiler.GetVarData(osrc.Id); Contract.Assert(vsrc != null); FunctionDeclaration.Argument srcArgType = targs[i]; CompilerVar vdst = GetOverlappingVariable(cc, srcArgType); if (vsrc == vdst) { rsrc.InDone++; processed[i] = true; didWork = true; continue; } else if (vdst != null) { VarCallRecord rdst = (VarCallRecord)(vdst.Temp); if (rdst == null) { cc.SpillVar(vdst); vdst = null; } else if (rdst.InDone >= rdst.InCount && (rdst.Flags & VarCallFlags.CALL_OPERAND_REG) == 0) { // Safe to spill. if (rdst.OutCount != 0 || vdst.LastItem == this) cc.UnuseVar(vdst, VariableState.Unused); else cc.SpillVar(vdst); vdst = null; } else { int x = Declaration.FindArgumentByRegisterCode(VariableInfo.GetVariableRegisterCode(vsrc.Type, vsrc.RegisterIndex)); bool doSpill = true; if ((VariableInfo.GetVariableClass(vdst.Type) & VariableClass.GP) != 0) { // Try to emit mov to register which is possible for call() operand. if (x == InvalidValue && (rdst.Flags & VarCallFlags.CALL_OPERAND_REG) != 0) { int rIndex; // The mask which contains registers which are not-preserved // (these that might be clobbered by the callee) and which are // not used to pass function arguments. Each register contained // in this mask is ideal to be used by call() instruction. RegisterMask possibleMask = ~Declaration.PreservedGP & ~Declaration.PassedGP & (RegisterMask.MaskToIndex(RegNum.GP) & ~RegisterMask.FromIndex(RegIndex.Eax)); if (possibleMask != RegisterMask.Zero) { for (rIndex = 0; rIndex < RegNum.GP; rIndex++) { RegisterMask rBit = RegisterMask.FromIndex((RegIndex)rIndex); if ((possibleMask & rBit) != RegisterMask.Zero) { if (cc.State.GP[rIndex] == null) { // This is the best possible solution, the register is // free. We do not need to continue with this loop, the // rIndex will be used by the call(). break; } else { // Wait until the register is freed or try to find another. doSpill = false; didWork = true; } } } } else { // Try to find a register which is free and which is not used // to pass a function argument. possibleMask = Declaration.PreservedGP; for (rIndex = 0; rIndex < RegNum.GP; rIndex++) { RegisterMask rBit = RegisterMask.FromIndex((RegIndex)rIndex); if ((possibleMask & rBit) != RegisterMask.Zero) { // Found one. if (cc.State.GP[rIndex] == null) break; } } } if (rIndex < RegNum.GP) { if (temporaryGpReg == vsrc.RegisterIndex) temporaryGpReg = (RegIndex)rIndex; compiler.Emit(InstructionCode.Mov, Register.gpn((RegIndex)rIndex), Register.gpn(vsrc.RegisterIndex)); cc.State.GP[(int)vsrc.RegisterIndex] = null; cc.State.GP[rIndex] = vsrc; vsrc.RegisterIndex = (RegIndex)rIndex; cc.AllocatedGPRegister((RegIndex)rIndex); doSpill = false; didWork = true; } } // Emit xchg instead of spill/alloc if possible. else if (x != InvalidValue) { FunctionDeclaration.Argument dstArgType = targs[x]; if (VariableInfo.GetVariableInfo(dstArgType._variableType).Class == VariableInfo.GetVariableInfo(srcArgType._variableType).Class) { RegIndex dstIndex = vdst.RegisterIndex; RegIndex srcIndex = vsrc.RegisterIndex; if (srcIndex == dstArgType._registerIndex) { compiler.Emit(InstructionCode.Xchg, Register.gpn(dstIndex), Register.gpd(srcIndex)); if (Util.IsX64) { if (vdst.Type != VariableType.GPD || vsrc.Type != VariableType.GPD) compiler.Emit(InstructionCode.Xchg, Register.gpq(dstIndex), Register.gpq(srcIndex)); else compiler.Emit(InstructionCode.Xchg, Register.gpd(dstIndex), Register.gpd(srcIndex)); } else { compiler.Emit(InstructionCode.Xchg, Register.gpd(dstIndex), Register.gpd(srcIndex)); } cc.State.GP[(int)srcIndex] = vdst; cc.State.GP[(int)dstIndex] = vsrc; vdst.RegisterIndex = srcIndex; vsrc.RegisterIndex = dstIndex; rdst.InDone++; rsrc.InDone++; processed[i] = true; processed[x] = true; doSpill = false; } } } } if (doSpill) { cc.SpillVar(vdst); vdst = null; } } } if (vdst == null) { VarCallRecord rec = (VarCallRecord)(vsrc.Temp); MoveSrcVariableToRegister(cc, vsrc, srcArgType); switch (srcArgType._variableType) { case VariableType.GPD: case VariableType.GPQ: cc.MarkGPRegisterModified(srcArgType._registerIndex); break; case VariableType.MM: cc.MarkMMRegisterModified(srcArgType._registerIndex); break; case VariableType.XMM: case VariableType.XMM_1F: case VariableType.XMM_1D: case VariableType.XMM_4F: case VariableType.XMM_2D: cc.MarkXMMRegisterModified(srcArgType._registerIndex); break; } rec.InDone++; processed[i] = true; } } } while (didWork); // -------------------------------------------------------------------------- // STEP 7: // // Allocate operand used by CALL instruction. // -------------------------------------------------------------------------- for (int i = 0; i < variablesCount; i++) { VarCallRecord r = _variables[i]; if ((r.Flags & VarCallFlags.CALL_OPERAND_REG) != 0 && (r.vdata.RegisterIndex == RegIndex.Invalid)) { // If the register is not allocated and the call form is 'call reg' then // it's possible to keep it in memory. if ((r.Flags & VarCallFlags.CALL_OPERAND_MEM) == 0) { _target = GPVar.FromData(r.vdata).ToMem(); break; } if (temporaryGpReg == RegIndex.Invalid) temporaryGpReg = FindTemporaryGpRegister(cc, true); cc.AllocGPVar(r.vdata, RegisterMask.FromIndex(temporaryGpReg), VariableAlloc.Register | VariableAlloc.Read); } } { Operand[] operands = { _target }; cc.TranslateOperands(operands); _target = operands[0]; } // -------------------------------------------------------------------------- // STEP 8: // // Spill all preserved variables. // -------------------------------------------------------------------------- preserved = Declaration.PreservedGP; for (int i = 0; i < (int)RegNum.GP; i++) { RegisterMask mask = RegisterMask.FromIndex((RegIndex)i); CompilerVar vdata = cc.State.GP[i]; if (vdata != null && (preserved & mask) == RegisterMask.Zero) { VarCallRecord rec = (VarCallRecord)(vdata.Temp); if (rec != null && (rec.OutCount != 0 || (rec.Flags & VarCallFlags.UnuseAfterUse) != 0 || vdata.LastItem == this)) cc.UnuseVar(vdata, VariableState.Unused); else cc.SpillGPVar(vdata); } } preserved = Declaration.PreservedMM; for (int i = 0; i < (int)RegNum.MM; i++) { RegisterMask mask = RegisterMask.FromIndex((RegIndex)i); CompilerVar vdata = cc.State.MM[i]; if (vdata != null && (preserved & mask) == RegisterMask.Zero) { VarCallRecord rec = (VarCallRecord)(vdata.Temp); if (rec != null && (rec.OutCount != 0 || vdata.LastItem == this)) cc.UnuseVar(vdata, VariableState.Unused); else cc.SpillMMVar(vdata); } } preserved = Declaration.PreservedXMM; for (int i = 0; i < (int)RegNum.XMM; i++) { RegisterMask mask = RegisterMask.FromIndex((RegIndex)i); CompilerVar vdata = cc.State.XMM[i]; if (vdata != null && (preserved & mask) == RegisterMask.Zero) { VarCallRecord rec = (VarCallRecord)(vdata.Temp); if (rec != null && (rec.OutCount != 0 || vdata.LastItem == this)) cc.UnuseVar(vdata, VariableState.Unused); else cc.SpillXMMVar(vdata); } } // -------------------------------------------------------------------------- // STEP 9: // // Emit CALL instruction. // -------------------------------------------------------------------------- compiler.Emit(InstructionCode.Call, _target); // Restore the stack offset. if (Declaration.CalleePopsStack) { int s = Declaration.ArgumentsStackSize; if (s != 0) compiler.Emit(InstructionCode.Sub, Register.nsp, (Imm)s); } // -------------------------------------------------------------------------- // STEP 10: // // Prepare others for return value(s) and cleanup. // -------------------------------------------------------------------------- // Clear temp data, see AsmJit::VarData::temp why it's needed. for (int i = 0; i < variablesCount; i++) { VarCallRecord rec = _variables[i]; CompilerVar vdata = rec.vdata; if ((rec.Flags & (VarCallFlags.OUT_EAX | VarCallFlags.OUT_EDX)) != 0) { if ((VariableInfo.GetVariableInfo(vdata.Type).Class & VariableClass.GP) != 0) { cc.AllocGPVar(vdata, (rec.Flags & VarCallFlags.OUT_EAX) != 0 ? RegisterMask.FromIndex(RegIndex.Eax) : RegisterMask.FromIndex(RegIndex.Edx), VariableAlloc.Register | VariableAlloc.Write); vdata.Changed = true; } } if ((rec.Flags & (VarCallFlags.OUT_MM0)) != 0) { if ((VariableInfo.GetVariableInfo(vdata.Type).Class & VariableClass.MM) != 0) { cc.AllocMMVar(vdata, RegisterMask.FromIndex(RegIndex.Mm0), VariableAlloc.Register | VariableAlloc.Write); vdata.Changed = true; } } if ((rec.Flags & (VarCallFlags.OUT_XMM0 | VarCallFlags.OUT_XMM1)) != 0) { if ((VariableInfo.GetVariableInfo(vdata.Type).Class & VariableClass.XMM) != 0) { cc.AllocXMMVar(vdata, RegisterMask.FromIndex((rec.Flags & VarCallFlags.OUT_XMM0) != 0 ? RegIndex.Xmm0 : RegIndex.Xmm1), VariableAlloc.Register | VariableAlloc.Write); vdata.Changed = true; } } if ((rec.Flags & (VarCallFlags.OUT_ST0 | VarCallFlags.OUT_ST1)) != 0) { if ((VariableInfo.GetVariableInfo(vdata.Type).Class & VariableClass.XMM) != 0) { Mem mem = cc.GetVarMem(vdata); cc.UnuseVar(vdata, VariableState.Memory); switch (vdata.Type) { case VariableType.XMM_1F: case VariableType.XMM_4F: { //mem.Size = 4; if (mem.Size != 4) throw new NotImplementedException("Size is now an immutable property."); compiler.Emit(InstructionCode.Fstp, mem); break; } case VariableType.XMM_1D: case VariableType.XMM_2D: { //mem.Size = 8; if (mem.Size != 4) throw new NotImplementedException("Size is now an immutable property."); compiler.Emit(InstructionCode.Fstp, mem); break; } default: { compiler.Comment("*** WARNING: Can't convert float return value to untyped XMM\n"); break; } } } } // Cleanup. vdata.Temp = null; } for (int i = 0; i < variablesCount; i++) { cc.UnuseVarOnEndOfScope(this, _variables[i]); } return Next; }
public bool SetReturn(Operand first, Operand second) { first = first ?? Operand.None; second = second ?? Operand.None; if (!(first.IsNone || first.IsVarMem) || !(second.IsNone || second.IsVarMem)) throw new ArgumentException("The return value storage location must be a variable or memory location."); _ret[0] = first; _ret[1] = second; return true; }
public bool SetReturn(Operand first) { return SetReturn(first, Operand.None); }
public void SetArgument(int i, Operand operand) { if (i < 0) throw new ArgumentOutOfRangeException("i"); if (i >= _functionPrototype.Arguments.Length) throw new ArgumentException(); _args[i] = operand; }