[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Chicken-hackers] New dimensions in ABI design braindamage
From: |
John Cowan |
Subject: |
Re: [Chicken-hackers] New dimensions in ABI design braindamage |
Date: |
Thu, 9 Jul 2015 14:44:08 -0400 |
User-agent: |
Mutt/1.5.20 (2009-06-14) |
address@hidden scripsit:
> In other words, I don't care about any formal definition of C (which
> nobody reads, anyway.) It's only now, where H/W-designers have run
> out of ideas, and every attempt is taken to squeeze out a bit more
> performance through S/W, recklessly taking advantage of holes in the
> language Specs - and for this goal vendors that don't care much about
> everything but their own development-tools and -processes like to
> take shortcuts. This change in iOS ABI is just dumb, a stupid idea,
> a quick hack, done without much thought of everything but Xcode,
> ObjC and a bunch of C libraries that are considered OK on iOS.
Emotionally, I totes agree with you. What's happening to C is awful.
But the fact is that it is the wave of the future. If you want to go
on generating C code that works with increasingly picky and hostile C
compilers, which will throw your code under the bus for the sake of
making someone else's code 0.00001% faster, you *have* to care about
what the C standard calls "undefined behavior", which is equivalent to
"is an error" in RnRS.
See "Proposal for a Friendly Dialect of C" at
<http://blog.regehr.org/archives/1180>, which tells you some of the
things that C programmers expect C implementations to do, *but they
don't*, in the form of proposing an option to force them to do so.
You'll notice the name of a well-known Scheme implementer at the top of
the page. See also the linked pages on undefined behavior, especially
<http://blog.regehr.org/archives/213>, which gives us this example:
int stupid (int a) {
return (a+1) > a;
}
The precondition for avoiding undefined behavior is: (a != INT_MAX).
Here the case analysis done by an optimizing C or C++ compiler is:
Case 1: a != INT_MAX. Behavior of + is defined → Computer is obligated
to return 1
Case 2: a == INT_MAX. Behavior of + is undefined → Compiler has no
particular obligations
Again, Case 2 is degenerate and disappears from the compiler’s
reasoning. Case 1 is all that matters. Thus, a good x86-64 compiler
will emit:
stupid:
movl $1, %eax
ret
If we use the -fwrapv flag to tell GCC that integer overflow has two’s
complement behavior, we get a different case analysis:
Case 1: a != INT_MAX. Behavior is defined → Computer is obligated to return 1
Case 2: a == INT_MAX. Behavior is defined → Compiler is obligated to return 0
Here the cases cannot be collapsed and the compiler is obligated to
actually perform the addition and check its result:
stupid:
leal 1(%rdi), %eax
cmpl %edi, %eax
setg %al
movzbl %al, %eax
ret
Here's the list of things to do to help with a large C code base
(which is what Chicken is after the compiler gets done with it):
Enable and heed compiler warnings, preferably using multiple compilers.
Use static analyzers (like Clang’s, Coverity, etc.) to get even more warnings.
Use compiler-supported dynamic checks; for example, gcc’s -ftrapv flag
generates code to trap signed integer overflows.
Use tools like Valgrind to get additional dynamic checks.
When functions are [sometimes defined, sometimes undefined, depending
on arguments] as categorized above, document their preconditions and
postconditions.
Use assertions to verify that functions’ preconditions and
postconditions actually hold.
--
John Cowan http://www.ccil.org/~cowan address@hidden
Don't be so humble. You're not that great.
--Golda Meir