Eliot Miranda uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-eem.1071.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.1071 Author: eem Time: 18 February 2015, 7:25:44.963 pm UUID: 6b4dfa33-242b-4b9b-8b1a-0aee9139cf6c Ancestors: VMMaker.oscog-eem.1070
Fix several bugs in the new type inferrence code, resulting in a functional VM again (phew!).
Do a much better job at typeForArithmetic:in:; answering the longest type for integral types.
In inferTypesForImplicitlyTypedVariablesIn:, observe assignments from both sends and typed vars. Comment the method better so that alreadyExplicitlyTyped's usage is clear(er).
On type compatibility of inlined expressions, insist on signed compatibility or accept an untyped actual.
Provide a return type for asFloat (so inlining in primitiveAsFloat still occurs)
Provide an exception in unsignedTypeForBitwiseSend:in: for currentBytecode to preserve the nice constant inlining of currentBytecode & N in the bytecode cases.
This time I feel that the Slang Sensei has hit me over the head and some enlightenment has ensued. That's a first ;-).
=============== Diff against VMMaker.oscog-eem.1070 ===============
Item was changed: ----- Method: CCodeGenerator>>isActualType:compatibleWithFormalType: (in category 'inlining') ----- isActualType: actualTypeOrNil compatibleWithFormalType: formalTypeOrNil | actualType formalType | actualType := actualTypeOrNil ifNil: [#sqInt]. formalType := formalTypeOrNil ifNil: [#sqInt]. ((self isIntegralCType: actualType) and: [self isIntegralCType: formalType]) ifFalse: [^actualType = formalType or: [formalType = 'double' and: [actualType = 'float']]]. "For now, insist that the signedness agrees." ^(actualType first = $u) = (formalType first = $u) + or: [actualTypeOrNil isNil] "a nil formal defaults to #sqInt"! - or: [actualTypeOrNil isNil or: [formalTypeOrNil isNil]]!
Item was changed: ----- Method: CCodeGenerator>>returnTypeForSend:in: (in category 'type inference') ----- returnTypeForSend: sendNode in: aTMethod "Answer the return type for a send. Absent sends default to #sqInt. The bitwise operators answer unsigned versions of their argument types, at least in gcc although this author can't find that in the C99 spec. If you can find this, please let me know." | sel | ^(self anyMethodNamed: (sel := sendNode selector)) ifNil: [kernelReturnTypes at: sel ifAbsent: [^sel caseOf: { [#+] -> [self typeForArithmetic: sendNode in: aTMethod]. [#-] -> [self typeForArithmetic: sendNode in: aTMethod]. [#*] -> [self typeForArithmetic: sendNode in: aTMethod]. [#/] -> [self typeForArithmetic: sendNode in: aTMethod]. [#addressOf:] -> [(self typeFor: sendNode receiver in: aTMethod) ifNil: [#sqInt] ifNotNil: [:type| type, (type last isLetter ifTrue: [' *'] ifFalse: ['*'])]]. [#at:] -> [self typeForDereference: sendNode in: aTMethod]. [#bitAnd:] -> [self unsignedTypeForBitwiseSend: sendNode in: aTMethod]. [#bitOr:] -> [self unsignedTypeForBitwiseSend: sendNode in: aTMethod]. [#bitXor:] -> [self unsignedTypeForBitwiseSend: sendNode in: aTMethod]. + [#asFloat] -> [#double]. - [#asVoidPointer] -> [#'void *']. - [#asVoidPointer] -> [#'void *']. - [#asUnsignedInteger] -> [#usqInt]. [#asLong] -> [#long]. + [#asUnsignedInteger] -> [#usqInt]. [#asUnsignedLong] -> [#'unsigned long']. + [#asVoidPointer] -> [#'void *']. [#signedIntToLong] -> [#usqInt]. "c.f. generateSignedIntToLong:on:indent:" [#signedIntToShort] -> [#usqInt]. "c.f. generateSignedIntToShort:on:indent:" [#cCoerce:to:] -> [sendNode args last value]. [#cCoerceSimple:to:] -> [sendNode args last value] } otherwise: [#sqInt]]] ifNotNil: [:m| m returnType ifNotNil: [:type| self baseTypeForType: type]]!
Item was changed: ----- Method: CCodeGenerator>>typeForArithmetic:in: (in category 'type inference') ----- typeForArithmetic: sendNode in: aTMethod "Answer the return type for an arithmetic sendThis is so that the inliner can still + inline simple expressions. Deal with pointer arithmetic, floating point arithmetic + and promotion." - inline simple expressions. Deal with pointer arithmetic and floating point arithmetic" | rcvrType argType | argType := self typeFor: sendNode args first in: aTMethod. argType = #double ifTrue: [^#double]. rcvrType := self typeFor: sendNode receiver in: aTMethod. + "deal with unknowns, answering nil." + (rcvrType isNil or: [argType isNil]) ifTrue: + [^nil]. + "deal with pointer arithmetic" + (rcvrType last = $* or: [argType last = $*]) ifTrue: + [(sendNode selector == #- + and: [rcvrType last = $* and: [argType last = $*]]) ifTrue: + [^#int]. + ^rcvrType last = $ + ifTrue: [rcvrType] + ifFalse: [argType]]. + "deal with promotion; answer the longest type, defaulting to the recever if they're the same" + ^(self sizeOfIntegralCType: rcvrType) >= (self sizeOfIntegralCType: argType) + ifTrue: [rcvrType] + ifFalse: [argType]! - (sendNode selector == #- - and: [rcvrType notNil and: [rcvrType last = $* - and: [argType notNil and: [argType last = $*]]]]) ifTrue: - [^#int]. - ^rcvrType!
Item was changed: ----- Method: CCodeGenerator>>unsignedTypeForBitwiseSend:in: (in category 'type inference') ----- unsignedTypeForBitwiseSend: aTSendNode in: aTMethod + "The result of the bitwise operators in C is unsigned. + We make an exception for currentBytecode bitAnd: N to allow better inlining in cases." - "The result of the bitwise operators in C is unsigned." | t1 t2 type | + (aTSendNode receiver isVariable + and: [aTSendNode receiver name = 'currentBytecode' + and: [aTSendNode selector == #bitAnd:]]) ifTrue: + [^#sqInt]. t1 := (self typeFor: aTSendNode receiver in: aTMethod) ifNil: [^nil]. t2 := (self typeFor: aTSendNode args first in: aTMethod) ifNil: [^nil]. type := (self sizeOfIntegralCType: t1) >= (self sizeOfIntegralCType: t1) ifTrue: [t1] ifFalse: [t2]. ^type first = $u ifTrue: [type] ifFalse: [(type beginsWith: 'sq') ifTrue: ['u', type] ifFalse: ['unsigned ', type]]!
Item was changed: ----- Method: TMethod>>inferTypesForImplicitlyTypedVariablesIn: (in category 'type inference') ----- inferTypesForImplicitlyTypedVariablesIn: aCodeGen "infer types for untyped variables from assignments and arithmetic uses. For debugging answer a Dictionary from var to the nodes that determined types This for debugging: (self copy inferTypesForImplicitlyTypedVariablesIn: aCodeGen)" + | alreadyExplicitlyTyped effectiveNodes | + "selector = #blockDispatchTargetsFor:perform:arg: ifTrue: + [self halt]." + alreadyExplicitlyTyped := declarations keys asSet. - | explicitlyTyped effectiveNodes | - explicitlyTyped := declarations keys asSet. effectiveNodes := Dictionary new. "this for debugging" parseTree nodesDo: [:node| | type var | "If there is something of the form i >= 0, then i should be signed, not unsigned." (node isSend and: [(locals includes: (var := node receiver variableNameOrNil)) + and: [(alreadyExplicitlyTyped includes: var) not "don't be fooled by inferred unsigned types" - and: [(explicitlyTyped includes: var) not and: [(#(<= < >= >) includes: node selector) and: [node args first isConstant and: [node args first value = 0 and: [(type := self typeFor: var in: aCodeGen) notNil and: [type first == $u]]]]]]]) ifTrue: [declarations at: var put: (aCodeGen signedTypeForIntegralType: type), ' ', var. effectiveNodes at: var put: { declarations at: var. node }]. + "if an assignment to an untyped local of a known type, set the local's type to that type. + Only observe known sends (methods in the current set) and typed local variables." - "if an assignment to an untyped local of a known type, set the local's type to that type." (node isAssignment and: [(locals includes: (var := node variable name)) and: [(declarations includesKey: var) not + and: [(type := node expression isSend + ifTrue: [aCodeGen returnTypeForSend: node expression in: self] + ifFalse: [self typeFor: node expression in: aCodeGen]) notNil - and: [(type := self typeFor: node expression in: aCodeGen) notNil and: [type ~= #void]]]]) ifTrue: [declarations at: var put: type, ' ', var. effectiveNodes at: var put: { declarations at: var. node }]]. ^effectiveNodes!
vm-dev@lists.squeakfoundation.org