On Sun, Nov 29, 2015 at 9:59 AM, 'Davide Libenzi' via Akaros <
[email protected]> wrote:

> On Sun, Nov 29, 2015 at 5:28 AM, barret rhoden <[email protected]>
> wrote:
>
>> They do come from the original plan 9 code, but we can still change
>> them to be more descriptive (and inlines).
>>
>> One thing though is that we do want to keep the Plan 9 implementations
>> of those functions that do not use ifdefs:
>> http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
>> (at least I think we do).
>>
>
> I dispute almost every single point he makes there, but I kept my inlines
> the slow, fully open coded version ☺
> First, is more code? Yes, but, in many CPUs (like, Intel, which is what
> matter most) is much faster.
>

But very often these functions are on the boundary of a program; a place
where performance doesn't matter that much.

And I'm not sure that Intel matters all that much. There are probably more
ARM machines out there than Intel machines at this point. And who knows how
many other weirdo processors are running embedded things? AVR and PIC are
super common; I imagine that eZ80 and HC11s and all sorts of random junk
still has a huge footprint out there.

Second, you can have a swap32() and swap64() APIs, which in Intel turns
> into dedicated, single insn operation (would not matter for LE, the most
> common case).
>

Little-endian being the most common case has only been true for a
comparatively short time. That assertion reminds me of Henry Spencer's "10
Commandments of C Programmers" in which the tenth of Henry's commandments
was to avoid falling into the mistaken belief that, "all the world's a VAX"
(https://www.lysator.liu.se/c/ten-commandments.html). The point is that
what's most common today may not be tomorrow....

Regardless, a dedicated interface for these functions is really good. Even
in Plan 9, such a thing existed (though the implementation probably used
shifts and or's; Barret alludes to that with the conv* functions). Under
Plan 9 today, there are functions for getting big- and little- endian data
from somewhere.

I think the overarching point of Rob's post was that if a programmer feels
like s/he needs to write something to deal with endianness of the machine
one is on, one's almost certainly going to be wrong. You program to some
defined interface and don't worry about it beyond that. Binary data is
fine, provided it's well-defined with respect to byte order etc, and
presented in some packed representation so that I don't have to care about
things like alignment of elements within the data stream. But the point is
that one divorces the specifics of the processor one is working on from

Third, alignment? Define an HAVE_FAST_UNALIGNED_ACCESS in the arch/ domain,
> and use that to select the proper behavior (#if LE && FAST_UNALIGNED -> Use
> single insn load/store).
>

But now one is resorting to tricks with conditional compilation (which is
kind of Rob's point), which gives rise to a combinatorial explosion of
options that I can't compile and test everywhere. That sort of thing
usually leads to ugly assumptions being baked in over time, but the naive
code won't work on every *machine*. For example, 68000 would trap on
unaligned accesses to multi-byte data types.

        MOVE.L #$10001,D0        | Oh no you didn't!

One could argue that 68k doesn't matter anymore (and one would mostly be
right). But what about Power, MIPS, ARM, or some new hypothetical processor
that hasn't been invented yet?

Having every application have an #ifdef that does the right thing is a step
backward; conditional compilation is really nasty stuff because it's hard
to test without a number of separate compilations that quickly becomes
exponential in the number of boolean terms in the conditional.... Instead,
a far better option is to program to a library that makes it not matter,
and implement that library in the most performant way for whatever platform
one is running on. #ifdef is a technique to put all that code in a single
file, but it is only one of many (and not a very good one, frankly:
conditional compilation leads to fragile code that's frankly hard to read).
So instead of LE && FAST_UNALIGNED one has
/sys/src/libc/x86_64/accessdata.s that has things like,

; X
.globl gets32le
 gets32le:
        movl (%rdi),%eax
        ret

Then I just link against the library that's right for my platform. No
#ifdef's in site.

Fourth, *(int)ptr? Really? ☺ Those should be using u16, u32, u64, and not
> short, int, long, etc...
>

Indeed. But there's a lot of code out there that's written in terms of
'int'. Rob's no dummy; he's writing from really long experience using lots
of production systems. He's seen that code out in the wild; so have I. :-(

For encoding/decoding a few tenths on bytes coming into a file API, maybe
> you can get along with the fully open coded version.
>

A tenth of a byte, eh? That's less than a bit unless you're on a PDP-10.
:-P  (Just kidding! Just kidding!)

But say, if you are decoding packed docdata, or a posting list payloads,
> the three lines of code more per function will make a difference.
>

...or decoding IP or TCP headers.

I don't think his point was to always write things using (foo[0] << 24 |
...); I think rather his point was that application programmers who are
worrying about those issues are thinking at the wrong level of abstraction.
Hide it behind a function call or similar, but don't think about "I need an
#ifdef because I'm dealing with binary data...."

To sum up, program to the *data*, not the CPU that's manipulating the data.

        - Dan C.

-- 
You received this message because you are subscribed to the Google Groups 
"Akaros" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to