Re: bswap is slow on SPARC

Dennis Clarke <[email protected]> Tue, 25 Nov 2025 00:19:29 -0500
Newsgroups gmane.os.netbsd.ports.sparc64,gmane.os.netbsd.ports.sparc
Organization GENUNIX
Message-ID <[email protected]>
On 11/24/25 14:55, Sad Clouds wrote:
> On Mon, 24 Nov 2025 13:30:50 +0000
> nia <[email protected]> wrote:
> 
>> When encryption algorithms expect to be able to encode little-endian
>> integers in a tight loop, that adds up to being *slow*. Especially
>> when NetBSD encrypts swap by default now.
> 
> I wonder, why store data in a little-endian byte order on a big-endian
> architecture? Is it that common to access the same swap partition
> across multiple architectures?

It can just make life easy to store data in the most commonly used
format. Swapping around 8 bytes from end to end is no big deal and all
the code looks like :


     uint64_t result, b[8] = {0,0,0,0,0,0,0,0};

     b[0] = ( ( x & 0xff ) << 56 );
     b[1] = ( ( x & 0xff00 ) << 40 );
     b[2] = ( ( x & 0xff0000 ) << 24 );
     b[3] = ( ( x & 0xff000000 ) << 8 );
     b[4] = ( ( x & 0xff00000000 ) >> 8 );
     b[5] = ( ( x & 0xff0000000000 ) >> 24 );
     b[6] = ( ( x & 0xff000000000000 ) >> 40 );
     b[7] = ( x >> 56 );

     result = b[0] | b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7];


The final output asm is generally about the same :


000118  ! predecessor blocks: .L14
000119
000120                          .L15:
000121
000122  !   50                !    uint64_t result, b[8] = 
{0,0,0,0,0,0,0,0};
000123
000124
000125  ! predecessor blocks: .L15
000126
000127                          .L19:
000128  /* 0x0020         50 */         stx     %g0,[%fp+1959]
000129  /* 0x0024            */         stx     %g0,[%fp+1967]
000130  /* 0x0028            */         stx     %g0,[%fp+1975]
000131  /* 0x002c            */         stx     %g0,[%fp+1983]
000132  /* 0x0030            */         stx     %g0,[%fp+1991]
000133  /* 0x0034            */         stx     %g0,[%fp+1999]
000134  /* 0x0038            */         stx     %g0,[%fp+2007]
000135  /* 0x003c            */         stx     %g0,[%fp+2015]
000136
000137  !   52                !    b[0] = ( ( x & 0xff ) << 56 );
000138
000139
000140  ! predecessor blocks: .L19
000141
000142                          .L20:
000143  /* 0x0040         52 */         ldx     [%fp+2039],%o0
000144  /* 0x0044            */         and     %o0,255,%o0
000145  /* 0x0048            */         sllx    %o0,56,%o0
000146  /* 0x004c            */         stx     %o0,[%fp+1959] ! volatile
000147
000148  !   53                !    b[1] = ( ( x & 0xff00 ) << 40 );
000149
000150
000151  ! predecessor blocks: .L20
000152
000153                          .L21:
000154  /* 0x0050         53 */         ldx     [%fp+2039],%o0
000155  /* 0x0054            */         sethi   %hi(0xfc00),%o1
000156  /* 0x0058            */         add     %o1,768,%o1
000157  /* 0x005c            */         and     %o0,%o1,%o0
000158  /* 0x0060            */         sllx    %o0,40,%o0
000159  /* 0x0064            */         stx     %o0,[%fp+1967] ! volatile
000160
000161  !   54                !    b[2] = ( ( x & 0xff0000 ) << 24 );
000162
000163
000164  ! predecessor blocks: .L21
000165
000166                          .L22:
000167  /* 0x0068         54 */         ldx     [%fp+2039],%o0
000168  /* 0x006c            */         sethi   %hi(0xff0000),%o1
000169  /* 0x0070            */         and     %o0,%o1,%o0
000170  /* 0x0074            */         sllx    %o0,24,%o0
000171  /* 0x0078            */         stx     %o0,[%fp+1975] ! volatile
000172
000173  !   55                !    b[3] = ( ( x & 0xff000000 ) << 8 );
000174
000175
000176  ! predecessor blocks: .L22
000177
000178                          .L23:
000179  /* 0x007c         55 */         ldx     [%fp+2039],%o0
000180  /* 0x0080            */         sethi   %hi(0xff000000),%o1
000181  /* 0x0084            */         and     %o0,%o1,%o0
000182  /* 0x0088            */         sllx    %o0,8,%o0
000183  /* 0x008c            */         stx     %o0,[%fp+1983] ! volatile
000184
000185  !   56                !    b[4] = ( ( x & 0xff00000000 ) >> 8 );
000186
000187
000188  ! predecessor blocks: .L23
000189
000190                          .L24:
000191  /* 0x0090         56 */         ldx     [%fp+2039],%o0
000192  /* 0x0094            */         sethi   %hi(0x3fc00),%o1
000193  /* 0x0098            */         sllx    %o1,22,%o1
000194  /* 0x009c            */         and     %o0,%o1,%o0
000195  /* 0x00a0            */         srlx    %o0,8,%o0
000196  /* 0x00a4            */         stx     %o0,[%fp+1991] ! volatile
000197
000198  !   57                !    b[5] = ( ( x & 0xff0000000000 ) >> 24 );
000199
000200
000201  ! predecessor blocks: .L24
000202
000203                          .L25:
000204  /* 0x00a8         57 */         ldx     [%fp+2039],%o0
000205  /* 0x00ac            */         sethi   %hi(0x3fc0000),%o1
000206  /* 0x00b0            */         sllx    %o1,22,%o1
000207  /* 0x00b4            */         and     %o0,%o1,%o0
000208  /* 0x00b8            */         srlx    %o0,24,%o0
000209  /* 0x00bc            */         stx     %o0,[%fp+1999] ! volatile
000210
000211  !   58                !    b[6] = ( ( x & 0xff000000000000 ) >> 
40 );
000212
000213
000214  ! predecessor blocks: .L25
000215
000216                          .L26:
000217  /* 0x00c0         58 */         ldx     [%fp+2039],%o0
000218  /* 0x00c4            */         sethi   %hi(0xff000000),%o1
000219  /* 0x00c8            */         sllx    %o1,24,%o1
000220  /* 0x00cc            */         and     %o0,%o1,%o0
000221  /* 0x00d0            */         srlx    %o0,40,%o0
000222  /* 0x00d4            */         stx     %o0,[%fp+2007] ! volatile
000223
000224  !   59                !    b[7] = ( x >> 56 );
000225
000226
000227  ! predecessor blocks: .L26
000228
000229                          .L27:
000230  /* 0x00d8         59 */         ldx     [%fp+2039],%o0
000231  /* 0x00dc            */         srlx    %o0,56,%o0
000232  /* 0x00e0            */         stx     %o0,[%fp+2015] ! volatile
000233
000234  !   61                !    result = b[0] | b[1] | b[2] | b[3] | 
b[4] | b[5] | b[6] | b[7];
000235
000236
000237  ! predecessor blocks: .L27
000238
000239                          .L28:
000240  /* 0x00e4         61 */         ldx     [%fp+1959],%o0
000241  /* 0x00e8            */         ldx     [%fp+1967],%o1
000242  /* 0x00ec            */         or      %o0,%o1,%o0
000243  /* 0x00f0            */         ldx     [%fp+1975],%o1
000244  /* 0x00f4            */         or      %o0,%o1,%o0
000245  /* 0x00f8            */         ldx     [%fp+1983],%o1
000246  /* 0x00fc            */         or      %o0,%o1,%o0
000247  /* 0x0100            */         ldx     [%fp+1991],%o1
000248  /* 0x0104            */         or      %o0,%o1,%o0
000249  /* 0x0108            */         ldx     [%fp+1999],%o1
000250  /* 0x010c            */         or      %o0,%o1,%o0
000251  /* 0x0110            */         ldx     [%fp+2007],%o1
000252  /* 0x0114            */         or      %o0,%o1,%o0
000253  /* 0x0118            */         ldx     [%fp+2015],%o1
000254  /* 0x011c            */         or      %o0,%o1,%o0
000255  /* 0x0120            */         stx     %o0,[%fp+2023]
000256
000257  !   63                !    return result;
000258
000259
000260  ! predecessor blocks: .L28
000261
000262                          .L29:
000263  /* 0x0124         63 */         ldx     [%fp+2023],%o0
000264  /* 0x0128            */         stx     %o0,[%fp+2031]
000265  /* 0x012c            */         ba      .L12
000266  /* 0x0130            */         nop
000267
000268
000269                          .L30:
000270
000271  ! predecessor blocks: .L30
000272
000273                          .L31:
000274
000275  ! predecessor blocks: .L29 .L31
000276
000277                          .L12:
000278  /* 0x0134         63 */         ldx     [%fp+2031],%i0
000279  /* 0x0138            */         ret     ! Result =  %i0
000280  /* 0x013c            */         restore %g0,%g0,%g0
000281  /* 0x0140          0 */         .type   swap_eight,#function
000282  /* 0x0140          0 */         .size   swap_eight,(.-swap_eight)
000283
000284

That is from the ORACLE Studio 12.6 C90 clean compiler on a SPARC-S7 and 
the output from GCC does pretty much the same thing. However it does it
in a weird order. Same result. The really tight optimal stuff looks like
this :

000096  ! predecessor blocks: swap_eight
000097
000098                          .L900000109:
000099  /* 000000          0 */         sethi   %hi(0xff000000),%g5
000100
000101  !   50                !    uint64_t result, b[8] = 
{0,0,0,0,0,0,0,0};
000102  !   52                !    b[0] = ( ( x & 0xff ) << 56 );
000103  !   53                !    b[1] = ( ( x & 0xff00 ) << 40 );
000104  !   54                !    b[2] = ( ( x & 0xff0000 ) << 24 );
000105  !   55                !    b[3] = ( ( x & 0xff000000 ) << 8 );
000106  !   56                !    b[4] = ( ( x & 0xff00000000 ) >> 8 );
000107  !   57                !    b[5] = ( ( x & 0xff0000000000 ) >> 24 );
000108  !   58                !    b[6] = ( ( x & 0xff000000000000 ) >> 
40 );
000109  !   59                !    b[7] = ( x >> 56 );
000110  !   61                !    result = b[0] | b[1] | b[2] | b[3] | 
b[4] | b[5] | b[6] | b[7];
000111  !   63                !    return result;
000112
000113  /* 0x0004         63 */         sethi   %hi(0xfc00),%g4
000114  /* 0x0008            */         and     %o0,%g5,%o5
000115  /* 0x000c            */         sllx    %g5,24,%g5
000116  /* 0x0010            */         sllx    %o5,8,%o1
000117  /* 0x0014            */         sethi   %hi(0xff0000),%o4
000118  /* 0x0018            */         add     %g4,768,%g1
000119  /* 0x001c            */         and     %o0,%o4,%o3
000120  /* 0x0020            */         sllx    %o3,24,%o2
000121  /* 0x0024            */         sllx    %o0,56,%o3
000122  /* 0x0028            */         and     %o0,%g1,%o5
000123  /* 0x002c            */         or      %o1,%o2,%o2
000124  /* 0x0030            */         sllx    %o5,40,%o4
000125  /* 0x0034            */         sethi   %hi(0x3fc0000),%g1
000126  /* 0x0038            */         sllx    %g1,22,%o5
000127  /* 0x003c            */         or      %o3,%o4,%o1
000128  /* 0x0040            */         sethi   %hi(0x3fc00),%o3
000129  /* 0x0044            */         or      %o1,%o2,%g4
000130  /* 0x0048            */         sllx    %o3,22,%o2
000131  /* 0x004c            */         and     %o0,%o5,%o4
000132  /* 0x0050            */         srlx    %o4,24,%o1
000133  /* 0x0054            */         and     %o0,%o2,%g1
000134  /* 0x0058            */         srlx    %g1,8,%o5
000135  /* 0x005c            */         and     %o0,%g5,%o3
000136  /* 0x0060            */         srlx    %o0,56,%o0
000137  /* 0x0064            */         srlx    %o3,40,%o2
000138  /* 0x0068            */         or      %o1,%g4,%o4
000139  /* 0x006c            */         or      %o0,%o2,%g1
000140  /* 0x0070            */         or      %o5,%o4,%g4
000141
000142  !   65                !}
000143
000144  /* 0x0074         65 */         retl    ! Result =  %o0
000145  /* 0x0078         63 */         or      %g4,%g1,%o0
000146  /* 0x007c          0 */         .type   swap_eight,#function
000147  /* 0x007c          0 */         .size   swap_eight,(.-swap_eight)
000148
000149

However truth be told it is just plain convenient to store data in the
little endian format when dealing with a whack of machines. Most of them
are going to be little endian these days in this millenium :)



-- 
--
Dennis Clarke
RISC-V/SPARC/PPC/ARM/CISC
UNIX and Linux spoken

ps: IBM POWER9 big endian hardware looks about the same.