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

commits at source.squeak.org commits at source.squeak.org
Wed Jul 7 02:06:27 UTC 2021


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

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

Name: VMMaker.oscog-eem.2978
Author: eem
Time: 6 July 2021, 7:06:17.83025 pm
UUID: 289db7d6-6952-42cc-92bb-8b9a49818971
Ancestors: VMMaker.oscog-eem.2977

Do a better job eliding dead code by including casts in sends that are effect free and broadening the range of arithmetic and conditional sends that are considered for being effect free, and in argument passing.
Provide cppIf:ifFalse:.
Implement generateInlineCppIfElse:asArgument:on:indent: much more directly.

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

Item was added:
+ ----- Method: CCodeGenerator>>deny: (in category 'error notification') -----
+ deny: aBooleanOrBlock
+ 	aBooleanOrBlock value ifTrue: [AssertionFailure signal: 'Assertion failed']!

Item was changed:
  ----- Method: CCodeGenerator>>emitCAPIExportHeaderOn: (in category 'C code generator') -----
  emitCAPIExportHeaderOn: aStream 
  	"Store prototype declarations for all API methods on the given stream."
  	| exportedAPIMethods usedConstants |
  	exportedAPIMethods := self sortMethods: (methods select: [:m| m isAPIMethod]).
  	exportedAPIMethods do:
  		[:m|
  		m static ifTrue:
  			[logger ensureCr; show: m selector, ' excluded from export API because it is static'; cr]].
+ 	exportedAPIMethods := exportedAPIMethods reject: [:m| m static].
  	self emitCFunctionPrototypes: exportedAPIMethods on: aStream.
  	self emitGlobalCVariablesOn: aStream.
  	usedConstants := self emitCMacros: exportedAPIMethods on: aStream.
  	self emitCConstants: usedConstants on: aStream!

Item was changed:
  ----- Method: CCodeGenerator>>generateInlineCppIfElse:asArgument:on:indent: (in category 'C translation') -----
  generateInlineCppIfElse: msgNode asArgument: asArgument on: aStream indent: level
  	"Generate the C code for this message onto the given stream."
+ 	| lastCondition allAlternativesWereDeterminable expr pos directive index keywords |
- 	| putStatement allAlternativesWereDeterminable expr pos |
  	"Compile-time expansion for constants set in the options dictionary,
  	 e.g. to cut down on noise for MULTIPLEBYTECODESETS."
- 	putStatement := asArgument
- 		ifTrue: "emitCCodeAsArgumentOn: doesn't indent, the code needs indenting if it takes multiple lines, so post-process."
- 			[[:node| | expansion |
- 			  expansion := String streamContents: [:s| node emitCCodeAsArgumentOn: s level: level generator: self].
- 			  aStream nextPutAll:
- 			  ((expansion includes: Character cr)
- 				ifTrue:
- 					[(String streamContents:
- 							[:s|
- 							s position > 0 ifTrue: [s tab: level + 1].
- 							node emitCCodeAsArgumentOn: s level: level generator: self])
- 						copyReplaceAll: (String with: Character cr)
- 						with: (String with: Character cr), (String new: level + 1 withAll: Character tab)]
- 				ifFalse: [expansion])]]
- 		ifFalse:
- 			[[:node| | expansion |
- 			  expansion := String streamContents: [:s| node emitCCodeOn: s level: level generator: self].
- 			 "Remove tabs from first line to avoid indenting a second time"
- 			 expansion ifNotEmpty:
- 				[expansion := expansion allButFirst: (expansion findFirst: [:c| c ~~ Character tab]) - 1].
- 			 aStream nextPutAll: expansion]].
  
  	"First attempt to expand statically..."
  	allAlternativesWereDeterminable := true.
+ 	lastCondition := nil.
+ 	msgNode selector keywords "Deal with cppIf:ifTrue:, cppIf:ifTrue:ifFalse:, cppIf:ifTrue:cppIf:ifTrue:ifFalse:, etc"
+ 		with: msgNode args
+ 		do: [:keyword :node| | expansion |
+ 			self assert: (#(cppIf: ifFalse: ifTrue:) includes: keyword).
+ 			keyword = #cppIf:
+ 				ifTrue:
+ 					[(self nilOrBooleanConditionFor: node)
+ 						ifNil: [allAlternativesWereDeterminable := false]
+ 						ifNotNil: [:condition| lastCondition := condition]]
+ 				ifFalse:
+ 					[(allAlternativesWereDeterminable
+ 					 and: [lastCondition == (keyword = #ifTrue:)]) ifTrue:
+ 						[asArgument
+ 							ifTrue: "emitCCodeAsArgumentOn: doesn't indent, the code needs indenting if it takes multiple lines, so post-process."
+ 								[expansion := String streamContents: [:s| node emitCCodeAsArgumentOn: s level: level generator: self].
+ 								  aStream nextPutAll:
+ 									  ((expansion includes: Character cr)
+ 										ifTrue:
+ 											[(String streamContents:
+ 													[:s|
+ 													s position > 0 ifTrue: [s tab: level + 1].
+ 													node emitCCodeAsArgumentOn: s level: level generator: self])
+ 												copyReplaceAll: (String with: Character cr)
+ 												with: (String with: Character cr), (String new: level + 1 withAll: Character tab)]
+ 										ifFalse: [expansion])]
+ 							ifFalse:
+ 								[expansion := String streamContents: [:s| node emitCCodeOn: s level: level generator: self].
+ 								 "Remove tabs from first line to avoid indenting a second time"
+ 								 expansion ifNotEmpty:
+ 									[expansion := expansion allButFirst: (expansion findFirst: [:c| c ~~ Character tab]) - 1].
+ 								 aStream nextPutAll: expansion].
+ 						 ^self]]].
+ 	self deny: allAlternativesWereDeterminable.
- 	1 to: msgNode args size - 1 by: 2 do: "Deal with cppIf:ifTrue:, cppIf:ifTrue:ifFalse:, cppIf:ifTrue:cppIf:ifTrue:ifFalse:, etc"
- 		[:conditionIndex|
- 		(self nilOrBooleanConditionFor: (msgNode args at: conditionIndex))
- 			ifNil: [allAlternativesWereDeterminable := false]
- 			ifNotNil:
- 				[:condition|
- 				 condition ifTrue:
- 					[putStatement value: (msgNode args at: conditionIndex + 1).
- 					 ^self]]].
- 	allAlternativesWereDeterminable ifTrue:
- 		[msgNode args size odd ifTrue: "there is an ifFalse:"
- 			[putStatement value: msgNode args last].
- 		 ^self].
  
  	"Expand for compile-time evaluation. Full #if ... #else..."
- 	putStatement := asArgument
- 		ifTrue: "emitCCodeAsArgumentOn: doesn't indent, the code needs indenting in this case, so post-process."
- 			[[:node|
- 			  aStream nextPutAll:
- 				((String streamContents:
- 						[:s|
- 						s next: level + 1 put: Character tab.
- 						node emitCCodeAsArgumentOn: s level: level generator: self])
- 					copyReplaceAll: (String with: Character cr)
- 					with: (String with: Character cr), (String new: level + 1 withAll: Character tab))]]
- 		ifFalse:
- 			[[:node| node emitCCodeOn: aStream level: level generator: self]].
  
+ 	directive := 'if'.
+ 	index := 0.
+ 	expr := nil.
+ 	(keywords := msgNode selector keywords) "Deal with cppIf:ifTrue:, cppIf:ifFalse:, cppIf:ifTrue:ifFalse:, cppIf:ifTrue:cppIf:ifTrue:ifFalse:, etc"
+ 		with: msgNode args
+ 		do: [:keyword :node| | expansion |
+ 			self assert: (#(cppIf: ifFalse: ifTrue:) includes: keyword).
+ 			index := index + 1.
+ 			keyword = #cppIf:
+ 				ifTrue:
+ 					[lastCondition := node.
+ 					expansion := String streamContents: [:es| node emitCCodeAsArgumentOn: es level: 0 generator: self].
+ 					(keywords at: index + 1) = #ifFalse: ifTrue:
+ 						[expansion := node isLeaf ifTrue: ['!!', expansion] ifFalse: ['!!(', expansion, ')']].
+ 					[expansion last isSeparator] whileTrue:
+ 						[expansion := expansion allButLast].
+ 					aStream
+ 						ensureCr;
+ 						nextPut: $#; space: level * 2; nextPutAll: directive; space; nextPutAll: expansion; cr.
+ 					directive := 'elif'.
+ 					expr := (expr ifNil: [' // '] ifNotNil: [expr, ' || ']), expansion]
+ 				ifFalse:
+ 					[(keywords at: index - 1) = #cppIf: ifFalse: "this is an else..."
+ 						[aStream
+ 							ensureCr;
+ 							nextPut: $#; next: level * 2 put: Character space; nextPutAll: 'else'.
+ 						 aStream position - pos >= 128 ifTrue:
+ 							[aStream nextPutAll: expr].
+ 						 aStream cr].
+ 					pos := aStream position.
+ 					self with: lastCondition
+ 						ifAppropriateSetTo: keyword = #ifTrue:
+ 						do: [asArgument
+ 								ifTrue: "emitCCodeAsArgumentOn: doesn't indent, the code needs indenting in this case, so post-process."
+ 									[aStream nextPutAll:
+ 										((String streamContents:
+ 												[:s|
+ 												s next: level + 1 put: Character tab.
+ 												node emitCCodeAsArgumentOn: s level: level generator: self])
+ 											copyReplaceAll: (String with: Character cr)
+ 											with: (String with: Character cr), (String new: level + 1 withAll: Character tab))]
+ 								ifFalse:
+ 									[node emitCCodeOn: aStream level: level generator: self]]]].
- 	1 to: msgNode args size - 1 by: 2 do: "Deal with cppIf:ifTrue:, cppIf:ifTrue:ifFalse:, cppIf:ifTrue:cppIf:ifTrue:ifFalse:, etc"
- 		[:conditionIndex| | condition |
- 		condition := String streamContents:
- 						[:es|
- 						(msgNode args at: conditionIndex)
- 							emitCCodeAsArgumentOn: es
- 							level: 0
- 							generator: self].
- 		[condition last isSeparator] whileTrue:
- 			[condition := condition allButLast].
- 		aStream
- 			ensureCr;
- 			nextPut: $#; next: level * 2 put: Character space; nextPutAll: (conditionIndex = 1 ifTrue: ['if '] ifFalse: ['elif ']); nextPutAll: condition; cr.
- 
- 		pos := aStream position.
- 		self with: (msgNode args at: conditionIndex)
- 			ifAppropriateSetTo: true
- 			do: [putStatement value: (msgNode args at: conditionIndex + 1)].
- 		expr := (expr ifNil: [' /* '] ifNotNil: [expr, ' || ']), condition].
- 	expr := expr, ' */'.
- 	msgNode args size odd ifTrue: "there is an ifFalse:"
- 		[aStream
- 			ensureCr;
- 			nextPut: $#; next: level * 2 put: Character space; nextPutAll: 'else'.
- 		 aStream position - pos >= 128 ifTrue:
- 			[aStream nextPutAll: expr].
- 		 aStream cr.
- 		pos := aStream position.
- 		msgNode args size <= 3
- 			ifTrue: "ifTrue:ifFalse:, so negate condition for ifFalse:"
- 				[self with: msgNode args last
- 					ifAppropriateSetTo: false
- 					do: [putStatement value: msgNode args third]]
- 			ifFalse:
- 				[putStatement value: msgNode args last]].
  	aStream
  		ensureCr;
  		nextPut: $#; next: level * 2 put: Character space; nextPutAll: 'endif'.
  	aStream position - pos >= 128 ifTrue:
  		[aStream nextPutAll: expr].
  	aStream cr.
  	asArgument ifTrue:
  		[aStream next: level + 1 put: Character tab]!

Item was changed:
  ----- Method: CCodeGenerator>>initializeCTranslationDictionary (in category 'C translation support') -----
  initializeCTranslationDictionary 
  	"Initialize the dictionary mapping message names to actions for C code generation."
  
  	| pairs |
  	
  	translationDict := Dictionary new: 200.
  	pairs := #(
  	#&				#generateAnd:on:indent:
  	#|				#generateOr:on:indent:
  	#abs			#generateAbs:on:indent:
  	#and:			#generateSequentialAnd:on:indent:
  	#or:			#generateSequentialOr:on:indent:
  	#not			#generateNot:on:indent:
  
  	#+				#generatePlus:on:indent:
  	#-				#generateMinus:on:indent:
  	#negated		#generateNegated:on:indent:
  	#*				#generateTimes:on:indent:
  	#/				#generateDivide:on:indent:
  	#//				#generateDivide:on:indent:
  	#\\				#generateModulo:on:indent:
  	#<<			#generateShiftLeft:on:indent:
  	#>>			#generateShiftRight:on:indent:
  	#>>>			#generateSignedShiftRight:on:indent:
  	#,				#generateComma:on:indent:
  	#min:			#generateMin:on:indent:
  	#max:			#generateMax:on:indent:
  	#between:and:	#generateBetweenAnd:on:indent:
  
  	#bitAnd:			#generateBitAnd:on:indent:
  	#bitOr:				#generateBitOr:on:indent:
  	#bitXor:			#generateBitXor:on:indent:
  	#bitShift:			#generateBitShift:on:indent:
  	#signedBitShift:	#generateSignedBitShift:on:indent:
  	#bitInvert32		#generateBitInvert:on:indent:
  	#bitInvert64		#generateBitInvert:on:indent:
  	#bitClear:			#generateBitClear:on:indent:
  	#truncateTo:		#generateTruncateTo:on:indent:
  	#rounded			#generateRounded:on:indent:
  	#even				#generateEven:on:indent:
  	#odd				#generateOdd:on:indent:
  
  	#byteSwap32		#generateByteSwap32:on:indent:
  	#byteSwap64		#generateByteSwap64:on:indent:
  	#byteSwapped32IfBigEndian:	generateByteSwap32IfBigEndian:on:indent:
  	#byteSwapped64IfBigEndian:	generateByteSwap64IfBigEndian:on:indent:
  	
  	#<				#generateLessThan:on:indent:
  	#<=			#generateLessThanOrEqual:on:indent:
  	#=				#generateEqual:on:indent:
  	#>				#generateGreaterThan:on:indent:
  	#>=			#generateGreaterThanOrEqual:on:indent:
  	#~=			#generateNotEqual:on:indent:
  	#==			#generateEqual:on:indent:
  	#~~			#generateNotEqual:on:indent:
  	#isNil			#generateIsNil:on:indent:
  	#notNil			#generateNotNil:on:indent:
  
  	#whileTrue: 	#generateWhileTrue:on:indent:
  	#whileFalse:	#generateWhileFalse:on:indent:
  	#whileTrue 	#generateDoWhileTrue:on:indent:
  	#whileFalse		#generateDoWhileFalse:on:indent:
  	#to:do:			#generateToDo:on:indent:
  	#to:by:do:		#generateToByDo:on:indent:
  	#repeat 		#generateRepeat:on:indent:
  	#timesRepeat:	#generateTimesRepeat:on:indent:
  
  	#ifTrue:			#generateIfTrue:on:indent:
  	#ifFalse:		#generateIfFalse:on:indent:
  	#ifTrue:ifFalse:	#generateIfTrueIfFalse:on:indent:
  	#ifFalse:ifTrue:	#generateIfFalseIfTrue:on:indent:
  
  	#ifNotNil:		#generateIfNotNil:on:indent:
  	#ifNil:			#generateIfNil:on:indent:
  	#ifNotNil:ifNil:	#generateIfNotNilIfNil:on:indent:
  	#ifNil:ifNotNil:	#generateIfNilIfNotNil:on:indent:
  
  	#at:			#generateAt:on:indent:
  	#at:put:		#generateAtPut:on:indent:
  	#basicAt:		#generateAt:on:indent:
  	#basicAt:put:	#generateAtPut:on:indent:
  
  	#integerValueOf:			#generateIntegerValueOf:on:indent:
  	#integerObjectOf:			#generateIntegerObjectOf:on:indent:
  	#isIntegerObject: 			#generateIsIntegerObject:on:indent:
  	#cCode:					#generateInlineCCode:on:indent:
  	#cCode:inSmalltalk:		#generateInlineCCode:on:indent:
  	#cPreprocessorDirective:	#generateInlineCPreprocessorDirective:on:indent:
  	#cppIf:ifTrue:ifFalse:				#generateInlineCppIfElse:on:indent:
  	#cppIf:ifTrue:cppIf:ifTrue:ifFalse:	#generateInlineCppIfElse:on:indent:
  	#cppIf:ifTrue:						#generateInlineCppIfElse:on:indent:
+ 	#cppIf:ifFalse:						#generateInlineCppIfElse:on:indent:
  	#cCoerce:to:				#generateCCoercion:on:indent:
  	#cCoerceSimple:to:			#generateCCoercion:on:indent:
  	#addressOf:				#generateAddressOf:on:indent:
  	#addressOf:put:			#generateAddressOf:on:indent:
  	#asAddress:put:			#generateAsAddress:on:indent:
  	#signedIntFromLong64	#generateSignedIntFromLong64:on:indent:
  	#signedIntFromLong		#generateSignedIntFromLong:on:indent:
  	#signedIntFromShort		#generateSignedIntFromShort:on:indent:
  	#signedIntToLong64		#generateSignedIntToLong64:on:indent:
  	#signedIntToLong			#generateSignedIntToLong:on:indent:
  	#signedIntToShort			#generateSignedIntToShort:on:indent:
  	#preIncrement				#generatePreIncrement:on:indent:
  	#preDecrement			#generatePreDecrement:on:indent:
  	#inline:						#generateInlineDirective:on:indent:
  	#asFloat					#generateAsFloat:on:indent:
  	#asInteger					#generateAsInteger:on:indent:
  	#asIntegerPtr				#generateAsIntegerPtr:on:indent:
  	#asUnsignedInteger		#generateAsUnsignedInteger:on:indent:
  	#asUnsignedIntegerPtr		#generateAsUnsignedIntegerPtr:on:indent:
  	#asLong					#generateAsLong:on:indent:
  	#asUnsignedLong			#generateAsUnsignedLong:on:indent:
  	#asUnsignedLongLong		#generateAsUnsignedLongLong:on:indent:
  	#asVoidPointer				#generateAsVoidPointer:on:indent:
  	#asSymbol					#generateAsSymbol:on:indent:
  	#flag:						#generateFlag:on:indent:
  	#anyMask:					#generateBitAnd:on:indent:
  	#allMask:					#generateAllMask:on:indent:
  	#noMask:					#generateNoMask:on:indent:
  	#raisedTo:					#generateRaisedTo:on:indent:
  	#touch:					#generateTouch:on:indent:
  
  	#bytesPerOop 				#generateBytesPerOop:on:indent:
  	#bytesPerWord 			#generateBytesPerWord:on:indent:
  	#wordSize		 			#generateBytesPerWord:on:indent:
  	#baseHeaderSize			#generateBaseHeaderSize:on:indent:
  	#minSmallInteger			#generateSmallIntegerConstant:on:indent:
  	#maxSmallInteger			#generateSmallIntegerConstant:on:indent:
  	
  	#sharedCodeNamed:inCase:		#generateSharedCodeDirective:on:indent:
  
  	#perform:							#generatePerform:on:indent:
  	#perform:with:						#generatePerform:on:indent:
  	#perform:with:with:				#generatePerform:on:indent:
  	#perform:with:with:with:			#generatePerform:on:indent:
  	#perform:with:with:with:with:		#generatePerform:on:indent:
  	#perform:with:with:with:with:with:	#generatePerform:on:indent:
  
  	#value									#generateValue:on:indent:
  	#value:									#generateValue:on:indent:
  	#value:value:							#generateValue:on:indent:
  	#value:value:value:						#generateValue:on:indent:
  	#value:value:value:value:				#generateValue:on:indent:
  	#value:value:value:value:value:			#generateValue:on:indent:
  	#value:value:value:value:value:value:	#generateValue:on:indent:
  
  	#deny:								#generateDeny:on:indent:
  
  	#shouldNotImplement				#generateSmalltalkMetaError:on:indent:
  	#shouldBeImplemented			#generateSmalltalkMetaError:on:indent:
  	#subclassResponsibility				#generateSmalltalkMetaError:on:indent:
  	).
  
  	1 to: pairs size by: 2 do: [:i |
  		translationDict at: (pairs at: i) put: (pairs at: i + 1)].
  
  	pairs := #(
  	#ifTrue:				#generateIfTrueAsArgument:on:indent:	
  	#ifFalse:				#generateIfFalseAsArgument:on:indent:
  	#ifTrue:ifFalse:			#generateIfTrueIfFalseAsArgument:on:indent:
  	#ifFalse:ifTrue:			#generateIfFalseIfTrueAsArgument:on:indent:
  	#ifNotNil:				#generateIfNotNilAsArgument:on:indent:	
  	#ifNil:					#generateIfNilAsArgument:on:indent:
  	#ifNotNil:ifNil:			#generateIfNotNilIfNilAsArgument:on:indent:
  	#ifNil:ifNotNil:			#generateIfNilIfNotNilAsArgument:on:indent:
  	#cCode:				#generateInlineCCodeAsArgument:on:indent:
  	#cCode:inSmalltalk:	#generateInlineCCodeAsArgument:on:indent:
  	#cppIf:ifTrue:ifFalse:	#generateInlineCppIfElseAsArgument:on:indent:
  	#cppIf:ifTrue:			#generateInlineCppIfElseAsArgument:on:indent:
  
  	#value					#generateValueAsArgument:on:indent:
  	#value:					#generateValueAsArgument:on:indent:
  	#value:value:			#generateValueAsArgument:on:indent:
  	).
  
  	asArgumentTranslationDict := Dictionary new: 8.
  	1 to: pairs size by: 2 do: [:i |
  		asArgumentTranslationDict at: (pairs at: i) put: (pairs at: i + 1)].
  !

Item was added:
+ ----- Method: TConstantNode>>isEffectFree (in category 'testing') -----
+ isEffectFree
+ 	^true!

Item was changed:
  ----- Method: TMethod>>isNode:substitutableFor:inMethod:in: (in category 'inlining') -----
  isNode: aNode substitutableFor: argName inMethod: targetMeth in: aCodeGen
  	"Answer if the given parameter node may be substituted directly into the body of
  	 the method during inlining, instead of being bound to the actual parameter variable.
  	 We allow a constant, a local variable, or a formal parameter, or simple expressions
  	 involving only these to to be directly substituted. Note that global variables cannot
  	 be subsituted into methods with possible side effects (i.e., methods that may assign
  	 to global variables) because the inlined method might depend on having the value of
  	 the global variable captured when it is passed in as an argument."
  
+ 	| theNode madeNonTrivialCall count constantExpression usageCount |
- 	| madeNonTrivialCall count constantExpression usageCount |
  	aNode isConstant ifTrue: [^true].
  
+ 	theNode := (aNode isSend and: [aNode isCast]) ifTrue: [aNode targetOfCast] ifFalse: [aNode].
+ 	theNode isVariable ifTrue:
+ 		[((locals includes: theNode name)
+ 		 or: [(args includes: theNode name)
+ 		 or: [#('self' 'true' 'false' 'nil') includes: theNode name]]) ifTrue: [^true].
- 	aNode isVariable ifTrue:
- 		[((locals includes: aNode name)
- 		 or: [(args includes: aNode name)
- 		 or: [#('self' 'true' 'false' 'nil') includes: aNode name]]) ifTrue: [^true].
  		"We can substitute any variable provided it is only read in the method being inlined,
  		 and if it is not read after any non-trivial call (which may update the variable)."
  		madeNonTrivialCall := false.
  		(targetMeth isComplete
  		 and: [targetMeth parseTree
  				noneSatisfy:
  					[:node|
  					 (node isSend
  					  and: [(aCodeGen isBuiltinSelector: node selector) not]) ifTrue:
  						[madeNonTrivialCall := true].
  					 (madeNonTrivialCall and: [node isVariable and: [node name = argName]])
  					 or: [node isAssignment
  						  and: [node variable name = argName]]]
  				unless:
  					[:node|
  					node isSend and: [aCodeGen isAssertSelector: node selector]]]) ifTrue:
  			[^true].
+ 		^targetMeth maySubstituteGlobal: theNode name in: aCodeGen].
- 		^targetMeth maySubstituteGlobal: aNode name in: aCodeGen].
  
  	"don't much up asserts with complex expansions"
  	(targetMeth usesVariableUninlinably: argName in: aCodeGen) ifTrue:
  		[^false].
  
  	"For now allow literal blocks to be substituted.  They better be accessed only
  	 with value[:value:*] messages though!!"
  	aNode isLiteralBlock ifTrue: [^true].
  
  	"Don't inline expressions unless type-compatible,"
  	aNode isSend ifTrue:
  		[(aCodeGen
  				isActualType: (aCodeGen returnTypeForSend: aNode in: self ifNil: #incompatible)
  				compatibleWithFormalType: (self typeFor: argName in: aCodeGen)) ifFalse:
  			[^false]].
  
  	count := 0.
  	constantExpression := true.
  	"scan expression tree; must contain only constants, builtin ops, and inlineable vars"
  	aNode nodesDo:
  		[:node|
  		node isConstant
  			ifTrue: [] ifFalse:
  		[node isSend
  			ifTrue:
  				[((VMBasicConstants mostBasicConstantSelectors includes: node selector)
  				  or: [node isBuiltinOperator]) ifFalse: [^false].
  				 count := count + 1] ifFalse:
  		[node isVariable ifTrue:
  			[(aCodeGen isNonArgumentImplicitReceiverVariableName: node name) ifFalse:
  				[constantExpression := false.
  				((locals includes: node name)
  				 or: [(args includes: node name)
  				 or: [(#('self' 'true' 'false' 'nil') includes: node name)
  				 or: [targetMeth maySubstituteGlobal: node name in: aCodeGen]]]) ifFalse: [^false]]] ifFalse:
  		[^false]]]].
  	"inline constant expressions"
  	constantExpression ifNil: [^true].
  
  	"scan target to find usage count"
  	usageCount := 0.
  	targetMeth parseTree nodesDo:
  		[:node|
  		(node isVariable and: [node name = argName]) ifTrue:
  			[usageCount := usageCount + 1]].
  	"(usageCount > 1 and: [count <= usageCount]) ifTrue:
  		[[UsageCounts := Dictionary new.
  		  self removeClassVarName: #UsageCounts].
  		 (UsageCounts at: usageCount ifAbsentPut: [Set new]) add: ({targetMeth. argName. aNode})]."
  	"Now only inline expressions if they are used only once or are simple
  	 w.r.t. the usage count, and the usage count is not large; a heuristic that seems to work well enough."
  	^usageCount = 1 or: [usageCount <= 7 and: [count <= usageCount]]!

Item was added:
+ ----- Method: TParseNode>>isEffectFree (in category 'testing') -----
+ isEffectFree
+ 	^false!

Item was changed:
  ----- Method: TSendNode>>hasEffect (in category 'testing') -----
  hasEffect
  	"Answer if this node has an effect on execution state (does something).
  	 Statements that don't have any effect can be elided if their value is unused."
+ 	selector == #not ifTrue:
+ 		[^receiver hasEffect].
+ 	self isBinaryArithmeticOrConditional ifTrue:
+ 		[^receiver hasEffect or: [arguments first hasEffect]].
+ 	self isUnaryCast ifTrue:
+ 		[^receiver hasEffect].
+ 	self isBinaryCast ifTrue:
- 	(#(#+ #- #* #/ #// #\\ #= #== #~= #~~ not) includes: selector) ifTrue:
- 		[^false].
- 	(#(cCoerce:to: cCoerceSimple:to:) includes: selector) ifTrue:
  		[^arguments first hasEffect].
  	^true!

Item was changed:
  ----- Method: TSendNode>>hasSideEffect (in category 'testing') -----
  hasSideEffect
  	"Answer if the parse tree rooted at this node has a side-effect or not.
+ 	 We assume most sends do, but filter-out arithmetic and certain reads."
- 	 We aassume most sends do, but filter-out arithmetic and certain reads."
  	(#(	baseHeaderSize bytesPerOop bytesPerWord logBytesPerOop
  		numSmallIntegerBits numSmallIntegerTagBits numTagBits
  		shiftForWord tagMask wordSize) includes: selector) ifTrue:
  		[^false].
  	(#(#+ #- #* #/ #// #\\ #= #== #~= #~~ << >>
  		"These two important for Spur is:instanceOf:compactClassIndex: et al"
  		longAt: fetchPointer:ofObject: splObj:) includes: selector) ifFalse:
  		[^true].
  	^receiver hasSideEffect or: [arguments first hasSideEffect]!

Item was added:
+ ----- Method: TSendNode>>isBinaryArithmeticOrConditional (in category 'testing') -----
+ isBinaryArithmeticOrConditional
+ 	^arguments size = 2
+ 	 and: [#(+ - * / // \\ mod: quo:
+ 			<< >> bitShift: bitAnd: bitOr: bitXor:
+ 			= == ~= ~~ > >= < <=
+ 			& | and: or:) includes: selector]!

Item was added:
+ ----- Method: TSendNode>>isBinaryCast (in category 'testing') -----
+ isBinaryCast
+ 	^#(cCoerce:to: cCoerceSimple:to:) includes: selector!

Item was added:
+ ----- Method: TSendNode>>isCast (in category 'testing') -----
+ isCast
+ 	^#(cCoerce:to: cCoerceSimple:to: asUnsignedInteger asVoidPointer) includes: selector!

Item was added:
+ ----- Method: TSendNode>>isEffectFree (in category 'testing') -----
+ isEffectFree
+ 	^(self isUnaryCast and: [receiver isEffectFree])
+ 	 or: [(self isBinaryCast and: [arguments first isEffectFree])
+ 	 or: [self isBinaryArithmeticOrConditional and: [receiver isEffectFree and: [arguments first isEffectFree]]]]!

Item was changed:
  ----- Method: TSendNode>>isPreprocessorDirective (in category 'testing') -----
  isPreprocessorDirective
+ 	^#(cPreprocessorDirective: cppIf:ifTrue: cppIf:ifFalse: cppIf:ifTrue:ifFalse: cppIf:ifTrue:cppIf:ifTrue:ifFalse:) includes: selector!
- 	^#(cPreprocessorDirective: cppIf:ifTrue: cppIf:ifTrue:ifFalse: cppIf:ifTrue:cppIf:ifTrue:ifFalse:) includes: selector!

Item was added:
+ ----- Method: TSendNode>>isUnaryCast (in category 'testing') -----
+ isUnaryCast
+ 	^#(asUnsignedInteger asVoidPointer) includes: selector!

Item was added:
+ ----- Method: TSendNode>>targetOfCast (in category 'testing') -----
+ targetOfCast
+ 	self isUnaryCast ifTrue: [^receiver].
+ 	self isBinaryCast ifTrue: [^arguments first].
+ 	^nil!

Item was changed:
  ----- Method: TStmtListNode>>emitCCodeOn:prependToEnd:level:generator: (in category 'C code generation') -----
  emitCCodeOn: aStream prependToEnd: aNodeOrNil level: level generator: aCodeGen
  	| statementToElide |
  	self emitCCommentOn: aStream level: level generator: aCodeGen.
  	(aNodeOrNil notNil or: [statements isEmpty or: [statements last hasEffect]]) ifFalse:
  		[statementToElide := statements last].
  	statements withIndexDo:
  		[:s :idx| | position  lastWhilePrepending |
  		s emitCCommentOn: aStream level: level generator: aCodeGen.
  		(s == statementToElide
+ 		 or: [s isEffectFree and: [aNodeOrNil isNil or: [idx < statements size]]]) ifFalse:
- 		 or: [s isLeaf and: [s isLabel not and: [aNodeOrNil isNil or: [idx < statements size]]]]) ifFalse:
  			[((s isSend and: [s isPreprocessorDirective]) or: [aStream peekLast == Character tab]) ifFalse:
  				[aStream tab: level].
  			position := aStream position.
  			(lastWhilePrepending := aNodeOrNil notNil and: [idx = statements size])
  				ifTrue: [s emitCCodeOn: aStream prependToEnd: aNodeOrNil level: level generator: aCodeGen]
  				ifFalse: [s emitCCodeOn: aStream level: level generator: aCodeGen].
  			aStream position > position ifTrue:
  				[(self stream: aStream endsWithAnyOf: '};') ifFalse:
  					[s needsTrailingSemicolon ifTrue:
  						[aStream nextPut: $;]].
  					 (lastWhilePrepending or: [aStream peekLast == Character cr]) ifFalse:
  						[aStream cr]]]]!

Item was added:
+ ----- Method: TVariableNode>>isEffectFree (in category 'testing') -----
+ isEffectFree
+ 	^true!

Item was added:
+ ----- Method: VMClass>>cppIf:ifFalse: (in category 'translation support') -----
+ cppIf: conditionBlockOrValue ifFalse: falseExpressionOrBlockOrNil
+ 	"When translated, produces #if (condition) #else #endif CPP directives.
+ 	 Example usage:
+ 
+ 		self cppIf: #DUAL_MAPPED_CODE_ZONE
+ 			ifFalse: [(backEnd needsCodeZoneExecuteWriteSwitch
+ 					 and: [codeZoneIsExecutableNotWritable]) ifTrue:
+ 						[backEnd makeCodeZoneWritable.
+ 						codeZoneIsExecutableNotWritable := false]]"
+ 	<doNotGenerate>
+ 	^self cppIf: conditionBlockOrValue ifTrue: nil ifFalse: falseExpressionOrBlockOrNil!



More information about the Vm-dev mailing list