<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 class="" style="white-space:pre">        </span>| t t2 |</div><div><span class="" style="white-space:pre">        </span>t := self yourself.</div><div><span class="" style="white-space:pre">        </span>t2 := self + 1.</div><div><span class="" style="white-space:pre">        </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><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>