[Vm-dev] VM Maker: VMMaker.oscog-eem.2330.mcz

commits at source.squeak.org commits at source.squeak.org
Tue Feb 6 19:45:04 UTC 2018


Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2330.mcz

==================== Summary ====================

Name: VMMaker.oscog-eem.2330
Author: eem
Time: 6 February 2018, 11:44:42.955827 am
UUID: 90c31ff5-bcbb-46e4-b6ca-e14c79d71d80
Ancestors: VMMaker.oscog-eem.2329

RegisterAllocatingCogit:
Refactor reconcilePushingWith: & reconcilePoppingWith: into reconcileWith:spillOffset:onSpillOrUnspill:.  

Delete several now obsolete methods.

Fix a slip in attemptToComputeTempNamesFor:

=============== Diff against VMMaker.oscog-eem.2329 ===============

Item was changed:
  ----- Method: CogRegisterAllocatingSimStackEntry>>ensureSpilledAt:from: (in category 'compile abstract instructions') -----
  ensureSpilledAt: baseOffset from: baseRegister
  	spilled ifTrue:
  		[type = SSSpill ifTrue:
  			[self assert: ((offset = baseOffset and: [register = baseRegister]) or: [cogit violatesEnsureSpilledSpillAssert]).
  			 liveRegister := NoReg.
  			 ^self]].
  	self assert: type ~= SSSpill.
  	cogit traceSpill: self.
  	"N.B. Keep the type of SSConstant spills as SSConstant so that when joins occur
  	 as a result of expressions with constants on the stack, the constant on stack
  	 can be recovered.  e.g. as in
  		self at: 1 put: (self foo ifTrue: [self bar] ifFalse: [self baz])."
  	type = SSConstant
  		ifTrue:
+ 			[liveRegister = NoReg
+ 				ifTrue: [cogit genPushConstant: constant]
+ 				ifFalse: [cogit PushR: liveRegister]]
- 			[cogit genPushConstant: constant]
  		ifFalse:
  			[type = SSBaseOffset
  				ifTrue:
  					[liveRegister = NoReg
  						ifTrue: 
  							[cogit MoveMw: offset r: register R: TempReg.
  					 		 cogit PushR: TempReg]
  						ifFalse: [cogit PushR: liveRegister]]
  				ifFalse:
  					[self assert: type = SSRegister.
  					 cogit PushR: register].
  			 type := SSSpill].
  	liveRegister := NoReg.
  	spilled := true.
  	offset := baseOffset.
  	register := baseRegister!

Item was changed:
  ----- Method: CogRegisterAllocatingSimStackEntry>>popToReg: (in category 'compile abstract instructions') -----
  popToReg: reg
  	liveRegister ~= NoReg
  		ifTrue: 
  			[self deny: (type = SSRegister and: [register ~= liveRegister and: [cogit needsFrame]]).
  			 spilled ifTrue: "This is rare, and in some cases it isn't even needed (e.g. frameful return) but we can't tell as yet."
  				[cogit AddCq: objectRepresentation wordSize R: SPReg].
  			 reg ~= liveRegister
  				ifTrue: [cogit MoveR: liveRegister R: reg]
  				ifFalse: [cogit Label]]
  		ifFalse: 
  			[spilled
  				ifTrue:
  					[cogit PopR: reg]
  				ifFalse:
  					[type caseOf: {
  						[SSBaseOffset]	-> [cogit MoveMw: offset r: register R: reg].
+ 						[SSSpill]		-> [cogit MoveMw: offset r: register R: reg].
  						[SSConstant]	-> [cogit genMoveConstant: constant R: reg].
  						[SSRegister]	-> [reg ~= register
  												ifTrue: [cogit MoveR: register R: reg]
  												ifFalse: [cogit Label]] }]].
  
  	(reg ~= TempReg and: [liveRegister = NoReg and: [type ~= SSRegister]]) ifTrue:
  		[liveRegister := reg.
  		 cogit copyLiveRegisterToCopiesOf: self]!

Item was removed:
- ----- Method: CogRegisterAllocatingSimStackEntry>>reconcileBackwardsWith: (in category 'compile abstract instructions') -----
- reconcileBackwardsWith: targetEntry
- 	"Make the state of the receiver, a stack entry at a backward jump,
- 	 the same as the corresponding simStackEntry at the target of the jump"
- 	<var: #targetEntry type: #'SimStackEntry *'>
- 	| targetReg |
- 	(targetReg := targetEntry registerOrNone) = NoReg ifTrue:
- 		[^self].
- 	targetEntry type = SSConstant ifTrue:
- 		[self assert: (type = SSConstant and: [constant = targetEntry constant]).
- 		 ^self].
- 	liveRegister ~= NoReg ifTrue:
- 		[liveRegister ~= targetReg ifTrue:
- 			[cogit MoveR: liveRegister R: targetReg].
- 		 ^self].
- 	type caseOf: {
- 		[SSBaseOffset]	-> [cogit MoveMw: offset r: register R: targetReg].
- 		[SSSpill]		-> [cogit MoveMw: offset r: register R: targetReg].
- 		[SSConstant]	-> [cogit genMoveConstant: constant R: targetReg].
- 		[SSRegister]	-> [register ~= targetReg ifTrue:
- 								[cogit MoveR: register R: targetReg]] }!

Item was removed:
- ----- Method: CogRegisterAllocatingSimStackEntry>>reconcileForwardsWith: (in category 'compile abstract instructions') -----
- reconcileForwardsWith: targetEntry
- 	"Make the state of the receiver, a stack entry at the end of a basic block,
- 	 the same as the corresponding simStackEntry at the target of a preceding
- 	 jump to the beginning of the next basic block.  Make sure targetEntry
- 	 reflects the state of the merged simStack; it will be installed as the current
- 	 entry by restoreSimStackAtMergePoint: in mergeWithFixupIfRequired:.
- 
- 	 Answer if the liveRegister for the targetEntry (if any) should be deassigned;
- 	 this is because if merging a non-temp with a temp that has a live register we
- 	 can assign to the register, but must unassign the register from the temp,
- 	 otherwise the temp will acquire the merged value without an assignment."
- 	<var: #targetEntry type: #'SimStackEntry *'>
- 	| targetReg |
- 	(targetReg := targetEntry registerOrNone) = NoReg ifTrue:
- 		[| reg |
- 		 self assert: targetEntry spilled.
- 		 (self isSameEntryAs: targetEntry) ifTrue:
- 			[self assert: spilled.
- 			 ^false].
- 		 (reg := self registerOrNone) = NoReg ifTrue: [reg := TempReg].
- 		 self storeToReg: reg.
- 		 spilled
- 			ifTrue: [cogit MoveR: reg Mw: targetEntry offset r: targetEntry register]
- 			ifFalse: [cogit PushR: reg].
- 		 ^false].
- 	liveRegister ~= NoReg ifTrue:
- 		[liveRegister ~= targetReg ifTrue:
- 			[cogit MoveR: liveRegister R: targetReg].
- 		 (spilled and: [targetEntry spilled not]) ifTrue:
- 			[cogit AddCq: objectRepresentation wordSize R: SPReg].
- 		 ^false].
- 	spilled
- 		ifTrue:
- 			[targetEntry spilled ifFalse:
- 				[cogit PopR: targetReg. "KISS; generate the least number of instructions..."
- 				 ^false]]
- 		ifFalse:
- 			[targetEntry spilled ifTrue:
- 				[cogit SubCq: objectRepresentation wordSize R: SPReg]].
- 	type caseOf: {
- 		[SSBaseOffset]	-> [cogit MoveMw: offset r: register R: targetReg].
- 		[SSSpill]		-> [cogit MoveMw: offset r: register R: targetReg].
- 		[SSConstant]	-> [cogit genMoveConstant: constant R: targetReg].
- 		[SSRegister]	-> [register ~= targetReg ifTrue:
- 								[cogit MoveR: register R: targetReg]] }.
- 	(targetEntry type = SSConstant
- 	 and: [type ~= SSConstant or: [constant ~= targetEntry constant]]) ifTrue:
- 		[targetEntry
- 			register: targetReg;
- 			type: SSRegister].
- 	"If merging a constant with a constant assigned to a register, then the register must be deassigned from any temps."
- 	^targetEntry type = SSConstant
- 	"If merging a non-temp with a temp that has a live register we can assign
- 	 to the register, but must unassign the register from the temp, otherwise
- 	 the temp will acquire the merged value without an assignment."
- 	 or: [targetEntry isFrameTempVar and: [(self isSameEntryAs: targetEntry) not]]!

Item was removed:
- ----- Method: CogRegisterAllocatingSimStackEntry>>reconcilePoppingWith: (in category 'compile abstract instructions') -----
- reconcilePoppingWith: targetEntry
- 	"Make the state of a targetEntry, a stack entry following a non-inlined special selector
- 	 send, the same as the corresponding entry (the receiver) along the inlined path."
- 	<var: #targetEntry type: #'SimStackEntry *'>
- 	| targetReg |
- 	spilled = targetEntry spilled ifTrue:
- 		[self assert: ((self isSameEntryAs: targetEntry)
- 					 or: [(targetEntry spilled not and: [targetEntry registerOrNone ~= NoReg])
- 					 or: [spilled and: [type = SSConstant and: [offset = targetEntry offset]]]]).
- 		 (targetReg := targetEntry registerOrNone) = NoReg ifTrue:
- 			[liveRegister := NoReg.
- 			 ^self].
- 		 type caseOf: {
- 			[SSBaseOffset]	-> [liveRegister ~= targetReg ifTrue:
- 									[cogit MoveMw: offset r: register R: targetReg].
- 								targetEntry type caseOf: {
- 									[SSBaseOffset]	-> [liveRegister := targetReg.
- 														(self isSameEntryAs: targetEntry) ifFalse:
- 															[type := SSSpill]].
- 									[SSSpill]		-> [liveRegister := targetReg. type := SSSpill].
- 									[SSConstant]	-> [liveRegister := targetReg. type := SSSpill].
- 									[SSRegister]	-> [register := targetReg. type := SSRegister] }].
- 			[SSSpill]		-> [cogit MoveMw: offset r: register R: targetReg.
- 								liveRegister := targetReg].
- 			[SSConstant]	-> [cogit genMoveConstant: constant R: targetReg.
- 								type := SSRegister. register := targetReg].
- 			[SSRegister]	-> [targetReg ~= register ifTrue:
- 									[cogit MoveR: register R: targetReg.
- 									 register := targetReg]] }.
- 		 ^self].
- 	self assert: spilled.
- 	(targetReg := targetEntry registerOrNone) ~= NoReg
- 		ifTrue: [cogit PopR: targetReg]
- 		ifFalse: [cogit AddCq: objectRepresentation wordSize R: SPReg].
- 	liveRegister ~= targetReg ifTrue:
- 		[liveRegister := NoReg]!

Item was removed:
- ----- Method: CogRegisterAllocatingSimStackEntry>>reconcilePushingWith: (in category 'compile abstract instructions') -----
- reconcilePushingWith: targetEntry
- 	"Make the state of the receiver, a stack entry at the end of a basic block,
- 	 the same as the corresponding simStackEntry at the target of a preceding
- 	 jump to the beginning of the next basic block.  Make sure targetEntry
- 	 reflects the state of the merged simStack; it will be installed as the current
- 	 entry by restoreSimStackAtMergePoint: in mergeWithFixupIfRequired:."
- 	<var: #targetEntry type: #'SimStackEntry *'>
- 	| targetReg |
- 	spilled = targetEntry spilled ifTrue:
- 		[self assert: ((self isSameEntryAs: targetEntry)
- 					 or: [(targetEntry spilled not and: [targetEntry registerOrNone ~= NoReg])
- 					 or: [spilled and: [type = SSConstant and: [offset = targetEntry offset]]]]).
- 		 (targetReg := targetEntry registerOrNone) = NoReg ifTrue:
- 			[liveRegister := NoReg.
- 			 ^self].
- 		 type caseOf: {
- 			[SSBaseOffset]	-> [liveRegister ~= targetReg ifTrue:
- 									[cogit MoveMw: offset r: register R: targetReg].
- 								targetEntry type caseOf: {
- 									[SSBaseOffset]	-> [liveRegister := targetReg.
- 														(self isSameEntryAs: targetEntry) ifFalse:
- 															[type := SSSpill]].
- 									[SSSpill]		-> [liveRegister := targetReg. type := SSSpill].
- 									[SSConstant]	-> [liveRegister := targetReg. type := SSSpill].
- 									[SSRegister]	-> [register := targetReg. type := SSRegister] }].
- 			[SSSpill]		-> [cogit MoveMw: offset r: register R: targetReg.
- 								liveRegister := targetReg].
- 			[SSConstant]	-> [cogit genMoveConstant: constant R: targetReg.
- 								type := SSRegister. register := targetReg].
- 			[SSRegister]	-> [targetReg ~= register ifTrue:
- 									[cogit MoveR: register R: targetReg.
- 									 register := targetReg]] }.
- 		 ^self].
- 	self assert: spilled.
- 	(targetReg := targetEntry registerOrNone) ~= NoReg
- 		ifTrue: [cogit PopR: targetReg]
- 		ifFalse: [cogit AddCq: objectRepresentation wordSize R: SPReg].
- 	liveRegister ~= targetReg ifTrue:
- 		[liveRegister := NoReg]!

Item was added:
+ ----- Method: CogRegisterAllocatingSimStackEntry>>reconcileWith:spillOffset:onSpillOrUnspill: (in category 'compile abstract instructions') -----
+ reconcileWith: targetEntry spillOffset: spillOffset onSpillOrUnspill: spillOrUnspillBlock
+ 	"Make the state of a targetEntry, a stack entry following a non-inlined special selector
+ 	 send, the same as the corresponding entry (the receiver) along the inlined path.
+ 	 spillOffset is zero for non-spill locations (self & temps), and the offset of the spill for
+ 	 volatile stack entries. spillOrUnspillBlock is a block evaluated with the target's
+ 	 registerOrNone if the receiver and target have different spilledness.
+ 	 Answer if the reconciliation merged a register; merged registers must be deassigned."
+ 	<var: #targetEntry type: #'SimStackEntry *'>
+ 	<inline: true>
+ 	| targetReg mergedRegister |
+ 	spilled = targetEntry spilled ifTrue:
+ 		[self assert: ((self isSameEntryAs: targetEntry)
+ 					 or: [(targetEntry spilled not and: [targetEntry registerOrNone ~= NoReg])
+ 					 or: [spilled and: [type = SSConstant and: [offset = targetEntry offset]]]]).
+ 		 (targetReg := targetEntry registerOrNone) = NoReg ifTrue:
+ 			[liveRegister := NoReg.
+ 			 ^false].
+ 		 mergedRegister := false.
+ 		 type caseOf: {
+ 			[SSBaseOffset]	-> [liveRegister ~= targetReg ifTrue:
+ 									[cogit MoveMw: offset r: register R: targetReg.
+ 									 mergedRegister := true].
+ 								targetEntry type caseOf: {
+ 									[SSBaseOffset]	-> [liveRegister := targetReg.
+ 														(self isSameEntryAs: targetEntry) ifFalse:
+ 															[type := SSSpill.
+ 															 offset := spillOffset]].
+ 									[SSSpill]		-> [liveRegister := targetReg. type := SSSpill.
+ 														offset := spillOffset].
+ 									[SSConstant]	-> [liveRegister := targetReg. type := SSSpill.
+ 														offset := spillOffset].
+ 									[SSRegister]	-> [register := targetReg. type := SSRegister] }].
+ 			[SSSpill]		-> [cogit MoveMw: offset r: register R: targetReg.
+ 								liveRegister := targetReg.
+ 								mergedRegister := true].
+ 			[SSConstant]	-> [cogit genMoveConstant: constant R: targetReg.
+ 								type := SSRegister. register := targetReg.
+ 								mergedRegister := true].
+ 			[SSRegister]	-> [targetReg ~= register ifTrue:
+ 									[cogit MoveR: register R: targetReg.
+ 									 register := targetReg.
+ 									 mergedRegister := true]] }.
+ 		 ^mergedRegister].
+ 	targetReg := targetEntry registerOrNone.
+ 	spillOrUnspillBlock value: targetReg.
+ 	liveRegister ~= targetReg ifTrue:
+ 		[liveRegister := NoReg].
+ 	^false!

Item was changed:
  ----- Method: Cogit class>>attemptToComputeTempNamesFor: (in category 'in-image compilation support') -----
  attemptToComputeTempNamesFor: aCompiledMethod
  	(aCompiledMethod respondsTo: #tempNames) ifTrue:
  		[| blocks |
  		 blocks := aCompiledMethod embeddedBlockClosures.
  		 initializationOptions
  			at: #tempNames
  			put: (Dictionary withAll: {aCompiledMethod initialPC -> ([aCompiledMethod tempNames]
  																		on: MessageNotUnderstood
  																		do: [:ex|
  																			(self isSistaMessage: ex message unimplementedIn: Decompiler) ifTrue:
  																				[^self].
  																			 (Smalltalk classNamed: #AssemblerAbsentClassImport) ifNotNil:
  																				[:aaciClass|
  																				 (ex receiver isKindOf: aaciClass) ifTrue:
  																					[^self]].
  																			 ex pass])},
  				(blocks
  					ifEmpty: [#()]
  					ifNotEmpty:
  						[aCompiledMethod embeddedBlockClosures
  							with: ((aCompiledMethod methodNode schematicTempNamesString allButFirst:
  									(aCompiledMethod methodNode schematicTempNamesString indexOf: $[)) piecesCutWhere: [:a :b| b = $[])
+ 							collect: [:c :s| c startpc -> (s substrings collect: [:ea| ea copyWithout: $] ])]]))]!
- 							collect: [:c :s| c startpc -> s substrings]]))]!

Item was changed:
  ----- Method: Cogit>>promptForBreakPC (in category 'simulation only') -----
  promptForBreakPC
  	<doNotGenerate>
  	| s first pc |
+ 	s := UIManager default request: 'Break pc (hex, + to add, - to remove)'.
- 	s := UIManager default request: 'Break pc (hex)'.
  	s := s withBlanksTrimmed.
  	s isEmpty ifTrue: [^self].
  	('+-' includes: s first) ifTrue: [first := s first. s := s allButFirst].
  	(s isEmpty and: [first = $-]) ifTrue:
  		[^self breakPC: nil].
  	pc := (s includes: $r)
  			ifTrue:
  				[Number readFrom: s readStream]
  			ifFalse:
  				[(#('0x' '-0x') detect: [:prefix| s beginsWith: prefix] ifNone: []) ifNotNil:
  					[:prefix|
  					s := s allButFirst: prefix size.
  					prefix first = $- ifTrue: [s := '-', s]].
  				Integer readFrom: s readStream base: 16].
  	first = $+ ifTrue:
  		[^self breakPC: (breakPC addBreakpoint: pc)].
  	first = $- ifTrue:
  		[^self breakPC: (breakPC removeBreakpoint: pc)].
  	self breakPC: pc!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>deassignRegister:in: (in category 'bytecode generator support') -----
+ deassignRegister: register in: aSimStack
+ 	"When a merge has assigned a register to a volatile stack entry
+ 	 deassign that register from any temporaries."
+ 	self assert: register ~= NoReg.
+ 	0 to: methodOrBlockNumTemps do:
+ 		[:i|
+ 		(self simStack: aSimStack at: i) liveRegister = register ifTrue:
+ 			[(self simStack: aSimStack at: i) liveRegister: NoReg]]!

Item was removed:
- ----- Method: RegisterAllocatingCogit>>deassignRegisterForTempVar:in: (in category 'bytecode generator support') -----
- deassignRegisterForTempVar: targetEntry in: mergeSimStack
- 	"If merging a non-temp with a temp that has a live register we can assign
- 	 to the register, but must unassign the register from the temp, otherwise
- 	 the temp will acquire the merged value without an assignment.  The targetEntry
- 	 must also be transmogrified into an SSRegister entry, which is done in the caller."
- 	<var: #targetEntry type: #'SimStackEntry *'>
- 	<var: #duplicateEntry type: #'SimStackEntry *'>
- 	<var: #mergeSimStack type: #'SimStackEntry *'>
- 	<inline: true>
- 	| reg |
- 	self halt.  "Clément and I hope this shouldn't happen as of the new merge code in reconcileRegistersInTempVarsInCurrentSimStackWithThoseIn:"
- 	reg := targetEntry liveRegister.
- 	self assert: (reg ~= NoReg and: [targetEntry type = SSConstant or: [targetEntry isFrameTempVar]]).
- 	targetEntry type = SSConstant
- 		ifTrue:
- 			[simStackPtr to: 1 by: -1 do:
- 				[:j| | duplicateEntry |
- 				 duplicateEntry := self simStack: mergeSimStack at: j.
- 				 (duplicateEntry registerOrNone = reg
- 				  and: [duplicateEntry type = SSBaseOffset or: [duplicateEntry type = SSSpill]]) ifTrue:
- 					[duplicateEntry liveRegister: NoReg]]]
- 		ifFalse:
- 			[simStackPtr to: 1 by: -1 do:
- 				[:j| | duplicateEntry |
- 				 duplicateEntry := self simStack: mergeSimStack at: j.
- 				 (targetEntry isSameEntryAs: duplicateEntry) ifTrue:
- 					[j <= methodOrBlockNumTemps
- 						ifTrue: [duplicateEntry liveRegister: NoReg]
- 						ifFalse: [duplicateEntry type: SSRegister; register: reg]]]]!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>ensureFixupAt: (in category 'bytecode generator support') -----
  ensureFixupAt: targetPC
  	"Make sure there's a flagged fixup at the target pc in fixups.
  	 Initially a fixup's target is just a flag.  Later on it is replaced with a proper instruction.
  	 Override to generate stack merging code if required."
  	| fixup |	
  	<var: #fixup type: #'BytecodeFixup *'>
  	self assert: targetPC > bytecodePC.
+ 	self cCode: '' inSmalltalk:
+ 		[self assert: simStackPtr + (needsFrame ifTrue: [0] ifFalse: [1])
+ 					= (self debugStackPointerFor: targetPC)].
  	fixup := self fixupAt: targetPC.
  	"If a non-merge fixup has already been defined then where-ever that was done didn't
  	 realise there needed to be a merge and forgot to save the stack state for that merge."
  	self deny: fixup isNonMergeFixup.
  	fixup needsFixup 
  		ifTrue:
  			[fixup mergeSimStack
  				ifNil: [self setMergeSimStackOf: fixup]
  				ifNotNil:
  					[self copySimStackToScratch: simSpillBase.
+ 					 self mergeCurrentSimStackWith: fixup.
- 					 self mergeCurrentSimStackWith: fixup forwards: true.
  					 self restoreSimStackFromScratch]]
  		ifFalse: 
  			[self assert: (fixup mergeSimStack isNil or: [compilationPass = 2]).
  			 fixup mergeSimStack
  				ifNil: [self setMergeSimStackOf: fixup]
  				ifNotNil:
  					[self moveVolatileSimStackEntriesToRegisters.
  					 self assert: (self simStack: simStack isIdenticalTo: fixup mergeSimStack)]].
  	^super ensureFixupAt: targetPC!

Item was removed:
- ----- Method: RegisterAllocatingCogit>>initOptStatus: (in category 'simulation stack') -----
- initOptStatus: receiverResultRegLive
- 	<inline: true>!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>liveRegistersInSelfAndTemps (in category 'debugging') -----
+ liveRegistersInSelfAndTemps
+ 	^self liveRegistersFrom: 0 to: methodOrBlockNumTemps in: simStack!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>mergeCurrentSimStackWith: (in category 'bytecode generator support') -----
  mergeCurrentSimStackWith: fixup
  	"At a merge point the cogit expects the stack to be in the same state as fixup's mergeSimStack.
  	 mergeSimStack is the state as of some jump forward or backward to this point.  So make
  	 simStack agree with mergeSimStack (it is, um, problematic to plant code at the jump). Values
  	 may have to be assigned to registers.  Registers may have to be swapped.
  	 Generate code to merge the current simStack with that of the target fixup, the goal being to
  	 keep as many registers live as possible."
  	"self printSimStack; printSimStack: fixup mergeSimStack"
  	"self simStackPrintString-> fixup simStackPrintString"
  	"abstractOpcodes object copyFrom: startIndex to: opcodeIndex"
  	<var: #fixup type: #'BytecodeFixup *'>
+ 	| currentRegisters targetRegisters mergeSimStack current target spillOffset |
- 	| currentRegisters targetRegisters mergeSimStack current target |
  	(mergeSimStack := fixup mergeSimStack) ifNil: [^self].
  	self assert: simStackPtr = fixup simStackPtr.
  	currentRegisters := self liveRegistersFrom: 0 to: simStackPtr in: simStack.
  	targetRegisters := self liveRegistersFrom: 0 to: simStackPtr in: mergeSimStack.
  	self resolveConflicts: (currentRegisters bitAnd: targetRegisters) with: fixup mergeSimStack to: fixup simStackPtr.
  	self assert: (self conflictsResolvedBetweenSimStackAnd: mergeSimStack).
- 	"if we simply compare spill bases it is trivial here to decide whether to push or pop.
- 	 Otherwise we have to determine the spill base in fixup's mergeSimStack."
  	(self pushForMergeWith: mergeSimStack)
  		ifTrue:
  			[0 to: simStackPtr do:
  				[:i|
+ 				 spillOffset := i > methodOrBlockNumTemps
+ 									ifTrue: [self frameOffsetOfTemporary: i - 1]
+ 									ifFalse: [0].
+ 				 ((current := self simStack: simStack at: i)
+ 					reconcileWith: (target := self simStack: mergeSimStack at: i)
+ 					spillOffset: spillOffset
+ 					onSpillOrUnspill:
+ 						[:targetReg|
+ 						 self deny: current spilled.
+ 						 self assert: spillOffset ~= 0.
+ 						 current ensureSpilledAt: spillOffset from: FPReg]) ifTrue:
+ 					[i > methodOrBlockNumTemps ifTrue:
+ 						[self deassignRegister: current registerOrNone in: mergeSimStack.
+ 						 self deny: (self register: current registerOrNone
+ 										isInMask: self liveRegistersInSelfAndTemps)]]]]
- 				 current := self simStack: simStack at: i.
- 				 target := self simStack: mergeSimStack at: i.
- 				 current reconcilePushingWith: target]]
  		ifFalse:
  			[simStackPtr to: 0 by: -1 do:
  				[:i|
+ 				 spillOffset := i > methodOrBlockNumTemps
+ 									ifTrue: [self frameOffsetOfTemporary: i - 1]
+ 									ifFalse: [0].
+ 				 ((current := self simStack: simStack at: i)
+ 					reconcileWith: (target := self simStack: mergeSimStack at: i)
+ 					spillOffset: spillOffset
+ 					onSpillOrUnspill:
+ 						[:targetReg|
+ 						 self assert: current spilled.
+ 						 self assert: spillOffset ~= 0.
+ 						 targetReg  ~= NoReg
+ 							ifTrue: [self PopR: targetReg]
+ 							ifFalse: [self AddCq: objectRepresentation wordSize R: SPReg]]) ifTrue:
+ 					[i > methodOrBlockNumTemps ifTrue:
+ 						[self deassignRegister: current registerOrNone in: mergeSimStack.
+ 						 self deny: (self register: current registerOrNone
+ 										isInMask: self liveRegistersInSelfAndTemps)]]]].
+ 	self updateSimSpillBase!
- 				 current := self simStack: simStack at: i.
- 				 target := self simStack: mergeSimStack at: i.
- 				 current reconcilePoppingWith: target]].
- 	self assertCorrectSimStackPtr!

Item was removed:
- ----- Method: RegisterAllocatingCogit>>mergeCurrentSimStackWith:forwards: (in category 'bytecode generator support') -----
- mergeCurrentSimStackWith: fixup forwards: forwards
- 	"At a merge point the cogit expects the stack to be in the same state as mergeSimStack.
- 	 mergeSimStack is the state as of some jump forward or backward to this point.  So make
- 	 simStack agree with mergeSimStack (it is, um, problematic to plant code at the jump).
- 	 Values may have to be assigned to registers.  Registers may have to be swapped.
- 	 The state of optStatus must agree.
- 	 Generate code to merge the current simStack with that of the target fixup,
- 	 the goal being to keep as many registers live as possible.  If the merge is forwards
- 	 registers can be deassigned (since registers are always written to temp vars).
- 	 But if backwards, nothing can be deassigned, and the state /must/ reflect the target."
- 	"self printSimStack; printSimStack: fixup mergeSimStack"
- 	"abstractOpcodes object copyFrom: startIndex to: opcodeIndex"
- 	<var: #fixup type: #'BytecodeFixup *'>
- 	| startIndex mergeSimStack |
- 	<var: #mergeSimStack type: #'SimStackEntry *'>
- 	<var: #targetEntry type: #'SimStackEntry *'>
- 	<var: #currentEntry type: #'SimStackEntry *'>
- 	(mergeSimStack := fixup mergeSimStack) ifNil: [^self].
- 	startIndex := opcodeIndex. "for debugging"
- 	"Assignments amongst the registers must be made in order to avoid overwriting.
- 	 If necessary exchange registers amongst simStack's entries to resolve any conflicts."
- 	self reconcileRegistersInTempVarsInCurrentSimStackWithThoseIn: mergeSimStack.
- 	(self asserta: (self conflictsResolvedBetweenSimStackAnd: mergeSimStack)) ifFalse:
- 		[Notification new tag: #failedMerge; signal].
- 	(self pushForMergeWith: mergeSimStack)
- 		ifTrue:
- 			[methodOrBlockNumTemps + 1 to: simStackPtr do:
- 				[:i| self mergePushingWithEntryInTargetSimStack: mergeSimStack at: i]]
- 		ifFalse:
- 			[simStackPtr to: methodOrBlockNumTemps + 1 by: -1 do:
- 				[:i| self mergePoppingWithEntryInTargetSimStack: mergeSimStack at: i]].
- 	"Still haven't handled simSpillBase."
- 	self assert: (simSpillBase > simStackPtr
- 				or: [simSpillBase > methodOrBlockNumTemps
- 					and: [(self simStack: mergeSimStack at: simSpillBase - 1) spilled]])!

Item was removed:
- ----- Method: RegisterAllocatingCogit>>mergePoppingWithEntryInTargetSimStack:at: (in category 'bytecode generator support') -----
- mergePoppingWithEntryInTargetSimStack: mergeSimStack at: i
- 	"Merge an intermediate result on currentSimStack with the corresponding one in target's mergeSimStack.
- 	 Depending on spilledness, the stack may need to be pushed or popped, or simply a register assignment made."
- 	| currentEntry targetEntry |
- 	<inline: true>
- 	currentEntry := self simStack: simStack at: i.
- 	targetEntry := self simStack: mergeSimStack at: i.
- 	currentEntry reconcilePoppingWith: targetEntry.
- 	 "Note, we could update the simStack and spillBase here but that is done in restoreSimStackAtMergePoint:
- 	 spilled ifFalse:
- 		[simSpillBase := i - 1].
- 	 simStack
- 		at: i
- 		put: (self
- 				cCode: [mergeSimStack at: i]
- 				inSmalltalk: [(mergeSimStack at: i) copy])"!

Item was removed:
- ----- Method: RegisterAllocatingCogit>>mergePushingWithEntryInTargetSimStack:at: (in category 'bytecode generator support') -----
- mergePushingWithEntryInTargetSimStack: mergeSimStack at: i
- 	"Merge an intermediate result on currentSimStack with the corresponding one in target's mergeSimStack.
- 	 Depending on spilledness, the stack may need to be pushed or popped, or simply a register assignment made."
- 	| currentEntry targetEntry |
- 	<inline: true>
- 	currentEntry := self simStack: simStack at: i.
- 	targetEntry := self simStack: mergeSimStack at: i.
- 	(currentEntry reconcilePushingWith: targetEntry) ifTrue:
- 		[self assert: i > methodOrBlockNumTemps.
- 		 self deassignRegisterForTempVar: targetEntry in: mergeSimStack.
- 		 targetEntry
- 			type: SSRegister;
- 			register: targetEntry liveRegister].
- 	 "Note, we could update the simStack and spillBase here but that is done in restoreSimStackAtMergePoint:
- 	 spilled ifFalse:
- 		[simSpillBase := i - 1].
- 	 simStack
- 		at: i
- 		put: (self
- 				cCode: [mergeSimStack at: i]
- 				inSmalltalk: [(mergeSimStack at: i) copy])"!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>reconcileRegisterStateForJoinAfterSpecialSelectorSend (in category 'bytecode generator support') -----
  reconcileRegisterStateForJoinAfterSpecialSelectorSend
  	"When the control flow from the inlined special selector code (e.g. add or comparison)
  	 joins the control flow from the send, taken when the inlined code fails, we should decide
  	 whether to reload any registers known to contain useful values or mark them as dead."
  	 
  	"Restore the simStack to that in scratchSimStack,
  	 popping any spilled state back into allocated registers."
+ 	| current spillOffset target |
  	simSpillBase := scratchSpillBase.
  	simStackPtr to: 0 by: -1 do:
  		[:i|
+ 		 spillOffset := i > methodOrBlockNumTemps
+ 							ifTrue: [self frameOffsetOfTemporary: i - 1]
+ 							ifFalse: [0].
+ 		 (current := self simStack: simStack at: i)
+ 			reconcileWith: (target := self simStack: scratchSimStack at: i)
+ 			spillOffset: spillOffset
+ 			onSpillOrUnspill:
+ 				[:targetReg|
+ 				 self assert: current spilled.
+ 				 self assert: spillOffset ~= 0.
+ 				 targetReg  ~= NoReg
+ 					ifTrue: [self PopR: targetReg]
+ 					ifFalse: [self AddCq: objectRepresentation wordSize R: SPReg]].
- 		 self assert: (i = simStackPtr
- 						ifTrue: [(self simStackAt: i) type = SSRegister]
- 						ifFalse: [(self simStackAt: i) spilled]).
- 		 (self simStackAt: i) reconcilePoppingWith: (self simStack: scratchSimStack at: i).
  		 simStack
  			at: i
  			put: (self
  					cCode: [scratchSimStack at: i]
  					inSmalltalk: [(scratchSimStack at: i) copy])]!

Item was removed:
- ----- Method: RegisterAllocatingCogit>>reconcileRegistersInTempVarsInCurrentSimStackWithThoseIn: (in category 'bytecode generator support') -----
- reconcileRegistersInTempVarsInCurrentSimStackWithThoseIn: mergeSimStack
- 	<var: #mergeSimStack type: #'SimStackEntry *'>
- 	0 to: methodOrBlockNumTemps do: 
- 		[ :i | | current target |
- 		current := self simStack: simStack at: i.
- 		target := self simStack: mergeSimStack at: i.
- 		target registerMaskOrNone ~= 0 
- 			ifTrue:
- 				[ target registerMaskOrNone ~= current registerMaskOrNone ifTrue:
- 					[ self swap: target with: current at: i]]
- 			ifFalse: [current liveRegister: NoReg]].
- 	^0!

Item was removed:
- ----- Method: RegisterAllocatingCogit>>swap:with:at: (in category 'bytecode generator support') -----
- swap: target with: current at: index
- 	"Swaps the registers between target and current.
- 	 target is guaranteed to be in a register. Current is not.
- 	 If current is in a register, just perform a register swap and update the simStack.
- 	 If current is not in a register, free the target register and use it.
- 	 Invariant:
- 		items in current's simStack up to index have been resolved with target because we are visiting the stack in order 0 to siumStackPtr.
- 	 Strategy:
- 		since the target simStack is valid (it has a unique disposition of temps) we can
- 		spill to obtain registers (since once an entry is written to ther stack its register, if any, can be freed)
- 		pop to assign after fully spilling (if necessary)"
- 	| currentLiveRegisters |
- 	self assert: target registerMaskOrNone ~= 0.
- 	current registerMaskOrNone ~= 0 ifTrue: 
- 		[ self SwapR: target liveRegister R: current liveRegister Scratch: RISCTempReg.
- 		  methodOrBlockNumTemps + 1 to: simStackPtr do: 
- 			[:i| | localCurrent |
- 			localCurrent := self simStack: simStack at: i.
- 			localCurrent liveRegister = current liveRegister 
- 				ifTrue: [ localCurrent liveRegister: target liveRegister ]
- 				ifFalse: [ localCurrent liveRegister = target liveRegister
- 						ifTrue: [ localCurrent liveRegister: current liveRegister ] ] ].
- 		current liveRegister: target liveRegister.
- 		 ^ 0 ].
- 	0 to: index - 1 do: [:j | self assert: (self simStack: simStack at: j) liveRegister ~= target liveRegister].
- 	
- 	currentLiveRegisters := self liveRegistersExceptingTopNItems: 0 in: simStack.
- 	(self register: target liveRegister isInMask: currentLiveRegisters) ifTrue:
- 		[self ssAllocateRequiredReg: target liveRegister].
- 	"Now target liveRegister is available. we set it."
- 	current storeToReg: target liveRegister.
- 	^0!



More information about the Vm-dev mailing list