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

commits at source.squeak.org commits at source.squeak.org
Tue Nov 29 02:40:28 UTC 2016


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

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

Name: VMMaker.oscog-eem.2008
Author: eem
Time: 28 November 2016, 6:39:13.224577 pm
UUID: dbe9f47c-6639-4cbd-8ad6-733af9601f76
Ancestors: VMMaker.oscog-eem.2007, VMMaker.oscog-nice.2003

Merge with VMMaker.oscog-nice.2003.  Use SysV ifTrue: ... not cppIf:ifTrue:... as we are now going to generate two Cogits for X64.  Refactor the CogInLineLiteralsX64Compiler/CogOutOfLineLiteralsX64Compiler overrides for RISCTempReg vs ExtraReg6 to avoid testing SysV.

RegisterAllocatingCogit:
Change StackToRegisterMappingCogit>>allocateRegForStackEntryAt:notConflictingWith: et al to use registerOrNone to allow RegisterAllocatingCogit to allocate the live reg since it overrides registerOrNone.  Add registerMaskOrNone to complement.

Refactor maybeCountFixup to maybeCountFixup: and count extra fixups for jumps following inlined special selectors.

Avoid assigning temp vars to ReceiverResultReg et al by introducing registerMaskUndesirableForTempVars.

Add special selector comparison and special selector class handling.  Improve the code in CogObjectRepresentationForSpur>>genGetClassObjectOf:into:scratchReg:instRegIsReceiver: to avoid spilling instReg.

Have ensureNonMergeFixupAt: set the merge sim stack for the fixup.

Avoid allocating a liveRegister for SSRegister types in popToReg: and storeToReg: by not setting liveRegister and copyLiveRegisterToCopiesOf: if type is SSRegister.

Execution currently blows up in the block in send:toClassesNamedIn:with: trying to start-up Delay (a regression from earlier today).

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

Item was changed:
  ----- Method: CoInterpreter>>printFrameMethodFor: (in category 'debug printing') -----
  printFrameMethodFor: theFP
  	<inline: false>
  	| address it homeMethod obj |
  	<var: #theFP type: #'char *'>
  	<var: #address type: #'char *'>
  	<var: #homeMethod type: #'CogMethod *'>
  
  	address := theFP + FoxMethod.
  	it := stackPages longAt: address.
  	self printHex: address asInteger;
  		printChar: $:.
  	self print: '      method: ';
  		printHex: it.
  	self tab.
  	((self isMachineCodeFrame: theFP)
  	 and: [self mframeIsBlockActivation: theFP]) ifTrue:
  		[homeMethod := self mframeHomeMethod: theFP.
  		 self print: 'hm: '; printHex: homeMethod asInteger; tab].
  	obj := self frameMethodObject: theFP.
+ 	self shortPrintOop: obj!
- 	self printHex: obj; space; shortPrintOop: obj!

Item was changed:
  ----- Method: CogIA32Compiler>>genRemoveNArgsFromStack: (in category 'abi') -----
  genRemoveNArgsFromStack: n 
+ 	n = 0 ifFalse: [cogit AddCq: n * 4 R: ESP].
- 	cogit AddCq: n * 4 R: ESP.
  	^0!

Item was removed:
- ----- Method: CogInLineLiteralsX64Compiler class>>initializeAbstractRegisters (in category 'class initialization') -----
- initializeAbstractRegisters
- 	"Assign the abstract registers with the identities/indices of the relevant concrete registers."
- 
- 	super initializeAbstractRegisters.
- 	RISCTempReg := R8!

Item was added:
+ ----- Method: CogInLineLiteralsX64Compiler class>>initializeAbstractRegistersSysV (in category 'class initialization') -----
+ initializeAbstractRegistersSysV
+ 	"Assign the abstract registers with the identities/indices of the relevant concrete registers."
+ 
+ 	super initializeAbstractRegistersSysV.
+ 	RISCTempReg := R8!

Item was added:
+ ----- Method: CogInLineLiteralsX64Compiler class>>initializeAbstractRegistersWin64 (in category 'class initialization') -----
+ initializeAbstractRegistersWin64
+ 	"Assign the abstract registers with the identities/indices of the relevant concrete registers."
+ 
+ 	super initializeAbstractRegistersWin64.
+ 	RISCTempReg := R11!

Item was changed:
  ----- Method: CogObjectRepresentationForSpur>>genGetClassObjectOf:into:scratchReg:instRegIsReceiver: (in category 'compile abstract instructions') -----
  genGetClassObjectOf: instReg into: destReg scratchReg: scratchReg instRegIsReceiver: instRegIsReceiver
  	"Fetch the instance's class into destReg.  If the instance is not the receiver and is forwarded, follow forwarding."
  	| jumpIsImm jumpNotForwarded loop |
  	<var: #jumpIsImm type: #'AbstractInstruction *'>
  	<var: #jumpNotForwarded type: #'AbstractInstruction *'>
  	<var: #loop type: #'AbstractInstruction *'>
+ 	(instReg = destReg or: [instReg = scratchReg or: [destReg = scratchReg]]) ifTrue:
- 	instReg = destReg ifTrue:
  		[^BadRegisterSet].
  	loop := cogit MoveR: instReg R: scratchReg.
  	cogit AndCq: objectMemory tagMask R: scratchReg.
  	jumpIsImm := cogit JumpNonZero: 0.
  	self flag: #endianness.
  	"Get least significant half of header word in destReg"
  	cogit MoveMw: 0 r: instReg R: scratchReg.
  	"mask off class index"
  	cogit AndCq: objectMemory classIndexMask R: scratchReg.
  	instRegIsReceiver ifFalse:
  		["if it is forwarded..."
  		cogit CmpCq: objectMemory isForwardedObjectClassIndexPun R: scratchReg.
  		jumpNotForwarded := cogit JumpNonZero: 0.
  		"...follow the forwarding pointer and loop to fetch its classIndex"
  		cogit MoveMw: objectMemory baseHeaderSize r: instReg R: instReg.
  		cogit Jump: loop.
  		jumpNotForwarded jmpTarget: cogit Label].
  	jumpIsImm jmpTarget:
  	(cogit MoveR: scratchReg R: destReg).
+ 	scratchReg = TempReg
+ 		ifTrue: [cogit PushR: instReg]
+ 		ifFalse: [cogit MoveR: instReg R: scratchReg].
- 	cogit PushR: instReg.
  	self genGetClassObjectOfClassIndex: destReg into: instReg scratchReg: TempReg.
  	cogit MoveR: instReg R: destReg.
+ 	scratchReg = TempReg
+ 		ifTrue: [cogit PopR: instReg]
+ 		ifFalse: [cogit MoveR: scratchReg R: instReg].
- 	cogit PopR: instReg.
  	^0!

Item was removed:
- ----- Method: CogOutOfLineLiteralsX64Compiler class>>initializeAbstractRegisters (in category 'class initialization') -----
- initializeAbstractRegisters
- 	"Assign the abstract registers with the identities/indices of the relevant concrete registers."
- 
- 	super initializeAbstractRegisters.
- 	Extra6Reg := R8!

Item was added:
+ ----- Method: CogOutOfLineLiteralsX64Compiler class>>initializeAbstractRegistersSysV (in category 'class initialization') -----
+ initializeAbstractRegistersSysV
+ 	"Assign the abstract registers with the identities/indices of the relevant concrete registers."
+ 	super initializeAbstractRegistersSysV.
+ 	Extra6Reg := R8!

Item was added:
+ ----- Method: CogOutOfLineLiteralsX64Compiler class>>initializeAbstractRegistersWin64 (in category 'class initialization') -----
+ initializeAbstractRegistersWin64
+ 	"Assign the abstract registers with the identities/indices of the relevant concrete registers."
+ 	super initializeAbstractRegistersWin64.
+ 	Extra6Reg := R11!

Item was changed:
  ----- Method: CogRegisterAllocatingSimStackEntry>>popToReg: (in category 'compile abstract instructions') -----
  popToReg: reg
  	<var: #inst type: #'AbstractInstruction *'>
  	liveRegister ~= NoReg
  		ifTrue: 
  			[self deny: spilled.
+ 			 self deny: (type = SSRegister and: [register ~= liveRegister]).
  			 reg ~= liveRegister
  				ifTrue: [cogit MoveR: liveRegister R: reg]
+ 				ifFalse: [cogit Label]]
- 				ifFalse: [cogit Label] ]
  		ifFalse: 
  			[spilled
  				ifTrue:
  					[cogit PopR: reg]
  				ifFalse:
  					[type caseOf: {
  						[SSBaseOffset]	-> [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: [reg ~= liveRegister and: [type ~= SSRegister]]) ifTrue:
- 	reg ~= TempReg ifTrue:
  		[liveRegister := reg.
  		 cogit copyLiveRegisterToCopiesOf: self]!

Item was added:
+ ----- Method: CogRegisterAllocatingSimStackEntry>>registerMaskOrNone (in category 'accessing') -----
+ registerMaskOrNone
+ 	liveRegister ~= NoReg ifTrue:
+ 		[^cogit registerMaskFor: register].
+ 	^super registerMaskOrNone!

Item was changed:
  ----- Method: CogRegisterAllocatingSimStackEntry>>storeToReg: (in category 'compile abstract instructions') -----
  storeToReg: reg
- 	| inst |
- 	<var: #inst type: #'AbstractInstruction *'>
  	liveRegister ~= NoReg
  		ifTrue:
+ 			[self deny: spilled.
+ 			 self deny: (type = SSRegister and: [register ~= liveRegister]).
+ 			 reg ~= liveRegister
+ 				ifTrue: [cogit MoveR: liveRegister R: reg]
+ 				ifFalse: [cogit Label]]
- 			[inst := 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]] }].
+ 
+ 	(reg ~= TempReg and: [reg ~= liveRegister and: [type ~= SSRegister]]) ifTrue:
- 				[SSBaseOffset]	-> [inst := cogit MoveMw: offset r: register R: reg].
- 				[SSSpill]		-> [inst := cogit MoveMw: offset r: register R: reg].
- 				[SSConstant]	-> [inst := cogit genMoveConstant: constant R: reg].
- 				[SSRegister]	-> [inst := reg ~= register
- 												ifTrue: [cogit MoveR: register R: reg]
- 												ifFalse: [cogit Label]] }].
- 	reg ~= TempReg ifTrue:
  		[liveRegister := reg.
  		 cogit copyLiveRegisterToCopiesOf: self]!

Item was added:
+ ----- Method: CogSimStackEntry>>registerMaskOrNone (in category 'accessing') -----
+ registerMaskOrNone
+ 	^type = SSRegister ifTrue: [cogit registerMaskFor: register] ifFalse: [0]!

Item was changed:
  CogAbstractInstruction subclass: #CogX64Compiler
  	instanceVariableNames: ''
+ 	classVariableNames: 'CDQ CMPXCHGAwR CMPXCHGMwrR CPUID IDIVR IMULRR LFENCE LOCK MFENCE ModReg ModRegInd ModRegIndDisp32 ModRegIndSIB ModRegRegDisp32 ModRegRegDisp8 R10 R11 R12 R13 R14 R15 R8 R9 RAX RBP RBX RCX RDI RDX RSI RSP SFENCE SIB1 SIB2 SIB4 SIB8 SysV XCHGAwR XCHGMwrR XCHGRR XMM0L XMM10L XMM11L XMM12L XMM13L XMM14L XMM15L XMM1L XMM2L XMM3L XMM4L XMM5L XMM6L XMM7L XMM8L XMM9L'
- 	classVariableNames: 'ABI CDQ CMPXCHGAwR CMPXCHGMwrR CPUID IDIVR IMULRR LFENCE LOCK MFENCE ModReg ModRegInd ModRegIndDisp32 ModRegIndSIB ModRegRegDisp32 ModRegRegDisp8 R10 R11 R12 R13 R14 R15 R8 R9 RAX RBP RBX RCX RDI RDX RSI RSP SFENCE SIB1 SIB2 SIB4 SIB8 XCHGAwR XCHGMwrR XCHGRR XMM0L XMM10L XMM11L XMM12L XMM13L XMM14L XMM15L XMM1L XMM2L XMM3L XMM4L XMM5L XMM6L XMM7L XMM8L XMM9L'
  	poolDictionaries: ''
  	category: 'VMMaker-JIT'!
  
  !CogX64Compiler commentStamp: 'eem 9/14/2015 17:12' prior: 0!
  I generate x64 (x86-64) instructions from CogAbstractInstructions.  For reference see
  1. IA-32 Intel® Architecture Software Developer's Manual Volume 2A: Instruction Set Reference, A-M
  2. IA-32 Intel® Architecture Software Developer's Manual Volume 2A: Instruction Set Reference, N-Z
  	http://www.intel.com/products/processor/manuals/
  or
  AMD64 Architecture Programmer's Manual Volume 3: General-Purpose and System Instructions
  AMD64 Architecture Programmer's Manual Volume 4: 128-bit Media Instructions
  AMD64 Architecture Programmer's Manual Volume 5: 64-bit Media and x87 Floating Point Instructions
  	http://developer.amd.com/resources/documentation-articles/developer-guides-manuals/
  (® is supposed to be the Unicode "registered  sign").!

Item was removed:
- ----- Method: CogX64Compiler class>>ABI (in category 'accessing') -----
- ABI
- 	"Answer the name of the supported ABI, #SysV or #MSVC"
- 	^ABI!

Item was changed:
  ----- Method: CogX64Compiler class>>initialize (in category 'class initialization') -----
  initialize
  	"Initialize various x64 instruction-related constants.
  	 [1] IA-32 Intel® Architecture Software Developer's Manual Volume 2A: Instruction Set Reference, A-M"
  
  	"CogX64Compiler initialize"
  
  	self ~~ CogX64Compiler ifTrue: [^self].
  
+ 	initializationOptions
+ 		at: #ABI
+ 		ifPresent: [:abi| SysV := abi asUppercase ~= #WIN64]
+ 		ifAbsent: [SysV := true]. "Default ABI; set to true for SysV, false for WIN64"
- 	ABI ifNil:
- 		[ABI := #SysV]. "Default ABI; other choice is #MSVC"
  
  	RAX := 0.
  	RCX := 1.  "Were they completely mad or simply sadistic?"
  	RDX := 2.
  	RBX := 3.
  	RSP := 4.
  	RBP := 5.
  	RSI := 6.
  	RDI := 7.
  	R8 := 8.
  	R9 := 9.
  	R10 := 10.
  	R11 := 11.
  	R12 := 12.
  	R13 := 13.
  	R14 := 14.
  	R15 := 15.
  
  	XMM0L := 0.
  	XMM1L := 1.
  	XMM2L := 2.
  	XMM3L := 3.
  	XMM4L := 4.
  	XMM5L := 5.
  	XMM6L := 6.
  	XMM7L := 7.
  	XMM8L := 8.
  	XMM9L := 9.
  	XMM10L := 10.
  	XMM11L := 11.
  	XMM12L := 12.
  	XMM13L := 13.
  	XMM14L := 14.
  	XMM15L := 15.
  
  	"Mod R/M Mod fields.  See [1] Sec 2.4, 2.5 & 2.6 & Table 2-2"
  	ModRegInd := 0.
  		ModRegIndSIB := 4.
  		ModRegIndDisp32 := 5.
  	ModRegRegDisp8 := 1.
  	ModRegRegDisp32 := 2.
  	ModReg := 3.
  
  	"SIB Scaled Index modes.  See [1] Sec 2.4, 2.5 & 2.6 & Table 2-3"
  	SIB1 := 0.
  	SIB2 := 1.
  	SIB4 := 2.
  	SIB8 := 3.
  
  	"Specific instructions"
  	self
  		initializeSpecificOpcodes: #(CDQ IDIVR IMULRR CPUID LFENCE MFENCE SFENCE LOCK CMPXCHGAwR CMPXCHGMwrR XCHGAwR XCHGMwrR XCHGRR)
  		in: thisContext method!

Item was changed:
  ----- Method: CogX64Compiler class>>initializeAbstractRegisters (in category 'class initialization') -----
  initializeAbstractRegisters
  	"Assign the abstract registers with the identities/indices of the relevant concrete registers."
  	"[1] Figure 3.4 Register Usage in
  		System V Application Binary Interface
  		AMD64 Architecture Processor Supplement"
  
  	super initializeAbstractRegisters.
  
  	"N.B. RAX RCX & RDX are caller-save (scratch) registers.  Hence we use RCX for class and RDX for
  		receiver/result since these are written in all normal sends."
  
+ 	SysV
+ 		ifTrue: [self initializeAbstractRegistersSysV]
+ 		ifFalse: [self initializeAbstractRegistersWin64].
- 	CallerSavedRegisterMask := self
- 									registerMaskFor: RAX
- 									and: RCX
- 									and: RDX
- 									and: RSI
- 									and: RDI
- 									and: R8
- 									and: R9
- 									and: R10
- 									and: R11.
  
- 	TempReg				:= RAX.
- 	ClassReg				:= RCX.
- 	ReceiverResultReg		:= RDX.
- 	SendNumArgsReg		:= R9.
- 	SPReg					:= RSP.
- 	FPReg					:= RBP.
- 	Arg0Reg				:= RDI. "So as to agree with C ABI arg 0"
- 	Arg1Reg				:= RSI. "So as to agree with C ABI arg 1"
- 	VarBaseReg			:= RBX. "Must be callee saved"
- 	"R8 is either RISCTempReg or Extra6Reg depending on subclass."
- 	Extra0Reg				:= R10.
- 	Extra1Reg				:= R11.
- 	Extra2Reg				:= R12.
- 	Extra3Reg				:= R13.
- 	Extra4Reg				:= R14.
- 	Extra5Reg				:= R15.
- 
  	DPFPReg0				:= XMM0L.
  	DPFPReg1				:= XMM1L.
  	DPFPReg2				:= XMM2L.
  	DPFPReg3				:= XMM3L.
  	DPFPReg4				:= XMM4L.
  	DPFPReg5				:= XMM5L.
  	DPFPReg6				:= XMM6L.
  	DPFPReg7				:= XMM7L.
  	DPFPReg8				:= XMM8L.
  	DPFPReg9				:= XMM9L.
  	DPFPReg10				:= XMM10L.
  	DPFPReg11				:= XMM11L.
  	DPFPReg12				:= XMM12L.
  	DPFPReg13				:= XMM13L.
  	DPFPReg14				:= XMM14L.
  	DPFPReg15				:= XMM15L!

Item was added:
+ ----- Method: CogX64Compiler class>>initializeAbstractRegistersSysV (in category 'class initialization') -----
+ initializeAbstractRegistersSysV
+ 	"Assign the abstract registers with the identities/indices of the relevant concrete registers."
+ 	"[1] Figure 3.4 Register Usage in
+ 		System V Application Binary Interface
+ 		AMD64 Architecture Processor Supplement"
+ 
+ 	"N.B. RAX RCX & RDX are caller-save (scratch) registers.  Hence we use RCX for class and RDX for
+ 		receiver/result since these are written in all normal sends."
+ 
+ 	CallerSavedRegisterMask := self
+ 									registerMaskFor: RAX
+ 									and: RCX
+ 									and: RDX
+ 									and: RSI
+ 									and: RDI
+ 									and: R8
+ 									and: R9
+ 									and: R10
+ 									and: R11.
+ 
+ 	TempReg				:= RAX.
+ 	ClassReg				:= RCX.
+ 	ReceiverResultReg		:= RDX.
+ 	SendNumArgsReg		:= R9.
+ 	SPReg					:= RSP.
+ 	FPReg					:= RBP.
+ 	Arg0Reg				:= RDI. "So as to agree with C ABI arg 0"
+ 	Arg1Reg				:= RSI. "So as to agree with C ABI arg 1"
+ 	VarBaseReg			:= RBX. "Must be callee saved"
+ 	"R8 is either RISCTempReg or Extra6Reg depending on subclass."
+ 	Extra0Reg				:= R10.
+ 	Extra1Reg				:= R11.
+ 	Extra2Reg				:= R12.
+ 	Extra3Reg				:= R13.
+ 	Extra4Reg				:= R14.
+ 	Extra5Reg				:= R15!

Item was added:
+ ----- Method: CogX64Compiler class>>initializeAbstractRegistersWin64 (in category 'class initialization') -----
+ initializeAbstractRegistersWin64
+ 	"Assign the abstract registers with the identities/indices of the relevant concrete registers."
+ 
+ 	"N.B. Since receiver/result are written in all normal sends,
+ 	it's better to use scratch registers for them (those which are caller-saved).
+ 	In Win64 ABI, this does not let that many choices:
+ 	- RAX is TempReg (overwritten by result etc...)
+ 	- RCX and RDX are used for first 2 args (see genMarshallNArgs:arg:arg:arg:arg:)
+ 	- it remains R8,R9,R10 & R11 : we choose the first two"
+ 
+ 	CallerSavedRegisterMask := self
+ 									registerMaskFor: RAX
+ 									and: RCX
+ 									and: RDX
+ 									and: R8
+ 									and: R9
+ 									and: R10
+ 									and: R11.
+ 
+ 	TempReg				:= RAX.
+ 	ClassReg				:= R8.
+ 	ReceiverResultReg		:= R9.
+ 	SendNumArgsReg		:= R10.
+ 	SPReg					:= RSP.
+ 	FPReg					:= RBP.
+ 	Arg0Reg				:= RCX. "So as to agree with C ABI arg 0"
+ 	Arg1Reg				:= RDX. "So as to agree with C ABI arg 1"
+ 	VarBaseReg			:= RBX. "Must be callee saved"
+ 	"R11 is either RISCTempReg or Extra6Reg depending on subclass."
+ 	Extra0Reg				:= RDI.
+ 	Extra1Reg				:= RSI.
+ 	Extra2Reg				:= R12.
+ 	Extra3Reg				:= R13.
+ 	Extra4Reg				:= R14.
+ 	Extra5Reg				:= R15!

Item was added:
+ ----- Method: CogX64Compiler class>>isSysV (in category 'accessing') -----
+ isSysV
+ 	"Answer true is ABI is SysV, false otherwise (for WIN64)"
+ 	^SysV!

Item was changed:
  ----- Method: CogX64Compiler>>cResultRegister (in category 'accessing') -----
  cResultRegister
+ 	"Answer the register through which C functions return integral results."
- 	"Answer the register through which C funcitons return integral results."
  	<inline: true>
  	^RAX!

Item was changed:
  ----- Method: CogX64Compiler>>genMarshallNArgs:arg:arg:arg:arg: (in category 'abi') -----
  genMarshallNArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3
  	"Generate the code to pass up to four arguments in a C run-time call.  Hack: each argument is
  	 either a negative number, which encodes a constant, or a non-negative number, that of a register.
  
  	 Run-time calls have no more than four arguments, so chosen so that on ARM, where in its C ABI the
  	 first four integer arguments are passed in registers, all arguments can be passed in registers.  We
  	 defer to the back end to generate this code not so much that the back end knows whether it uses
  	 the stack or registers to pass arguments (it does, but...). In fact we defer for an extremely evil reason.
  	 Doing so allows the x64 (where up to 6 args are passed) to assign the register arguments in an order
  	 that allows some of the argument registers to be used for specific abstract  registers, specifically
  	 ReceiverResultReg and ClassReg.  This is evil, evil, evil, but also it's really nice to keep using the old
  	 register assignments the original author has grown accustomed to.
  
  	 How can this possibly work?  Look at Cogit class>>runtime for a list of the run-time calls and their
  	 arguments, including which arguments are passed in which registers.  Look at CogX64Compiler's
  	 subclass implementations of initializeAbstractRegisters.  There are no calls in which ReceiverResultReg
  	 (RDX) and/or ClassReg (RCX) are passed along with Arg0Reg and Arg1Reg, and none in which the use of
  	 either ReceiverResultReg or ClassReg conflict for args 3 & 4.  So if args are assigned in order, the
  	 registers do not get overwritten.  Yes, this is evil, but it's so nice to continue to use RCX & RDX.
  
+ 	 Argument registers for args 0 to 3 in SysV are RDI RSI RDX RCX, and in Win64 are RCX RDX R8 R9"
- 	 Argument registers for args 0 to 3 in SysV are RDI RSI RDX RCX, and in Win64 are RDI RSI R8 R9"
  	<inline: true>
+ 	SysV ifFalse: "WIN64 ABI allways reserve shadow space on the stack for callee to save up to 4 register parameters"
+ 		[cogit SubCq: 32 R: RSP].
  	numArgs = 0 ifTrue: [^self].
+ 	SysV
+ 		 ifTrue:
+ 			[(cogit isTrampolineArgConstant: regOrConst0)
+ 				ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst0) R: RDI] "a.k.a. Arg0Reg"
+ 				ifFalse:
+ 					[regOrConst0 ~= RDI ifTrue:
+ 						[cogit MoveR: regOrConst0 R: RDI]].
+ 			numArgs = 1 ifTrue: [^self].
+ 			(cogit isTrampolineArgConstant: regOrConst1)
+ 				ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst1) R: RSI] "a.k.a. Arg1Reg"
+ 				ifFalse:
+ 					[regOrConst1 ~= RSI ifTrue:
+ 						[cogit MoveR: regOrConst1 R: RSI]].
+ 			numArgs = 2 ifTrue: [^self].
+ 			(cogit isTrampolineArgConstant: regOrConst2)
+ 				ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst2) R: RDX] "a.k.a. ReceiverResultReg"
+ 				ifFalse:
+ 					[regOrConst2 ~= RDX ifTrue:
+ 						[cogit MoveR: regOrConst2 R: RDX]].
+ 			 numArgs = 3 ifTrue: [^self].
+ 			 (cogit isTrampolineArgConstant: regOrConst3)
+ 					ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst3) R: RCX] "a.k.a. ClassReg"
+ 					ifFalse:
+ 						[regOrConst3 ~= RCX ifTrue:
+ 							[cogit MoveR: regOrConst3 R: RCX]]]
- 	(cogit isTrampolineArgConstant: regOrConst0)
- 		ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst0) R: RDI] "a.k.a. Arg0Reg"
  		ifFalse:
+ 			[(cogit isTrampolineArgConstant: regOrConst0)
+ 				ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst0) R: RCX] "a.k.a. Arg0Reg"
- 			[regOrConst0 ~= RDI ifTrue:
- 				[cogit MoveR: regOrConst0 R: RDI]].
- 	numArgs = 1 ifTrue: [^self].
- 	(cogit isTrampolineArgConstant: regOrConst1)
- 		ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst1) R: RSI] "a.k.a. Arg1Reg"
- 		ifFalse:
- 			[regOrConst1 ~= RSI ifTrue:
- 				[cogit MoveR: regOrConst1 R: RSI]].
- 	numArgs = 2 ifTrue: [^self].
- 	self cppIf: ABI == #SysV ifTrue:
- 		[(cogit isTrampolineArgConstant: regOrConst2)
- 			ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst2) R: RDX] "a.k.a. ReceiverResultReg"
- 			ifFalse:
- 				[regOrConst2 ~= RDX ifTrue:
- 					[cogit MoveR: regOrConst2 R: RDX]].
- 		 numArgs = 3 ifTrue: [^self].
- 		 (cogit isTrampolineArgConstant: regOrConst3)
- 				ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst3) R: RCX] "a.k.a. ClassReg"
  				ifFalse:
+ 					[regOrConst0 ~= RCX ifTrue:
+ 						[cogit MoveR: regOrConst0 R: RCX]].
+ 			numArgs = 1 ifTrue: [^self].
+ 			(cogit isTrampolineArgConstant: regOrConst1)
+ 				ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst1) R: RDX] "a.k.a. Arg1Reg"
- 					[regOrConst3 ~= RCX ifTrue:
- 						[cogit MoveR: regOrConst3 R: RCX]]].
- 	self cppIf: ABI == #MSVC ifTrue: "completely untested..."
- 		[(cogit isTrampolineArgConstant: regOrConst2)
- 			ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst2) R: R8] "a.k.a. RISCTempReg in CogInLineLiteralsX64Compiler and Extra6Reg in CogOutOfLineLiteralsX64Compiler"
- 			ifFalse:
- 				[regOrConst2 ~= R8 ifTrue:
- 					[cogit MoveR: regOrConst2 R: R8]].
- 		 numArgs = 3 ifTrue: [^self].
- 		 (cogit isTrampolineArgConstant: regOrConst3)
- 				ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst3) R: R9] "a.k.a. SendNumArgsReg"
  				ifFalse:
+ 					[regOrConst1 ~= RDX ifTrue:
+ 						[cogit MoveR: regOrConst1 R: RDX]].
+ 			numArgs = 2 ifTrue: [^self].
+ 			(cogit isTrampolineArgConstant: regOrConst2)
+ 				ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst2) R: R8] "a.k.a. RISCTempReg in CogInLineLiteralsX64Compiler and Extra6Reg in CogOutOfLineLiteralsX64Compiler"
+ 				ifFalse:
+ 					[regOrConst2 ~= R8 ifTrue:
+ 						[cogit MoveR: regOrConst2 R: R8]].
+ 			 numArgs = 3 ifTrue: [^self].
+ 			 (cogit isTrampolineArgConstant: regOrConst3)
+ 					ifTrue: [cogit MoveCq: (cogit trampolineArgValue: regOrConst3) R: R9] "a.k.a. SendNumArgsReg"
+ 					ifFalse:
+ 						[regOrConst3 ~= R9 ifTrue:
+ 							[cogit MoveR: regOrConst3 R: R9]]].
- 					[regOrConst3 ~= R9 ifTrue:
- 						[cogit MoveR: regOrConst3 R: R9]]].
  	self assert: numArgs <= 4!

Item was changed:
  ----- Method: CogX64Compiler>>genRemoveNArgsFromStack: (in category 'abi') -----
  genRemoveNArgsFromStack: n
+ 	"This is a no-op on x64 SysV since the ABI passes up to 6 args in registers and trampolines currently observe a limit of 4.
+ 	But the WIN64 ABI allways reserve shadow space for saving up to 4 parameter registers (even if less than 4 args)."
+ 	self assert: n <= 4.
+ 	SysV ifFalse: [cogit AddCq: 32 R: RSP].
- 	"This is a no-op on x64 since the ABI passes up to 6 args in registers and trampolines currently observe a limit of 4."
- 	self assert: n <= 6.
  	^0!

Item was changed:
  ----- Method: CogX64Compiler>>numIntRegArgs (in category 'accessing') -----
  numIntRegArgs
+ 	^SysV ifTrue: [6] ifFalse: [4]!
- 	^6!

Item was changed:
  ----- Method: Cogit>>compileCallFor:numArgs:arg:arg:arg:arg:floatResultReg:regsToSave: (in category 'initialization') -----
  compileCallFor: aRoutine numArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3 floatResultReg: resultRegOrNone regsToSave: regMask
  	"Generate a call to aRoutine with up to 4 arguments.  If resultRegOrNone is not
  	 NoReg assign the C result to resultRegOrNone.  If saveRegs, save all registers.
  	 Hack: a negative arg value indicates an abstract register, a non-negative value
  	 indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<inline: false>
  	| regsToSave |
  	regsToSave := resultRegOrNone = NoReg
  						ifTrue: [regMask]
  						ifFalse: [regMask bitClear: (self registerMaskFor: resultRegOrNone)].
  	cStackAlignment > objectMemory wordSize ifTrue:
  		[backEnd
  			genAlignCStackSavingRegisters: regsToSave
  			numArgs: numArgs
  			wordAlignment: cStackAlignment / objectMemory wordSize].
  	backEnd
  		genSaveRegs: regsToSave;
  		genMarshallNArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3.
  	self CallFullRT: (self cCode: [aRoutine asUnsignedInteger]
  						inSmalltalk: [self simulatedTrampolineFor: aRoutine]).
  	resultRegOrNone ~= NoReg ifTrue:
  		[backEnd cFloatResultToRd: resultRegOrNone].
+ 	 backEnd genRemoveNArgsFromStack: numArgs.
- 	 numArgs > 0 ifTrue:
- 		[backEnd genRemoveNArgsFromStack: numArgs].
  	backEnd genRestoreRegs: regsToSave!

Item was changed:
  ----- Method: Cogit>>compileCallFor:numArgs:arg:arg:arg:arg:resultReg:regsToSave: (in category 'initialization') -----
  compileCallFor: aRoutine numArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3 resultReg: resultRegOrNone regsToSave: regMask
  	"Generate a call to aRoutine with up to 4 arguments.  If resultRegOrNone is not
  	 NoReg assign the C result to resultRegOrNone.  If saveRegs, save all registers.
  	 Hack: a negative arg value indicates an abstract register, a non-negative value
  	 indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<inline: false>
  	| regsToSave |
  	regsToSave := resultRegOrNone = NoReg
  						ifTrue: [regMask]
  						ifFalse: [regMask bitClear: (self registerMaskFor: resultRegOrNone)].
  	cStackAlignment > objectMemory wordSize ifTrue:
  		[backEnd
  			genAlignCStackSavingRegisters: regsToSave
  			numArgs: numArgs
  			wordAlignment: cStackAlignment / objectMemory wordSize].
  	backEnd
  		genSaveRegs: regsToSave;
  		genMarshallNArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3.
  	self CallFullRT: (self cCode: [aRoutine asUnsignedInteger]
  						inSmalltalk: [self simulatedTrampolineFor: aRoutine]).
  	resultRegOrNone ~= NoReg ifTrue:
  		[backEnd genWriteCResultIntoReg: resultRegOrNone].
+ 	backEnd genRemoveNArgsFromStack: numArgs.
- 	 numArgs > 0 ifTrue:
- 		[backEnd genRemoveNArgsFromStack: numArgs].
  	backEnd genRestoreRegs: regsToSave!

Item was changed:
  ----- Method: Cogit>>compileCallFor:numArgs:arg:arg:arg:arg:resultReg:resultReg:regsToSave: (in category 'initialization') -----
  compileCallFor: aRoutine numArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3 resultReg: resultRegOrNone resultReg: resultReg2OrNone regsToSave: regMask
  	"Generate a call to aRoutine with up to 4 arguments.  If resultRegOrNone is not
  	 NoReg assign the C result to resultRegOrNone.  If saveRegs, save all registers.
  	 Hack: a negative arg value indicates an abstract register, a non-negative value
  	 indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<inline: false>
  	| regsToSave |
  	regsToSave := resultRegOrNone = NoReg
  						ifTrue: [regMask]
  						ifFalse: [regMask bitClear: (self registerMaskFor: resultRegOrNone)].
  	cStackAlignment > objectMemory wordSize ifTrue:
  		[backEnd
  			genAlignCStackSavingRegisters: regsToSave
  			numArgs: numArgs
  			wordAlignment: cStackAlignment / objectMemory wordSize].
  	backEnd
  		genSaveRegs: regsToSave;
  		genMarshallNArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3.
  	self CallFullRT: (self cCode: [aRoutine asUnsignedInteger]
  						inSmalltalk: [self simulatedTrampolineFor: aRoutine]).
  	resultRegOrNone ~= NoReg ifTrue:
  		[backEnd genWriteCResultIntoReg: resultRegOrNone].
  	resultReg2OrNone ~= NoReg ifTrue:
  		[backEnd genWriteCSecondResultIntoReg: resultReg2OrNone].
+ 	backEnd genRemoveNArgsFromStack: numArgs.
- 	 numArgs > 0 ifTrue:
- 		[backEnd genRemoveNArgsFromStack: numArgs].
  	backEnd genRestoreRegs: regsToSave!

Item was changed:
  ----- Method: Cogit>>compileCallFor:numArgs:floatArg:floatArg:floatArg:floatArg:resultReg:regsToSave: (in category 'initialization') -----
  compileCallFor: aRoutine numArgs: numArgs floatArg: regOrConst0 floatArg: regOrConst1 floatArg: regOrConst2 floatArg: regOrConst3 resultReg: resultRegOrNone regsToSave: regMask
  	"Generate a call to aRoutine with up to 4 arguments.  If resultRegOrNone is not
  	 NoReg assign the C result to resultRegOrNone.  If saveRegs, save all registers.
  	 Hack: a negative arg value indicates an abstract register, a non-negative value
  	 indicates a constant."
  	<option: #LowcodeVM>
  	<var: #aRoutine type: #'void *'>
  	<inline: false>
  	| regsToSave |
  	regsToSave := resultRegOrNone = NoReg
  						ifTrue: [regMask]
  						ifFalse: [regMask bitClear: (self registerMaskFor: resultRegOrNone)].
  	cStackAlignment > objectMemory wordSize ifTrue:
  		[backEnd
  			genAlignCStackSavingRegisters: regsToSave
  			numArgs: numArgs
  			wordAlignment: cStackAlignment / objectMemory wordSize].
  	backEnd
  		genSaveRegs: regsToSave;
  		genMarshallNArgs: numArgs floatArg: regOrConst0 floatArg: regOrConst1 floatArg: regOrConst2 floatArg: regOrConst3.
  	self CallFullRT: (self cCode: [aRoutine asUnsignedInteger]
  						inSmalltalk: [self simulatedTrampolineFor: aRoutine]).
  	resultRegOrNone ~= NoReg ifTrue:
  		[backEnd genWriteCResultIntoReg: resultRegOrNone].
+ 	backEnd genRemoveNFloatArgsFromStack: numArgs.
- 	 numArgs > 0 ifTrue:
- 		[backEnd genRemoveNFloatArgsFromStack: numArgs].
  	backEnd genRestoreRegs: regsToSave!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>allocateRegForStackEntryAt: (in category 'simulation stack') -----
+ allocateRegForStackEntryAt: index
+ 	"If the stack entry is already in a register, answers it,
+ 	else allocate a new register for it"
+ 	<inline: true>
+ 	^self allocateRegForStackEntryAt: index notConflictingWith: (self registerMaskFor: FPReg and: SPReg and: TempReg)!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>ensureNonMergeFixupAt: (in category 'compile abstract instructions') -----
+ ensureNonMergeFixupAt: targetIndex
+ 	"Make sure there's a flagged fixup at the targetIndex (pc relative to first pc) in fixups.
+ 	 Initially a fixup's target is just a flag.  Later on it is replaced with a proper instruction."
+ 	| fixup |
+ 	fixup := super ensureNonMergeFixupAt: targetIndex.
+ 	self setMergeSimStackOf: fixup.
+ 	^fixup!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>genSpecialSelectorClass (in category 'bytecode generators') -----
+ genSpecialSelectorClass
+ 	| topReg destReg scratchReg |
+ 	topReg := self allocateRegForStackEntryAt: 0.
+ 	destReg := self allocateRegNotConflictingWith: (self registerMaskFor: topReg).
+ 	scratchReg := self allocateRegNotConflictingWith: (self registerMaskFor: topReg and: destReg).
+ 	self ssTop popToReg: topReg.
+ 	self asserta: (objectRepresentation
+ 					genGetClassObjectOf: topReg
+ 					into: destReg
+ 					scratchReg: scratchReg
+ 					instRegIsReceiver: false) ~= BadRegisterSet.
+ 	self ssPop: 1; ssPushRegister: destReg.
+ 	^0!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>genSpecialSelectorComparison (in category 'bytecode generators') -----
+ genSpecialSelectorComparison
+ 	| nextPC postBranchPC targetBytecodePC primDescriptor branchDescriptor
+ 	  rcvrIsInt argIsInt argInt jumpNotSmallInts inlineCAB index rcvrReg argReg regMask |
+ 	<var: #primDescriptor type: #'BytecodeDescriptor *'>
+ 	<var: #branchDescriptor type: #'BytecodeDescriptor *'>
+ 	<var: #jumpNotSmallInts type: #'AbstractInstruction *'>
+ 	primDescriptor := self generatorAt: byte0.
+ 	argIsInt := self ssTop type = SSConstant
+ 				 and: [objectMemory isIntegerObject: (argInt := self ssTop constant)].
+ 	rcvrIsInt := (self ssValue: 1) type = SSConstant
+ 				 and: [objectMemory isIntegerObject: (self ssValue: 1) constant].
+ 
+ 	(argIsInt and: [rcvrIsInt]) ifTrue:
+ 		[^ self genStaticallyResolvedSpecialSelectorComparison].
+ 
+ 	self extractMaybeBranchDescriptorInto: [ :descr :next :postBranch :target | 
+ 		branchDescriptor := descr. nextPC := next. postBranchPC := postBranch. targetBytecodePC := target ].
+ 
+ 	"Only interested in inlining if followed by a conditional branch."
+ 	inlineCAB := branchDescriptor isBranchTrue or: [branchDescriptor isBranchFalse].
+ 	"Further, only interested in inlining = and ~= if there's a SmallInteger constant involved.
+ 	 The relational operators successfully statically predict SmallIntegers; the equality operators do not."
+ 	(inlineCAB and: [primDescriptor opcode = JumpZero or: [primDescriptor opcode = JumpNonZero]]) ifTrue:
+ 		[inlineCAB := argIsInt or: [rcvrIsInt]].
+ 	inlineCAB ifFalse:
+ 		[^self genSpecialSelectorSend].
+ 
+ 	"In-line, but if the types are not SmallInteger then we will need to do a send.
+ 	 Since we're allocating values in registers we would like to keep those registers live on the inlined path
+ 	 and reload registers along the non-inlined send path.  But any values that would need to be spilled
+ 	 along the non-inlined path must be captured before the split so that both paths can join.  If we don't
+ 	 capture the values on the non-iblined path we could access stale values.  So for all stack entries that
+ 	 would be spilled along the non-inlined path, assign them to registers, or spill if none are available."
+ 	argIsInt
+ 		ifTrue:
+ 			[rcvrReg := self allocateRegForStackEntryAt: 1.
+ 			 (self ssValue: 1) popToReg: rcvrReg.
+ 			 self MoveR: rcvrReg R: TempReg.
+ 			 regMask := self registerMaskFor: rcvrReg]
+ 		ifFalse:
+ 			[self allocateRegForStackTopTwoEntriesInto: [:rTop :rNext| argReg := rTop. rcvrReg := rNext].
+ 			 rcvrReg = Arg0Reg ifTrue:
+ 				[rcvrReg := argReg. argReg := Arg0Reg].
+ 			 self ssTop popToReg: argReg.
+ 			 (self ssValue: 1) popToReg: rcvrReg.
+ 			 self MoveR: argReg R: TempReg.
+ 			 regMask := self registerMaskFor: rcvrReg and: argReg].
+ 	self ssPop: 2.
+ 	self captureUnspilledSpillsForSpecialSelectorSend: regMask.
+ 	jumpNotSmallInts := (argIsInt or: [rcvrIsInt])
+ 							ifTrue: [objectRepresentation genJumpNotSmallIntegerInScratchReg: TempReg]
+ 							ifFalse: [objectRepresentation genJumpNotSmallIntegersIn: rcvrReg andScratch: TempReg scratch: ClassReg].
+ 	argIsInt
+ 		ifTrue: [self CmpCq: argInt R: rcvrReg]
+ 		ifFalse: [self CmpR: argReg R: rcvrReg].
+ 	"Cmp is weird/backwards so invert the comparison.  Further since there is a following conditional
+ 	 jump bytecode define non-merge fixups and leave the cond bytecode to set the mergeness."
+ 	self genConditionalBranch: (branchDescriptor isBranchTrue
+ 				ifTrue: [primDescriptor opcode]
+ 				ifFalse: [self inverseBranchFor: primDescriptor opcode])
+ 		operand: (self ensureNonMergeFixupAt: targetBytecodePC - initialPC) asUnsignedInteger.
+ 	self Jump: (self ensureNonMergeFixupAt: postBranchPC - initialPC).
+ 	jumpNotSmallInts jmpTarget: self Label.
+ 	self ssFlushTo: simStackPtr.
+ 	self deny: rcvrReg = Arg0Reg.
+ 	argIsInt
+ 		ifTrue: [self MoveCq: argInt R: Arg0Reg]
+ 		ifFalse: [argReg ~= Arg0Reg ifTrue: [self MoveR: argReg R: Arg0Reg]].
+ 	rcvrReg ~= ReceiverResultReg ifTrue: [self MoveR: rcvrReg R: ReceiverResultReg].
+ 	index := byte0 - self firstSpecialSelectorBytecodeOffset.
+ 	self genMarshalledSend: index negated - 1 numArgs: 1 sendTable: ordinarySendTrampolines.
+ 	^0!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>genStorePop:TemporaryVariable: (in category 'bytecode generator support') -----
  genStorePop: popBoolean TemporaryVariable: tempIndex
+ 	<inline: false>
- 	"Override so that if a register other than TempReg is allocated, the temp is marked as being live in that register."
  	| reg |
  	self ssFlushUpThroughTemporaryVariable: tempIndex.
+ 	"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."
+ 	((self ssTop registerMaskOrNone anyMask: self registerMaskUndesirableForTempVars)
+ 	 and: [(reg := self availableRegOrNoneNotConflictingWith:  self registerMaskUndesirableForTempVars) ~= NoReg])
+ 		ifTrue: [self ssStorePop: popBoolean toReg: reg]
+ 		ifFalse: [reg := self ssStorePop: popBoolean toPreferredReg: TempReg].
- 	reg := self ssStorePop: popBoolean toPreferredReg: TempReg.
  	self MoveR: reg
  		Mw: (self frameOffsetOfTemporary: tempIndex)
  		r: FPReg.
  	reg ~= TempReg ifTrue:
  		[(self simStackAt: tempIndex) liveRegister: reg.
  		 self copyLiveRegisterToCopiesOf: (self simStackAt: tempIndex)].
  	^0!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>initSimStackForFramelessMethod: (in category 'simulation stack') -----
  initSimStackForFramelessMethod: startpc
  	super initSimStackForFramelessMethod: startpc.
  	simSelf liveRegister: NoReg.
  	0 to: simStackPtr do:
  		[:i| | desc |
  		desc := self simStackAt: 1.
+ 		desc liveRegister: desc registerOrNone]!
- 		desc liveRegister: (desc type = SSRegister ifTrue: [desc register] ifFalse: [NoReg])]!

Item was removed:
- ----- Method: RegisterAllocatingCogit>>maybeCountFixup (in category 'compile abstract instructions') -----
- maybeCountFixup
- 	<inline: true>
- 	numFixups := numFixups + 1!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>maybeCountFixup: (in category 'as yet unclassified') -----
+ maybeCountFixup: descriptor
+ 	"Count needed fixups; descriptor is known to be a branch or a block creation."
+ 	<var: #descriptor type: #'BytecodeDescriptor *'>
+ 	<inline: true>
+ 	numFixups := numFixups + ((descriptor isBranchTrue or: [descriptor isBranchFalse])
+ 									ifTrue:
+ 										[(prevBCDescriptor generator == #genSpecialSelectorEqualsEquals
+ 										   or: [prevBCDescriptor generator == #genSpecialSelectorComparison])
+ 											ifTrue: [3]
+ 											ifFalse: [2]]
+ 									ifFalse:  [1])!

Item was added:
+ ----- Method: RegisterAllocatingCogit>>registerMaskUndesirableForTempVars (in category 'bytecode generator support') -----
+ registerMaskUndesirableForTempVars
+ 	"Answer the mask containing registers to avoid for temporary variables."
+ 	<inline: true>
+ 	^self registerMaskFor: ReceiverResultReg and: ClassReg and: SendNumArgsReg and: TempReg!

Item was changed:
  ----- Method: RegisterAllocatingCogit>>ssStorePop:toPreferredReg: (in category 'simulation stack') -----
  ssStorePop: popBoolean toPreferredReg: preferredReg
  	"Store or pop the top simulated stack entry to a register.
  	 Use preferredReg if the entry is not itself a register.
  	 Answer the actual register the result ends up in."
  	| actualReg |
  	actualReg := preferredReg.
  	self ssTop type = SSRegister ifTrue: 
  		[self assert: (self ssTop liveRegister = NoReg
  					  or: [self ssTop liveRegister = self ssTop register]).
  		self assert: self ssTop spilled not.
  		actualReg := self ssTop register].
  	self ssTop liveRegister ~= NoReg ifTrue:
  		[actualReg := self ssTop liveRegister].
  	self ssStorePop: popBoolean toReg: actualReg. "generates nothing if ssTop is already in actualReg"
+ 	^actualReg!
- 	^ actualReg!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>allocateRegForStackEntryAt:notConflictingWith: (in category 'simulation stack') -----
  allocateRegForStackEntryAt: index notConflictingWith: regMask
  	"If the stack entry is already in a register not conflicting with regMask, answers it,
  	else allocate a new register not conflicting with reg mask"
  	<var: #stackEntry type: #'CogSimStackEntry *'>
+ 	| stackEntry mask |
- 	| stackEntry |
  	stackEntry := self ssValue: index.
+ 	mask := stackEntry registerMaskOrNone.
+ 	(mask ~= 0 and: [mask noMask: regMask]) ifTrue: 
+ 		[^stackEntry register].
+ 	^self allocateRegNotConflictingWith: regMask!
- 	(stackEntry type = SSRegister and: [ (self register: stackEntry register isInMask: regMask) not ]) ifTrue: 
- 		[ ^ stackEntry register].
- 	^ self allocateRegNotConflictingWith: regMask
- 	!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>allocateRegForStackTopThreeEntriesInto:thirdIsReceiver: (in category 'simulation stack') -----
  allocateRegForStackTopThreeEntriesInto: trinaryBlock thirdIsReceiver: thirdIsReceiver
  	"Answers registers for the 3 top values on stack. If the values are already in registers, answers
  	these registers, else allocate registers not conflicting with each others.
  	If thirdIsReceiver is true, allocate ReceiverResultReg for stackTop - 2 (for ceStoreCheck)."
  	<inline: true>
  	| topRegistersMask rTop rNext rThird |
  	
  	topRegistersMask := 0.
  	rTop := rNext := rThird := NoReg.
  	
+ 	(self ssTop registerOrNone ~= NoReg and: [ thirdIsReceiver not or: [ self ssTop registerOrNone ~= ReceiverResultReg ] ]) ifTrue: 
+ 		[ topRegistersMask := self registerMaskFor: (rTop := self ssTop registerOrNone)].
+ 	((self ssValue: 1) registerOrNone ~= NoReg and: [ thirdIsReceiver not or: [ (self ssValue: 1) registerOrNone ~= ReceiverResultReg ] ]) ifTrue: 
+ 		[ topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: (rNext := (self ssValue: 1) registerOrNone))].
+ 	((self ssValue: 2) registerOrNone ~= NoReg and: [thirdIsReceiver not or: [ (self ssValue: 2) registerOrNone = ReceiverResultReg ] ]) ifTrue: 
+ 		[ topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: (rThird := (self ssValue: 2) registerOrNone))].
- 	(self ssTop type = SSRegister and: [ thirdIsReceiver not or: [ self ssTop register ~= ReceiverResultReg ] ]) ifTrue: 
- 		[ topRegistersMask := self registerMaskFor: (rTop := self ssTop register)].
- 	((self ssValue: 1) type = SSRegister and: [ thirdIsReceiver not or: [ (self ssValue: 1) register ~= ReceiverResultReg ] ]) ifTrue: 
- 		[ topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: (rNext := (self ssValue: 1) register))].
- 	((self ssValue: 2) type = SSRegister and: [thirdIsReceiver not or: [ (self ssValue: 2) register = ReceiverResultReg ] ]) ifTrue: 
- 		[ topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: (rThird := (self ssValue: 2) register))].
  	
  	rThird = NoReg ifTrue:
  		[ thirdIsReceiver 
  			ifTrue:
  				[ rThird := ReceiverResultReg.  "Free ReceiverResultReg if it was not free"
  				self ssAllocateRequiredReg: ReceiverResultReg.
  				optStatus isReceiverResultRegLive: false ]
  			ifFalse: [ rThird := self allocateRegNotConflictingWith: topRegistersMask ].
  		topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: rThird) ].
  	
  	rTop = NoReg ifTrue:
  		[ rTop := self allocateRegNotConflictingWith: topRegistersMask.
  		  topRegistersMask := topRegistersMask bitOr: (self registerMaskFor: rTop) ].
  	
  	rNext = NoReg ifTrue:
  		[ rNext := self allocateRegNotConflictingWith: topRegistersMask ].
  
  	self deny: (rTop = NoReg or: [rNext = NoReg or: [rThird = NoReg]]).
  
  	^ trinaryBlock value: rTop value: rNext value: rThird!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>allocateRegForStackTopTwoEntriesInto: (in category 'simulation stack') -----
  allocateRegForStackTopTwoEntriesInto: binaryBlock
  	"Answers registers for the 2 top values on stack. If the values are already in registers, answers
  	these registers, else allocate registers not conflicting with each others."
  	<inline: true>
  	| topRegistersMask rTop rNext |
  	
  	topRegistersMask := 0.
  	rTop := rNext := NoReg.
  	
+ 	self ssTop  registerOrNone ~= NoReg ifTrue: 
+ 		[ rTop := self ssTop registerOrNone].
+ 	(self ssValue: 1)  registerOrNone ~= NoReg ifTrue: 
+ 		[ topRegistersMask := self registerMaskFor: (rNext := (self ssValue: 1) registerOrNone)].
- 	self ssTop type = SSRegister ifTrue: 
- 		[ rTop := self ssTop register].
- 	(self ssValue: 1) type = SSRegister ifTrue: 
- 		[ topRegistersMask := self registerMaskFor: (rNext := (self ssValue: 1) register)].
  	
  	rTop = NoReg ifTrue:
  		[ rTop := self allocateRegNotConflictingWith: topRegistersMask ].
  	
  	rNext = NoReg ifTrue:
  		[ rNext := self allocateRegNotConflictingWith: (self registerMaskFor: rTop) ].
  
  	self deny: (rTop = NoReg or: [rNext = NoReg]).
  
  	^ binaryBlock value: rTop value: rNext!

Item was removed:
- ----- Method: StackToRegisterMappingCogit>>maybeCountFixup (in category 'compile abstract instructions') -----
- maybeCountFixup
- 	"This is a hook for RegisterAllocatingCogit"
- 	<inline: true>!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>maybeCountFixup: (in category 'compile abstract instructions') -----
+ maybeCountFixup: descriptor
+ 	"This is a hook for RegisterAllocatingCogit"
+ 	<inline: true>!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>scanMethod (in category 'compile abstract instructions') -----
  scanMethod
  	"Scan the method (and all embedded blocks) to determine
  		- what the last bytecode is; extra bytes at the end of a method are used to encode things like source pointers or temp names
  		- if the method needs a frame or not
  		- what are the targets of any backward branches.
  		- how many blocks it creates
  	 Answer the block count or on error a negative error code"
  	| latestContinuation nExts descriptor pc numBlocks distance targetPC framelessStackDelta seenInstVarStore |
  	<var: #descriptor type: #'BytecodeDescriptor *'>
  	needsFrame := useTwoPaths := seenInstVarStore := false.
  	LowcodeVM ifTrue: [ hasNativeFrame := false ].
  	self maybeInitNumFixups.
  	self maybeInitNumCounters.
  	prevBCDescriptor := nil.
  	NewspeakVM ifTrue:
  		[numIRCs := 0].
  	(primitiveIndex > 0
  	 and: [coInterpreter isQuickPrimitiveIndex: primitiveIndex]) ifTrue:
  		[^0].
  	pc := latestContinuation := initialPC.
  	numBlocks := framelessStackDelta := nExts := extA := extB := 0.
  	[pc <= endPC] whileTrue:
  		[byte0 := (objectMemory fetchByte: pc ofObject: methodObj) + bytecodeSetOffset.
  		 descriptor := self generatorAt: byte0.
  		 descriptor isExtension ifTrue:
  			[descriptor opcode = Nop ifTrue: "unknown bytecode tag; see Cogit class>>#generatorTableFrom:"
  				[^EncounteredUnknownBytecode].
  			 self loadSubsequentBytesForDescriptor: descriptor at: pc.
  			 self perform: descriptor generator].
  		 (descriptor isReturn
  		  and: [pc >= latestContinuation]) ifTrue:
  			[endPC := pc].
  
  		  needsFrame ifFalse:
  			[(descriptor needsFrameFunction isNil
  			  or: [self perform: descriptor needsFrameFunction with: framelessStackDelta])
  					ifTrue:
  						["With immutability we win simply by avoiding a frame build if the receiver is young and not immutable."
  						 self cppIf: IMMUTABILITY
  							ifTrue: [descriptor is1ByteInstVarStore
  									ifTrue: [useTwoPaths := true]
  									ifFalse: [needsFrame := true. useTwoPaths := false]]
  							ifFalse: [needsFrame := true. useTwoPaths := false]]
  					ifFalse:
  						[framelessStackDelta := framelessStackDelta + descriptor stackDelta.
  						 "Without immutability we win if there are two or more stores and the receiver is new."
  						 self cppIf: IMMUTABILITY
  							ifTrue: []
  							ifFalse:
  								[descriptor is1ByteInstVarStore ifTrue:
  									[seenInstVarStore
  										ifTrue: [useTwoPaths := true]
  										ifFalse: [seenInstVarStore := true]]]]].
  
  		 descriptor isBranch ifTrue:
  			[distance := self spanFor: descriptor at: pc exts: nExts in: methodObj.
  			 targetPC := pc + descriptor numBytes + distance.
  			 (self isBackwardBranch: descriptor at: pc exts: nExts in: methodObj)
  				ifTrue: [self initializeFixupAt: targetPC - initialPC]
  				ifFalse:
  					[latestContinuation := latestContinuation max: targetPC.
+ 					 self maybeCountFixup: descriptor.
- 					 (descriptor isBranchTrue or: [descriptor isBranchFalse]) ifTrue:
- 						[self maybeCountFixup].
- 					 self maybeCountFixup.
  					 self maybeCountCounter]].
  		 descriptor isBlockCreation ifTrue:
  			[numBlocks := numBlocks + 1.
  			 distance := self spanFor: descriptor at: pc exts: nExts in: methodObj.
  			 targetPC := pc + descriptor numBytes + distance.
  			 latestContinuation := latestContinuation max: targetPC.
+ 			 self maybeCountFixup: descriptor].
- 			 self maybeCountFixup].
  
  		 NewspeakVM ifTrue:
  			[descriptor hasIRC ifTrue: [numIRCs := numIRCs + 1]].
  		 pc := pc + descriptor numBytes.
  		 nExts := descriptor isExtension ifTrue: [nExts + 1] ifFalse: [extA := extB := 0].
  		 prevBCDescriptor := descriptor].
  	^numBlocks!



More information about the Vm-dev mailing list