2014-07-01 0:41 GMT+02:00 Eliot Miranda <eliot.miranda@gmail.com>:
Hi All,sorry for that noise...On Mon, Jun 30, 2014 at 12:24 PM, Eliot Miranda <eliot.miranda@gmail.com> wrote:
Hi All,I recently eliminated the optimization in Slang that replaces a division by a power of two with a shift, because the code cast the argument to signed, and hence broke unsigned division. That's what used to be controlled by the UseRightShiftForDivide class var of CCodeGenerator.Yesterday I found out that that optimization is the only thing that's keeping the LargeIntegers plugin afloat. To whit:LargeIntegersPlugin>>cDigitSub: pByteSmalllen: smallLenwith: pByteLargelen: largeLeninto: pByteRes| z limit |<var: #pByteSmall type: 'unsigned char * '><var: #pByteLarge type: 'unsigned char * '><var: #pByteRes type: 'unsigned char * '>z := 0."Loop invariant is -1<=z<=1"limit := smallLen - 1.0 to: limit do:[:i |z := z + (pByteLarge at: i) - (pByteSmall at: i).pByteRes at: i put: z - (z // 256 * 256)."sign-tolerant form of (z bitAnd: 255)"z := z // 256].limit := largeLen - 1.smallLen to: limit do:[:i |z := z + (pByteLarge at: i) .pByteRes at: i put: z - (z // 256 * 256)."sign-tolerant form of (z bitAnd: 255)"z := z // 256].The "z := z // 256"'s at the end of the loops were being generated asz = ((sqInt) z) >> 8;which is essential for the signed arithmetic implicit in "z := z + (pByteLarge at: i) - (pByteSmall at: i)" to work.So what's the right thing to do?In C -1 // 256 = 0, but in Smalltalk -1 // 256 = -1 (// rounds towards - infinity), whereas (-1 quo: 256) = 0 (quo: rounds towards 0).I could modify the code generator to generate Smalltalk semantics for //, but its not pretty (one has to check signedness, check if there's a remainder, etc).What I'd like is to have a signed bitShift:. Wait you say, bitShift: is signed. Ah, but the code generator generates unsigned shifts for all bitShift:'s !!!!.So some ideas:1. change bitShift: to obey the type of the receiver (Slang allows one to type variables, defaulting to a singed long). This is my preference, but it risks breaking a good handful of negative bitShift: uses in plugins (which is where I'm worried about regressions).2. change bitShift: to obey explicit casts, generating a signed shift forfoo asInteger bitShift: expr(self cCoerceSimple: #foo to: #sqInt) bitShift: exprSeriously?!?! this stinks.3. writez := self cCode: [z >>= 8] inSmalltalk: [z // 256]
Seriously?!?! this stinks too.Anything else that makes any sense?Doh:Intger methdos for *VMMakersignedBitShift: anInteger"For historical reasons Slang generates an unsigned shift from all of the shift operators >>, << & bitShift:.These are too deeply entrenched to try and redefine the semantics. So instead we provide a signed bitShift:that signals to Slang that its argument should be cast to signed, not to unsigned, when being shifted."^self bitShift: anIntegerapologies--
best,EliotThough remember that signed right shift is theoretically implementation defined (though I'm not aware of a compiler/processor providing 0 expansion), and that signed right shift behavior is undefined in case of overflow...
C is a very strange language... Portable?
I just hate its (lack of) signed integer arithmetic model.