private static void HandleLoadArgumentSystemVAbi( CompilerContext cctx, IntrusiveList <Node> nodes, Node node, Operand[] preservedArgs, Operation operation) { Operand source = operation.GetSource(0); Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind."); int index = source.AsInt32(); int intCount = 0; int vecCount = 0; for (int cIndex = 0; cIndex < index; cIndex++) { OperandType argType = cctx.FuncArgTypes[cIndex]; if (argType.IsInteger()) { intCount++; } else if (argType == OperandType.V128) { intCount += 2; } else { vecCount++; } } bool passOnReg; if (source.Type.IsInteger()) { passOnReg = intCount < CallingConvention.GetIntArgumentsOnRegsCount(); } else if (source.Type == OperandType.V128) { passOnReg = intCount + 1 < CallingConvention.GetIntArgumentsOnRegsCount(); } else { passOnReg = vecCount < CallingConvention.GetVecArgumentsOnRegsCount(); } if (passOnReg) { Operand dest = operation.Destination; if (preservedArgs[index] == null) { if (dest.Type == OperandType.V128) { // V128 is a struct, we pass each half on a GPR if possible. Operand pArg = Local(OperandType.V128); Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64); Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64); Operation copyL = new Operation(Instruction.VectorCreateScalar, pArg, argLReg); Operation copyH = new Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1)); cctx.Cfg.Entry.Operations.AddFirst(copyH); cctx.Cfg.Entry.Operations.AddFirst(copyL); preservedArgs[index] = pArg; } else { Operand pArg = Local(dest.Type); Operand argReg = dest.Type.IsInteger() ? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type) : Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type); Operation copyOp = new Operation(Instruction.Copy, pArg, argReg); cctx.Cfg.Entry.Operations.AddFirst(copyOp); preservedArgs[index] = pArg; } } Operation argCopyOp = new Operation(Instruction.Copy, dest, preservedArgs[index]); nodes.AddBefore(node, argCopyOp); Delete(nodes, node, operation); } else { // TODO: Pass on stack. } }
public void Sequence(List <Operation> sequence) { Dictionary <Register, Register> locations = new Dictionary <Register, Register>(); Dictionary <Register, Register> sources = new Dictionary <Register, Register>(); Dictionary <Register, OperandType> types = new Dictionary <Register, OperandType>(); Queue <Register> pendingQueue = new Queue <Register>(); Queue <Register> readyQueue = new Queue <Register>(); foreach (Copy copy in _copies) { locations[copy.Source] = copy.Source; sources[copy.Dest] = copy.Source; types[copy.Dest] = copy.Type; pendingQueue.Enqueue(copy.Dest); } foreach (Copy copy in _copies) { // If the destination is not used anywhere, we can assign it immediately. if (!locations.ContainsKey(copy.Dest)) { readyQueue.Enqueue(copy.Dest); } } while (pendingQueue.TryDequeue(out Register current)) { Register copyDest; Register origSource; Register copySource; while (readyQueue.TryDequeue(out copyDest)) { origSource = sources[copyDest]; copySource = locations[origSource]; OperandType type = types[copyDest]; EmitCopy(sequence, GetRegister(copyDest, type), GetRegister(copySource, type)); locations[origSource] = copyDest; if (origSource == copySource && sources.ContainsKey(origSource)) { readyQueue.Enqueue(origSource); } } copyDest = current; origSource = sources[copyDest]; copySource = locations[origSource]; if (copyDest != copySource) { OperandType type = types[copyDest]; type = type.IsInteger() ? OperandType.I64 : OperandType.V128; EmitXorSwap(sequence, GetRegister(copyDest, type), GetRegister(copySource, type)); locations[origSource] = copyDest; Register swapOther = copySource; if (copyDest != locations[sources[copySource]]) { // Find the other swap destination register. // To do that, we search all the pending registers, and pick // the one where the copy source register is equal to the // current destination register being processed (copyDest). foreach (Register pending in pendingQueue) { // Is this a copy of pending <- copyDest? if (copyDest == locations[sources[pending]]) { swapOther = pending; break; } } } // The value that was previously at "copyDest" now lives on // "copySource" thanks to the swap, now we need to update the // location for the next copy that is supposed to copy the value // that used to live on "copyDest". locations[sources[swapOther]] = copySource; } } }