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

commits at source.squeak.org commits at source.squeak.org
Fri Dec 2 17:00:19 UTC 2016


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

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

Name: VMMaker.oscog-eem.2020
Author: eem
Time: 2 December 2016, 8:59:35.572375 am
UUID: f53bedb4-3a2d-42ed-bf04-56ed996e7aa0
Ancestors: VMMaker.oscog-eem.2019

RegisterAllocatingCogit:
Give sensible names to the three reconciliation methods in CogRegisterAllocatingSimStackEntry.  Be sure to use registerOrNone, not just liveRegister.
Refactor mergeCurrentSimStackWith: for clarity.
Have restoreSimStackAtMergePoint: maintain optStatus.

Execution gets as far as a stack imbalance in a send from Dictionary>noCheckNoGrowFillFrom: during EventSensor startUp:.

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

Item was added:
+ ----- 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: #'targetEntry *'>
+ 	| 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 added:
+ ----- 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."
+ 	<var: #targetEntry type: #'targetEntry *'>
+ 	| targetReg |
+ 	(targetReg := targetEntry registerOrNone) = NoReg ifTrue:
+ 		[self assert: (self isSameEntryAs: targetEntry).
+ 		 ^self].
+ 	liveRegister ~= NoReg ifTrue:
+ 		[liveRegister ~= targetReg ifTrue:
+ 			[cogit MoveR: liveRegister R: targetReg].
+ 		 (spilled and: [targetEntry spilled not]) ifTrue:
+ 			[cogit AddCq: objectRepresentation wordSize R: SPReg].
+ 		 ^self].
+ 	spilled
+ 		ifTrue:
+ 			[targetEntry spilled ifTrue:
+ 				[cogit PopR: targetReg. "KISS; generate the least number of instructions..."
+ 				 ^self]]
+ 		ifFalse:
+ 			[self deny: targetEntry spilled].
+ 	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 changed:
  ----- 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: #'targetEntry *'>
+ 	| targetReg |
  	targetEntry spilled ifTrue:
  		[self assert: (self isSameEntryAs: targetEntry).
+ 		 (targetReg := targetEntry registerOrNone) = NoReg ifTrue:
- 		 targetEntry liveRegister = NoReg ifTrue:
  			[^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]	-> [targetReg ~= register ifTrue:
+ 										[cogit MoveR: register R: targetReg]] }.
- 				[SSBaseOffset]	-> [cogit MoveMw: offset r: register R: targetEntry liveRegister].
- 				[SSSpill]		-> [cogit MoveMw: offset r: register R: targetEntry liveRegister].
- 				[SSConstant]	-> [cogit genMoveConstant: constant R: targetEntry liveRegister].
- 				[SSRegister]	-> [targetEntry liveRegister ~= register ifTrue:
- 										[cogit MoveR: register R: targetEntry liveRegister]] }.
  		 ^self].
  	targetEntry type = SSConstant ifTrue:
+ 		[self assert: (targetEntry registerOrNone) = NoReg.
+ 		 cogit AddCq: objectRepresentation wordSize R: SPReg.
- 		[cogit AddCw: BytesPerWord R: SPReg.
  		 ^self].
+ 	(targetReg := targetEntry registerOrNone) ~= NoReg ifTrue:
+ 		[cogit PopR: targetReg.
- 	targetEntry registerOrNone ~= NoReg ifTrue:
- 		[cogit PopR: targetEntry registerOrNone.
  		 ^self].
  	self halt!

Item was removed:
- ----- Method: CogRegisterAllocatingSimStackEntry>>reconcileWith: (in category 'compile abstract instructions') -----
- reconcileWith: 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: #'targetEntry *'>
- 	targetEntry liveRegister = NoReg ifTrue:
- 		[^self].
- 	targetEntry type = SSConstant ifTrue:
- 		[self assert: (type = SSConstant and: [constant = targetEntry constant]).
- 		 ^self].
- 	liveRegister ~= NoReg ifTrue:
- 		[liveRegister ~= targetEntry liveRegister ifTrue:
- 			[cogit MoveR: liveRegister R: targetEntry liveRegister].
- 		 ^self].
- 	type caseOf: {
- 		[SSBaseOffset]	-> [cogit MoveMw: offset r: register R: targetEntry liveRegister].
- 		[SSSpill]		-> [cogit MoveMw: offset r: register R: targetEntry liveRegister].
- 		[SSConstant]	-> [cogit genMoveConstant: constant R: targetEntry liveRegister].
- 		[SSRegister]	-> [register ~= targetEntry liveRegister ifTrue:
- 								[cogit MoveR: register R: targetEntry liveRegister]] }!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>mergeCurrentSimStackWith: (in category 'bytecode generator support') -----
  mergeCurrentSimStackWith: mergeSimStack
  	<var: #mergeSimStack type: #'SimStackEntry *'>
  	"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 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."
+ 	| currentEntry targetEntry |
- 	| currentRegsMask mergeRegsMask potentialConflictRegMask conflictingRegsMask
- 	   currentRegMask mergeRegMask currentEntry targetEntry |
  	<var: #currentEntry type: #'SimStackEntry *'>
  	<var: #targetEntry type: #'SimStackEntry *'>
  	mergeSimStack ifNil: [^self].
+ 	"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 resolveRegisterOrderConflictsBetweenCurrentSimStackAnd: mergeSimStack.
- 	currentRegsMask := mergeRegsMask := potentialConflictRegMask := 0.
- 	0 to: simStackPtr do:
- 		[:i|
- 		 currentRegMask := (currentEntry := self simStack: simStack at: i) registerMaskOrNone.
- 		 mergeRegMask := (targetEntry := self simStack: mergeSimStack at: i) registerMaskOrNone.
- 		 currentRegMask = mergeRegMask
- 			ifTrue:
- 				[self assert: (currentEntry isSameEntryAs: targetEntry)]
- 			ifFalse: "This checks for a potential conflict..."
- 				[(currentRegMask ~= 0 or: [mergeRegMask ~= 0]) ifTrue:
- 					[potentialConflictRegMask := potentialConflictRegMask bitOr: (currentRegMask bitOr: mergeRegMask)]].
- 		 currentRegsMask := currentRegsMask bitOr: currentRegMask.
- 		 mergeRegsMask := mergeRegsMask bitOr: mergeRegMask].
- 	conflictingRegsMask := potentialConflictRegMask bitAnd: (currentRegsMask bitAnd: mergeRegsMask).
- 	"One simple algorithm is to spill everything if there are any conflicts and then pop back.
- 	 But this is terrible :-(  Can we do better? Yes... Consider the following two simStacks
- 		target:		0: | rA | __ | rB | rC | rD | <- sp
- 		current:	0: | __ | __ | rD | rA | rC | <- sp
- 	 If we were to assign in a naive order, 0 through sp rA would be overwritten before its value in current[3] is written to rC,
- 	 and rC would be overwritten before its value in current[4] is written to rD.  But if we swap the registers in current so that
- 	 they respect the reverse ordering in target we can assign directly:
- 		swap current[3] & current[4]
- 					0: | __ | __ | rD | rC | rA | <- sp
- 	now do the assignment in the order target[0] := current[0],  target[1] := current[1], ...  target[4] := current[4],
- 	i.e. rA := current[0]; rB := rD; (rC := rC); (rD := rD)."
- 	conflictingRegsMask ~= 0 ifTrue:
- 		[(self isAPowerOfTwo: conflictingRegsMask) "Multiple conflicts mean we have to sort"
- 			ifFalse: [self swapCurrentRegistersInMask: currentRegsMask accordingToRegisterOrderIn: mergeSimStack]
- 			ifTrue: [self assignToTempRegConflictingRegisterIn: conflictingRegsMask]].
  	self assert: (self conflcitsResolvedBetweenSimStackAnd: mergeSimStack).
  	simStackPtr to: 0 by: -1 do:
  		[:i|
+ 		 currentEntry := self simStack: simStack at: i.
+ 		 targetEntry := self simStack: mergeSimStack at: i.
+ 		 currentEntry reconcileForwardsWith: 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])"]!
- 		 currentRegMask := (currentEntry := self simStack: simStack at: i) registerMaskOrNone.
- 		 mergeRegMask := (targetEntry := self simStack: mergeSimStack at: i) registerMaskOrNone.
- 		 mergeRegMask ~= 0
- 			ifTrue:
- 				[currentRegMask ~= mergeRegMask
- 					ifTrue:
- 						[currentEntry reconcilePoppingWith: targetEntry.
- 						 simStack
- 							at: i
- 							put: (self
- 									cCode: [mergeSimStack at: i]
- 									inSmalltalk: [(mergeSimStack at: i) copy])]
- 					ifFalse:
- 						[self assert: (currentEntry isSameEntryAs: targetEntry)]]
- 			ifFalse:
- 				[self assert: (currentRegMask = 0 or: [currentEntry spilled]).
- 				 self assert: (currentEntry isSameEntryAs: targetEntry) "really? here to check"]]!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>reconcileRegisterStateForBackwardJoin: (in category 'bytecode generator support') -----
  reconcileRegisterStateForBackwardJoin: fixup 
  	<var: #fixup type: #'SSBytecodeFixup *'>
  	| fixupSimStack |
  	<var: #fixupSimStack type: #'SimStackEntry *'>
  	self assert: (optStatus ssEntry isSameEntryAs: simSelf). 
  	fixup isReceiverResultRegSelf ifTrue:
  		[optStatus isReceiverResultRegLive ifFalse:
  			[optStatus ssEntry storeToReg: ReceiverResultReg]].
  	fixupSimStack := fixup mergeSimStack.
  	simStackPtr to: 0 by: -1 do:
  		[:i|
  		 self assert: (self simStackAt: i) spilled.
+ 		 (self simStackAt: i) reconcileBackwardsWith: (fixupSimStack at: i)]!
- 		 (self simStackAt: i) reconcileWith: (fixupSimStack at: i)]!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>resolveRegisterOrderConflictsBetweenCurrentSimStackAnd: (in category 'bytecode generator support') -----
+ resolveRegisterOrderConflictsBetweenCurrentSimStackAnd: mergeSimStack
+ 	<var: #mergeSimStack type: #'SimStackEntry *'>
+ 	"One simple algorithm is to spill everything if there are any conflicts and then pop back.
+ 	 But this is terrible :-(  Can we do better? Yes... Consider the following two simStacks
+ 		target:		0: | rA | __ | rB | rC | rD | <- sp
+ 		current:	0: | __ | __ | rD | rA | rC | <- sp
+ 	 If we were to assign in a naive order, 0 through sp rA would be overwritten before its value in current[3] is written to rC,
+ 	 and rC would be overwritten before its value in current[4] is written to rD.  But if we swap the registers in current so that
+ 	 they respect the reverse ordering in target we can assign directly:
+ 		swap current[3] & current[4]
+ 					0: | __ | __ | rD | rC | rA | <- sp
+ 	 now do the assignment in the order target[0] := current[0],  target[1] := current[1], ...  target[4] := current[4],
+ 	 i.e. rA := current[0]; rB := rD; (rC := rC); (rD := rD).
+ 
+ 	 So find any conflicts, and if there are any, swap registers in the simStack to resolve them.
+ 	 The trivial case of a single conflict is resolved by assigning that conflict to TempReg.
+ 	"
+ 	| currentRegsMask mergeRegsMask potentialConflictRegMask conflictingRegsMask
+ 	   currentRegMask mergeRegMask currentEntry targetEntry |
+ 	<var: #currentEntry type: #'SimStackEntry *'>
+ 	<var: #targetEntry type: #'SimStackEntry *'>
+ 	currentRegsMask := mergeRegsMask := potentialConflictRegMask := 0.
+ 	0 to: simStackPtr do:
+ 		[:i|
+ 		 currentRegMask := (currentEntry := self simStack: simStack at: i) registerMaskOrNone.
+ 		 mergeRegMask := (targetEntry := self simStack: mergeSimStack at: i) registerMaskOrNone.
+ 		 (currentRegMask ~= mergeRegMask
+ 		  and: [currentRegMask ~= 0 or: [mergeRegMask ~= 0]]) ifTrue:
+ 			[potentialConflictRegMask := potentialConflictRegMask bitOr: (currentRegMask bitOr: mergeRegMask)].
+ 		 currentRegsMask := currentRegsMask bitOr: currentRegMask.
+ 		 mergeRegsMask := mergeRegsMask bitOr: mergeRegMask].
+ 	conflictingRegsMask := potentialConflictRegMask bitAnd: (currentRegsMask bitAnd: mergeRegsMask).
+ 	conflictingRegsMask ~= 0 ifTrue:
+ 		[(self isAPowerOfTwo: conflictingRegsMask) "Multiple conflicts mean we have to sort"
+ 			ifFalse: [self swapCurrentRegistersInMask: currentRegsMask accordingToRegisterOrderIn: mergeSimStack]
+ 			ifTrue: [self assignToTempRegConflictingRegisterIn: conflictingRegsMask]].!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>restoreSimStackAtMergePoint: (in category 'simulation stack') -----
  restoreSimStackAtMergePoint: fixup
  	<inline: true>
  	"All the execution paths reaching a merge point expect everything to be spilled
  	 on stack and the optStatus is unknown.  If the merge point follows a return, it
+ 	 isn't a merge, but a skip past a return.  If it is a real merge point then throw
- 	 isn't a merge, but a sdkip past a return.  If it is a real merge point then throw
  	 away all simStack and optStatus optimization state."
+ 	optStatus isReceiverResultRegLive: fixup isReceiverResultRegSelf.
  	fixup mergeSimStack ifNotNil:
  		[simSpillBase := methodOrBlockNumTemps.
- 		 self flag: 'try and maintain this through the merge'.
- 		 optStatus isReceiverResultRegLive: false.
  		 0 to: simStackPtr do:
  			[:i|
  			self cCode: [simStack at: i put: (fixup mergeSimStack at: i)]
  				inSmalltalk: [(simStack at: i) copyFrom: (fixup mergeSimStack at: i)]]].
  	^0!



More information about the Vm-dev mailing list