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

commits at source.squeak.org commits at source.squeak.org
Tue Feb 20 02:25:03 UTC 2018


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

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

Name: VMMaker.oscog-eem.2335
Author: eem
Time: 19 February 2018, 6:24:41.264084 pm
UUID: 9525a938-a6aa-43d4-8bdc-e844e8e7e360
Ancestors: VMMaker.oscog-eem.2334

RegisterAllocatingCogit:
Improve (dare I say, fix??) the register permutation engine in the control flow merge logic.  Fix reconciling entries that oproduce an SSRegister entry (the liveRegister must be set to NoReg).  Fux recinciling a constanty with itself (this happens at the end of ifTrue:ifFalse: given that the bytecode compiler preserves the value of ifTrue:ifFalse: until a single trailing pop).  N.B. the merge engine could save effort by peeking ahead for a pop, but Scorch likely won't produyce such bad code so we shouldn't waste effort making the RegisterAllocatingCogit generate better code for non-Scorch input.

Simplify the incomprehensible garbage I wrote for assigning registers on temp var assignment.

Correct isFrameTempVar now that simSelf is niw a normal simStackEntry beneath the temps.  Add isFrameVar to be inclusive of self and temps.

Fix a slip in CogMIPSELCompiler class>>initializeAbstractRegisters.

Simulator:
Correct the size of the border around the display in the simulator windows,

VMMaker:
Add configurations for the mutli-threaded Spur VM.  It would be great to make progress on this yjis year.

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

Item was changed:
  ----- Method: CogMIPSELCompiler class>>initializeAbstractRegisters (in category 'class initialization') -----
  initializeAbstractRegisters
  	"Assign the abstract registers with the identities/indices of the relevant concrete registers."
  
  	"See MIPSConstants>>initializeRegisters for a description of the C ABI."
  
  	"Note we can fit all of the abstract registers in C preserved registers, and
  	 not need to save or restore them at runtime calls."
  	super initializeAbstractRegisters.
  
  	self flag: #OABI.
  	CallerSavedRegisterMask := self
  									registerMaskFor: T0 and: T1 and: T2 and: T3
  									and: T4 and: T5 and: T6 and: T7 and: T8 and: T9.
  
  	ReceiverResultReg		:= S0.
  	Arg0Reg				:= S1.
  	Arg1Reg				:= S2.
  	ClassReg				:= S3.
  	SendNumArgsReg		:= S4.
  	TempReg				:= S5.
  	VarBaseReg			:= S6. "Must be callee saved"
  	SPReg					:= SP.
  	FPReg					:= FP.
  	RISCTempReg			:= AT.
  	LinkReg					:= RA.
  
+ 	NumRegisters := 32.
- 	NumRegisters := 32
  
  	self flag: #todo.
  	"Extra0Reg			:= ??.
  	Extra1Reg			:= ??.
  	Extra2Reg			:= ??.
  	Extra3Reg			:= ??.
  	Extra4Reg			:= ??.
  	Extra5Reg			:= ??.
  	Extra6Reg			:= ??.
  	Extra7Reg			:= ??."
  
  	self flag: #todo.
  	"DPFPReg0				:= ??.
  	DPFPReg1				:= ??.
  	DPFPReg2				:= ??.
  	DPFPReg3				:= ??.
  	DPFPReg4				:= ??.
  	DPFPReg5				:= ??.
  	DPFPReg6				:= ??.
  	DPFPReg7				:= ??.
  	DPFPReg8				:= ??.
  	DPFPReg9				:= ??.
  	DPFPReg10				:= ??.
  	DPFPReg11				:= ??.
  	DPFPReg12				:= ??.
  	DPFPReg13				:= ??.
  	DPFPReg14				:= ??.
  	DPFPReg15				:= ??"!

Item was added:
+ ----- Method: CogRegisterAllocatingSimStackEntry>>popToRegNoAssign: (in category 'compile abstract instructions') -----
+ popToRegNoAssign: 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]] }]]!

Item was changed:
  ----- 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:
+ 									[liveRegister = NoReg
+ 										ifTrue: [cogit MoveMw: offset r: register R: targetReg]
+ 										ifFalse: [cogit MoveR: liveRegister R: targetReg].
- 									[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. liveRegister := NoReg] }].
+ 			[SSSpill]		-> [liveRegister = NoReg
+ 									ifTrue: [cogit MoveMw: offset r: register R: targetReg]
+ 									ifFalse: [cogit MoveR: liveRegister R: targetReg].
- 									[SSRegister]	-> [register := targetReg. type := SSRegister] }].
- 			[SSSpill]		-> [cogit MoveMw: offset r: register R: targetReg.
  								liveRegister := targetReg.
  								mergedRegister := true].
+ 			[SSConstant]	-> [(targetEntry type = SSConstant
+ 								 and: [targetEntry constant = constant
+ 								 and: [liveRegister = targetReg]]) ifFalse:
+ 									[liveRegister = NoReg
+ 										ifTrue: [cogit genMoveConstant: constant R: targetReg]
+ 										ifFalse: [cogit MoveR: liveRegister R: targetReg].
+ 									type := SSRegister. register := targetReg. liveRegister := NoReg.
+ 									mergedRegister := true]].
- 			[SSConstant]	-> [liveRegister = NoReg
- 									ifTrue: [cogit genMoveConstant: constant R: targetReg]
- 									ifFalse: [cogit MoveR: liveRegister R: targetReg].
- 								type := SSRegister. register := targetReg. liveRegister := NoReg.
- 								mergedRegister := true].
  			[SSRegister]	-> [targetReg ~= register ifTrue:
  									[cogit MoveR: register R: targetReg.
+ 									 register := targetReg. liveRegister := NoReg.
- 									 register := targetReg.
  									 mergedRegister := true]] }.
  		 ^mergedRegister].
  	targetReg := targetEntry registerOrNone.
  	spillOrUnspillBlock value: targetReg.
  	(type = SSConstant
  	 and: [targetEntry type ~= SSConstant or: [targetEntry constant ~= constant]]) ifTrue:
  		[type := SSSpill. offset := spillOffset. register := FPReg].
  	(spilled not and: [type = SSSpill]) ifTrue:
  		[self assert: targetReg ~= NoReg. type := SSRegister. register := targetReg].
  	liveRegister ~= targetReg ifTrue:
  		[liveRegister := NoReg.
  		 ^true].
  	^false!

Item was added:
+ ----- Method: CogRegisterAllocatingSimStackEntry>>storeToRegNoAssign: (in category 'compile abstract instructions') -----
+ storeToRegNoAssign: reg
+ 	liveRegister ~= NoReg
+ 		ifTrue:
+ 			[self deny: (type = SSRegister and: [register ~= liveRegister]).
+ 			 reg ~= liveRegister
+ 				ifTrue: [cogit MoveR: liveRegister R: reg]
+ 				ifFalse: [cogit Label]]
+ 		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]] }]!

Item was changed:
  VMStructType subclass: #CogSimStackEntry
  	instanceVariableNames: 'cogit objectRepresentation type spilled liveRegister register offset constant bcptr'
  	classVariableNames: ''
+ 	poolDictionaries: 'CogAbstractRegisters CogCompilationConstants CogRTLOpcodes VMStackFrameOffsets'
- 	poolDictionaries: 'CogAbstractRegisters CogCompilationConstants CogRTLOpcodes'
  	category: 'VMMaker-JIT'!
  
  !CogSimStackEntry commentStamp: 'eem 1/22/2018 17:13' prior: 0!
  A CogSimStackEntry represents an object pushed on the stack, but during the partial evaluation that occurs as part of the StackToRegisterMappingCogit's compilation.  Bytecodes that produce operands (push items onto the stack) push suitably descriptive instances of CogSimStackEntry onto the simStack (simulation stack).  Bytecodes that consume operands (sends, assignments, returns, etc) take items off the simStack.  Hence the generated code avoids pushing items onto the real stack, and the StackToRegisterMappngCogit can put the operands found on the simStack in registers, etc.  Hence actual stack traffic is much reduced, a much more efficient calling convention is enabled, and so overall performance is increased.  This scheme is due to L. Peter Deutsch and extended here.
  
  Instance Variables
  	bcptr:					<Integer>
  	cogit:					<StackToRegisterMappingCogit>
  	constant:				<Oop>
  	liveRegister:			<Integer>
  	objectRepresentation:	<CogObjectRepresentation>
  	offset:					<Integer>
  	register:				<Integer>
  	spilled:					<Boolean>
  	type:					<Integer from SSBaseOffset, SSConstant, SSRegister or SSSpill>
  
  bcptr
  	- the bytecode PC at which this particular entry was created (pushed onto the stack).
  
  cogit
  	- the StackToRegisterMappingCogit using this instance
  
  constant
  	- if type = SSConstant then this is the constant's oop
  
  liveRegister
  	- unused other than for simSelf.  This is here for simSelf and for the subclass CogRegisterAllocatingSimStackEntry
  
  objectRepresentation
  	- the CogObjectRepresentation in use for the current object model
  
  offset
  	- if type = SSBaseOffset or type = SSSpill then this is the offset from register
  
  register
  	- type = SSBaseOffset or type = SSSpill or type = SSRegister then this is the register's code (NoReg, TempReg, ReceiverResultReg et al)
  
  spilled
  	- if true, then this entry has been spilled onto the actual stack (or rather code has been generated to push the entry onto the real stack)
  
  type
  	- SSBaseOffset, SSConstant, SSRegister or SSSpill!

Item was added:
+ ----- Method: CogSimStackEntry>>isFrameSimSelf (in category 'comparing') -----
+ isFrameSimSelf
+ 	"Answer if the receiver is self.  This only works in a frameful method, hence the weird name."
+ 	<inline: true>
+ 	^type = SSBaseOffset and: [register = FPReg and: [offset = FoxMFReceiver]]!

Item was changed:
  ----- Method: CogSimStackEntry>>isFrameTempVar (in category 'comparing') -----
  isFrameTempVar
  	"Answer if the receiver is a temporary variable.  This
  	 only works in a frameful method, hence the weird name."
  	<inline: true>
+ 	^type = SSBaseOffset and: [register = FPReg and: [offset ~= FoxMFReceiver]]!
- 	^type = SSBaseOffset and: [register = FPReg]!

Item was added:
+ ----- Method: CogSimStackEntry>>isFrameVar (in category 'comparing') -----
+ isFrameVar
+ 	"Answer if the receiver is a temporary variable or self.  This
+ 	 only works in a frameful method, hence the weird name."
+ 	<inline: true>
+ 	^type = SSBaseOffset and: [register = FPReg]!

Item was changed:
  ----- Method: CogVMSimulator>>openAsMorph (in category 'UI') -----
  openAsMorph
  	"Open a morphic view on this simulation."
  	| localImageName borderWidth window |
  	localImageName := imageName
  							ifNotNil: [FileDirectory default localNameFor: imageName]
  							ifNil: [' synthetic image'].
  	window := (SystemWindow labelled: 'Simulation of ', localImageName) model: self.
  	window paneColor: self windowColorToUse.
  
  	window addMorph: (displayView := SimulatorImageMorph new image: displayForm)
  			frame: (0 at 0 corner: 1 at 0.8).
  	displayView activeHand addEventListener: self.
  	eventTransformer := SimulatorEventTransformer new.
  
  	transcript := TranscriptStream on: (String new: 10000).
  	window addMorph: (PluggableTextMorph
  							on: transcript text: nil accept: nil
  							readSelection: nil menu: #codePaneMenu:shifted:)
  			frame: (0 at 0.8 corner: 0.7 at 1).
  	window addMorph: (PluggableTextMorph on: self
  						text: #byteCountText accept: nil
  						readSelection: nil menu: #utilitiesMenu:) hideScrollBarsIndefinitely
  			frame: (0.7 at 0.8 corner: 1 at 1).
  
  	borderWidth := [SystemWindow borderWidth] "Squeak 4.1"
  						on: MessageNotUnderstood
  						do: [:ex| 0]. "3.8"
  	borderWidth := borderWidth + window borderWidth.
  	window openInWorldExtent: (self desiredDisplayExtent
+ 								+ (2 * borderWidth @ borderWidth)
- 								+ (2 * borderWidth)
  								+ (0 at window labelHeight)
  								* (1@(1/0.8))) rounded.
  	^window!

Item was changed:
  ----- Method: CogVMSimulator>>openAsMorphNoTranscript (in category 'UI') -----
  openAsMorphNoTranscript
  	"Open a morphic view on this simulation."
  	| localImageName borderWidth window |
  	localImageName := imageName
  							ifNotNil: [FileDirectory default localNameFor: imageName]
  							ifNil: [' synthetic image'].
  	window := (SystemWindow labelled: 'Simulation of ', localImageName) model: self.
  	window paneColor: self windowColorToUse.
  
  	window addMorph: (displayView := SimulatorImageMorph new image: displayForm)
  			frame: (0 at 0 corner: 1 at 0.95).
  	displayView activeHand addEventListener: self.
  	eventTransformer := SimulatorEventTransformer new.
  
  	window addMorph: (PluggableTextMorph on: self
  						text: #byteCountText accept: nil
  						readSelection: nil menu: #utilitiesMenu:) hideScrollBarsIndefinitely
  		frame: (0 at 0.95 corner: 1 at 1).
  
  	borderWidth := [SystemWindow borderWidth] "Squeak 4.1"
  						on: MessageNotUnderstood
  						do: [:ex| 0]. "3.8"
  	borderWidth := borderWidth + window borderWidth.
  	window openInWorldExtent: (self desiredDisplayExtent
+ 								+ (2 * borderWidth at borderWidth)
- 								+ (2 * borderWidth)
  								+ (0 at window labelHeight)
  								* (1@(1/0.95))) rounded!

Item was changed:
  ----- Method: Cogit>>methodFoundInvalidPostScan (in category 'testing') -----
  methodFoundInvalidPostScan
  	"This is a hook for subclasses to filter out methods they can't deal with."
+ 	<inline: true>
  	^false!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>genPushReceiverBytecode (in category 'bytecode generators') -----
+ genPushReceiverBytecode
+ 	^self ssPushDesc: self simSelf!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>genStorePop:TemporaryVariable: (in category 'bytecode generator support') -----
  genStorePop: popBoolean TemporaryVariable: tempIndex
  	<inline: false>
+ 	| top targetTemp srcRegOrNone destReg |
- 	| top srcRegOrNone destReg |
  	self deny: self duplicateRegisterAssignmentsInTemporaries.
  	self ssFlushUpThroughTemporaryVariable: tempIndex.
  	"To avoid a stall writing through destReg, remember srcReg before the potential ssPop: 1 in ssStorePop:toReg:"
  	top := self ssTop.
+ 	targetTemp := self simStackAt: tempIndex + 1.
  	srcRegOrNone := top registerOrNone.
+ 	"Take care to avoid duplicating registers in different temps and/or self."
+ 	destReg := targetTemp liveRegister.
+ 	destReg = NoReg ifTrue:
+ 		[destReg := self availableRegOrNoneNotConflictingWith: (self registerMaskUndesirableForTempVars bitOr: self liveRegisters)].
+ 	destReg = NoReg ifTrue:
+ 		[destReg := TempReg].
+ 	self deny: srcRegOrNone = destReg.
+ 	srcRegOrNone = NoReg
+ 		ifTrue: "Avoid duplicating destReg into top; this would only be ok if top
+ 				is the same entry as the target, which is not worth optimizing."
+ 			[self ssStorePopNoAssign: popBoolean toReg: destReg]
- 	"ssStorePop:toPreferredReg: will allocate a register, and indeed may allocate ReceiverResultReg
- 	 if, for example, the ssEntry to be popped is already in ReceiverResultReg (as the result of a send).
- 	 ReceiverResultReg is not a good choice for a temporary variable; it has other uses.  So if the ssEntry
- 	 at top of stack has ReceiverResultReg as its live variable, try and allocate an alternative."
- 	destReg := (self simStackAt: tempIndex + 1) liveRegister.
- 	destReg ~= NoReg
- 		ifTrue:
- 			[self ssStorePop: popBoolean toReg: destReg]
  		ifFalse:
+ 			[self ssStorePop: popBoolean toReg: destReg].
+ 	(destReg ~= TempReg and: [targetTemp liveRegister = NoReg]) ifTrue:
+ 		[targetTemp liveRegister: destReg.
+ 		 self copyLiveRegisterToCopiesOf: targetTemp].
- 			[((top type = SSConstant
- 			    or: [srcRegOrNone = NoReg
- 			    or: [self register: srcRegOrNone isInMask: self registerMaskUndesirableForTempVars]])
- 			  and: [(destReg := self availableRegOrNoneNotConflictingWith: (self registerMaskUndesirableForTempVars bitOr: self liveRegisters)) ~= NoReg])
- 				ifTrue: [self ssStorePop: popBoolean toReg: destReg]
- 				ifFalse: [destReg := self ssStorePop: popBoolean toPreferredReg: TempReg].
- 			 "The ssStorePop: may end up assigning a register to ssTop, and if it is also a temp then a new
- 			  register must be found for the destination temp, sicne two temp vars can't share a register."
- 			 (top isFrameTempVar and: [top liveRegister = destReg]) ifTrue:
- 				[srcRegOrNone := destReg.
- 				 destReg := self availableRegOrNoneNotConflictingWith: (self registerMaskUndesirableForTempVars bitOr: self liveRegisters).
- 				 destReg ~= NoReg ifTrue:
- 					[self MoveR: srcRegOrNone R: destReg]].
- 			 (destReg ~= NoReg and: [destReg ~= TempReg]) ifTrue:
- 				[(self simStackAt: tempIndex + 1) liveRegister: destReg.
- 				 self copyLiveRegisterToCopiesOf: (self simStackAt: tempIndex + 1)]].
  	self MoveR: (srcRegOrNone ~= NoReg ifTrue: [srcRegOrNone] ifFalse: [destReg])
  		Mw: (self frameOffsetOfTemporary: tempIndex)
  		r: FPReg.
+ 	targetTemp bcptr: bytecodePC. "for debugging"
- 	(self simStackAt: tempIndex + 1) bcptr: bytecodePC. "for debugging"
  	self deny: self duplicateRegisterAssignmentsInTemporaries.
  	^0!

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 them |
- 	| currentRegisters targetRegisters mergeSimStack current target spillOffset |
  	(mergeSimStack := fixup mergeSimStack) ifNil: [^self].
+ 	self cCode: '' inSmalltalk: [them := {self simStackPrintString. fixup simStackPrintString}].
  	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).
  	(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.
  						 simSpillBase <= i ifTrue:
  							[simSpillBase := i + 1]]) ifTrue:
  					[| targetReg |
  					 (i > methodOrBlockNumTemps and: [(targetReg := target registerOrNone) ~= NoReg]) ifTrue:
  						[self deassignRegister: targetReg in: simStack.
  						 self deassignRegister: targetReg in: mergeSimStack.
  						 self deny: (self register: targetReg isInMask: self liveRegistersInSelfAndTemps)]]]]
  		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].
  						 current spilled: false.
  						 simSpillBase > i ifTrue:
  							[simSpillBase := i]]) ifTrue:
  					[| targetReg |
  					 (i > methodOrBlockNumTemps and: [(targetReg := target registerOrNone) ~= NoReg]) ifTrue:
  						[self deassignRegister: targetReg in: simStack.
  						 self deassignRegister: targetReg in: mergeSimStack.
  						 self deny: (self register: targetReg isInMask: self liveRegistersInSelfAndTemps)]]]].
  	self updateSimSpillBase!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>mergeWithFixupIfRequired: (in category 'simulation stack') -----
  mergeWithFixupIfRequired: fixup
  	"If this bytecode has a fixup, some kind of merge needs to be done. There are 4 cases:
  		1) the bytecode has no fixup (fixup isNotAFixup)
  			do nothing
  		2) the bytecode has a non merge fixup
  			the fixup has needsNonMergeFixup.
  			The code generating non merge fixup (currently only special selector code) is responsible
  				for the merge so no need to do it.
  			We set deadCode to false as the instruction can be reached from jumps.
  		3) the bytecode has a merge fixup, but execution flow *cannot* fall through to the merge point.
  			the fixup has needsMergeFixup and deadCode = true.
  			ignores the current simStack as it does not mean anything 
  			restores the simStack to the state the jumps to the merge point expects it to be.
  		4) the bytecode has a merge fixup and execution flow *can* fall through to the merge point.
  			the fixup has needsMergeFixup and deadCode = false.
  			Merge the state into the fixup's state via mergeCurrentSimStackWith:forwards:.
  			
  	In addition, if this is a backjump merge point, we patch the fixup to hold the current simStackPtr 
  	for later assertions. self printSimStack: fixup mergeSimStack"
  
  	<var: #fixup type: #'BytecodeFixup *'>
  	deadCode ifFalse:
  		[self assertCorrectSimStackPtr].
  
  	"case 1"
  	fixup notAFixup ifTrue:
  		[^0].
  
  	"case 2"
  	fixup isNonMergeFixup ifTrue:
  		[deadCode
  			ifTrue:
  				[self deny: fixup simStackPtr isNil.
  				 simStackPtr := fixup simStackPtr.
  				 self restoreSimStackAtMergePoint: fixup.
  				 deadCode := false.
  				 self assertCorrectSimStackPtr]
  			ifFalse:
  				[self flushRegistersOnlyLiveOnFallThrough: fixup].
  		 ^0].
  
  	"cases 3 and 4"
  	self assert: fixup isMergeFixup.
  	self traceMerge: fixup.
  	deadCode 
  		ifTrue: "case 3"
+ 			[(fixup isBackwardBranchFixup and: [fixup mergeSimStack isNil]) "e.g. a loop within false ifTrue: []"
+ 				ifTrue: [self assert: fixup simStackPtr isNil]
+ 				ifFalse:
+ 					[simStackPtr := fixup simStackPtr.
+ 					 self restoreSimStackAtMergePoint: fixup.
+ 					 deadCode := false]]
- 			[simStackPtr := fixup simStackPtr.
- 			self restoreSimStackAtMergePoint: fixup.
- 			deadCode := false]
  		ifFalse: "case 4"
  			[(fixup isBackwardBranchFixup and: [compilationPass > 1])
  				ifTrue:
  					[fixup simStackPtr: simStackPtr.
  					 self mergeCurrentSimStackWith: fixup.
  					 self copySimStackToFixup: fixup]
  				ifFalse:
  					[self mergeCurrentSimStackWith: fixup]].
  	"cases 3 and 4"
  	fixup isBackwardBranchFixup ifTrue:
  		[fixup mergeSimStack ifNil:
  			[self assert: compilationPass = 1.
  			 self setMergeSimStackOf: fixup]].
  	fixup targetInstruction: self Label.
  	self assertCorrectSimStackPtr.
  	self assert: (self simStackMergeCompatibleWith: fixup).
  	"self simStackPrintString, fixup simStackPrintString"
  	^0!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>putSelfInReceiverResultReg (in category 'bytecode generator support') -----
+ putSelfInReceiverResultReg
+ 	"Override to force copying the register to duplicates on stack."
+ 	<inline: true>
+ 	| simSelfHasRegister |
+ 	simSelfHasRegister := self simSelf liveRegister ~= NoReg.
+ 	super putSelfInReceiverResultReg.
+ 	simSelfHasRegister ifTrue:
+ 		[self simSelf liveRegister: ReceiverResultReg.
+ 		 self copyLiveRegisterToCopiesOf: self simSelf]!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>resolveConflicts:with:to: (in category 'bytecode generator support') -----
  resolveConflicts: registersInCommon with: mergeSimStack to: simStackPtr
  	"registersInCommon is the register mask of registers in use in both the current
  	 simStack and the target mergeSimStack. Swap any and all conflicting register uses
  	 in registersInCommon, until register uses in simStack agree with mergeSimStack."
+ 	| registerExchanges registerLocations agreements visited initialIndex |
- 	| registerLocations visited |
  	"registerLocations records where a register has moved to
  	 during an exchange. This allows a single pass of the stack
  	 to rename registers, instead of 1/2 N^2; max stack ~ 56"
+ 	<var: 'registerExchanges' declareC: 'int registerExchanges[NumRegisters]'>
  	<var: 'registerLocations' declareC: 'int registerLocations[NumRegisters]'>
+ 	self deny: self duplicateRegisterAssignmentsInTemporaries.
  	registersInCommon = (self registerMaskFor: FPReg) ifTrue:
+ 		[self assert: (self conflictsResolvedBetweenSimStackAnd: mergeSimStack).
+ 		 ^self].
- 		[^self].
  	self cCode: '' inSmalltalk:
+ 		[registerExchanges := CArrayAccessor on: (Array new: NumRegisters).
+ 		 registerLocations := CArrayAccessor on: (Array new: NumRegisters)].
- 		[registerLocations := CArrayAccessor on: (Array new: NumRegisters)].
  	0 to: NumRegisters - 1 do:
+ 		[:i| registerExchanges at: i put: i].
+ 	initialIndex := opcodeIndex. "for debugging"
+ 	agreements := visited := 0.
- 		[:i| registerLocations at: i put: i].
- 	visited := 0.
  	0 to: simStackPtr do:
  		[:i| | currentReg targetReg |
  		currentReg := (self simStackAt: i) registerOrNone.
  		targetReg := (self simStack: mergeSimStack at: i) registerOrNone.
  		(currentReg ~= NoReg
  		 and: [targetReg ~= NoReg]) ifTrue:
+ 			[currentReg := registerExchanges at: currentReg.
+ 			 currentReg = targetReg
+ 				ifTrue:
+ 					[(self register: currentReg isInMask: visited) ifFalse:
+ 						[visited := visited bitOr: (self registerMaskFor: currentReg).
+ 						 agreements := agreements bitOr: (self registerMaskFor: currentReg)]]
+ 				ifFalse:
+ 					[((self register: currentReg isInMask: registersInCommon)
+ 					  and: [(self register: currentReg isNotInMask: visited)
+ 							or: [self register: targetReg isNotInMask: visited]]) ifTrue:
+ 						[| this that |
+ 						 visited := visited bitOr: (self registerMaskFor: currentReg and: targetReg).
+ 						 self SwapR: targetReg R: currentReg Scratch: RISCTempReg.
+ 						 this := registerExchanges at: currentReg.
+ 						 that := registerExchanges at: targetReg.
+ 						 registerExchanges
+ 							at: currentReg put: that;
+ 							at: targetReg put: this]]]].
+ 	(visited := visited bitClear: agreements) = 0 ifTrue:
+ 		[self assert: (self conflictsResolvedBetweenSimStackAnd: mergeSimStack).
+ 		 ^self].
+ 	0 to: NumRegisters - 1 do:
+ 		[:i| registerLocations at: (registerExchanges at: i) put: i].
- 			[currentReg := registerLocations at: currentReg.
- 			 (currentReg ~= targetReg
- 			  and: [(self register: currentReg isInMask: registersInCommon)
- 			  and: [(self register: currentReg isNotInMask: visited)]]) ifTrue:
- 				[visited := visited + (self registerMaskFor: currentReg).
- 				 self SwapR: targetReg R: currentReg Scratch: RISCTempReg.
- 				 registerLocations
- 					at: currentReg put: targetReg;
- 					at: targetReg put: currentReg]]].
- 	visited = 0 ifTrue:
- 		[^self].
  	0 to: simStackPtr do:
  		[:i| | ssEntry reg |
  		ssEntry := self simStackAt: i.
  		reg := ssEntry registerOrNone.
  		(reg ~= NoReg
  		 and: [(self register: reg isInMask: registersInCommon)
  		 and: [reg ~= (self simStack: mergeSimStack at: i) registerOrNone]]) ifTrue:
  			[ssEntry type = SSRegister
  				ifTrue: [ssEntry register: (registerLocations at: reg)]
+ 				ifFalse: [ssEntry liveRegister: (registerLocations at: reg)]]].
+ 	self deny: self duplicateRegisterAssignmentsInTemporaries.
+ 	self assert: (self conflictsResolvedBetweenSimStackAnd: mergeSimStack)
+ 	"(initialIndex to: opcodeIndex - 1) collect: [:x| abstractOpcodes at: x]"!
- 				ifFalse: [ssEntry liveRegister: (registerLocations at: reg)]]]!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>ssStorePopNoAssign:toReg: (in category 'simulation stack') -----
+ ssStorePopNoAssign: popBoolean toReg: reg
+ 	"Store or pop the top simulated stack entry to a register.
+ 	 Do /not/ assign reg to ssTop.
+ 	N.B.: popToReg: and storeToReg: does not generate anything if 
+ 	it moves a register to the same register."	
+ 	popBoolean
+ 		ifTrue: [self ssTop popToRegNoAssign: reg.
+ 				self ssPop: 1]
+ 		ifFalse: [self ssTop storeToRegNoAssign: reg].!

Item was changed:
  ----- Method: StackInterpreterSimulator>>openAsMorph (in category 'UI') -----
  openAsMorph
  	"Open a morphic view on this simulation."
  	| localImageName borderWidth window |
  	localImageName := imageName
  							ifNotNil: [FileDirectory default localNameFor: imageName]
  							ifNil: [' synthetic image'].
  	window := (SystemWindow labelled: 'Simulation of ', localImageName) model: self.
  	window paneColor: self windowColorToUse.
  
  	window addMorph: (displayView := SimulatorImageMorph new image: displayForm)
  			frame: (0 at 0 corner: 1 at 0.8).
  	displayView activeHand addEventListener: self.
  	eventTransformer := SimulatorEventTransformer new.
  
  	transcript := TranscriptStream on: (String new: 10000).
  	window addMorph: (PluggableTextMorph
  							on: transcript text: nil accept: nil
  							readSelection: nil menu: #codePaneMenu:shifted:)
  			frame: (0 at 0.8 corner: 0.7 at 1).
  	window addMorph: (PluggableTextMorph on: self
  						text: #byteCountText accept: nil
  						readSelection: nil menu: #utilitiesMenu:) hideScrollBarsIndefinitely
  			frame: (0.7 at 0.8 corner: 1 at 1).
  
  	borderWidth := [SystemWindow borderWidth] "Squeak 4.1"
  						on: MessageNotUnderstood
  						do: [:ex| 0]. "3.8"
  	borderWidth := borderWidth + window borderWidth.
  	window openInWorldExtent: (self desiredDisplayExtent
+ 								+ (2 * borderWidth at borderWidth)
- 								+ (2 * borderWidth)
  								+ (0 at window labelHeight)
  								* (1@(1/0.8))) rounded.
  	^window!

Item was changed:
  ----- Method: StackInterpreterSimulator>>openAsMorphNoTranscript (in category 'UI') -----
  openAsMorphNoTranscript
  	"Open a morphic view on this simulation."
  	| localImageName borderWidth window |
  	localImageName := imageName
  							ifNotNil: [FileDirectory default localNameFor: imageName]
  							ifNil: [' synthetic image'].
  	window := (SystemWindow labelled: 'Simulation of ', localImageName) model: self.
  	window paneColor: self windowColorToUse.
  
  	window addMorph: (displayView := SimulatorImageMorph new image: displayForm)
  			frame: (0 at 0 corner: 1 at 0.95).
  	displayView activeHand addEventListener: self.
  	eventTransformer := SimulatorEventTransformer new.
  
  	window addMorph: (PluggableTextMorph on: self
  						text: #byteCountText accept: nil
  						readSelection: nil menu: #utilitiesMenu:) hideScrollBarsIndefinitely
  		frame: (0 at 0.95 corner: 1 at 1).
  
  	borderWidth := [SystemWindow borderWidth] "Squeak 4.1"
  						on: MessageNotUnderstood
  						do: [:ex| 0]. "3.8"
  	borderWidth := borderWidth + window borderWidth.
  	window openInWorldExtent: (self desiredDisplayExtent
+ 								+ (2 * borderWidth at borderWidth)
- 								+ (2 * borderWidth)
  								+ (0 at window labelHeight)
  								* (1@(1/0.95))) rounded!

Item was added:
+ ----- Method: VMMaker class>>generateSqueakSpurCog64MTVM (in category 'configurations') -----
+ generateSqueakSpurCog64MTVM
+ 	"No primitives since we can use those for the Cog VM"
+ 	^VMMaker
+ 		generate: CoInterpreterMT
+ 		and: StackToRegisterMappingCogit
+ 		with: #(COGMTVM true
+ 				ObjectMemory Spur64BitCoMemoryManager
+ 				MULTIPLEBYTECODESETS true
+ 				bytecodeTableInitializer initializeBytecodeTableForSqueakV3PlusClosuresSistaV1Hybrid)
+ 		to: (FileDirectory default pathFromURI: self sourceTree, '/spur64src')
+ 		platformDir: (FileDirectory default pathFromURI: self sourceTree, '/platforms')
+ 		including:#()!

Item was added:
+ ----- Method: VMMaker class>>generateSqueakSpurCogMTVM (in category 'configurations') -----
+ generateSqueakSpurCogMTVM
+ 	"No primitives since we can use those for the Cog VM"
+ 	^VMMaker
+ 		generate: CoInterpreterMT
+ 		and: StackToRegisterMappingCogit
+ 		with: #(COGMTVM true
+ 				ObjectMemory Spur32BitCoMemoryManager
+ 				MULTIPLEBYTECODESETS true
+ 				bytecodeTableInitializer initializeBytecodeTableForSqueakV3PlusClosuresSistaV1Hybrid)
+ 		to: (FileDirectory default pathFromURI: self sourceTree, '/spursrc')
+ 		platformDir: (FileDirectory default pathFromURI: self sourceTree, '/platforms')
+ 		including:#()!



More information about the Vm-dev mailing list