chicken-hackers
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]