[Vm-dev] VM Maker: VMMaker.oscog-nice.1844.mcz

commits at source.squeak.org commits at source.squeak.org
Mon Apr 25 21:17:28 UTC 2016


Nicolas Cellier uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-nice.1844.mcz

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

Name: VMMaker.oscog-nice.1844
Author: nice
Time: 25 April 2016, 11:13:38.071 pm
UUID: a0e829f0-7d01-424f-a6d3-520759f4a30d
Ancestors: VMMaker.oscog-nice.1843

Change overflow tests in precondition rather than postcondition for small integer multiplication.

Because integer overflow is undefined behaviour, and because we can't rely on undefined behaviour, the compiler has a license to eliminate the post-condition as dead code (at least since iso c89 acception).
Post-condition currently works because we use -fwrapv compiler flag, but relying on specific compiler flags is bad practice in the long term. 

The pre-condition test is not much more expensive and we can avoid a isIntegerObject: test in post-condition, so there's no reason to not follow the C99 standard.

Anyway, Cog will detect and accelerate these multiplication with just (integer multiply, jump on overflow) instructions, so we're speaking of the fallback code here (like in case of byte code simulation).

Note that I used a 64 bits (sqLong) result and signedInteger64For: in my own branch to completely eliminate overflow in 32bits and go beyond SmallInteger limits. I did not reproduce it here because it's a departure from SmallInteger primitive that states:

	"Primitive. Multiply the receiver by the argument and answer with the
	result if it is a SmallInteger. Fail if the argument or the result is not a
	SmallInteger. Essential. No Lookup. See Object documentation whatIsAPrimitive."

Maybe we could implement this large integer trick in bytecodePrimMultiply (since it already has special case for Float argument, why not for large integer result...)...

=============== Diff against VMMaker.oscog-nice.1843 ===============

Item was changed:
  ----- Method: InterpreterPrimitives>>primitiveMultiply (in category 'arithmetic integer primitives') -----
  primitiveMultiply
+ 	| integerRcvr integerArg integerResult overflow |
- 	| integerRcvr integerArg integerResult |
  	integerRcvr := self stackIntegerValue: 1.
  	integerArg := self stackIntegerValue: 0.
  	self successful ifTrue:
+ 		[overflow := integerRcvr > 0
+ 					ifTrue:  [integerArg > 0
+ 						ifTrue: [integerRcvr > (objectMemory maxSmallInteger / integerArg)]
+ 						ifFalse: [integerArg < (objectMemory minSmallInteger / integerRcvr)]]
+ 					ifFalse: [integerArg > 0
+ 						ifTrue: [integerRcvr < (objectMemory minSmallInteger / integerArg)]
+ 						ifFalse: [(integerRcvr < 0) and: [integerArg < (objectMemory maxSmallInteger / integerRcvr)]]].
+ 		overflow
+ 			ifTrue: [self primitiveFail]
+ 			ifFalse:
+ 				[integerResult := integerRcvr * integerArg.
+ 				self pop: 2 thenPush: (self integerObjectOf: integerResult)]]!
- 		[integerResult := integerRcvr * integerArg.
- 		"check for C overflow by seeing if computation is reversible"
- 		((integerArg = 0) or: [(integerResult // integerArg) = integerRcvr])
- 			ifTrue: [self pop2AndPushIntegerIfOK: integerResult]
- 			ifFalse: [self primitiveFail]]!

Item was changed:
  ----- Method: StackInterpreter>>bytecodePrimMultiply (in category 'common selector sends') -----
  bytecodePrimMultiply
+ 	| rcvr arg result overflow oop |
- 	| rcvr arg result |
  	rcvr := self internalStackValue: 1.
  	arg := self internalStackValue: 0.
  	(objectMemory areIntegers: rcvr and: arg)
  		ifTrue: [rcvr := objectMemory integerValueOf: rcvr.
  				arg := objectMemory integerValueOf: arg.
+ 				overflow := rcvr > 0
+ 							ifTrue:  [arg > 0
+ 								ifTrue: [rcvr > (objectMemory maxSmallInteger / arg)]
+ 								ifFalse: [arg < (objectMemory minSmallInteger / rcvr)]]
+ 							ifFalse: [arg > 0
+ 								ifTrue: [rcvr < (objectMemory minSmallInteger / arg)]
+ 								ifFalse: [(rcvr < 0) and: [arg < (objectMemory maxSmallInteger / rcvr)]]].
+ 				overflow
+ 					ifFalse:
+ 						[result := rcvr * arg.
+ 						oop := self integerObjectOf: result.
+       					self internalPop: 2 thenPush: oop.
+ 						^self fetchNextBytecode "success"]]
- 				result := rcvr * arg.
- 				(arg = 0
- 				 or: [(result // arg) = rcvr and: [objectMemory isIntegerValue: result]]) ifTrue:
- 					[self internalPop: 2 thenPush: (objectMemory integerObjectOf: result).
- 					 ^self fetchNextBytecode "success"]]
  		ifFalse: [self initPrimCall.
  				self externalizeIPandSP.
  				self primitiveFloatMultiply: rcvr byArg: arg.
  				self internalizeIPandSP.
  				self successful ifTrue: [^ self fetchNextBytecode "success"]].
  
  	messageSelector := self specialSelector: 8.
  	argumentCount := 1.
  	self normalSend!



More information about the Vm-dev mailing list