Mahdi Safsafi 225 Posted June 8, 2020 (edited) @Kas Ob. Again, shifting outside range is implementation defined as I said before !!! Compilers, Interpreters, CPU, Virtual-Machines, are free to choose how to handle it !!! The behavior may even vary between same vendor products !!! So comparing to FPC is worthless !!! Delphi always mask with 0x1F meaning for your example : X := A shl b; // TConst=UInt64 => B = 63 and $1F = 31. 31 < 64 ... compiles. X := A shl b; // TConst=UInt32 => B = 63 and $1F = 31. 31 < 32 ... compiles. X := A shl b; // TConst=UInt16 => B = 63 and $1F = 31. 31 > 16 ... error. Edited June 8, 2020 by Mahdi Safsafi Share this post Link to post
Guest Posted June 8, 2020 4 minutes ago, Mahdi Safsafi said: Again, shifting outside range is implementation defined as I said before !!! Thank you. But at least shouldn't the compiler warns when successfully compiled the case with Quote TMyVar = UInt32; // Delphi TConst = UInt32; // True for 32bit and refuse to compile on 64bit I think it should either warn on 32bit that the code is not compliable on 64bit, or refuse to compile on both , can we agree at least on this ? Share this post Link to post
Mahdi Safsafi 225 Posted June 8, 2020 (edited) @Kas Ob. For programming language, the better way for my opinion is to refuse compiling. On x86, the CPU may just choose to mask the amount and continue execution. On ARM, It's even not possible to encode an amount (as immediate) that violates instruction range ! However when amount is specified as register. CPU masks the amount before processing the instruction: # x86: shl r/m32, amount # amount = amount and RegSizeMask. # aarch32(arm): lsl Rd Rm, 65 # you can not encode it ! lsl Rd, Rm, Rs # Rs = Rs and RegSizeMask. # aarch64: shl Vd, Vn, amount # UNDEFINED if shift > RegSizeMask! While masking the amount is the most popular way ... its still considered as unpredictable behavior and may vary between implementation and all are corrects ! MSVC: const int C = 1 << 100 ; // just warning ... but it compiles and gives 0! int main() { cout << C << endl; // C = 0. } Edited June 8, 2020 by Mahdi Safsafi Share this post Link to post
Mahdi Safsafi 225 Posted June 8, 2020 Moreover, compiler on a specific platform such aarch32/aarch64 must not at any case allow shifting outside a given range ! because mostly the opcode is qualified as invalid/reserved. Meaning CPU may raise UD exception. Or worse, you may end-up executing another different instruction. Share this post Link to post
Guest Posted June 8, 2020 Dropped this subject and was working but what to say i came across a note i wrote to my self, so here one last example without negative values or wide shifting range {$R+} type TMyVar = NativeUInt; const A = $FF; B = 8 * (SizeOf(TMyVar) div 2); // 16 for 32bit and 32 for 64bit var X, Y: TMyVar; begin X := A shl B; Y := A; Y := Y shl B; if X = Y then Writeln('True') else Writeln('False'); Writeln('A = ' + IntToHex(A, 16)); Writeln('B = ' + IntToHex(B, 16)); Writeln('X = ' + IntToHex(X, 16)); Writeln('Y = ' + IntToHex(Y, 16)); Readln; end. The result Quote On 32bit True A = 00000000000000FF B = 0000000000000010 X = 0000000000FF0000 Y = 0000000000FF0000 On 64bit False A = 00000000000000FF B = 0000000000000020 X = 00000000000000FF Y = 000000FF00000000 Here we notice 1) the untyped constant are handled as Cardinal or Integer ( with size of 4 byte ). 2) no warning or failing to compile 3) the value of X should either be 0 when the compiler sees it as Cardinal and shift it by 32 or handled internally by casted it (because it is untyped) as destination in this case NativeUInt (UInt64) and returned the value $FF00000000, 4) there is no mention of the documentation http://docwiki.embarcadero.com/RADStudio/Rio/en/Declared_Constants of such behaviour for untyped constant. 5) the way X and Y calculated in not mentioned anywhere in documentation of such behaviour when using untyped constant or (from older example different types and values like negative and other), i believe already few example established. is result right, what do you think ? Share this post Link to post
Mahdi Safsafi 225 Posted June 8, 2020 @Kas Ob. Yes, you're right ! untyped constant is handled as Integer : // a fix: this will produce true, true for both (x86, x64): X := TMyVar(A) shl B; Y := A; Y := TMyVar(Y) shl B; Share this post Link to post