Nicolas Cellier uploaded a new version of Compiler to project The Inbox:
http://source.squeak.org/inbox/Compiler-nice.139.mcz ==================== Summary ==================== Name: Compiler-nice.139 Author: nice Time: 7 April 2010, 3:06:44.988 am UUID: a131f445-c2f7-dd47-85fd-b0d38ab18874 Ancestors: Compiler-nice.138 nil out locals in a block if readBeforeWritten - Use noteOptimizedIn: instead of noteOptimized - Let accept: return the result of message sent to visitor =============== Diff against Compiler-nice.138 =============== Item was changed: ----- Method: CommentNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitCommentNode: self! - aVisitor visitCommentNode: self! Item was changed: ----- Method: TempVariableNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitTempVariableNode: self! - aVisitor visitTempVariableNode: self! Item was changed: ----- Method: RemoteTempVectorNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitRemoteTempVectorNode: self! - aVisitor visitRemoteTempVectorNode: self! Item was changed: ----- Method: MessageNode>>transformToDo: (in category 'macro transformations') ----- transformToDo: encoder " var := rcvr. L1: [var <= arg1] Bfp(L2) [block body. var := var + inc] Jmp(L1) L2: " | limit increment block initStmt test incStmt limitInit blockVar myRange blockRange | "First check for valid arguments" ((arguments last isMemberOf: BlockNode) and: [arguments last numberOfArguments = 1 and: [arguments last firstArgument isVariableReference "As with debugger remote vars"]]) ifFalse: [^false]. arguments size = 3 ifTrue: [increment := arguments at: 2. (increment isConstantNumber and: [increment literalValue ~= 0]) ifFalse: [^ false]] ifFalse: [increment := encoder encodeLiteral: 1]. arguments size < 3 ifTrue: "transform to full form" [selector := SelectorNode new key: #to:by:do: code: #macro]. "Now generate auxiliary structures" myRange := encoder rawSourceRanges at: self ifAbsent: [1 to: 0]. block := arguments last. blockRange := encoder rawSourceRanges at: block ifAbsent: [1 to: 0]. blockVar := block firstArgument. initStmt := AssignmentNode new variable: blockVar value: receiver. limit := arguments at: 1. limit isVariableReference | limit isConstantNumber ifTrue: [limitInit := nil] ifFalse: "Need to store limit in a var" [limit := encoder bindBlockArg: blockVar key, 'LimiT' within: block. limit scope: -2. "Already done parsing block; flag so it won't print" block addArgument: limit. limitInit := AssignmentNode new variable: limit value: arguments first]. test := MessageNode new receiver: blockVar selector: (increment key > 0 ifTrue: [#<=] ifFalse: [#>=]) arguments: (Array with: limit) precedence: precedence from: encoder sourceRange: (myRange first to: blockRange first). incStmt := AssignmentNode new variable: blockVar value: (MessageNode new receiver: blockVar selector: #+ arguments: (Array with: increment) precedence: precedence from: encoder) from: encoder sourceRange: (myRange last to: myRange last). arguments := (Array with: limit with: increment with: block), (Array with: initStmt with: test with: incStmt with: limitInit). + block noteOptimizedIn: self. - block noteOptimized. ^true! Item was added: + ----- Method: OptimizedBlockLocalTempReadBeforeWrittenVisitor>>visitBlockNode: (in category 'visiting') ----- + visitBlockNode: aBlockNode + | savedWritten | + "If we're in the optimized block in one side of an optimized ifTrue:ifFalse: et al + leave it to the enclosing visitMessageNode: activation to handle merging written." + inOptimizedBlock ifTrue: + [^super visitBlockNode: aBlockNode]. + "If we're not then don't update written because without evaluating the guard(s) + we can't tell if the block is evaluated or not, and we must avoid false positives." + savedWritten := written copy. + super visitBlockNode: aBlockNode. + written := savedWritten! Item was changed: ----- Method: AssignmentNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitAssignmentNode: self! - aVisitor visitAssignmentNode: self! Item was added: + ----- Method: ParseNode>>sizeForBlockValue: (in category 'code generation') ----- + sizeForBlockValue: encoder + "Answer the size for evaluating the last statement in a block" + ^self sizeForValue: encoder! Item was changed: ----- Method: BlockNode>>analyseTempsWithin:rootNode:assignmentPools: (in category 'code generation (closures)') ----- analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>" | effectiveScope blockStart | effectiveScope := optimized ifTrue: [actualScopeIfOptimized := scopeBlock] ifFalse: [self]. arguments ifNotNil: [arguments do: [:temp| temp definingScope: self]]. temporaries ifNotNil: [temporaries do: [:temp| temp definingScope: self]]. optimized ifFalse: "if optimized this isn't an actual scope" [rootNode noteBlockEntry: [:entryNumber| blockExtent := (blockStart := entryNumber) to: 0]]. "Need to enumerate a copy because closure analysis can add a statement via ifHasRemoteTempNodeEnsureInitializationStatementExists:." statements copy do: [:statement| statement analyseTempsWithin: effectiveScope rootNode: rootNode assignmentPools: assignmentPools]. + optimized + ifTrue: "if optimized loop need to add nils for any temps read before written" + [optimizedMessageNode isOptimizedLoop ifTrue: + [self nilReadBeforeWrittenTemps]] + ifFalse: "if optimized this isn't an actual scope" + [rootNode noteBlockExit: + [:exitNumber| + blockExtent := blockStart to: exitNumber]]. - optimized ifFalse: "if optimized this isn't an actual scope" - [rootNode noteBlockExit: - [:exitNumber| - blockExtent := blockStart to: exitNumber]]. "Now that the analysis is done move any temps that need to be moved." self postNumberingProcessTempsWithin: effectiveScope rootNode: rootNode. "This is simply a nicety for compiler developers..." temporaries do: [:temp| (temp isIndirectTempVector and: [temp name includes: $?]) ifTrue: [temp name: temp definingScope remoteTempNodeName]]! Item was changed: ----- Method: NewArrayNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitNewArrayNode: self! - aVisitor visitNewArrayNode: self! Item was changed: ParseNode subclass: #BlockNode + instanceVariableNames: 'arguments statements returns nArgsNode size remoteCopyNode temporaries optimized optimizedMessageNode actualScopeIfOptimized blockExtent remoteTempNode copiedValues closureCreationNode startOfLastStatement' - instanceVariableNames: 'arguments statements returns nArgsNode size remoteCopyNode temporaries optimized actualScopeIfOptimized blockExtent remoteTempNode copiedValues closureCreationNode startOfLastStatement' classVariableNames: '' poolDictionaries: '' category: 'Compiler-ParseNodes'! !BlockNode commentStamp: '<historical>' prior: 0! I represent a bracketed block with 0 or more arguments and 1 or more statements. If I am initialized with no statements, I create one. I have a flag to tell whether my last statement returns a value from the enclosing method. My last three fields remember data needed for code generation. I can emit for value in the usual way, in which case I create a literal method (actually a context remotely copied) to be evaluated by sending it value: at run time. Or I can emit code to be evaluated in line; this only happens at the top level of a method and in conditionals and while-loops, none of which have arguments.! Item was changed: ----- Method: MessageNode>>transformIfFalseIfTrue: (in category 'macro transformations') ----- transformIfFalseIfTrue: encoder ^(self checkBlock: (arguments at: 1) as: 'False arg' from: encoder) and: [(self checkBlock: (arguments at: 2) as: 'True arg' from: encoder) and: [selector := SelectorNode new key: #ifTrue:ifFalse: code: #macro. arguments swap: 1 with: 2. + arguments do: [:arg| arg noteOptimizedIn: self]. - arguments do: [:arg| arg noteOptimized]. true]]! Item was changed: ----- Method: BlockNode>>emitForEvaluatedValue:on: (in category 'code generation') ----- emitForEvaluatedValue: stack on: aStream self emitExceptLast: stack on: aStream. + statements last emitForBlockValue: stack on: aStream. - statements last emitForValue: stack on: aStream. ! Item was changed: ----- Method: ParseNode>>accept: (in category 'visiting') ----- accept: aVisitor + "Accept a visitor by double-dispatching to a type-specific method on the visitor, e.g. visitBlockNode:. + All such implementations under ParseNode should answer the result of the dispatch, e.g. + ^aVisitor visitBlockNode: self" ^self subclassResponsibility! Item was changed: ----- Method: BraceNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitBraceNode: self! - aVisitor visitBraceNode: self! Item was changed: ----- Method: InstanceVariableNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitInstanceVariableNode: self! - aVisitor visitInstanceVariableNode: self! Item was changed: ----- Method: ReturnNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitReturnNode: self! - aVisitor visitReturnNode: self! Item was changed: ----- Method: MessageNode>>transformIfTrue: (in category 'macro transformations') ----- transformIfTrue: encoder (self transformBoolean: encoder) ifTrue: [arguments := Array + with: ((arguments at: 1) noteOptimizedIn: self) + with: ((BlockNode withJust: NodeNil) noteOptimizedIn: self). - with: (arguments at: 1) noteOptimized - with: (BlockNode withJust: NodeNil) noteOptimized. ^true] ifFalse: [^false]! Item was changed: ----- Method: MessageNode>>transformIfNilIfNotNil: (in category 'macro transformations') ----- transformIfNilIfNotNil: encoder "vb: Changed to support one-argument ifNotNil: branch. In the 1-arg case we transform the receiver to (var := receiver) which is further transformed to (var := receiver) == nil ifTrue: .... ifFalse: ... This does not allow the block variable to shadow an existing temp, but it's no different from how to:do: is done." | ifNotNilArg | ifNotNilArg := arguments at: 2. ((self checkBlock: (arguments at: 1) as: 'Nil arg' from: encoder) and: [self checkBlock: ifNotNilArg as: 'NotNil arg' from: encoder maxArgs: 1]) ifFalse: [^false]. ifNotNilArg numberOfArguments = 1 ifTrue: [receiver := AssignmentNode new variable: ifNotNilArg firstArgument value: receiver]. selector := SelectorNode new key: #ifTrue:ifFalse: code: #macro. receiver := MessageNode new receiver: receiver selector: #== arguments: (Array with: NodeNil) precedence: 2 from: encoder. + arguments do: [:arg| arg noteOptimizedIn: self]. - arguments do: [:arg| arg noteOptimized]. ^true! Item was changed: ----- Method: MessageNode>>transformOr: (in category 'macro transformations') ----- transformOr: encoder (self transformBoolean: encoder) ifTrue: [arguments := Array + with: ((BlockNode withJust: NodeTrue) noteOptimizedIn: self) + with: ((arguments at: 1) noteOptimizedIn: self). - with: (BlockNode withJust: NodeTrue) noteOptimized - with: (arguments at: 1) noteOptimized. ^true] ifFalse: [^false]! Item was changed: ----- Method: MessageNode>>transformIfNotNilIfNil: (in category 'macro transformations') ----- transformIfNotNilIfNil: encoder "vb: Changed to support one-argument ifNotNil: branch. In the 1-arg case we transform the receiver to (var := receiver) which is further transformed to (var := receiver) == nil ifTrue: .... ifFalse: ... This does not allow the block variable to shadow an existing temp, but it's no different from how to:do: is done." | ifNotNilArg | ifNotNilArg := arguments at: 1. ((self checkBlock: ifNotNilArg as: 'NotNil arg' from: encoder maxArgs: 1) and: [self checkBlock: (arguments at: 2) as: 'Nil arg' from: encoder]) ifFalse: [^false]. ifNotNilArg numberOfArguments = 1 ifTrue: [receiver := AssignmentNode new variable: ifNotNilArg firstArgument value: receiver]. selector := SelectorNode new key: #ifTrue:ifFalse: code: #macro. receiver := MessageNode new receiver: receiver selector: #== arguments: (Array with: NodeNil) precedence: 2 from: encoder. arguments swap: 1 with: 2. + arguments do: [:arg| arg noteOptimizedIn: self]. - arguments do: [:arg| arg noteOptimized]. ^true! Item was changed: ----- Method: MethodNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitMethodNode: self! - aVisitor visitMethodNode: self. - ^aVisitor! Item was changed: ----- Method: MessageNode>>transformIfNil: (in category 'macro transformations') ----- transformIfNil: encoder "vb: Removed the original transformBoolean: which amounds to a test we perform in each of the branches below." (MacroSelectors at: special) = #ifNotNil: ifTrue: [(self checkBlock: arguments first as: 'ifNotNil arg' from: encoder maxArgs: 1) ifFalse: [^false]. "Transform 'ifNotNil: [stuff]' to 'ifNil: [nil] ifNotNil: [stuff]'. Slightly better code and more consistent with decompilation." self noteSpecialSelector: #ifNil:ifNotNil:. selector := SelectorNode new key: (MacroSelectors at: special) code: #macro. arguments := Array + with: ((BlockNode withJust: NodeNil) noteOptimizedIn: self) + with: (arguments first noteOptimizedIn: self). - with: (BlockNode withJust: NodeNil) noteOptimized - with: arguments first noteOptimized. (self transform: encoder) ifFalse: [self error: 'compiler logic error']. ^true]. (self checkBlock: arguments first as: 'ifNil arg' from: encoder) ifFalse: [^false]. + arguments first noteOptimizedIn: self. - arguments first noteOptimized. ^true! Item was changed: ----- Method: MessageNode>>transformAnd: (in category 'macro transformations') ----- transformAnd: encoder (self transformBoolean: encoder) ifTrue: [arguments := Array + with: ((arguments at: 1) noteOptimizedIn: self) + with: ((BlockNode withJust: NodeFalse) noteOptimizedIn: self). - with: (arguments at: 1) noteOptimized - with: (BlockNode withJust: NodeFalse) noteOptimized. ^true] ifFalse: [^false]! Item was changed: ----- Method: MessageNode>>transformCase: (in category 'macro transformations') ----- transformCase: encoder | caseNode | caseNode := arguments first. (caseNode isMemberOf: BraceNode) ifTrue: [((caseNode blockAssociationCheck: encoder) and: [arguments size = 1 or: [self checkBlock: arguments last as: 'otherwise arg' from: encoder]]) ifFalse: [^false]. caseNode elements do: [:messageNode| + messageNode receiver noteOptimizedIn: self. + messageNode arguments first noteOptimizedIn: self]. - messageNode receiver noteOptimized. - messageNode arguments first noteOptimized]. arguments size = 2 ifTrue: + [arguments last noteOptimizedIn: self]. - [arguments last noteOptimized]. ^true]. (caseNode canBeSpecialArgument and: [(caseNode isMemberOf: BlockNode) not]) ifTrue: [^false]. "caseOf: variable" ^encoder notify: 'caseOf: argument must be a brace construct or a variable'! Item was changed: ----- Method: FieldNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitFieldNode: self! - aVisitor visitFieldNode: self! Item was changed: ----- Method: SelectorNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitSelectorNode: self! - aVisitor visitSelectorNode: self! Item was added: + ----- Method: OptimizedBlockLocalTempReadBeforeWrittenVisitor>>initialize (in category 'initialize-release') ----- + initialize + inOptimizedBlock := false! Item was changed: ----- Method: MessageNode>>transformIfTrueIfFalse: (in category 'macro transformations') ----- transformIfTrueIfFalse: encoder ^(self checkBlock: (arguments at: 1) as: 'True arg' from: encoder) and: [(self checkBlock: (arguments at: 2) as: 'False arg' from: encoder) + and: [arguments do: [:arg| arg noteOptimizedIn: self]. - and: [arguments do: [:arg| arg noteOptimized]. true]]! Item was changed: ----- Method: MessageNode>>transformIfFalse: (in category 'macro transformations') ----- transformIfFalse: encoder (self transformBoolean: encoder) ifTrue: [arguments := Array + with: ((BlockNode withJust: NodeNil) noteOptimizedIn: self) + with: ((arguments at: 1) noteOptimizedIn: self). - with: (BlockNode withJust: NodeNil) noteOptimized - with: (arguments at: 1) noteOptimized. ^true] ifFalse: [^false]! Item was changed: ----- Method: BlockNode>>sizeForEvaluatedValue: (in category 'code generation') ----- sizeForEvaluatedValue: encoder ^(self sizeExceptLast: encoder) + + (statements last sizeForBlockValue: encoder)! - + (statements last sizeForValue: encoder)! Item was added: + ----- Method: BlockNode>>nilReadBeforeWrittenTemps (in category 'code generation (closures)') ----- + nilReadBeforeWrittenTemps + | visitor readBeforeWritten | + self accept: (visitor := OptimizedBlockLocalTempReadBeforeWrittenVisitor new). + readBeforeWritten := visitor readBeforeWritten. + temporaries reverseDo: + [:temp| + ((readBeforeWritten includes: temp) + and: [temp isRemote not]) ifTrue: + [statements addFirst: (AssignmentNode new variable: temp value: NodeNil)]]! Item was changed: ----- Method: Encoder>>encodeVariable:sourceRange:ifUnknown: (in category 'encoding') ----- encodeVariable: name sourceRange: range ifUnknown: action | varNode | varNode := scopeTable at: name ifAbsent: [(self lookupInPools: name ifFound: [:assoc | varNode := self global: assoc name: name]) ifTrue: [varNode] + ifFalse: [^action value]]. - ifFalse: [action value]]. range ifNotNil: [ name first canBeGlobalVarInitial ifTrue: [globalSourceRanges addLast: { name. range. false }]. ]. (varNode isTemp and: [varNode scope < 0]) ifTrue: [ OutOfScopeNotification signal ifFalse: [ ^self notify: 'out of scope']. ]. ^ varNode! Item was changed: ----- Method: LiteralNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitLiteralNode: self! - aVisitor visitLiteralNode: self! Item was added: + ----- Method: ParseNode>>emitForBlockValue:on: (in category 'code generation') ----- + emitForBlockValue: stack on: aStream + "Generate code for evaluating the last statement in a block" + ^self emitForValue: stack on: aStream! Item was changed: ----- Method: VariableNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitVariableNode: self! - aVisitor visitVariableNode: self! Item was changed: ----- Method: BlockNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitBlockNode: self! - aVisitor visitBlockNode: self! Item was added: + ----- Method: BlockNode>>noteOptimizedIn: (in category 'code generation (closures)') ----- + noteOptimizedIn: anOptimizedMessageNode + optimized := true. + optimizedMessageNode := anOptimizedMessageNode! Item was added: + ----- Method: OptimizedBlockLocalTempReadBeforeWrittenVisitor>>visitAssignmentNode: (in category 'visiting') ----- + visitAssignmentNode: anAssignmentNode + anAssignmentNode value accept: self. + anAssignmentNode variable isTemp + ifTrue: + [written ifNil: [written := IdentitySet new]. + written add: anAssignmentNode variable] + ifFalse: + [anAssignmentNode variable accept: self]! Item was added: + ----- Method: OptimizedBlockLocalTempReadBeforeWrittenVisitor>>visitMessageNode: (in category 'visiting') ----- + visitMessageNode: aMessageNode + | savedWritten writtenPostFirstArm | + (aMessageNode isOptimized + and: [#(ifTrue:ifFalse: ifFalse:ifTrue: ifNil:ifNotNil: ifNotNil:ifNil:) includes: aMessageNode selector key]) ifFalse: + [^super visitMessageNode: aMessageNode]. + aMessageNode receiver accept: self. + aMessageNode selector accept: self. + savedWritten := written copy. + aMessageNode argumentsInEvaluationOrder + do: [:argument| + argument isBlockNode + ifTrue: [| savedIOB | + savedIOB := inOptimizedBlock. + inOptimizedBlock := true. + [argument accept: self] + ensure: [inOptimizedBlock := savedIOB]] + ifFalse: [argument accept: self]] + separatedBy: + [writtenPostFirstArm := written. + written := savedWritten]. + (written notNil + and: [writtenPostFirstArm notNil]) ifTrue: + [written := written intersection: writtenPostFirstArm]! Item was added: + ParseNodeVisitor subclass: #OptimizedBlockLocalTempReadBeforeWrittenVisitor + instanceVariableNames: 'inOptimizedBlock readBeforeWritten written' + classVariableNames: '' + poolDictionaries: '' + category: 'Compiler-Support'! + + !OptimizedBlockLocalTempReadBeforeWrittenVisitor commentStamp: '<historical>' prior: 0! + Answer the set of temporary variables that are read before they are written in the visited parse tree. Used by the compiler to detect those block-local temporaries of blocks in optimized loops that require nilling to prevent a value from a previous iteration persisting into a subsequent one.! Item was changed: ----- Method: LiteralVariableNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitLiteralVariableNode: self! - aVisitor visitLiteralVariableNode: self! Item was changed: ----- Method: MessageNode>>transformWhile: (in category 'macro transformations') ----- transformWhile: encoder (self checkBlock: receiver as: 'receiver' from: encoder) ifFalse: [^false]. arguments size = 0 ifTrue: "transform bodyless form to body form" [selector := SelectorNode new key: (special = 10 ifTrue: [#whileTrue:] ifFalse: [#whileFalse:]) code: #macro. + arguments := Array with: ((BlockNode withJust: NodeNil) noteOptimizedIn: self). + receiver noteOptimizedIn: self. - arguments := Array with: (BlockNode withJust: NodeNil) noteOptimized. - receiver noteOptimized. ^true]. ^(self transformBoolean: encoder) + and: [receiver noteOptimizedIn: self. + arguments first noteOptimizedIn: self. - and: [receiver noteOptimized. - arguments first noteOptimized. true]! Item was changed: ----- Method: MessageNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitMessageNode: self! - aVisitor visitMessageNode: self! Item was added: + ----- Method: OptimizedBlockLocalTempReadBeforeWrittenVisitor>>visitTempVariableNode: (in category 'visiting') ----- + visitTempVariableNode: aTempVariableNode + (aTempVariableNode isArg + or: [written notNil + and: [written includes: aTempVariableNode]]) ifTrue: + [^self]. + readBeforeWritten ifNil: + [readBeforeWritten := IdentitySet new]. + readBeforeWritten add: aTempVariableNode! Item was changed: ----- Method: CascadeNode>>accept: (in category 'visiting') ----- accept: aVisitor + ^aVisitor visitCascadeNode: self! - aVisitor visitCascadeNode: self! Item was added: + ----- Method: OptimizedBlockLocalTempReadBeforeWrittenVisitor>>readBeforeWritten (in category 'accessing') ----- + readBeforeWritten + ^readBeforeWritten ifNil: [IdentitySet new]! Item was removed: - ----- Method: BlockNode>>noteOptimized (in category 'code generation (closures)') ----- - noteOptimized - optimized := true! |
Free forum by Nabble | Edit this page |