private static bool IsLongConst(Operand operand) { long value = operand.Type == OperandType.I32 ? operand.AsInt32() : operand.AsInt64(); return(!ConstFitsOnS32(value)); }
private static Operand GetIntConst(Operand value) { if (value.Type == OperandType.FP32) { return(Const(value.AsInt32())); } else if (value.Type == OperandType.FP64) { return(Const(value.AsInt64())); } return(value); }
private static int GetOperandId(Operand operand) { if (operand.Kind == OperandKind.LocalVariable) { return(operand.AsInt32()); } else if (operand.Kind == OperandKind.Register) { return(GetRegisterId(operand.GetRegister())); } else { throw new ArgumentException($"Invalid operand kind \"{operand.Kind}\"."); } }
// Try to propagate Compare operations into their BranchIf uses, when these BranchIf uses are in the form // of: // // - BranchIf %x, 0x0, Equal ;; i.e BranchIfFalse %x // - BranchIf %x, 0x0, NotEqual ;; i.e BranchIfTrue %x // // The commutative property of Equal and NotEqual is taken into consideration as well. // // For example: // // %x = Compare %a, %b, comp // BranchIf %x, 0x0, NotEqual // // => // // BranchIf %a, %b, comp static bool IsZeroBranch(Operation operation, out Comparison compType) { compType = Comparison.Equal; if (operation.Instruction != Instruction.BranchIf) { return(false); } Operand src1 = operation.GetSource(0); Operand src2 = operation.GetSource(1); Operand comp = operation.GetSource(2); compType = (Comparison)comp.AsInt32(); return((src1.Kind == OperandKind.Constant && src1.Value == 0) || (src2.Kind == OperandKind.Constant && src2.Value == 0)); }
public AllocationResult RunPass( ControlFlowGraph cfg, StackAllocator stackAlloc, RegisterMasks regMasks) { int intUsedRegisters = 0; int vecUsedRegisters = 0; int intFreeRegisters = regMasks.IntAvailableRegisters; int vecFreeRegisters = regMasks.VecAvailableRegisters; BlockInfo[] blockInfo = new BlockInfo[cfg.Blocks.Count]; List <LocalInfo> locInfo = new List <LocalInfo>(); for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--) { BasicBlock block = cfg.PostOrderBlocks[index]; int intFixedRegisters = 0; int vecFixedRegisters = 0; bool hasCall = false; foreach (Node node in block.Operations) { if (node is Operation operation && operation.Instruction == Instruction.Call) { hasCall = true; } for (int srcIndex = 0; srcIndex < node.SourcesCount; srcIndex++) { Operand source = node.GetSource(srcIndex); if (source.Kind == OperandKind.LocalVariable) { locInfo[source.AsInt32() - 1].SetBlockIndex(block.Index); } } for (int dstIndex = 0; dstIndex < node.DestinationsCount; dstIndex++) { Operand dest = node.GetDestination(dstIndex); if (dest.Kind == OperandKind.LocalVariable) { LocalInfo info; if (dest.Value != 0) { info = locInfo[dest.AsInt32() - 1]; } else { dest.NumberLocal(locInfo.Count + 1); info = new LocalInfo(dest.Type, UsesCount(dest)); locInfo.Add(info); } info.SetBlockIndex(block.Index); } else if (dest.Kind == OperandKind.Register) { if (dest.Type.IsInteger()) { intFixedRegisters |= 1 << dest.GetRegister().Index; } else { vecFixedRegisters |= 1 << dest.GetRegister().Index; } } } } blockInfo[block.Index] = new BlockInfo(hasCall, intFixedRegisters, vecFixedRegisters); } int sequence = 0; for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--) { BasicBlock block = cfg.PostOrderBlocks[index]; BlockInfo blkInfo = blockInfo[block.Index]; int intLocalFreeRegisters = intFreeRegisters & ~blkInfo.IntFixedRegisters; int vecLocalFreeRegisters = vecFreeRegisters & ~blkInfo.VecFixedRegisters; int intCallerSavedRegisters = blkInfo.HasCall ? regMasks.IntCallerSavedRegisters : 0; int vecCallerSavedRegisters = blkInfo.HasCall ? regMasks.VecCallerSavedRegisters : 0; int intSpillTempRegisters = SelectSpillTemps( intCallerSavedRegisters & ~blkInfo.IntFixedRegisters, intLocalFreeRegisters); int vecSpillTempRegisters = SelectSpillTemps( vecCallerSavedRegisters & ~blkInfo.VecFixedRegisters, vecLocalFreeRegisters); intLocalFreeRegisters &= ~(intSpillTempRegisters | intCallerSavedRegisters); vecLocalFreeRegisters &= ~(vecSpillTempRegisters | vecCallerSavedRegisters); for (LinkedListNode <Node> llNode = block.Operations.First; llNode != null; llNode = llNode.Next) { Node node = llNode.Value; int intLocalUse = 0; int vecLocalUse = 0; for (int srcIndex = 0; srcIndex < node.SourcesCount; srcIndex++) { Operand source = node.GetSource(srcIndex); if (source.Kind != OperandKind.LocalVariable) { continue; } LocalInfo info = locInfo[source.AsInt32() - 1]; info.UseCount++; Debug.Assert(info.UseCount <= info.Uses); if (info.Register != -1) { node.SetSource(srcIndex, Register(info.Register, source.Type.ToRegisterType(), source.Type)); if (info.UseCount == info.Uses && !info.PreAllocated) { if (source.Type.IsInteger()) { intLocalFreeRegisters |= 1 << info.Register; } else { vecLocalFreeRegisters |= 1 << info.Register; } } } else { Operand temp = info.Temp; if (temp == null || info.Sequence != sequence) { temp = source.Type.IsInteger() ? GetSpillTemp(source, intSpillTempRegisters, ref intLocalUse) : GetSpillTemp(source, vecSpillTempRegisters, ref vecLocalUse); info.Sequence = sequence; info.Temp = temp; } node.SetSource(srcIndex, temp); Operation fillOp = new Operation(Instruction.Fill, temp, Const(info.SpillOffset)); block.Operations.AddBefore(llNode, fillOp); } } int intLocalAsg = 0; int vecLocalAsg = 0; for (int dstIndex = 0; dstIndex < node.DestinationsCount; dstIndex++) { Operand dest = node.GetDestination(dstIndex); if (dest.Kind != OperandKind.LocalVariable) { continue; } LocalInfo info = locInfo[dest.AsInt32() - 1]; if (info.UseCount == 0 && !info.PreAllocated) { int mask = dest.Type.IsInteger() ? intLocalFreeRegisters : vecLocalFreeRegisters; if (info.IsBlockLocal && mask != 0) { int selectedReg = BitUtils.LowestBitSet(mask); info.Register = selectedReg; if (dest.Type.IsInteger()) { intLocalFreeRegisters &= ~(1 << selectedReg); intUsedRegisters |= 1 << selectedReg; } else { vecLocalFreeRegisters &= ~(1 << selectedReg); vecUsedRegisters |= 1 << selectedReg; } } else { info.Register = -1; info.SpillOffset = stackAlloc.Allocate(dest.Type.GetSizeInBytes()); } } info.UseCount++; Debug.Assert(info.UseCount <= info.Uses); if (info.Register != -1) { node.SetDestination(dstIndex, Register(info.Register, dest.Type.ToRegisterType(), dest.Type)); } else { Operand temp = info.Temp; if (temp == null || info.Sequence != sequence) { temp = dest.Type.IsInteger() ? GetSpillTemp(dest, intSpillTempRegisters, ref intLocalAsg) : GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg); info.Sequence = sequence; info.Temp = temp; } node.SetDestination(dstIndex, temp); Operation spillOp = new Operation(Instruction.Spill, null, Const(info.SpillOffset), temp); llNode = block.Operations.AddAfter(llNode, spillOp); } } sequence++; intUsedRegisters |= intLocalAsg | intLocalUse; vecUsedRegisters |= vecLocalAsg | vecLocalUse; } } return(new AllocationResult(intUsedRegisters, vecUsedRegisters, stackAlloc.TotalSize)); }
private void DumpNode(Node node) { for (int index = 0; index < node.DestinationsCount; index++) { DumpOperand(node.GetDestination(index)); if (index == node.DestinationsCount - 1) { _builder.Append(" = "); } else { _builder.Append(", "); } } switch (node) { case PhiNode phi: _builder.Append("Phi "); for (int index = 0; index < phi.SourcesCount; index++) { _builder.Append('('); DumpBlockName(phi.GetBlock(index)); _builder.Append(": "); DumpOperand(phi.GetSource(index)); _builder.Append(')'); if (index < phi.SourcesCount - 1) { _builder.Append(", "); } } break; case Operation operation: bool comparison = false; _builder.Append(operation.Instruction); if (operation.Instruction == Instruction.Extended) { var intrinOp = (IntrinsicOperation)operation; _builder.Append('.').Append(intrinOp.Intrinsic); } else if (operation.Instruction == Instruction.BranchIf || operation.Instruction == Instruction.Compare) { comparison = true; } _builder.Append(' '); for (int index = 0; index < operation.SourcesCount; index++) { Operand source = operation.GetSource(index); if (index < operation.SourcesCount - 1) { DumpOperand(source); _builder.Append(", "); } else if (comparison) { _builder.Append((Comparison)source.AsInt32()); } else { DumpOperand(source); } } break; } if (_symbolNames.Count == 1) { _builder.Append(" ;; ").Append(_symbolNames.First().Value); } else if (_symbolNames.Count > 1) { _builder.Append(" ;;"); foreach ((ulong value, string name) in _symbolNames) { _builder.Append(" 0x").Append(value.ToString("X")).Append(" = ").Append(name); } } // Reset the set of symbols for the next Node we're going to dump. _symbolNames.Clear(); }
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. } }
private static void HandleLoadArgumentWindowsAbi( 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 retArgs = cctx.FuncReturnType == OperandType.V128 ? 1 : 0; int index = source.AsInt32() + retArgs; if (index < CallingConvention.GetArgumentsOnRegsCount()) { Operand dest = operation.Destination; if (preservedArgs[index] == null) { Operand argReg, pArg; if (dest.Type.IsInteger()) { argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type); pArg = Local(dest.Type); } else if (dest.Type == OperandType.V128) { argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), OperandType.I64); pArg = Local(OperandType.I64); } else { argReg = Xmm(CallingConvention.GetVecArgumentRegister(index), dest.Type); pArg = Local(dest.Type); } Operation copyOp = new Operation(Instruction.Copy, pArg, argReg); cctx.Cfg.Entry.Operations.AddFirst(copyOp); preservedArgs[index] = pArg; } Operation argCopyOp = new Operation(dest.Type == OperandType.V128 ? Instruction.Load : Instruction.Copy, dest, preservedArgs[index]); nodes.AddBefore(node, argCopyOp); Delete(nodes, node, operation); } else { // TODO: Pass on stack. } }
public AllocationResult RunPass( ControlFlowGraph cfg, StackAllocator stackAlloc, RegisterMasks regMasks) { int intUsedRegisters = 0; int vecUsedRegisters = 0; int intFreeRegisters = regMasks.IntAvailableRegisters; int vecFreeRegisters = regMasks.VecAvailableRegisters; BlockInfo[] blockInfo = new BlockInfo[cfg.Blocks.Count]; List <LocalInfo> locInfo = new List <LocalInfo>(); for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--) { BasicBlock block = cfg.PostOrderBlocks[index]; int intFixedRegisters = 0; int vecFixedRegisters = 0; bool hasCall = false; for (Node node = block.Operations.First; node != null; node = node.ListNext) { if (node is Operation operation && operation.Instruction == Instruction.Call) { hasCall = true; } for (int srcIndex = 0; srcIndex < node.SourcesCount; srcIndex++) { Operand source = node.GetSource(srcIndex); if (source.Kind == OperandKind.LocalVariable) { locInfo[source.AsInt32() - 1].SetBlockIndex(block.Index); } else if (source.Kind == OperandKind.Memory) { MemoryOperand memOp = (MemoryOperand)source; if (memOp.BaseAddress != null) { locInfo[memOp.BaseAddress.AsInt32() - 1].SetBlockIndex(block.Index); } if (memOp.Index != null) { locInfo[memOp.Index.AsInt32() - 1].SetBlockIndex(block.Index); } } } for (int dstIndex = 0; dstIndex < node.DestinationsCount; dstIndex++) { Operand dest = node.GetDestination(dstIndex); if (dest.Kind == OperandKind.LocalVariable) { LocalInfo info; if (dest.Value != 0) { info = locInfo[dest.AsInt32() - 1]; } else { dest.NumberLocal(locInfo.Count + 1); info = new LocalInfo(dest.Type, UsesCount(dest)); locInfo.Add(info); } info.SetBlockIndex(block.Index); } else if (dest.Kind == OperandKind.Register) { if (dest.Type.IsInteger()) { intFixedRegisters |= 1 << dest.GetRegister().Index; } else { vecFixedRegisters |= 1 << dest.GetRegister().Index; } } } } blockInfo[block.Index] = new BlockInfo(hasCall, intFixedRegisters, vecFixedRegisters); } int sequence = 0; for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--) { BasicBlock block = cfg.PostOrderBlocks[index]; BlockInfo blkInfo = blockInfo[block.Index]; int intLocalFreeRegisters = intFreeRegisters & ~blkInfo.IntFixedRegisters; int vecLocalFreeRegisters = vecFreeRegisters & ~blkInfo.VecFixedRegisters; int intCallerSavedRegisters = blkInfo.HasCall ? regMasks.IntCallerSavedRegisters : 0; int vecCallerSavedRegisters = blkInfo.HasCall ? regMasks.VecCallerSavedRegisters : 0; int intSpillTempRegisters = SelectSpillTemps( intCallerSavedRegisters & ~blkInfo.IntFixedRegisters, intLocalFreeRegisters); int vecSpillTempRegisters = SelectSpillTemps( vecCallerSavedRegisters & ~blkInfo.VecFixedRegisters, vecLocalFreeRegisters); intLocalFreeRegisters &= ~(intSpillTempRegisters | intCallerSavedRegisters); vecLocalFreeRegisters &= ~(vecSpillTempRegisters | vecCallerSavedRegisters); for (Node node = block.Operations.First; node != null; node = node.ListNext) { int intLocalUse = 0; int vecLocalUse = 0; void AllocateRegister(Operand source, MemoryOperand memOp, int srcIndex) { LocalInfo info = locInfo[source.AsInt32() - 1]; info.UseCount++; Debug.Assert(info.UseCount <= info.Uses); if (info.Register != -1) { Operand reg = Register(info.Register, source.Type.ToRegisterType(), source.Type); if (memOp != null) { if (srcIndex == 0) { memOp.BaseAddress = reg; } else /* if (srcIndex == 1) */ { memOp.Index = reg; } } else { node.SetSource(srcIndex, reg); } if (info.UseCount == info.Uses && !info.PreAllocated) { if (source.Type.IsInteger()) { intLocalFreeRegisters |= 1 << info.Register; } else { vecLocalFreeRegisters |= 1 << info.Register; } } } else if (node is Operation operation && operation.Instruction == Instruction.Copy) { Operation fillOp = Operation(Instruction.Fill, node.Destination, Const(info.SpillOffset)); block.Operations.AddBefore(node, fillOp); block.Operations.Remove(node); node = fillOp; }