2016-04-24 13:48 GMT+02:00 commits@source.squeak.org:
Nicolas Cellier uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-nice.1838.mcz
==================== Summary ====================
Name: VMMaker.oscog-nice.1838 Author: nice Time: 24 April 2016, 1:47:02.874 pm UUID: 73cf9fda-4e5a-4e0c-a1b9-92ace5f8f3c9 Ancestors: VMMaker.oscog-nice.1837
Use a type inference that better fits C rules (C99 standard section 6.3):
- in (float op int), int is promoted to double not float
- in (unsigned short op short) both operands are promoted to #int due to
int promotion rules.
The idea behind this is that behaviour of generated code for inlined and non inlined code should be the same. We can guaranty such property only if we adhere to C rules.
=============== Diff against VMMaker.oscog-nice.1837 ===============
Item was changed: ----- Method: CCodeGenerator>>computeKernelReturnTypes (in category 'public') ----- computeKernelReturnTypes | dictionary | dictionary := Dictionary newFromPairs: #(oopAt: #sqInt oopAt:put: #sqInt oopAtPointer: #sqInt oopAtPointer:put: #sqInt byteAt: #sqInt byteAt:put: #sqInt byteAtPointer: #sqInt byteAtPointer:put: #sqInt shortAt: #sqInt shortAt:put: #sqInt shortAtPointer: #sqInt shortAtPointer:put: #sqInt intAt: #sqInt intAt:put: #sqInt intAtPointer: #sqInt intAtPointer:put: #sqInt longAt: #sqInt longAt:put: #sqInt longAtPointer: #sqInt longAtPointer:put: #sqInt
long32At: #int long32At:put: #int
long32At: #sqInt long32At:put: #sqInt unalignedLongAt: #sqInt
unalignedLongAt:put: #sqInt
unalignedLong32At: #int
unalignedLong32At:put: #int
unalignedLong32At: #sqInt
unalignedLong32At:put: #sqInt
Ah, I forgot to comment the purpose of #computeKernelReturnTypes change: the idea is that we use a type inference that works both for 32 and 64 bits VM.
Why? Because we generate single source code for both 32 and 64 bits plugins. So we should have type inference as much independent of BytesPerWord as possible.
long64At: #sqLong long64At:put: #sqLong
fetchFloatAt:into: #void storeFloatAt:from: #void fetchFloatAtPointer:into: #void
storeFloatAtPointer:from: #void fetchSingleFloatAt:into: #void storeSingleFloatAt:from: #void fetchSingleFloatAtPointer:into: #void storeSingleFloatAtPointer:from: #void
pointerForOop: #'char *' oopForPointer: #sqInt).
BytesPerWord = 8 ifTrue:
[#(long32At: long32At:put: unalignedLong32At:
unalignedLong32At:put:) do:
[:accessor|
dictionary at: accessor put: #int]]. ^dictionary!
Item was changed: ----- Method: CCodeGenerator>>promoteArithmeticTypes:and: (in category 'type inference') ----- promoteArithmeticTypes: firstType and: secondType "Answer the return type for an arithmetic send. This is so that the inliner can still inline
simple expressions. Deal with pointer arithmetic, floating point
arithmetic and promotion.
It is important to choose deterministically to get stable source
generation.
Also, the behaviour of inlined and non inlined code should be
unchanged."
simple expressions. Deal with pointer arithmetic, floating point
arithmetic and promotion."
| firstSize secondSize | ((#(#double float) includes: firstType) or: [#(#double float) includes: secondType]) ifTrue:
[^(firstType = #double or: [secondType = #double])
ifTrue: [#double]
ifFalse: [#float] "in C99 6.3.1.8, float+int, int
is converted as a float"].
[^(firstType = #float and: [secondType = #float])
ifTrue: [#float]
ifFalse: [#double]]. "deal with unknowns, answering nil." (firstType isNil or: [secondType isNil]) ifTrue: [^nil].
"Deal with integer promotion and arithmetic conversion"
^self promoteIntegerArithmeticTypes: firstType and: secondType!
"Deal with promotion; answer the longest type, defaulting to the
recever if they're the same.
See e.g. section 6.3.1.8 Usual arithmetic conversions, from the
C99 standard:
Otherwise, the integer promotions are performed on both
operands
Then the following rules are applied to the promoted
operands:
If both operands have the same type, then no
further conversion is needed.
Otherwise, if both operands have signed integer
types or both have unsigned integer
types, the operand with the type of lesser integer
conversion rank is converted to the
type of the operand with greater rank.
Otherwise, if the operand that has unsigned
integer type has rank greater or equal to
the rank of the type of the other operand, then
the operand with signed integer type
is converted to the type of the operand with
unsigned integer type.
Otherwise, if the type of the operand with signed
integer type can represent all of the
values of the type of the operand with unsigned
integer type, then the operand with
unsigned integer type is converted to the type of
the operand with signed integer type.
Otherwise, both operands are converted to the
unsigned integer type corresponding to
the type of the operand with signed integer type.
It is important to choose deterministically to get stable source
generation. So if the types have
the same size but differ in signedness we choose the unsigned
type, which is in partial agreement
with the above"
^(firstSize := self sizeOfIntegralCType: firstType) = (secondSize
:= self sizeOfIntegralCType: secondType)
ifTrue:
[(firstType first = $u)
ifTrue: [firstType]
ifFalse: [(secondType first = $u) ifTrue:
[secondType] ifFalse: [firstType]]]
ifFalse:
[firstSize > secondSize ifTrue: [firstType]
ifFalse: [secondType]]!
Item was added:
- ----- Method: CCodeGenerator>>promoteIntegerArithmeticTypes:and: (in
category 'type inference') -----
- promoteIntegerArithmeticTypes: firstType and: secondType
"Answer the return type for an arithmetic send.
Deal with integer promotion rules of C99.
See section 6.3 Conversions of the standard.
6.3.1.1 ...snip...
If an int can represent all values of the original type,
the value is converted to an int;
otherwise, it is converted to an unsigned int. These are
called the integer promotions.
All other types are unchanged by the inte ger promotions
6.3.1.8 ...snip...
Otherwise, the integer promotions are performed on both
operands
Then the following rules are applied to the promoted
operands:
If both operands have the same type, then no
further conversion is needed.
Otherwise, if both operands have signed integer
types or both have unsigned integer
types, the operand with the type of lesser integer
conversion rank is converted to the
type of the operand with greater rank.
Otherwise, if the operand that has unsigned
integer type has rank greater or equal to
the rank of the type of the other operand, then
the operand with signed integer type
is converted to the type of the operand with
unsigned integer type.
Otherwise, if the type of the operand with signed
integer type can represent all of the
values of the type of the operand with unsigned
integer type, then the operand with
unsigned integer type is converted to the type of
the operand with signed integer type.
Otherwise, both operands are converted to the
unsigned integer type corresponding to
the type of the operand with signed integer type.
This is so that the generated code behaviour is unsensitive to
inlining."
| length1 length2 intSize |
length1 := self sizeOfIntegralCType: firstType.
length2 := self sizeOfIntegralCType: secondType.
intSize := self sizeOfIntegralCType: #int.
(length1 < intSize and: [length2 < intSize]) ifTrue: [^#int].
"Integer promotion"
length1 > length2 ifTrue: [^firstType].
length2 > length1 ifTrue: [^secondType].
firstType first = $u ifTrue: [^firstType].
secondType first = $u ifTrue: [^secondType].
^firstType!
vm-dev@lists.squeakfoundation.org