home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.arch      Apparently more than just beeps & boops      131,241 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 129,297 of 131,241   
   BGB to Anton Ertl   
   Re: I32LP64 vs. ILP64   
   06 Aug 25 12:00:36   
   
   From: cr88192@gmail.com   
      
   On 8/6/2025 6:28 AM, Anton Ertl wrote:   
   > BGB  writes:   
   >> counter-argument to ILP64, where the more natural alternative is LP64.   
   >   
   > I am curious what makes you think that I32LP64 is "more natural",   
   > given that C is a human creation.   
   >   
      
   We would have needed a new type to be able to express 32 bit values.   
      
   Though, goes and looks it up, apparently the solution was to add __int32   
   to address this issue.   
      
   So, it seems, an early occurrence of the __int8, __int16, __int32,   
   __int64, __int128 system.   
      
      
   > ILP64 is more consistent with the historic use of int: int is the   
   > integer type corresponding to the unnamed single type of B   
   > (predecessor of C), which was used for both integers and pointers.   
   > You can see that in various parts of C, e.g., in the integer type   
   > promotion rules (all integers are promoted at least to int in any   
   > case, beyond that only when another bigger integer is involved).   
   > Another example is   
   >   
   > main(argc, argv)   
   >       char *argv[];   
   > {   
   >    return 0;   
   > }   
   >   
   > Here the return type of main() defaults to int, and the type of argc   
   > defaults to int.   
   >   
   > As a consequence, one should be able to cast int->pointer->int and   
   > pointer->int->pointer without loss.  That's not the case with I32LP64.   
   > It is the case for ILP64.   
   >   
      
   Possibly.   
      
   Though, in BGBCC I did make a minor tweak in the behavior of K&R and C89   
   style code:   
   The 'implicit int' was replaced with 'implicit long'...   
      
   Which, ironically, allows a lot more K&R style code to run unmodified on   
   a 64-bit machine. Where, if one assumes 'int', then a lot of K&R style   
   code doesn't work correctly.   
      
      
   > Some people conspired in 1992 to set the de-facto standard, and made   
   > the mistake of deciding on I32LP64   
   > , and we have paid for   
   > this mistake ever since, one way or the other.   
   >   
   > E.g., the designers of ARM A64 included addressing modes for using   
   > 32-bit indices (but not 16-bit indices) into arrays.  The designers of   
   > RV64G added several sign-extending 32-bit instructions (ending in   
   > "W"), but not corresponding instructions for 16-bit operations.  The   
   > RISC-V manual justifies this with   
   >   
   > |A few new instructions (ADD[I]W/SUBW/SxxW) are required for addition   
   > |and shifts to ensure reasonable performance for 32-bit values.   
   >   
   > Why were 32-bit indices and 32-bit operations more important than   
   > 16-bit indices and 16-bit operations?  Because with 32-bit int, every   
   > integer type is automatically promoted to at least 32 bits.   
   >   
      
   It is a tradeoff.   
      
   A lot of 32 bit code expected int to be 32 bits, and also expects int to   
   wrap on overflow. Without ADDW and friends, the expected wrap on   
   overflow behavior is not preserved.   
      
   Early BitManip would have added an ADDWU instruction (ADDW but zero   
   extending); but then they dropped it.   
      
   In my own RV extensions, I re-added ADDWU because IMHO dropping it was a   
   mistake.   
      
      
   In Zba, they have ADDUW instead, which zero-extends Rs1; so "ADDUW Rd,   
   Rs, X0" can be used to zero-extend stuff, but this isn't as good. There   
   was at one point an ADDIWU instruction, but I did not re-add it. I   
   managed to add the original form of my jumbo prefix into the same   
   encoding space; but have since relocated it.   
      
      
   Re-adding ADDIWU is more debatable as the relative gains are smaller   
   than for ADDWU (in a compiler with zero-extended unsigned int).   
      
   For RV64G, it still needs, say:   
      ADD   Rd, Rs, Rt   
      SLLI  Rd, Rd, 32   
      SLRI  Rd, Rd, 32   
   Which isn't ideal.   
      
   Though, IMHO, the cost of needing 2 shifts for "unsigned int" ADD is   
   less than the mess that results from sign-extending "unsigned int".   
      
   Like, Zba adds "SHnADD.UW" and similar, which with zero-extended   
   "unsigned int" would have been entirely unnecessary.   
      
      
   So, that was my partial act of rebellion against the RV ABI spec (well,   
   that and different handling of passing and returning structs by value).   
      
   Where, BGBCC handles it in a way more like that in MS style ABIs, where:   
      1-16 bytes, pass in registers or register pair;   
      17+ bytes: pass or return via memory reference.   
      
   As opposed to using on-stack copying as the fallback case.   
   Though, arguably at least less of a mess than whatever was going on in   
   the design of the SysV AMD64 ABI.   
      
      
      
   > Likewise, with ILP64 the size of integers in computations would always   
   > be 64 bits, and many scalar variables (of type int and unsigned) would   
   > also be 64 bits.  As a result, 32-bit indices and 32-bit operations   
   > would be rare enough that including these addressing modes and   
   > instructions would not be justified.   
   >   
   > But, you might say, what about memory usage?  We would use int32_t   
   > where appropriate in big arrays and in fields of structs/classes with   
   > many instances.  We would access these array elements and fields with   
   > LW/SW on RV64G and the corresponding instructions on ARM A64, no need   
   > for the addressing modes and instructions mentioned above.   
   >   
   > So the addressing mode bloat of ARM A64 and the instruction set bloat   
   > of RV64G that I mentioned above is courtesy of I32LP64.   
   >   
      
   This assumes though that all 64 bit operations can have the same latency   
   as 32 bit operations.   
      
   If you have a machine where common 32-bit ops can have 1 cycle latency   
   but 64 needs 2 cycles, then it may be preferable to have 32 bit types   
   for cases where 64 isn't needed.   
      
      
   But, yeah, in an idealized world, maybe yeah, the avoidance of 32-bit   
   int, or at least the avoidance of a dependency on assumed wrap on   
   overflow semantics, or implicit promotion to whatever is the widest   
   natively supported type, could have led to less of a mess.   
      
      
   > - anton   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca