public void EmitLoadAddress(Format12OpCode opCode, LowRegister targetRegister, int target, bool thumbAdjustment) { var offset = target - ((CurrentAddress + 4) & ~2); if (offset >= 0) { Emit(opCode, targetRegister, target); if (thumbAdjustment) { Emit(Format3OpCode.ADD, targetRegister, 1); } } else { //While the Format12 instruction will clear the 1 bit of the PC, this code does not var remainder = -(target - (CurrentAddress + 4)); if (thumbAdjustment) { --remainder; } Emit(Format5OpCode.MOV, targetRegister, Register.PC); while (remainder != 0) { var amountToUse = Math.Min(remainder, 255); Emit(Format3OpCode.SUB, targetRegister, (byte)remainder); remainder -= amountToUse; } } }
public void Emit(Format1OpCode opCode, LowRegister rd, LowRegister rs, byte immediate) { CheckRange(immediate, 0, 31); var fluentComment = opCode.ToHumanReadable().MyConcat(" ", rd, ",", rs, ",#", immediate); EmitHelper(rd, 1, fluentComment, 0, 3, (int)opCode, 2, immediate, 5, rs.Index, 3, rd.Index, 3); }
private static LowRegister ProposeRegisterForValue(IReadable valueResult, LowRegister baseReg, LowRegister offsetReg) { var f = FuncBuilder.Instance; var scratch0 = f.Scratch0; if (baseReg.Index != scratch0.Index) { return(scratch0); } var scratch1 = f.Scratch1; if (offsetReg.Index != scratch1.Index) { return(scratch1); } var reference = valueResult as IReference; if (reference != null) { var lowRegister = reference.GetRepresentation() as LowRegister; if (lowRegister != null) { return(lowRegister); } } return(null); }
private void Format2Helper(Format2OpCode opCode, int immediateBit, LowRegister rd, LowRegister rs, int rnBits, string suffix) { var fluentComment = opCode.ToHumanReadable().MyConcat(" ", rd, ",", rs, ",", suffix); EmitHelper(rd, 2, fluentComment, 3, 5, immediateBit, 1, (int)opCode, 1, rnBits, 3, rs.Index, 3, rd.Index, 3); }
public void Emit(Format9OpCode opCode, LowRegister rsd, LowRegister rb, byte offset) { CheckRange(offset, 0, 31); var multiplier = (opCode == Format9OpCode.LDR || opCode == Format9OpCode.STR) ? "*4" : ""; var fluentComment = opCode.ToHumanReadable().MyConcat(" ", rsd, ",[", rb, ",#", offset + multiplier, "]"); EmitHelper(rsd, 9, fluentComment, 3, 3, (int)opCode, 2, offset, 5, rb.Index, 3, rsd.Index, 3); }
public void Emit(Format11OpCode opCode, LowRegister rd, uint unsigned10BitOffset) { CheckRange((int)unsigned10BitOffset, 0, 1023, 3); var fluentComment = opCode.ToHumanReadable().MyConcat(" ", rd, ",[SP,#", unsigned10BitOffset, "]"); var offsetBits = (unsigned10BitOffset >> 2) & 0xff; EmitHelper(rd, 11, fluentComment, 9, 4, (int)opCode, 1, rd.Index, 3, (int)offsetBits, 8); }
public void Emit(Format12OpCode opCode, LowRegister rd, int target) { var offset = target - ((CurrentAddress + 4) & ~2); CheckRange(offset, 0, 1023, 3); var fluentComment = opCode.ToHumanReadable().MyConcat(" ", rd, ",#0x", ((short)target).ToHex()); var offsetBits = (offset >> 2) & 0xff; EmitHelper(rd, 12, fluentComment, 10, 4, (int)opCode, 1, rd.Index, 3, offsetBits, 8); }
public void Emit(Format6OpCode opCode, LowRegister rd, int target) { var offset = (uint)(target - ((CurrentAddress + 4) & ~2)); CheckRange(target, 0, 1023, 3); var fluentComment = "LDR ".MyConcat(rd, ",[PC, #0x", ((short)target).ToHex(), "]"); var offsetBits = offset >> 2; EmitHelper(rd, 6, fluentComment, 9, 5, rd.Index, 3, (int)offsetBits, 8); }
public FuncBuilderHints RunOptimizer(bool scratch0Used, bool scratch1Used, out bool runAgain) { var liveLocalNonParameterVariableNames = new Hashtable(); var usedRegisterMask = 0; foreach (TerminalName variableName in liveLocalVariableNames.Keys) { var rep = (Representation)pinnedVariables[variableName]; if (rep == null) { liveLocalNonParameterVariableNames.Add(variableName, null); } else { var register = rep as Register; if (register != null) { usedRegisterMask |= 1 << register.Index; } } } var allocableRegisterMask = ((1 << Traits.NumAllocableRegisters) - 1) & ~usedRegisterMask; var result = VariableAllocator.Run(liveLocalNonParameterVariableNames.Keys, allocableRegisterMask, BuilderHints.VariableNameToRepresentation); var allUsedExcludingScratch = usedRegisterMask | result.UsedRegisterMask; //The reason for this is that scratch0 and scratch1 must not interfere with the calling convention var startingPoint = externalMethodWasInvoked ? 4 : 0; LowRegister scratch0 = null; for (var i = startingPoint; i < Traits.NumLowRegisters; ++i) { if ((allUsedExcludingScratch & (1 << i)) == 0) { var register = new LowRegister(i); if (scratch0 == null) { scratch0 = register; } else { var pt = new PassTraits(this.externalMethodWasInvoked, scratch0, register, scratch0Used, scratch1Used, allUsedExcludingScratch, result.AllocatedVariableOffset); runAgain = result.RunAgain || !pt.EqualTo(BuilderHints.PassTraits); return(BuilderHints.CloneSetValues(liveLocalVariableNames.AsReadOnlyDictionary(), result.VariableNameToRepresentation, pt)); } } } throw new Exception("never"); }
public Label LookupOrCreateBranchTo(LowRegister register) { var regIndex = register.Index; var label = registerIndexToLabelWhereItsBXInstructionIs[regIndex]; if (label == null) { label = DeclareStaticLabel("bxTo" + register); registerIndexToLabelWhereItsBXInstructionIs[regIndex] = label; } return(label); }
private void EmitBXInstructions() { for (var registerIndex = 0; registerIndex < registerIndexToLabelWhereItsBXInstructionIs.Length; ++registerIndex) { var label = registerIndexToLabelWhereItsBXInstructionIs[registerIndex]; if (label != null) { label.Mark(); var register = new LowRegister(registerIndex); emitter.Emit(Format5OpCode.BX, null, register); } } }
private LowRegister AllocateRegisterIfPossible(LowRegister register) { if (numberOfRegistersLeft != 0) { if (register != null && TryAllocate(register.Index)) { return(register); } for (var i = 0; i < 32; ++i) { if (TryAllocate(i)) { return(new LowRegister(i)); } } } return(null); }
public PassTraits(bool preserveLinkRegister, LowRegister scratch0, LowRegister scratch1, bool scratch0Used, bool scratch1Used, int registerMaskExcludingScratch, int allocatedVariableOffset) { PreserveLinkRegister = preserveLinkRegister; Scratch0 = scratch0; Scratch1 = scratch1; Scratch0Used = scratch0Used; Scratch1Used = scratch1Used; RegisterMask = registerMaskExcludingScratch; if (Scratch0Used) { RegisterMask |= 1 << (Scratch0.Index); } if (Scratch1Used) { RegisterMask |= 1 << (Scratch1.Index); } AllocatedVariableOffset = allocatedVariableOffset; }
public LowRegister ToRegisterHelper(LowRegister writeableReg) { var emitter = CodeGenerator.Emitter; if (value >= 0 && value < 256) { emitter.Emit(Format3OpCode.MOV, writeableReg, (byte)value); } else if (value < 0 && value > -256) { emitter.Emit(Format3OpCode.MOV, writeableReg, 0); emitter.Emit(Format3OpCode.SUB, writeableReg, (byte)(-value)); } else { var label = CodeGenerator.Instance.AllocateInlineConstant(value); var address = label.GetLabelAddressBestEffort(); emitter.Emit(Format6OpCode.LDR, writeableReg, address); } return(writeableReg); }
public void Emit(Format4OpCode opCode, LowRegister rd, LowRegister rs) { var fluentComment = opCode.ToHumanReadable().MyConcat(" ", rd, ",", rs); EmitHelper(rd, 4, fluentComment, 16, 6, (int)opCode, 4, rs.Index, 3, rd.Index, 3); }
public void Emit(Format3OpCode opCode, LowRegister rd, byte value) { var fluentComment = opCode.ToHumanReadable().MyConcat(" ", rd, ",#", value); EmitHelper(rd, 3, fluentComment, 1, 3, (int)opCode, 2, rd.Index, 3, value, 8); }
public void Invoke(FuncPointer fp, IReference optionalResult, params Expression[] arguments) { var callerCaresAboutResult = !ReferenceEquals(optionalResult, null) && !CanProveIsNeverRead(optionalResult); var g = CodeGenerator.Instance; var emitter = CodeGenerator.Emitter; using (this.OpenScope("invokeMethod")) { this.externalMethodWasInvoked = true; //use the caller's storage (if any) as a place to evaluate the func pointer var temp = this.Declare.Int("temp"); var fpReadable = fp.EvaluateTo(optionalResult ?? temp); using (this.OpenScope("params")) { //SUPER HACK: in order to participate in the function calling convention, I need to //relocate any existing variable stored in R0-R3 to the stack int registerMaskToSpill; int registersToSpillStackConsumption; localVariableToInfo.MigrateR0R3ToStack(out registerMaskToSpill, out registersToSpillStackConsumption); //Spill the affected registers to the stack emitter.EmitIfNecessary(Format14OpCode.PUSH, false, (byte)registerMaskToSpill); StackPointer += registersToSpillStackConsumption; //great! Now make your parameters (which may further adjust the stack) //we only need parameters up to our highest unused argument var parameterLength = arguments.Length; while (parameterLength > 0 && arguments[parameterLength - 1] == null) { --parameterLength; } var stackPointerBeforePush = StackPointer; var parameters = new IReference[parameterLength]; for (var i = parameterLength - 1; i >= 0; --i) { Representation representation; if (i < 4) { representation = new LowRegister(i); } else { StackPointer += -4; representation = new StackWordRelativeToZero(StackPointer); } var vi = new LocalVariableInfo(CreateTerminalName("param" + i), representation); var variable = new IntVariable(); localVariableToInfo.Add(variable, vi); parameters[i] = variable; } var additionalStackToAllocate = StackPointer - stackPointerBeforePush; emitter.EmitIfNecessary(Format13OpCode.ADDSP, additionalStackToAllocate); //Now move your arguments to the function parameters for (var i = 0; i < parameterLength; ++i) { var parameter = parameters[i]; var argument = arguments[i]; if (!ReferenceEquals(argument, null)) { Assignment.SpecialAssignAny(parameter, arguments[i]); } } //FIRE AWAY, BONGO var branchTargetReg = fpReadable.ToRegister(Scratch0); var targetLabel = g.LookupOrCreateBranchTo(branchTargetReg); var address = targetLabel.GetLabelAddressBestEffort(); emitter.Emit(Format19OpCode.BL, address); //woowee! we are back //R0 has a result... stash it in LR so that our pop logic can restore everything else if (callerCaresAboutResult) { emitter.EmitRegisterMoveIfDifferent(Register.LR, Register.R0); } //fix your stack emitter.EmitIfNecessary(Format13OpCode.ADDSP, -additionalStackToAllocate); StackPointer -= additionalStackToAllocate; //fix your registers emitter.EmitIfNecessary(Format14OpCode.POP, false, (byte)registerMaskToSpill); StackPointer -= registersToSpillStackConsumption; } } //if the caller cares about the result, provide it if (callerCaresAboutResult) { optionalResult.FromRegister(Register.LR); } }
public void Emit(Format2OpCode opCode, LowRegister rd, LowRegister rs, byte immediate3Bit) { CheckRange(immediate3Bit, 0, 7); Format2Helper(opCode, 1, rd, rs, immediate3Bit, "#" + immediate3Bit); }
public void Emit(Format2OpCode opCode, LowRegister rd, LowRegister rs, LowRegister rn) { Format2Helper(opCode, 0, rd, rs, rn.Index, rn.ToString()); }
public RegisterOrByte(LowRegister register, byte b) { Register = register; Byte = b; }
public static RegisterOrByte Create(LowRegister register) { return(new RegisterOrByte(register, 0)); }
public RegisterOrByte ToRegisterOrUnsignedConstantHelper(LowRegister writeable, int exclusiveUpperBound) { return(value >= 0 && value < exclusiveUpperBound ? RegisterOrByte.Create((byte)value) : RegisterOrByte.Create(ToRegisterHelper(writeable))); }
public void Emit(Format8OpCode opCode, LowRegister rsd, LowRegister rb, LowRegister ro) { var fluentComment = opCode.ToHumanReadable().MyConcat(" ", rsd, ",[", rb, ",", ro, "]"); EmitHelper(rsd, 7, fluentComment, 5, 4, (int)opCode, 2, 1, 1, ro.Index, 3, rb.Index, 3, rsd.Index, 3); }
private FuncBuilder(Namespace ns, FuncBuilderHints builderHints, ActionOnFuncBuilder action) { Instance = this; this.namespaceAndNextIndex = new NamespaceAndNextIndex(ns, 0); this.BuilderHints = builderHints; var pt = builderHints.PassTraits; this.Scratch0 = pt.Scratch0; this.Scratch1 = pt.Scratch1; var emitter = CodeGenerator.Emitter; var passTraits = BuilderHints.PassTraits; var preserveLr = passTraits.PreserveLinkRegister; var regsToPreserve = passTraits.RegisterMask & 0xf0; emitter.EmitIfNecessary(Format14OpCode.PUSH, preserveLr, (byte)regsToPreserve); if (preserveLr) { StackPointer += -4; } while (regsToPreserve != 0) { StackPointer += -4; regsToPreserve &= (regsToPreserve - 1); } this.EndOfVariableRegion = StackPointer; var avo = passTraits.AllocatedVariableOffset; emitter.EmitIfNecessary(Format13OpCode.ADDSP, avo); StackPointer += avo; this.TheExitLabel = DeclareLabel("leave"); action(this); TheExitLabel.Mark(); StackPointer += -avo; emitter.EmitIfNecessary(Format13OpCode.ADDSP, -avo); regsToPreserve = passTraits.RegisterMask & 0xf0; emitter.EmitIfNecessary(Format14OpCode.POP, false, (byte)regsToPreserve); Register bxRegister; if (passTraits.PreserveLinkRegister) { bxRegister = new LowRegister(1); emitter.EmitIfNecessary(Format14OpCode.POP, false, 1 << 1); } else { bxRegister = Register.LR; } emitter.Emit(Format5OpCode.BX, null, bxRegister); if (inflightUtterances.Count > 0) { var allUtterances = ""; foreach (string utterance in inflightUtterances.Values) { if (allUtterances.Length > 0) { allUtterances += ","; } allUtterances += utterance; } throw new Exception(allUtterances); } }
public static RegisterOrByte Create(LowRegister register) { return new RegisterOrByte(register, 0); }
public RegisterOrByte(LowRegister register, byte b) { Register=register; Byte=b; }