<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Apr 22, 2015 at 2:07 AM, Clément Bera <span dir="ltr">&lt;<a href="mailto:bera.clement@gmail.com" target="_blank">bera.clement@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> <br><div dir="ltr">Eliot here&#39;s a good example to stress the register allocation:<div><br></div><div><div>Integer&gt;&gt;#regStress</div><div><span style="white-space:pre-wrap">        </span>| t t2 |</div><div><span style="white-space:pre-wrap">        </span>t := self yourself.</div><div><span style="white-space:pre-wrap">        </span>t2 := self + 1.</div><div><span style="white-space:pre-wrap">        </span>^ { t == t2 .   t == t2 .  t == t2 .  t == t2 .  t == t2 .  t == t2 .  t == t2 }</div></div><div><br></div><div>I think the resulting machine code method is beautiful, it needs to spill only when it runs out of registers :-). Of course it makes sense mainly when you use inlined bytecodes instead of only #==.</div><div><br></div><div>Some extra register moves are done because the JIT does remember if a temporary value is currently in a register (It moves each time the temp t to the same register whereas the register value is not changed). Maybe we should add a feature that remembers if temporaries are currently in a register, and if so, when doing push temp, only push the register directly in the simStack, and in case of temporary store or stack flush the register associated with a temp is not valid anymore somehow...<br></div></div></blockquote><div><br></div><div>Yes, that would be ideal.  This would benefit from a full merge of the simstack as we discussed because otherwise the lifetime is likely to be limited.  I&#39;ve had the vague desire for stack slots to be mapped to registers, for example with the floating-point stack-to-registert mapping we&#39;ve discussed.  Before I&#39;d though that to do it for normal temporaries the Cogit would have to decide how many registers it wanted to allocate to temporary variables and how many to expressions, for example in the initial scan pass.  But that&#39;s a poor idea and unlikely to work well.  If you can instead do it as part of normal register allocation that would (as I said earlier) be ideal.  This is very exciting.</div><div><br></div><div>Let me know when you want the full merge support.</div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">2015-04-22 10:08 GMT+02:00  <span dir="ltr">&lt;<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a>&gt;</span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:<br>
<a href="http://source.squeak.org/VMMaker/VMMaker.oscog-cb.1236.mcz" target="_blank">http://source.squeak.org/VMMaker/VMMaker.oscog-cb.1236.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: VMMaker.oscog-cb.1236<br>
Author: cb<br>
Time: 22 April 2015, 10:07:41.028 am<br>
UUID: cf4af270-9dfa-4f2a-b84c-0cdb3c5f4913<br>
Ancestors: VMMaker.oscog-tpr.1235<br>
<br>
changed the names of register allocation methods for more explict names, for instance, allocateOneReg -&gt; allocateRegForStackTop<br>
<br>
Fixed a bug where not the best register was allocated in #== (was allocating a reg based on stackTop value instead of ssValue: 1)<br>
<br>
=============== Diff against VMMaker.oscog-tpr.1235 ===============<br>
<br>
Item was changed:<br>
  ----- Method: SistaStackToRegisterMappingCogit&gt;&gt;genExtJumpIfNotInstanceOfBehaviorsOrPopBytecode (in category &#39;bytecode generators&#39;) -----<br>
  genExtJumpIfNotInstanceOfBehaviorsOrPopBytecode<br>
        &quot;SistaV1: *     254             11111110        kkkkkkkk        jjjjjjjj                branch If Not Instance Of Behavior/Array Of Behavior kkkkkkkk (+ Extend A * 256, where Extend A &gt;= 0) distance jjjjjjjj (+ Extend B * 256, where Extend B &gt;= 0)&quot;<br>
<br>
        | reg literal distance targetFixUp |<br>
<br>
+       reg := self allocateRegForStackTopEntry.<br>
-       reg := self allocateOneRegister.<br>
        self ssTop popToReg: reg.<br>
<br>
        literal := self getLiteral: (extA * 256 + byte1).<br>
        extA := 0.<br>
        distance := extB * 256 + byte2.<br>
        extB := 0.<br>
<br>
        targetFixUp := (self ensureFixupAt: bytecodePC + 3 + distance - initialPC) asUnsignedInteger.<br>
<br>
        (objectMemory isArrayNonImm: literal)<br>
                ifTrue: [objectRepresentation branchIf: reg notInstanceOfBehaviors: literal target: targetFixUp]<br>
                ifFalse: [objectRepresentation branchIf: reg notInstanceOfBehavior: literal target: targetFixUp].<br>
<br>
        self genPopStackBytecode.<br>
<br>
        ^0!<br>
<br>
Item was changed:<br>
  ----- Method: SistaStackToRegisterMappingCogit&gt;&gt;genJumpIf:to: (in category &#39;bytecode generator support&#39;) -----<br>
  genJumpIf: boolean to: targetBytecodePC<br>
        &quot;The heart of performance counting in Sista.  Conditional branches are 6 times less<br>
         frequent than sends and can provide basic block frequencies (send counters can&#39;t).<br>
         Each conditional has a 32-bit counter split into an upper 16 bits counting executions<br>
         and a lower half counting untaken executions of the branch.  Executing the branch<br>
         decrements the upper half, tripping if the count goes negative.  Not taking the branch<br>
         decrements the lower half.  N.B. We *do not* eliminate dead branches (true ifTrue:/true ifFalse:)<br>
         so that scanning for send and branch data is simplified and that branch data is correct.&quot;<br>
        &lt;inline: false&gt;<br>
        | desc ok counterAddress countTripped retry counterReg |<br>
        &lt;var: #ok type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #desc type: #&#39;CogSimStackEntry *&#39;&gt;<br>
        &lt;var: #retry type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #countTripped type: #&#39;AbstractInstruction *&#39;&gt;<br>
<br>
        (coInterpreter isOptimizedMethod: methodObj) ifTrue: [ ^ super genJumpIf: boolean to: targetBytecodePC ].<br>
<br>
        self ssFlushTo: simStackPtr - 1.<br>
        desc := self ssTop.<br>
        self ssPop: 1.<br>
        desc popToReg: TempReg.<br>
<br>
+       counterReg := self allocateAnyReg.<br>
-       counterReg := self allocateRegisterNotConflictingWith: 0.<br>
        counterAddress := counters + ((self sizeof: #sqInt) * counterIndex).<br>
        counterIndex := counterIndex + 1.<br>
        self flag: &#39;will need to use MoveAw32:R: if 64 bits&#39;.<br>
        self assert: objectMemory wordSize = CounterBytes.<br>
        retry := self MoveAw: counterAddress R: counterReg.<br>
        self SubCq: 16r10000 R: counterReg. &quot;Count executed&quot;<br>
        &quot;Don&#39;t write back if we trip; avoids wrapping count back to initial value, and if we trip we don&#39;t execute.&quot;<br>
        countTripped := self JumpCarry: 0.<br>
        self MoveR: counterReg Aw: counterAddress. &quot;write back&quot;<br>
<br>
        &quot;Cunning trick by LPD.  If true and false are contiguous subtract the smaller.<br>
         Correct result is either 0 or the distance between them.  If result is not 0 or<br>
         their distance send mustBeBoolean.&quot;<br>
        self assert: (objectMemory objectAfter: objectMemory falseObject) = objectMemory trueObject.<br>
        self annotate: (self SubCw: boolean R: TempReg) objRef: boolean.<br>
        self JumpZero: (self ensureFixupAt: targetBytecodePC - initialPC).<br>
<br>
        self SubCq: 1 R: counterReg. &quot;Count untaken&quot;<br>
        self MoveR: counterReg Aw: counterAddress. &quot;write back&quot;<br>
<br>
        self CmpCq: (boolean == objectMemory falseObject<br>
                                        ifTrue: [objectMemory trueObject - objectMemory falseObject]<br>
                                        ifFalse: [objectMemory falseObject - objectMemory trueObject])<br>
                R: TempReg.<br>
        ok := self JumpZero: 0.<br>
        self MoveCq: 0 R: counterReg. &quot;if counterReg is 0 this is a mustBeBoolean, not a counter trip.&quot;<br>
        countTripped jmpTarget:<br>
                (self CallRT: (boolean == objectMemory falseObject<br>
                                                ifTrue: [ceSendMustBeBooleanAddFalseTrampoline]<br>
                                                ifFalse: [ceSendMustBeBooleanAddTrueTrampoline])).<br>
        &quot;If we&#39;re in an image which hasn&#39;t got the Sista code loaded then the ceCounterTripped:<br>
         trampoline will return directly to machine code, returning the boolean.  So the code should<br>
         jump back to the retry point. The trampoline makes sure that TempReg has been reloaded.&quot;<br>
        self annotateBytecode: self Label.<br>
        self Jump: retry.<br>
        ok jmpTarget: self Label.<br>
        ^0!<br>
<br>
Item was changed:<br>
  ----- Method: SistaStackToRegisterMappingCogit&gt;&gt;genSpecialSelectorComparison (in category &#39;bytecode generators&#39;) -----<br>
  genSpecialSelectorComparison<br>
        &quot;Override to count inlined branches if followed by a conditional branch.<br>
         We borrow the following conditional branch&#39;s counter and when about to<br>
         inline the comparison we decrement the counter (without writing it back)<br>
         and if it trips simply abort the inlining, falling back to the normal send which<br>
         will then continue to the conditional branch which will trip and enter the abort.&quot;<br>
        | nextPC postBranchPC targetBytecodePC primDescriptor branchDescriptor nExts<br>
          rcvrIsInt argIsInt rcvrInt argInt result jumpNotSmallInts inlineCAB annotateInst<br>
          counterAddress countTripped counterReg |<br>
        &lt;var: #countTripped type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #primDescriptor type: #&#39;BytecodeDescriptor *&#39;&gt;<br>
        &lt;var: #jumpNotSmallInts type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #branchDescriptor type: #&#39;BytecodeDescriptor *&#39;&gt;<br>
<br>
        (coInterpreter isOptimizedMethod: methodObj) ifTrue: [ ^ super genSpecialSelectorComparison ].<br>
<br>
        self ssFlushTo: simStackPtr - 2.<br>
        primDescriptor := self generatorAt: byte0.<br>
        argIsInt := self ssTop type = SSConstant<br>
                                 and: [objectMemory isIntegerObject: (argInt := self ssTop constant)].<br>
        rcvrIsInt := (self ssValue: 1) type = SSConstant<br>
                                 and: [objectMemory isIntegerObject: (rcvrInt := (self ssValue: 1) constant)].<br>
<br>
        &quot;short-cut the jump if operands are SmallInteger constants.&quot;<br>
        (argIsInt and: [rcvrIsInt]) ifTrue:<br>
                [self cCode: &#39;&#39; inSmalltalk: &quot;In Simulator ints are unsigned...&quot;<br>
                                [rcvrInt := objectMemory integerValueOf: rcvrInt.<br>
                                argInt := objectMemory integerValueOf: argInt].<br>
                 primDescriptor opcode caseOf: {<br>
                        [JumpLess]                              -&gt; [result := rcvrInt &lt; argInt].<br>
                        [JumpLessOrEqual]               -&gt; [result := rcvrInt &lt;= argInt].<br>
                        [JumpGreater]                   -&gt; [result := rcvrInt &gt; argInt].<br>
                        [JumpGreaterOrEqual]    -&gt; [result := rcvrInt &gt;= argInt].<br>
                        [JumpZero]                              -&gt; [result := rcvrInt = argInt].<br>
                        [JumpNonZero]                   -&gt; [result := rcvrInt ~= argInt] }.<br>
                 &quot;Must enter any annotatedConstants into the map&quot;<br>
                 self annotateBytecodeIfAnnotated: (self ssValue: 1).<br>
                 self annotateBytecodeIfAnnotated: self ssTop.<br>
                 &quot;Must annotate the bytecode for correct pc mapping.&quot;<br>
                 self ssPop: 2.<br>
                 ^self ssPushAnnotatedConstant: (result<br>
                                                                                        ifTrue: [objectMemory trueObject]<br>
                                                                                        ifFalse: [objectMemory falseObject])].<br>
<br>
        nextPC := bytecodePC + primDescriptor numBytes.<br>
        nExts := 0.<br>
        [branchDescriptor := self generatorAt: (objectMemory fetchByte: nextPC ofObject: methodObj) + (byte0 bitAnd: 256).<br>
         branchDescriptor isExtension] whileTrue:<br>
                [nExts := nExts + 1.<br>
                 nextPC := nextPC + branchDescriptor numBytes].<br>
        &quot;Only interested in inlining if followed by a conditional branch.&quot;<br>
        inlineCAB := branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse].<br>
        &quot;Further, only interested in inlining = and ~= if there&#39;s a SmallInteger constant involved.<br>
         The relational operators successfully statically predict SmallIntegers; the equality operators do not.&quot;<br>
        (inlineCAB and: [primDescriptor opcode = JumpZero or: [primDescriptor opcode = JumpNonZero]]) ifTrue:<br>
                [inlineCAB := argIsInt or: [rcvrIsInt]].<br>
        inlineCAB ifFalse:<br>
                [^self genSpecialSelectorSend].<br>
<br>
        targetBytecodePC := nextPC<br>
                                                        + branchDescriptor numBytes<br>
                                                        + (self spanFor: branchDescriptor at: nextPC exts: nExts in: methodObj).<br>
        postBranchPC := nextPC + branchDescriptor numBytes.<br>
        argIsInt<br>
                ifTrue:<br>
                        [(self ssValue: 1) popToReg: ReceiverResultReg.<br>
                         annotateInst := self ssTop annotateUse.<br>
                         self ssPop: 2.<br>
                         self MoveR: ReceiverResultReg R: TempReg]<br>
                ifFalse:<br>
                        [self marshallSendArguments: 1.<br>
                         self MoveR: Arg0Reg R: TempReg.<br>
                         rcvrIsInt ifFalse:<br>
                                [objectRepresentation isSmallIntegerTagNonZero<br>
                                        ifTrue: [self AndR: ReceiverResultReg R: TempReg]<br>
                                        ifFalse: [self OrR: ReceiverResultReg R: TempReg]]].<br>
        jumpNotSmallInts := objectRepresentation genJumpNotSmallIntegerInScratchReg: TempReg.<br>
<br>
+       counterReg := self allocateRegNotConflictingWith: (self registerMaskFor: ReceiverResultReg and: Arg0Reg). &quot;Use this as the count reg, can&#39;t conflict with the registers for the arg and the receiver&quot;<br>
-       counterReg := self allocateRegisterNotConflictingWith: (self registerMaskFor: ReceiverResultReg and: Arg0Reg). &quot;Use this as the count reg, can&#39;t conflict with the registers for the arg and the receiver&quot;<br>
        self ssAllocateRequiredReg: counterReg. &quot;Use this as the count reg.&quot;<br>
        counterAddress := counters + ((self sizeof: #sqInt) * counterIndex).<br>
        self flag: &#39;will need to use MoveAw32:R: if 64 bits&#39;.<br>
        self assert: objectMemory wordSize = CounterBytes.<br>
        self MoveAw: counterAddress R: counterReg.<br>
        self SubCq: 16r10000 R: counterReg. &quot;Count executed&quot;<br>
        &quot;If counter trips simply abort the inlined comparison and send continuing to the following<br>
         branch *without* writing back.  A double decrement will not trip the second time.&quot;<br>
        countTripped := self JumpCarry: 0.<br>
        self MoveR: counterReg Aw: counterAddress. &quot;write back&quot;<br>
<br>
        argIsInt<br>
                ifTrue: [annotateInst<br>
                                        ifTrue: [self annotateBytecode: (self CmpCq: argInt R: ReceiverResultReg)]<br>
                                        ifFalse: [self CmpCq: argInt R: ReceiverResultReg]]<br>
                ifFalse: [self CmpR: Arg0Reg R: ReceiverResultReg].<br>
        &quot;Cmp is weird/backwards so invert the comparison.  Further since there is a following conditional<br>
         jump bytecode define non-merge fixups and leave the cond bytecode to set the mergeness.&quot;<br>
        self gen: (branchDescriptor isBranchTrue<br>
                                ifTrue: [primDescriptor opcode]<br>
                                ifFalse: [self inverseBranchFor: primDescriptor opcode])<br>
                operand: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.<br>
        self SubCq: 1 R: counterReg. &quot;Count untaken&quot;<br>
        self MoveR: counterReg Aw: counterAddress. &quot;write back&quot;<br>
        self Jump: (self ensureNonMergeFixupAt: postBranchPC - initialPC).<br>
        countTripped jmpTarget: (jumpNotSmallInts jmpTarget: self Label).<br>
        argIsInt ifTrue:<br>
                [self MoveCq: argInt R: Arg0Reg].<br>
        ^self genMarshalledSend: (coInterpreter specialSelector: byte0 - self firstSpecialSelectorBytecodeOffset)<br>
                numArgs: 1<br>
                sendTable: ordinarySendTrampolines!<br>
<br>
Item was changed:<br>
  ----- Method: SistaStackToRegisterMappingCogit&gt;&gt;genSpecialSelectorEqualsEqualsWithForwarders (in category &#39;bytecode generators&#39;) -----<br>
  genSpecialSelectorEqualsEqualsWithForwarders<br>
        &quot;Override to count inlined branches if followed by a conditional branch.<br>
         We borrow the following conditional branch&#39;s counter and when about to<br>
         inline the comparison we decrement the counter (without writing it back)<br>
         and if it trips simply abort the inlining, falling back to the normal send which<br>
         will then continue to the conditional branch which will trip and enter the abort.&quot;<br>
        | nextPC postBranchPC targetBytecodePC primDescriptor branchDescriptor nExts label counterReg fixup<br>
          counterAddress countTripped unforwardArg unforwardRcvr argReg rcvrReg regMask |<br>
        &lt;var: #fixup type: #&#39;BytecodeFixup *&#39;&gt;<br>
        &lt;var: #countTripped type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #primDescriptor type: #&#39;BytecodeDescriptor *&#39;&gt;<br>
        &lt;var: #branchDescriptor type: #&#39;BytecodeDescriptor *&#39;&gt;<br>
<br>
        ((coInterpreter isOptimizedMethod: methodObj) or: [needsFrame not]) ifTrue: [ ^ super genSpecialSelectorEqualsEquals ].<br>
<br>
        primDescriptor := self generatorAt: byte0.<br>
        regMask := 0.<br>
<br>
        nextPC := bytecodePC + primDescriptor numBytes.<br>
        nExts := 0.<br>
        [branchDescriptor := self generatorAt: (objectMemory fetchByte: nextPC ofObject: methodObj) + (byte0 bitAnd: 256).<br>
         branchDescriptor isExtension] whileTrue:<br>
                [nExts := nExts + 1.<br>
                 nextPC := nextPC + branchDescriptor numBytes].<br>
<br>
        (branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifTrue:<br>
                [self ssFlushTo: simStackPtr - 2].<br>
<br>
        unforwardRcvr := (objectRepresentation isUnannotatableConstant: (self ssValue: 1)) not.<br>
        unforwardArg := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
<br>
        &quot;if the rcvr or the arg is an annotable constant, we need to push it to a register<br>
        else the forwarder check can&#39;t jump back to the comparison after unforwarding the constant&quot;<br>
        unforwardArg<br>
                ifTrue:<br>
                        [unforwardRcvr<br>
                                ifTrue:<br>
+                                       [self allocateRegForStackTopTwoEntriesInto: [:rTop :rNext| argReg := rTop. rcvrReg := rNext].<br>
-                                       [self allocateTwoRegistersInto: [:rTop :rNext| argReg := rTop. rcvrReg := rNext].<br>
                                         self ssTop popToReg: argReg.<br>
                                         (self ssValue:1) popToReg: rcvrReg]<br>
                                ifFalse:<br>
+                                       [argReg := self allocateRegForStackTopEntry.<br>
-                                       [argReg := self allocateOneRegister.<br>
                                         self ssTop popToReg: argReg]]<br>
                ifFalse:<br>
                        [self assert: unforwardRcvr.<br>
+                        rcvrReg := self allocateRegForStackEntryAt: 1.<br>
-                        rcvrReg := self allocateOneRegister.<br>
                         (self ssValue:1) popToReg: rcvrReg].<br>
<br>
        argReg ifNotNil: [ regMask := self registerMaskFor: regMask ].<br>
        rcvrReg ifNotNil: [ regMask := regMask bitOr: (self registerMaskFor: rcvrReg) ].<br>
<br>
        &quot;Here we can use Cq because the constant does not need to be annotated&quot;<br>
        self assert: (unforwardArg not or: [argReg notNil]).<br>
        self assert: (unforwardRcvr not or: [rcvrReg notNil]).<br>
<br>
        &quot;Only interested in inlining if followed by a conditional branch.&quot;<br>
        (branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifFalse:<br>
                [^ self genDirectEqualsEqualsArg: unforwardArg rcvr: unforwardRcvr argReg: argReg rcvrReg: rcvrReg].<br>
<br>
        targetBytecodePC := nextPC<br>
                                                        + branchDescriptor numBytes<br>
                                                        + (self spanFor: branchDescriptor at: nextPC exts: nExts in: methodObj).<br>
        postBranchPC := nextPC + branchDescriptor numBytes.<br>
<br>
+       counterReg := self allocateRegNotConflictingWith: regMask. &quot;Use this as the count reg, can&#39;t conflict with the registers for the arg and the receiver of #==.&quot;<br>
-       counterReg := self allocateRegisterNotConflictingWith: regMask. &quot;Use this as the count reg, can&#39;t conflict with the registers for the arg and the receiver of #==.&quot;<br>
        counterAddress := counters + ((self sizeof: #sqInt) * counterIndex).<br>
        self flag: &#39;will need to use MoveAw32:R: if 64 bits&#39;.<br>
        self assert: objectMemory wordSize = CounterBytes.<br>
        self MoveAw: counterAddress R: counterReg.<br>
        self SubCq: 16r10000 R: counterReg. &quot;Count executed&quot;<br>
        &quot;If counter trips simply abort the inlined comparison and send continuing to the following<br>
         branch *without* writing back.  A double decrement will not trip the second time.&quot;<br>
        countTripped := self JumpCarry: 0.<br>
        self MoveR: counterReg Aw: counterAddress. &quot;write back&quot;<br>
<br>
        self assert: (unforwardArg or: [ unforwardRcvr ]).<br>
<br>
        label := self Label.<br>
<br>
        unforwardArg<br>
                ifFalse: [ self CmpCq: self ssTop constant R: rcvrReg ]<br>
                ifTrue: [ unforwardRcvr<br>
                        ifFalse: [ self CmpCq: (self ssValue: 1) constant R: argReg ]<br>
                        ifTrue: [ self CmpR: argReg R: rcvrReg ] ].<br>
<br>
        self ssPop: 2.<br>
        branchDescriptor isBranchTrue ifTrue:<br>
                [ fixup := self ensureNonMergeFixupAt: postBranchPC - initialPC.<br>
                self JumpZero: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.<br>
                unforwardArg ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: argReg scratchReg: TempReg jumpBackTo: label  ].<br>
                unforwardRcvr ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: rcvrReg scratchReg: TempReg jumpBackTo: label ] ].<br>
        branchDescriptor isBranchFalse ifTrue:<br>
                [ fixup := self ensureNonMergeFixupAt: targetBytecodePC - initialPC.<br>
                self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.<br>
                unforwardArg ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: argReg scratchReg: TempReg jumpBackTo: label ].<br>
                unforwardRcvr ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: rcvrReg scratchReg: TempReg jumpBackTo: label ] ].<br>
        self ssPop: -2.<br>
<br>
        &quot;the jump has not been taken and forwarders have been followed.&quot;<br>
        self SubCq: 1 R: counterReg. &quot;Count untaken&quot;<br>
        self MoveR: counterReg Aw: counterAddress. &quot;write back&quot;<br>
        self Jump: (self ensureNonMergeFixupAt: postBranchPC - initialPC).<br>
<br>
        countTripped jmpTarget: self Label.<br>
<br>
        &quot;inlined version of #== ignoring the branchDescriptor if the counter trips to have normal state for the optimizer&quot;<br>
        ^ self genDirectEqualsEqualsArg: unforwardArg rcvr: unforwardRcvr argReg: argReg rcvrReg: rcvrReg!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit&gt;&gt;allocateAnyReg (in category &#39;simulation stack&#39;) -----<br>
+ allocateAnyReg<br>
+       &lt; inline: true &gt;<br>
+       ^ self allocateRegNotConflictingWith: 0!<br>
<br>
Item was removed:<br>
- ----- Method: StackToRegisterMappingCogit&gt;&gt;allocateOneRegister (in category &#39;simulation stack&#39;) -----<br>
- allocateOneRegister<br>
-<br>
-       self ssTop type = SSRegister ifTrue: [ ^ self ssTop register].<br>
-<br>
-       ^ self allocateRegisterNotConflictingWith: 0<br>
-       !<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit&gt;&gt;allocateRegForStackEntryAt: (in category &#39;simulation stack&#39;) -----<br>
+ allocateRegForStackEntryAt: index<br>
+       &lt;inline: true&gt;<br>
+       &lt;var: #stackEntry type: #&#39;CogSimStackEntry *&#39;&gt;<br>
+       | stackEntry |<br>
+       stackEntry := self ssValue: index.<br>
+       stackEntry type = SSRegister ifTrue: [ ^ stackEntry register].<br>
+       ^ self allocateAnyReg<br>
+       !<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit&gt;&gt;allocateRegForStackTopEntry (in category &#39;simulation stack&#39;) -----<br>
+ allocateRegForStackTopEntry<br>
+       ^ self allocateRegForStackEntryAt: 0<br>
+       !<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit&gt;&gt;allocateRegForStackTopThreeEntriesInto:thirdIsReceiver: (in category &#39;simulation stack&#39;) -----<br>
+ allocateRegForStackTopThreeEntriesInto: trinaryBlock thirdIsReceiver: thirdIsReceiver<br>
+       &lt;inline: true&gt;<br>
+       | topRegistersMask rTop rNext rThird |<br>
+<br>
+       topRegistersMask := 0.<br>
+<br>
+       (self ssTop type = SSRegister and: [ thirdIsReceiver not or: [ self ssTop register ~= ReceiverResultReg ] ]) ifTrue:<br>
+               [ topRegistersMask := self registerMaskFor: (rTop := self ssTop register)].<br>
+       ((self ssValue: 1) type = SSRegister and: [ thirdIsReceiver not or: [ (self ssValue: 1) register ~= ReceiverResultReg ] ]) ifTrue:<br>
+               [ topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: (rNext := (self ssValue: 1) register))].<br>
+       ((self ssValue: 2) type = SSRegister and: [thirdIsReceiver not or: [ (self ssValue: 2) register = ReceiverResultReg ] ]) ifTrue:<br>
+               [ topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: (rThird := (self ssValue: 2) register))].<br>
+<br>
+       rThird ifNil:<br>
+               [ thirdIsReceiver<br>
+                       ifTrue:<br>
+                               [ rThird := ReceiverResultReg.  &quot;Free ReceiverResultReg if it was not free&quot;<br>
+                               (self register: ReceiverResultReg isInMask: self liveRegisters) ifTrue:<br>
+                                       [ self ssAllocateRequiredReg: ReceiverResultReg ].<br>
+                               optStatus isReceiverResultRegLive: false ]<br>
+                       ifFalse: [ rThird := self allocateRegNotConflictingWith: topRegistersMask ].<br>
+               topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: rThird) ].<br>
+<br>
+       rTop ifNil: [<br>
+               rTop := self allocateRegNotConflictingWith: topRegistersMask.<br>
+               topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: rTop) ].<br>
+<br>
+       rNext ifNil: [ rNext := self allocateRegNotConflictingWith: topRegistersMask ].<br>
+<br>
+       ^ trinaryBlock value: rTop value: rNext value: rThird<br>
+<br>
+       !<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit&gt;&gt;allocateRegForStackTopTwoEntriesInto: (in category &#39;simulation stack&#39;) -----<br>
+ allocateRegForStackTopTwoEntriesInto: binaryBlock<br>
+       &lt;inline: true&gt;<br>
+       | topRegistersMask rTop rNext |<br>
+<br>
+       topRegistersMask := 0.<br>
+<br>
+       self ssTop type = SSRegister ifTrue:<br>
+               [ topRegistersMask := self registerMaskFor: (rTop := self ssTop register)].<br>
+       (self ssValue: 1) type = SSRegister ifTrue:<br>
+               [ topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: (rNext := (self ssValue: 1) register))].<br>
+<br>
+       rTop ifNil: [ rTop := self allocateRegNotConflictingWith: topRegistersMask ].<br>
+<br>
+       rNext ifNil: [ rNext := self allocateRegNotConflictingWith: (self registerMaskFor: rTop) ].<br>
+<br>
+       ^ binaryBlock value: rTop value: rNext<br>
+<br>
+       !<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit&gt;&gt;allocateRegNotConflictingWith: (in category &#39;simulation stack&#39;) -----<br>
+ allocateRegNotConflictingWith: regMask<br>
+       | reg |<br>
+       &quot;if there&#39;s a free register, use it&quot;<br>
+       reg := backEnd availableRegisterOrNilFor: (self liveRegisters bitOr: regMask).<br>
+       reg ifNil: &quot;No free register, choose one that does not conflict with regMask&quot;<br>
+               [reg := self freeAnyRegNotConflictingWith: regMask].<br>
+       reg = ReceiverResultReg ifTrue: &quot;If we&#39;ve allocated RcvrResultReg, it&#39;s not live anymore&quot;<br>
+               [ optStatus isReceiverResultRegLive: false ].<br>
+       ^ reg!<br>
<br>
Item was removed:<br>
- ----- Method: StackToRegisterMappingCogit&gt;&gt;allocateRegisterNotConflictingWith: (in category &#39;simulation stack&#39;) -----<br>
- allocateRegisterNotConflictingWith: regMask<br>
-       | reg |<br>
-       &quot;if there&#39;s a free register, use it&quot;<br>
-       reg := backEnd availableRegisterOrNilFor: (self liveRegisters bitOr: regMask).<br>
-       reg ifNil: &quot;No free register, choose one that does not conflict with regMask&quot;<br>
-               [reg := self freeRegisterNotConflictingWith: regMask].<br>
-       reg = ReceiverResultReg ifTrue: &quot;If we&#39;ve allocated RcvrResultReg, it&#39;s not live anymore&quot;<br>
-               [ optStatus isReceiverResultRegLive: false ].<br>
-       ^ reg!<br>
<br>
Item was removed:<br>
- ----- Method: StackToRegisterMappingCogit&gt;&gt;allocateThreeRegistersInto:thirdIsReceiver: (in category &#39;simulation stack&#39;) -----<br>
- allocateThreeRegistersInto: trinaryBlock thirdIsReceiver: thirdIsReceiver<br>
-       &lt;inline: true&gt;<br>
-       | topRegistersMask rTop rNext rThird |<br>
-<br>
-       topRegistersMask := 0.<br>
-<br>
-       (self ssTop type = SSRegister and: [ thirdIsReceiver not or: [ self ssTop register ~= ReceiverResultReg ] ]) ifTrue:<br>
-               [ topRegistersMask := self registerMaskFor: (rTop := self ssTop register)].<br>
-       ((self ssValue: 1) type = SSRegister and: [ thirdIsReceiver not or: [ (self ssValue: 1) register ~= ReceiverResultReg ] ]) ifTrue:<br>
-               [ topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: (rNext := (self ssValue: 1) register))].<br>
-       ((self ssValue: 2) type = SSRegister and: [thirdIsReceiver not or: [ (self ssValue: 2) register = ReceiverResultReg ] ]) ifTrue:<br>
-               [ topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: (rThird := (self ssValue: 2) register))].<br>
-<br>
-       rThird ifNil:<br>
-               [ thirdIsReceiver<br>
-                       ifTrue:<br>
-                               [ rThird := ReceiverResultReg.  &quot;Free ReceiverResultReg if it was not free&quot;<br>
-                               (self register: ReceiverResultReg isInMask: self liveRegisters) ifTrue:<br>
-                                       [ self ssAllocateRequiredReg: ReceiverResultReg ].<br>
-                               optStatus isReceiverResultRegLive: false ]<br>
-                       ifFalse: [ rThird := self allocateRegisterNotConflictingWith: topRegistersMask ].<br>
-               topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: rThird) ].<br>
-<br>
-       rTop ifNil: [<br>
-               rTop := self allocateRegisterNotConflictingWith: topRegistersMask.<br>
-               topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: rTop) ].<br>
-<br>
-       rNext ifNil: [ rNext := self allocateRegisterNotConflictingWith: topRegistersMask ].<br>
-<br>
-       ^ trinaryBlock value: rTop value: rNext value: rThird<br>
-<br>
-       !<br>
<br>
Item was removed:<br>
- ----- Method: StackToRegisterMappingCogit&gt;&gt;allocateTwoRegistersInto: (in category &#39;simulation stack&#39;) -----<br>
- allocateTwoRegistersInto: binaryBlock<br>
-       &lt;inline: true&gt;<br>
-       | topRegistersMask rTop rNext |<br>
-<br>
-       topRegistersMask := 0.<br>
-<br>
-       self ssTop type = SSRegister ifTrue:<br>
-               [ topRegistersMask := self registerMaskFor: (rTop := self ssTop register)].<br>
-       (self ssValue: 1) type = SSRegister ifTrue:<br>
-               [ topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: (rNext := (self ssValue: 1) register))].<br>
-<br>
-       rTop ifNil: [ rTop := self allocateRegisterNotConflictingWith: topRegistersMask ].<br>
-<br>
-       rNext ifNil: [ rNext := self allocateRegisterNotConflictingWith: (self registerMaskFor: rTop) ].<br>
-<br>
-       ^ binaryBlock value: rTop value: rNext<br>
-<br>
-       !<br>
<br>
Item was removed:<br>
- ----- Method: StackToRegisterMappingCogit&gt;&gt;availableRegister (in category &#39;simulation stack&#39;) -----<br>
- availableRegister<br>
-       | reg |<br>
-       reg := self availableRegisterOrNil.<br>
-       reg ifNil: [self error: &#39;no available register&#39;].<br>
-       ^reg!<br>
<br>
Item was removed:<br>
- ----- Method: StackToRegisterMappingCogit&gt;&gt;availableRegisterOrNil (in category &#39;simulation stack&#39;) -----<br>
- availableRegisterOrNil<br>
-       ^backEnd availableRegisterOrNilFor: self liveRegisters!<br>
<br>
Item was added:<br>
+ ----- Method: StackToRegisterMappingCogit&gt;&gt;freeAnyRegNotConflictingWith: (in category &#39;simulation stack&#39;) -----<br>
+ freeAnyRegNotConflictingWith: regMask<br>
+       &quot;Spill the closest register on stack not conflicting with regMask.<br>
+       Assertion Failure if regMask has already all the registers&quot;<br>
+       &lt;var: #desc type: #&#39;CogSimStackEntry *&#39;&gt;<br>
+       | reg index |<br>
+       index := simSpillBase max: 0.<br>
+       [reg isNil and: [index &lt; simStackPtr] ] whileTrue:<br>
+               [ | desc |<br>
+                desc := self simStackAt: index.<br>
+                desc type = SSRegister ifTrue:<br>
+                       [ (regMask anyMask: (self registerMaskFor: desc register)) ifFalse:<br>
+                               [ reg := desc register ] ].<br>
+                index := index + 1].<br>
+       self assert: reg notNil.<br>
+       self ssAllocateRequiredReg: reg.<br>
+       ^reg!<br>
<br>
Item was removed:<br>
- ----- Method: StackToRegisterMappingCogit&gt;&gt;freeRegisterNotConflictingWith: (in category &#39;simulation stack&#39;) -----<br>
- freeRegisterNotConflictingWith: regMask<br>
-       &quot;Spill the closest register on stack not conflicting with regMask.<br>
-       Assertion Failure if regMask has already all the registers&quot;<br>
-       &lt;var: #desc type: #&#39;CogSimStackEntry *&#39;&gt;<br>
-       | reg index |<br>
-       index := simSpillBase max: 0.<br>
-       [reg isNil and: [index &lt; simStackPtr] ] whileTrue:<br>
-               [ | desc |<br>
-                desc := self simStackAt: index.<br>
-                desc type = SSRegister ifTrue:<br>
-                       [ (regMask anyMask: (self registerMaskFor: desc register)) ifFalse:<br>
-                               [ reg := desc register ] ].<br>
-                index := index + 1].<br>
-       self assert: reg notNil.<br>
-       self ssAllocateRequiredReg: reg.<br>
-       ^reg!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit&gt;&gt;genBinaryConstOpVarInlinePrimitive: (in category &#39;inline primitive generators&#39;) -----<br>
  genBinaryConstOpVarInlinePrimitive: prim<br>
        &quot;Const op var version of binary inline primitives.&quot;<br>
        &quot;SistaV1: 248           11111000        iiiiiiii                mjjjjjjj                Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.<br>
         See EncoderForSistaV1&#39;s class comment and StackInterpreter&gt;&gt;#binaryInlinePrimitive:&quot;<br>
        | ra val untaggedVal adjust |<br>
+       ra := self allocateRegForStackTopEntry.<br>
-       ra := self allocateOneRegister.<br>
        self ssTop popToReg: ra.<br>
        self ssPop: 1.<br>
        val := self ssTop constant.<br>
        self ssPop: 1.<br>
        untaggedVal := val - objectMemory smallIntegerTag.<br>
        prim caseOf: {<br>
                &quot;0 through 6, +, -, *, /, //, \\, quo:, SmallInteger op SmallInteger =&gt; SmallInteger, no overflow&quot;<br>
                [0]     -&gt;      [self AddCq: untaggedVal R: ra].<br>
                [1]     -&gt;      [self MoveCq: val R: TempReg.<br>
                                 self SubR: ra R: TempReg.<br>
                                 objectRepresentation genAddSmallIntegerTagsTo: TempReg.<br>
                                 self MoveR: TempReg R: ra].<br>
                [2]     -&gt;      [objectRepresentation genRemoveSmallIntegerTagsInScratchReg: ra.<br>
                                 self MoveCq: (objectMemory integerValueOf: val) R: TempReg.<br>
                                 self MulR: TempReg R: ra.<br>
                                 objectRepresentation genAddSmallIntegerTagsTo: ra].<br>
<br>
                &quot;2016 through 2019, bitAnd:, bitOr:, bitXor, bitShift:, SmallInteger op SmallInteger =&gt; SmallInteger, no overflow&quot;<br>
<br>
                &quot;2032   through 2037, &gt;, &lt;, &gt;=, &lt;=. =, ~=, SmallInteger op SmallInteger =&gt; Boolean (flags?? then in jump bytecodes if ssTop is a flags value, just generate the instruction!!!!)&quot;<br>
                &quot;CmpCqR is SubRCq so everything is reversed, but because no CmpRCq things are reversed again and we invert the sense of the jumps.&quot;<br>
                [32] -&gt; [ self CmpCq: val R: ra.<br>
                                self genBinaryInlineComparison: JumpLess opFalse: JumpGreaterOrEqual destReg: ra ].<br>
                [33] -&gt; [ self CmpCq: val R: ra.<br>
                                self genBinaryInlineComparison: JumpGreater opFalse: JumpLessOrEqual destReg: ra ].<br>
                [34] -&gt; [ self CmpCq: val R: ra.<br>
                                self genBinaryInlineComparison: JumpLessOrEqual opFalse: JumpGreater destReg: ra ].<br>
                [35] -&gt; [ self CmpCq: val R: ra.<br>
                                self genBinaryInlineComparison: JumpGreaterOrEqual opFalse: JumpLess destReg: ra ].<br>
                [36] -&gt; [ self CmpCq: val R: ra.<br>
                                self genBinaryInlineComparison: JumpZero opFalse: JumpNonZero destReg: ra ].<br>
                [37] -&gt; [ self CmpCq: val R: ra.<br>
                                self genBinaryInlineComparison: JumpNonZero opFalse: JumpZero destReg: ra ].<br>
<br>
                &quot;2064   through 2068, Pointer Object&gt;&gt;at:, Byte Object&gt;&gt;at:, Short16 Word Object&gt;&gt;at: LongWord32 Object&gt;&gt;at: Quad64Word Object&gt;&gt;at:. obj op 0-rel SmallInteger =&gt; oop&quot;<br>
                [64] -&gt; [objectRepresentation genConvertSmallIntegerToIntegerInReg: ra.<br>
                                adjust := (objectMemory baseHeaderSize &gt;&gt; objectMemory shiftForWord) - 1. &quot;shift by baseHeaderSize and then move from 1 relative to zero relative&quot;<br>
                                adjust ~= 0 ifTrue: [ self AddCq: adjust R: ra. ].<br>
                                self genMoveConstant: val R: TempReg.<br>
                                self MoveXwr: ra R: TempReg R: ra].<br>
                [65] -&gt; [objectRepresentation genConvertSmallIntegerToIntegerInReg: ra.<br>
                                adjust := objectMemory baseHeaderSize - 1. &quot;shift by baseHeaderSize and then move from 1 relative to zero relative&quot;<br>
                                self AddCq: adjust R: ra.<br>
                                self genMoveConstant: val R: TempReg.<br>
                                self MoveXbr: ra R: TempReg R: ra.<br>
                                objectRepresentation genConvertIntegerToSmallIntegerInReg: ra]<br>
        }<br>
        otherwise: [^EncounteredUnknownBytecode].<br>
        self ssPushRegister: ra.<br>
        ^0!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit&gt;&gt;genBinaryVarOpConstInlinePrimitive: (in category &#39;inline primitive generators&#39;) -----<br>
  genBinaryVarOpConstInlinePrimitive: prim<br>
        &quot;Var op const version of inline binary inline primitives.&quot;<br>
        &quot;SistaV1: 248           11111000        iiiiiiii                mjjjjjjj                Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.<br>
         See EncoderForSistaV1&#39;s class comment and StackInterpreter&gt;&gt;#binaryInlinePrimitive:&quot;<br>
        | rr val untaggedVal |<br>
        val := self ssTop constant.<br>
        self ssPop: 1.<br>
+       rr := self allocateRegForStackTopEntry.<br>
-       rr := self allocateOneRegister.<br>
        self ssTop popToReg: rr.<br>
        self ssPop: 1.<br>
        untaggedVal := val - objectMemory smallIntegerTag.<br>
        prim caseOf: {<br>
                &quot;0 through 6, +, -, *, /, //, \\, quo:, SmallInteger op SmallInteger =&gt; SmallInteger, no overflow&quot;<br>
                [0]     -&gt;      [self AddCq: untaggedVal R: rr].<br>
                [1]     -&gt;      [self SubCq: untaggedVal R: rr ].<br>
                [2]     -&gt;      [self flag: &#39;could use MulCq:R&#39;.<br>
                                 objectRepresentation genShiftAwaySmallIntegerTagsInScratchReg: rr.<br>
                                 self MoveCq: (objectMemory integerValueOf: val) R: TempReg.<br>
                                 self MulR: TempReg R: rr.<br>
                                 objectRepresentation genAddSmallIntegerTagsTo: rr].<br>
<br>
                &quot;2016 through 2019, bitAnd:, bitOr:, bitXor, bitShift:, SmallInteger op SmallInteger =&gt; SmallInteger, no overflow&quot;<br>
<br>
                &quot;2032   through 2037, &gt;, &lt;, &gt;=, &lt;=. =, ~=, SmallInteger op SmallInteger =&gt; Boolean (flags?? then in jump bytecodes if ssTop is a flags value, just generate the instruction!!!!)&quot;<br>
                &quot;CmpCqR is SubRCq so everything is reversed.&quot;<br>
                [32] -&gt; [ self CmpCq: val R: rr.<br>
                                self genBinaryInlineComparison: JumpGreater opFalse: JumpLessOrEqual destReg: rr ].<br>
                [33] -&gt; [ self CmpCq: val R: rr.<br>
                                self genBinaryInlineComparison: JumpLess opFalse: JumpGreaterOrEqual destReg: rr ].<br>
                [34] -&gt; [ self CmpCq: val R: rr.<br>
                                self genBinaryInlineComparison: JumpGreaterOrEqual opFalse: JumpLess destReg: rr ].<br>
                [35] -&gt; [ self CmpCq: val R: rr.<br>
                                self genBinaryInlineComparison: JumpLessOrEqual opFalse: JumpGreater destReg: rr ].<br>
                [36] -&gt; [ self CmpCq: val R: rr.<br>
                                self genBinaryInlineComparison: JumpZero opFalse: JumpNonZero destReg: rr ].<br>
                [37] -&gt; [ self CmpCq: val R: rr.<br>
                                self genBinaryInlineComparison: JumpNonZero opFalse: JumpZero destReg: rr ].<br>
<br>
                &quot;2064   through 2068, Pointer Object&gt;&gt;at:, Byte Object&gt;&gt;at:, Short16 Word Object&gt;&gt;at: LongWord32 Object&gt;&gt;at: Quad64Word Object&gt;&gt;at:. obj op 0-rel SmallInteger =&gt; oop&quot;<br>
                [64] -&gt; [objectRepresentation genLoadSlot: (objectMemory integerValueOf: val) - 1 sourceReg: rr destReg: rr].<br>
                [65] -&gt; [self MoveCq: (objectMemory integerValueOf: val) + objectMemory baseHeaderSize - 1 R: TempReg.<br>
                                self MoveXbr: TempReg R: rr R: rr.<br>
                                objectRepresentation genConvertIntegerToSmallIntegerInReg: rr]<br>
<br>
        }<br>
        otherwise: [^EncounteredUnknownBytecode].<br>
        self ssPushRegister: rr.<br>
        ^0!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit&gt;&gt;genBinaryVarOpVarInlinePrimitive: (in category &#39;inline primitive generators&#39;) -----<br>
  genBinaryVarOpVarInlinePrimitive: prim<br>
        &quot;Var op var version of binary inline primitives.&quot;<br>
        &quot;SistaV1: 248           11111000        iiiiiiii                mjjjjjjj                Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.<br>
         See EncoderForSistaV1&#39;s class comment and StackInterpreter&gt;&gt;#binaryInlinePrimitive:&quot;<br>
        | ra rr adjust |<br>
+       self allocateRegForStackTopTwoEntriesInto: [:rTop :rNext | ra := rTop. rr := rNext ].<br>
-       self allocateTwoRegistersInto: [:rTop :rNext | ra := rTop. rr := rNext ].<br>
        self ssTop popToReg: ra.<br>
        self ssPop: 1.<br>
        self ssTop popToReg: rr.<br>
        self ssPop: 1.<br>
        prim caseOf: {<br>
                &quot;0 through 6, +, -, *, /, //, \\, quo:, SmallInteger op SmallInteger =&gt; SmallInteger, no overflow&quot;<br>
                [0]     -&gt;      [objectRepresentation genRemoveSmallIntegerTagsInScratchReg: ra.<br>
                                 self AddR: ra R: rr].<br>
                [1]     -&gt;      [self SubR: ra R: rr.<br>
                                 objectRepresentation genAddSmallIntegerTagsTo: rr].<br>
                [2]     -&gt;      [objectRepresentation genRemoveSmallIntegerTagsInScratchReg: rr.<br>
                                 objectRepresentation genShiftAwaySmallIntegerTagsInScratchReg: ra.<br>
                                 self MulR: ra R: rr.<br>
                                 objectRepresentation genAddSmallIntegerTagsTo: rr].<br>
<br>
                &quot;2016 through 2019, bitAnd:, bitOr:, bitXor, bitShift:, SmallInteger op SmallInteger =&gt; SmallInteger, no overflow&quot;<br>
<br>
                &quot;2032   through 2037, &gt;, &lt;, &gt;=, &lt;=. =, ~=, SmallInteger op SmallInteger =&gt; Boolean (flags?? then in jump bytecodes if ssTop is a flags value, just generate the instruction!!!!)&quot;<br>
                &quot;CmpCqR is SubRCq so everything is reversed.&quot;<br>
                [32] -&gt; [ self CmpR: ra R: rr.<br>
                                self genBinaryInlineComparison: JumpGreater opFalse: JumpLessOrEqual destReg: rr ].<br>
                [33] -&gt; [ self CmpR: ra R: rr.<br>
                                self genBinaryInlineComparison: JumpLess opFalse: JumpGreaterOrEqual destReg: rr ].<br>
                [34] -&gt; [ self CmpR: ra R: rr.<br>
                                self genBinaryInlineComparison: JumpGreaterOrEqual opFalse: JumpLess destReg: rr ].<br>
                [35] -&gt; [ self CmpR: ra R: rr.<br>
                                self genBinaryInlineComparison: JumpLessOrEqual opFalse: JumpGreater destReg: rr ].<br>
                [36] -&gt; [ self CmpR: ra R: rr.<br>
                                self genBinaryInlineComparison: JumpZero opFalse: JumpNonZero destReg: rr ].<br>
                [37] -&gt; [ self CmpR: ra R: rr.<br>
                                self genBinaryInlineComparison: JumpNonZero opFalse: JumpZero destReg: rr ].<br>
<br>
                &quot;2064   through 2068, Pointer Object&gt;&gt;at:, Byte Object&gt;&gt;at:, Short16 Word Object&gt;&gt;at: LongWord32 Object&gt;&gt;at: Quad64Word Object&gt;&gt;at:. obj op 0-rel SmallInteger =&gt; oop&quot;<br>
                [64] -&gt; [objectRepresentation genConvertSmallIntegerToIntegerInReg: ra.<br>
                                adjust := (objectMemory baseHeaderSize &gt;&gt; objectMemory shiftForWord) - 1. &quot;shift by baseHeaderSize and then move from 1 relative to zero relative&quot;<br>
                                adjust ~= 0 ifTrue: [ self AddCq: adjust R: ra. ].<br>
                                self MoveXwr: ra R: rr R: rr ].<br>
                [65] -&gt; [objectRepresentation genConvertSmallIntegerToIntegerInReg: ra.<br>
                                adjust := objectMemory baseHeaderSize - 1. &quot;shift by baseHeaderSize and then move from 1 relative to zero relative&quot;<br>
                                self AddCq: adjust R: ra.<br>
                                self MoveXbr: ra R: rr R: rr.<br>
                                objectRepresentation genConvertIntegerToSmallIntegerInReg: rr]<br>
<br>
        }<br>
        otherwise: [^EncounteredUnknownBytecode].<br>
        self ssPushRegister: rr.<br>
        ^0!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit&gt;&gt;genPushLiteralVariable: (in category &#39;bytecode generator support&#39;) -----<br>
  genPushLiteralVariable: literalIndex<br>
        &lt;inline: false&gt;<br>
        | association freeReg |<br>
+       freeReg := self allocateAnyReg.<br>
-       freeReg := self ssAllocatePreferredReg: ClassReg.<br>
        association := self getLiteral: literalIndex.<br>
        &quot;N.B. Do _not_ use ReceiverResultReg to avoid overwriting receiver in assignment in frameless methods.&quot;<br>
        &quot;So far descriptors are not rich enough to describe the entire dereference so generate the register<br>
         load but don&#39;t push the result.  There is an order-of-evaluation issue if we defer the dereference.&quot;<br>
        self genMoveConstant: association R: TempReg.<br>
        objectRepresentation<br>
                genEnsureObjInRegNotForwarded: TempReg<br>
                scratchReg: freeReg.<br>
        objectRepresentation<br>
                genLoadSlot: ValueIndex<br>
                sourceReg: TempReg<br>
                destReg: freeReg.<br>
        self ssPushRegister: freeReg.<br>
        ^0!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit&gt;&gt;genSpecialSelectorEqualsEqualsWithForwarders (in category &#39;bytecode generators&#39;) -----<br>
  genSpecialSelectorEqualsEqualsWithForwarders<br>
        | primDescriptor nextPC nExts branchDescriptor unforwardRcvr argReg targetBytecodePC<br>
        unforwardArg  rcvrReg jumpNotEqual jumpEqual postBranchPC label fixup |<br>
        &lt;var: #fixup type: #&#39;BytecodeFixup *&#39;&gt;<br>
        &lt;var: #jumpEqual type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpNotEqual type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #primDescriptor type: #&#39;BytecodeDescriptor *&#39;&gt;<br>
        &lt;var: #branchDescriptor type: #&#39;BytecodeDescriptor *&#39;&gt;<br>
<br>
        primDescriptor := self generatorAt: byte0.<br>
<br>
        nextPC := bytecodePC + primDescriptor numBytes.<br>
        nExts := 0.<br>
        [branchDescriptor := self generatorAt: (objectMemory fetchByte: nextPC ofObject: methodObj) + bytecodeSetOffset.<br>
         branchDescriptor isExtension] whileTrue:<br>
                [nExts := nExts + 1.<br>
                 nextPC := nextPC + branchDescriptor numBytes].<br>
        &quot;If branching the stack must be flushed for the merge&quot;<br>
        (branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifTrue:<br>
                [self ssFlushTo: simStackPtr - 2].<br>
<br>
        unforwardRcvr := (objectRepresentation isUnannotatableConstant: (self ssValue: 1)) not.<br>
        unforwardArg := (objectRepresentation isUnannotatableConstant: self ssTop) not.<br>
<br>
        &quot;if the rcvr or the arg is an annotable constant, we need to push it to a register<br>
        else the forwarder check can&#39;t jump back to the comparison after unforwarding the constant&quot;<br>
        unforwardArg<br>
                ifTrue:<br>
                        [unforwardRcvr<br>
                                ifTrue:<br>
+                                       [self allocateRegForStackTopTwoEntriesInto: [:rTop :rNext| argReg := rTop. rcvrReg := rNext].<br>
-                                       [self allocateTwoRegistersInto: [:rTop :rNext| argReg := rTop. rcvrReg := rNext].<br>
                                         self ssTop popToReg: argReg.<br>
                                         (self ssValue:1) popToReg: rcvrReg]<br>
                                ifFalse:<br>
+                                       [argReg := self allocateRegForStackTopEntry.<br>
-                                       [argReg := self allocateOneRegister.<br>
                                         self ssTop popToReg: argReg]]<br>
                ifFalse:<br>
                        [self assert: unforwardRcvr.<br>
+                        rcvrReg := self allocateRegForStackEntryAt: 1.<br>
-                        rcvrReg := self allocateOneRegister.<br>
                         (self ssValue:1) popToReg: rcvrReg].<br>
<br>
        label := self Label.<br>
<br>
        &quot;Here we can use Cq because the constant does not need to be annotated&quot;<br>
        self assert: (unforwardArg not or: [argReg notNil]).<br>
        self assert: (unforwardRcvr not or: [rcvrReg notNil]).<br>
        unforwardArg<br>
                ifFalse: [ self CmpCq: self ssTop constant R: rcvrReg ]<br>
                ifTrue: [ unforwardRcvr<br>
                        ifFalse: [ self CmpCq: (self ssValue: 1) constant R: argReg ]<br>
                        ifTrue: [ self CmpR: argReg R: rcvrReg ] ].<br>
<br>
        self ssPop: 2.<br>
<br>
        &quot;If not followed by a branch, resolve to true or false.&quot;<br>
        (branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifFalse:<br>
                [jumpEqual := self JumpZero: 0.<br>
                 unforwardArg ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: argReg scratchReg: TempReg jumpBackTo: label ].<br>
                 unforwardRcvr ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: rcvrReg scratchReg: TempReg jumpBackTo: label ].<br>
                 self genMoveFalseR: rcvrReg.<br>
                 jumpNotEqual := self Jump: 0.<br>
                 jumpEqual jmpTarget: (self genMoveTrueR: rcvrReg).<br>
                 jumpNotEqual jmpTarget: self Label.<br>
                 self ssPushRegister: rcvrReg.<br>
                 ^0].<br>
<br>
        &quot;Further since there is a following conditional jump bytecode, define<br>
         non-merge fixups and leave the cond bytecode to set the mergeness.&quot;<br>
        targetBytecodePC := nextPC<br>
                                                        + branchDescriptor numBytes<br>
                                                        + (self spanFor: branchDescriptor at: nextPC exts: nExts in: methodObj).<br>
        postBranchPC := nextPC + branchDescriptor numBytes.<br>
        (self fixupAt: nextPC - initialPC) targetInstruction = 0<br>
                ifTrue: &quot;The next instruction is dead.  we can skip it.&quot;<br>
                        [deadCode := true.<br>
                         self ensureFixupAt: targetBytecodePC - initialPC.<br>
                         self ensureFixupAt: postBranchPC - initialPC]<br>
                ifFalse:<br>
                        [self ssPushConstant: objectMemory trueObject]. &quot;dummy value&quot;<br>
<br>
        self assert: (unforwardArg or: [ unforwardRcvr ]).<br>
        branchDescriptor isBranchTrue ifTrue:<br>
                [ deadCode ifFalse: [ fixup := self ensureNonMergeFixupAt: postBranchPC - initialPC ].<br>
                self JumpZero:  (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.<br>
                unforwardArg ifTrue: [ (deadCode or: [ unforwardRcvr ])<br>
                        ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: argReg scratchReg: TempReg jumpBackTo: label ]<br>
                        ifFalse: [ objectRepresentation<br>
                                genEnsureOopInRegNotForwarded: argReg<br>
                                scratchReg: TempReg<br>
                                ifForwarder: label<br>
                                ifNotForwarder: fixup ] ].<br>
                unforwardRcvr ifTrue: [ deadCode<br>
                        ifTrue: [objectRepresentation genEnsureOopInRegNotForwarded: rcvrReg scratchReg: TempReg jumpBackTo: label ]<br>
                        ifFalse: [objectRepresentation<br>
                                genEnsureOopInRegNotForwarded: rcvrReg<br>
                                scratchReg: TempReg<br>
                                ifForwarder: label<br>
                                ifNotForwarder: fixup ] ] ].<br>
        branchDescriptor isBranchFalse ifTrue:<br>
                [ fixup := self ensureNonMergeFixupAt: targetBytecodePC - initialPC.<br>
                self JumpZero: (self ensureNonMergeFixupAt: postBranchPC - initialPC) asUnsignedInteger.<br>
                unforwardArg ifTrue: [ unforwardRcvr<br>
                        ifFalse: [objectRepresentation<br>
                                genEnsureOopInRegNotForwarded: argReg<br>
                                scratchReg: TempReg<br>
                                ifForwarder: label<br>
                                ifNotForwarder: fixup ]<br>
                        ifTrue: [ objectRepresentation genEnsureOopInRegNotForwarded: argReg scratchReg: TempReg jumpBackTo: label ] ].<br>
                unforwardRcvr ifTrue:<br>
                        [ objectRepresentation<br>
                                genEnsureOopInRegNotForwarded: rcvrReg<br>
                                scratchReg: TempReg<br>
                                ifForwarder: label<br>
                                ifNotForwarder: fixup ].<br>
                &quot;Not reached&quot;].<br>
        ^0!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit&gt;&gt;genTrinaryInlinePrimitive: (in category &#39;inline primitive generators&#39;) -----<br>
  genTrinaryInlinePrimitive: prim<br>
        &quot;Unary inline primitives.&quot;<br>
        &quot;SistaV1: 248           11111000        iiiiiiii                mjjjjjjj                Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.<br>
         See EncoderForSistaV1&#39;s class comment and StackInterpreter&gt;&gt;#trinaryInlinePrimitive:&quot;<br>
<br>
        | ra1 ra2 rr adjust |<br>
        &quot;The store check requires rr to be ReceiverResultReg&quot;<br>
+       self<br>
+               allocateRegForStackTopThreeEntriesInto: [:rTop :rNext :rThird | ra2 := rTop. ra1 := rNext. rr := rThird ]<br>
+               thirdIsReceiver: prim = 0.<br>
-       self allocateThreeRegistersInto: [:rTop :rNext :rThird | ra2 := rTop. ra1 := rNext. rr := rThird ] thirdIsReceiver: prim = 0.<br>
        self assert: (rr ~= ra1 and: [rr ~= ra2 and: [ra1 ~= ra2]]).<br>
        self ssTop popToReg: ra2.<br>
        self ssPop: 1.<br>
        self ssTop popToReg: ra1.<br>
        self ssPop: 1.<br>
        self ssTop popToReg: rr.<br>
        self ssPop: 1.<br>
        objectRepresentation genConvertSmallIntegerToIntegerInReg: ra1.<br>
        &quot;Now: ra is the variable object, rr is long, TempReg holds the value to store.&quot;<br>
        prim caseOf: {<br>
                &quot;0 - 1 pointerAt:put: and byteAt:Put:&quot;<br>
                [0] -&gt;  [ adjust := (objectMemory baseHeaderSize &gt;&gt; objectMemory shiftForWord) - 1. &quot;shift by baseHeaderSize and then move from 1 relative to zero relative&quot;<br>
                                adjust ~= 0 ifTrue: [ self AddCq: adjust R: ra1. ].<br>
                                self MoveR: ra2 Xwr: ra1 R: rr.<br>
                                objectRepresentation genStoreCheckReceiverReg: rr valueReg: ra2 scratchReg: TempReg inFrame: true].<br>
                [1] -&gt;  [ objectRepresentation genConvertSmallIntegerToIntegerInReg: ra2.<br>
                                adjust := objectMemory baseHeaderSize - 1. &quot;shift by baseHeaderSize and then move from 1 relative to zero relative&quot;<br>
                                self AddCq: adjust R: ra1.<br>
                                self MoveR: ra2 Xbr: ra1 R: rr.<br>
                                objectRepresentation genConvertIntegerToSmallIntegerInReg: ra2. ]<br>
        }<br>
        otherwise: [^EncounteredUnknownBytecode].<br>
        self ssPushRegister: ra2.<br>
        ^0!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit&gt;&gt;genUnaryInlinePrimitive: (in category &#39;inline primitive generators&#39;) -----<br>
  genUnaryInlinePrimitive: prim<br>
        &quot;Unary inline primitives.&quot;<br>
        &quot;SistaV1: 248           11111000        iiiiiiii                mjjjjjjj                Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution.<br>
         See EncoderForSistaV1&#39;s class comment and StackInterpreter&gt;&gt;#unaryInlinePrimitive:&quot;<br>
        | rcvrReg resultReg |<br>
+       rcvrReg := self allocateRegForStackTopEntry.<br>
+       resultReg := self allocateRegNotConflictingWith: (self registerMaskFor: rcvrReg).<br>
-       rcvrReg := self allocateOneRegister.<br>
-       resultReg := self allocateRegisterNotConflictingWith: (self registerMaskFor: rcvrReg).<br>
        self ssTop popToReg: rcvrReg.<br>
        self ssPop: 1.<br>
        prim<br>
                caseOf: {<br>
                                        &quot;00             unchecked class&quot;<br>
                        [1] -&gt;  &quot;01             unchecked pointer numSlots&quot;<br>
                                [objectRepresentation<br>
                                        genGetNumSlotsOf: rcvrReg into: resultReg;<br>
                                        genConvertIntegerToSmallIntegerInReg: resultReg].<br>
                                        &quot;02             unchecked pointer basicSize&quot;<br>
                        [3] -&gt;  &quot;03             unchecked byte numBytes&quot;<br>
                                [objectRepresentation<br>
                                        genGetNumBytesOf: rcvrReg into: resultReg;<br>
                                        genConvertIntegerToSmallIntegerInReg: resultReg].<br>
                                        &quot;04             unchecked short16Type format numShorts&quot;<br>
                                        &quot;05             unchecked word32Type format numWords&quot;<br>
                                        &quot;06             unchecked doubleWord64Type format numDoubleWords&quot;<br>
                                  }<br>
                otherwise:<br>
                        [^EncounteredUnknownBytecode]..<br>
        self ssPushRegister: resultReg.<br>
        ^0!<br>
<br>
Item was changed:<br>
  ----- Method: StackToRegisterMappingCogit&gt;&gt;genVanillaSpecialSelectorEqualsEquals (in category &#39;bytecode generators&#39;) -----<br>
  genVanillaSpecialSelectorEqualsEquals<br>
        | nextPC postBranchPC targetBytecodePC primDescriptor branchDescriptor nExts<br>
          jumpEqual jumpNotEqual rcvrReg argReg argIsConstant rcvrIsConstant  |<br>
        &lt;var: #jumpEqual type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #jumpNotEqual type: #&#39;AbstractInstruction *&#39;&gt;<br>
        &lt;var: #primDescriptor type: #&#39;BytecodeDescriptor *&#39;&gt;<br>
        &lt;var: #branchDescriptor type: #&#39;BytecodeDescriptor *&#39;&gt;<br>
        primDescriptor := self generatorAt: byte0.<br>
<br>
        nextPC := bytecodePC + primDescriptor numBytes.<br>
        nExts := 0.<br>
        [branchDescriptor := self generatorAt: (objectMemory fetchByte: nextPC ofObject: methodObj) + bytecodeSetOffset.<br>
         branchDescriptor isExtension] whileTrue:<br>
                [nExts := nExts + 1.<br>
                 nextPC := nextPC + branchDescriptor numBytes].<br>
        &quot;If branching the stack must be flushed for the merge&quot;<br>
        (branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifTrue:<br>
                [self ssFlushTo: simStackPtr - 2].<br>
<br>
        &quot;Don&#39;t use ReceiverResultReg for receiver to keep ReceiverResultReg live.<br>
         Optimize e.g. rcvr == nil, the common case for ifNil: et al.&quot;<br>
<br>
        argIsConstant := self ssTop type = SSConstant.<br>
        rcvrIsConstant := argIsConstant and: [ (self ssValue:1) type = SSConstant ].<br>
<br>
        argIsConstant<br>
                ifFalse:<br>
                        [rcvrIsConstant<br>
                                ifFalse:<br>
+                                       [self allocateRegForStackTopTwoEntriesInto: [:rTop :rNext| argReg := rTop. rcvrReg := rNext].<br>
-                                       [self allocateTwoRegistersInto: [:rTop :rNext| argReg := rTop. rcvrReg := rNext].<br>
                                         self ssTop popToReg: argReg.<br>
                                         (self ssValue:1) popToReg: rcvrReg]<br>
                                ifTrue:<br>
+                                       [argReg := self allocateRegForStackTopEntry.<br>
-                                       [argReg := self allocateOneRegister.<br>
                                         self ssTop popToReg: argReg]]<br>
                ifTrue:<br>
                        [self assert: rcvrIsConstant not.<br>
+                        rcvrReg := self allocateRegForStackEntryAt: 1.<br>
-                        rcvrReg := self allocateOneRegister.<br>
                         (self ssValue:1) popToReg: rcvrReg].<br>
<br>
        argIsConstant<br>
                ifTrue: [ self genCompConstant: self ssTop constant R: rcvrReg ]<br>
                ifFalse: [ rcvrIsConstant<br>
                        ifTrue: [ self genCompConstant: (self ssValue: 1) constant R: argReg ]<br>
                        ifFalse: [ self CmpR: argReg R: rcvrReg ] ].<br>
<br>
        self ssPop: 2.<br>
<br>
        &quot;If not followed by a branch, resolve to true or false.&quot;<br>
        (branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse]) ifFalse:<br>
                [jumpNotEqual := self JumpNonZero: 0.<br>
                 self genMoveTrueR: rcvrReg.<br>
                 jumpEqual := self Jump: 0.<br>
                 jumpNotEqual jmpTarget: (self genMoveFalseR: rcvrReg).<br>
                 jumpEqual jmpTarget: self Label.<br>
                 self ssPushRegister: rcvrReg.<br>
                 ^0].<br>
<br>
        &quot;Further since there is a following conditional jump bytecode, define<br>
         non-merge fixups and leave the cond bytecode to set the mergeness.&quot;<br>
        targetBytecodePC := nextPC<br>
                                                        + branchDescriptor numBytes<br>
                                                        + (self spanFor: branchDescriptor at: nextPC exts: nExts in: methodObj).<br>
        postBranchPC := nextPC + branchDescriptor numBytes.<br>
        (self fixupAt: nextPC - initialPC) targetInstruction = 0<br>
                ifTrue: &quot;The next instruction is dead.  we can skip it.&quot;<br>
                        [deadCode := true.<br>
                         self ensureFixupAt: targetBytecodePC - initialPC.<br>
                         self ensureFixupAt: postBranchPC - initialPC]<br>
                ifFalse:<br>
                        [self ssPushConstant: objectMemory trueObject]. &quot;dummy value&quot;<br>
        self gen: (branchDescriptor isBranchTrue ifTrue: [JumpZero] ifFalse: [JumpNonZero])<br>
                operand: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.<br>
                deadCode ifFalse: [self Jump: (self ensureNonMergeFixupAt: postBranchPC - initialPC)].<br>
        ^0!<br>
<br>
Item was removed:<br>
- ----- Method: StackToRegisterMappingCogit&gt;&gt;ssAllocatePreferredReg: (in category &#39;simulation stack&#39;) -----<br>
- ssAllocatePreferredReg: preferredReg<br>
-       | preferredMask lastPreferred liveRegs |<br>
-       lastPreferred := -1.<br>
-       &quot;compute live regs while noting the last occurrence of preferredReg.<br>
-        If there are none free we must spill from simSpillBase to last occurrence.&quot;<br>
-       preferredMask := (self registerMaskFor: preferredReg).<br>
-       liveRegs := self registerMaskFor: TempReg and: FPReg and: SPReg.<br>
-       (simSpillBase max: 0) to: simStackPtr do:<br>
-               [:i|<br>
-               liveRegs := liveRegs bitOr: (self simStackAt: i) registerMask.<br>
-               (liveRegs bitAnd: preferredMask) ~= 0 ifTrue:<br>
-                       [lastPreferred := i]].<br>
-       &quot;If preferredReg is not live we can allocate it.&quot;<br>
-       (self register: preferredReg isInMask: liveRegs) ifFalse:<br>
-               [^preferredReg].<br>
-       &quot;If any other is not live we can allocate it.&quot;<br>
-       GPRegMin to: GPRegMax do:<br>
-               [:reg|<br>
-               (self register: reg isInMask: liveRegs) ifFalse:<br>
-                       [^reg]].<br>
-       &quot;All live, must spill&quot;<br>
-       self ssFlushTo: lastPreferred.<br>
-       self assert: (self liveRegisters bitAnd: preferredMask) = 0.<br>
-       ^preferredReg!<br>
<br>
</blockquote></div><br></div>
<br></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature">best,<div>Eliot</div></div>
</div></div>