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 override LowRegister ToRegister(LowRegister storageReg) { var emitter=CodeGenerator.Emitter; var address=StorageLabel.GetLabelAddressBestEffort(); emitter.Emit(Format6OpCode.LDR, storageReg, address); return storageReg; }
public static LowRegister ToRegister(this IReadable self, LowRegister writeableReg) { //special case for IntConstant var ic=self as IntConstant; return !ReferenceEquals(ic, null) ? ic.ToRegisterHelper(writeableReg) : ((IReference)self).GetRepresentation().ToRegister(writeableReg); }
public static RegisterOrByte ToRegisterOrUnsignedConstant(this IReadable self, int exclusiveUpperBound, LowRegister writeableReg) { //special case for IntConstant var ic=self as IntConstant; return !ReferenceEquals(ic, null) ? ic.ToRegisterOrUnsignedConstantHelper(writeableReg, exclusiveUpperBound) : RegisterOrByte.Create(((IReference)self).GetRepresentation().ToRegister(writeableReg)); }
public static LowRegister ToRegister(this IReadable self, LowRegister writeableReg) { //special case for IntConstant var ic = self as IntConstant; return(!ReferenceEquals(ic, null) ? ic.ToRegisterHelper(writeableReg) : ((IReference)self).GetRepresentation().ToRegister(writeableReg)); }
public override LowRegister ToRegister(LowRegister storageReg) { var emitter = CodeGenerator.Emitter; var address = StorageLabel.GetLabelAddressBestEffort(); emitter.Emit(Format6OpCode.LDR, storageReg, address); return(storageReg); }
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 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 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 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 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 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); } } }
public abstract LowRegister ToRegister(LowRegister proposal);
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 static RegisterOrByte ToRegisterOrUnsignedConstant(this IReadable self, int exclusiveUpperBound, LowRegister writeableReg) { //special case for IntConstant var ic = self as IntConstant; return(!ReferenceEquals(ic, null) ? ic.ToRegisterOrUnsignedConstantHelper(writeableReg, exclusiveUpperBound) : RegisterOrByte.Create(((IReference)self).GetRepresentation().ToRegister(writeableReg))); }
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 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 static RegisterOrByte ToRegisterOrUint5(this IReadable self, LowRegister writeableReg) { return(self.ToRegisterOrUnsignedConstant(32, writeableReg)); }
public void Emit(Format2OpCode opCode, LowRegister rd, LowRegister rs, LowRegister rn) { Format2Helper(opCode, 0, rd, rs, rn.Index, rn.ToString()); }
public override LowRegister ToRegister(LowRegister proposal) { throw new NotImplementedException(); }
public override LowRegister ToRegister(LowRegister proposal) { return(this); }
public override LowRegister ToRegister(LowRegister proposal) { CodeGenerator.Emitter.Emit(Format11OpCode.LDR, proposal, (uint)CalculateOffset()); return proposal; }
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 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 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 override LowRegister ToRegister(LowRegister proposal) { return this; }
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; }
public void Emit(Format2OpCode opCode, LowRegister rd, LowRegister rs, byte immediate3Bit) { CheckRange(immediate3Bit, 0, 7); Format2Helper(opCode, 1, rd, rs, immediate3Bit, "#"+immediate3Bit); }
public RegisterOrByte ToRegisterOrUnsignedConstantHelper(LowRegister writeable, int exclusiveUpperBound) { return value>=0 && value<exclusiveUpperBound ? RegisterOrByte.Create((byte)value) : RegisterOrByte.Create(ToRegisterHelper(writeable)); }
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 static RegisterOrByte ToRegisterOrUint5(this IReadable self, LowRegister writeableReg) { return self.ToRegisterOrUnsignedConstant(32, writeableReg); }
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; }
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 override LowRegister ToRegister(LowRegister proposal) { CodeGenerator.Emitter.Emit(Format11OpCode.LDR, proposal, (uint)CalculateOffset()); return(proposal); }