159 comments

[ 2.3 ms ] story [ 224 ms ] thread
You can see the upvote counter constantly being updated ATM :)
Ugh, it's being edited constantly too! Someone just removed the "Hello" from the first line, which was part of what made it great...
For some reason that change was attributed to me when all I did was adding a comma after the »Hello« o.ô

EDIT: Ouch. I think those are SO's automatic attempts at making answers less chatty by removing salutations and thanks and the like. I'll rollback or try fixing it by doing evil Unicode things, then.

Boo. I read it with "Hello" and at that moment, I knew it will be a great read. Why someone remove it?
Stackoverflow is plagued by overzealous editing IMHO. I understand it's hard to balance it, but a question of mine recently got 3 downvotes and a close, to be reopened later! And now it even has 2 upvotes.

A guy answered it immediately, while some other peeps started whining about how it is not a proper question! I only wanted a quick fix, and I got it too, while the others nitpicked.

Hilarious.

I think it's great - it's not about solving your quick fix, it's about providing future value for googlers.
Then where does one go for quick fixes?
IRC, maybe.
I treat SO like a technically superior colleague - if I'm stuck with something and have exhausted my other options (documentation, examples, research, SO search), then I'll phrase my question clearly, showing my progress and what I'm stuck on. This makes me look good to my colleague, and enables him to understand where I'm coming from. A lot of the time by writing out the question in full I'll be able to solve it myself by getting my thoughts organised.
Hello. I'm a programmer.

I noticed you couldn't optimize my code to use SIMD so I went ahead and used inline assembly. It will probably take another 30 years before you can actually think like a human and perform optimizations like this.

Hello, I am your project manager, I thought you were working on the project XYZ, please come into my office.
You obviously don't work in games...
30 years? ICC already does automatic vectorization pretty well. LLVM and GCC have implementations that need more tuning. I bet they'll be solid within 5 years.

You still beat them with inline assembly, but you probably won't accelerate the code vectorwidth times anymore.

Exactly

ICC is the best one, but GCC from 4.0 could do it "automatically" (being very loose about the term)

And no one does inline assembly for that, they use intrinsics

> And no one does inline assembly for that, they use intrinsics

Depends on your architecture. With ARM, compilers will often not set the alignment bits in vector loads and stores, and this can be a big performance hit depending on the microarchitecture. In general, compilers sometimes deal poorly with instructions that have particularly strange register constraints, or loads/stores with address writeback.

Commercial compiler vendors tend to invest more in code generation quality as open source developers.

After all they need to provide reasons why you would buy them.

This paper from 2011 compares autovectorization in GCC against two proprietary compilers, from Intel and IBM: http://polaris.cs.uiuc.edu/~garzaran/doc/pact11.pdf

GCC got a 23% speedup vs 15% for XLC and 28% for ICC. GCC did well considering the proprietary compilers' narrow focus and corporate resources.

BTW, Fortran compilers for the 1980's supers did autovectorization pretty well. Funny that we've made it so hard today.

> 30 years? ICC already does automatic vectorization pretty well. LLVM and GCC have implementations that need more tuning. I bet they'll be solid within 5 years.

Unfortunately, the automatic vectorization compilers do is not very smart and is targeted at simple scalar loops in existing code bases. In many cases, a decent programmer can easily outperform the compiler with simple SIMD tricks, especially in cases where you can use clever vector shuffling tricks (e.g. sum of 4 numbers with 2 additions + 2 vector shuffles).

To get the best of both worlds, use compiler/machine specific intrinsic functions or vector extensions with a smart optimizing compiler. Clang's vector extensions work really well.

How would you sum 4 numbers with 2 adds + 2 shuffles

(sorry, I'm rusty in SIMD)

But remember, similar (old, but simpler) tricks were adopted by compilers, like xor to load 0, lea to do math (not sure about this one), shifts instead of multiply/divide etc

Sum of elements in a 4-vector with SIMD in OpenGL/OpenCL style vector shuffle syntax:

  vec4 s1 = v + v.yxwz; // s1 = (v.x+v.y, v.y+v.x, v.z+v.w, v.w+v.z)
  vec4 sum = s1 + s1.zwxy; // sum = sum of v
More practical examples, related to 3d graphics: https://github.com/rikusalminen/threedee-simd
Gcc does not vectorize to simd ins without more work than just using intrins. Gcc will vectorize to word size though
Actually, most modern compilers can vectorize for you. They are limited by imperative idioms of course, but much of the time they do a good job.
Ignoring for a moment that compilers are getting better at automatic vectorization, using a compiler allows you to write highly optimized inline assembly for the (usually) tiny parts of the code where it really matters, and gives you the convenience of a high level language everywhere else.
(comment deleted)
It takes a really good developer with vast knowledge to do optimizations such as using "inline assembly" for stuff like SIMD. And even though there are enough good developers able to do this, the mother of all problems when developing software is managing complexity.

Yes, you can take a subroutine and apply local optimizations on it. Building complex software in assembly that on the whole is better optimized than what a compiler can do is next to impossible.

Speaking of SIMD and stuff like it, there are already optimizations that LLVM is doing, but such optimizations are hard to apply ahead of time because (1) if you want to distribute those binaries easily, then you need to compile for the common denominator (which is less of an issue with LLVM) and (2) your programming language sucks. It's not the compiler's fault, but rather your own fault that you're using a programming language so confusing that inferring intent from your code is next to impossible. How can the compiler know that you're sorting freaking numbers if you're specifying exactly how bits move around in memory while doing so?

If you're speaking about virtual machines though, there are projects out there for .NET or Scala for instance that can recompile/retarget code at runtime to run with SIMD instructions or on your GPUs if you have any. All you need is a virtual machine that runs bytecode and a programming language (slash compiler) that lets you access at runtime the syntax trees of the routines that you want to optimize and that lets you generate new bytecode. So you can easily shove this kind of optimizations in libraries for special-purpose and descriptive DSLs (e.g. LINQ).

Of course, it gets tricky and doing stuff like this at runtime has overhead, but it's better than what 99.99% of developers can do, not to mention that good developers first and foremost ship.

> It's not the compiler's fault, but rather your own fault that you're using a programming language so confusing that inferring intent from your code is next to impossible.

And that's the long-running argument for why high-level languages have the possibility to be compiled to faster code eventually. We are mostly still waiting for the languages and compilers. (Even though ghc gives us hope.)

Hello I am a processor.

I have picked up your clever optimized SIMD and decided it was better to change the execution order, because another unit was bored without nothing to do.

Unfortunately the L2 cache seems to have some issues getting all required data for your instructions due to the way all your threads are manipulating the required addresses from multiple cores.

I have to admit this is the painful truth. The speed of the vector operations didn't actually improve using SSE3. But that doesn't dismiss the issue with compilers not being able to actually vectorize properly.
> It will probably take another 30 years before you can actually think like a human and perform optimizations like this.

ITYM "It will probably take another 30 years before I use a language that tells you what the required semantics of the code are, meanwhile I'll use my requirements interpretation privileges to relax the semantics in a few places"

Hello, this is the compiler calling back at you. I am very sorry that I cannot write efficient SIMD code but neither can you. If we can work together, we will outperform our individual selves as a team.

So you go ahead and write clever SIMD code but please use the SIMD intrinsics I can understand, not inline assembler which I cannot do anything with. You are very good in expressing algorithms in a SIMD friendly way and do a decent job in instruction selection.

You, however, are not very good in doing instruction scheduling and register allocation, so let me handle that and we can achieve a result that can keep the CPU pipelines busy. When you make the tiniest change to the program, I can re-do instruction scheduling and register allocation in an instant, when that would take you hours to rewrite the whole algorithm to use different registers.

my point: SIMD intrinsics + a smart C compiler produces a lot better code than a programmer writing assembly. Clang + vector extensions in particular is very good at it.

Reminds me that the best current chess player is actually a team mixing humans and computers. Even in that domain where computers are undoubtedly better than humans, the best solution still involve humans.
Who else is going to drive the computer to the event and set it up until Google get their why and we all have self-driving cars?
This has never quite been my experience. Look-mummy-my-first-SIMD-routine is usually within spitting distance of the compiler's best effort, and a lot neater-looking. Then you can just take it from there.

The compiler's output is far from useless, because compilers generally know a few tricks and/or cute sequences that you can copy. And using intrinsics is certainly better than relying on it to automatically vectorize things itself - I've never heard of that do anything remotely interesting. But, even though it's 2013, it still seems like the compiler is easier to beat by hand than you'd think.

I make no claim that this is worth doing in every case.

(As for the suggestion that the compiler can't rearrange inline assembly language, or provide symbolic register names - whyever not? Perhaps people have been conditioned by gcc and VC++ never to expect anything except the absolute bare minimum from inline assembly language support, but that's no reason to assume that these tasks are impossible. Code Warrior for Wii would rearrange assembly language for you to avoid holdups due to instruction latencies, and while automatically assigning registers for you. I believe most modern assemblers will do similar reordering and at least let you assign names to the registers you're using.)

Hello. I'm another programmer.

I noticed that it takes forever to understand inline assembly. I don't foresee myself ever thinking like a computer and reading assembly as well as a high-level language.

It isn't closed or locked? Huh.
Only questions are closed or locked, I think. And only if they are not very good questions that will just lead to debate or opinions but should stay around out of historical interest. This here is a question that can be answered reasonably but has a single whimsical answer. So no need of closing or locking here.

And even though the tone of that answer is humourous it still is a good answer, explaining why we don't all write Assembly instead of HLLs.

Yeah, I thought it was a great read as well. That answer pops to my mind every now and again.
Aaaand it's closed. I hate that SO can close a question as "non constructive" while I find it constructive instead.
Not closed or locked. In SO, only the questions can closed, answers and questions can locked. But this question is open for everybody, for now..
It was just closed as not constructive.
Fascinating, while I was reading that, it got 5 upvotes! Mindblowing.

This is a really awesome description too. The only thing I know about compilers is that I implemented one for class (without fancy optimisations) and I am surprised any software works, ever. Compiler are just ... mindbogglingly complex things. Almost as much voodoo dark magic as engineering.

One of the reason software still works is that compilers are (mostly ()) very easy to test. Just just need an input source code, and expected outcome (either compiler error, or the result when running the code). No intermediate state to consider, no concurrency, no test database to set up etc.

Oh, and many serious compilers can compile themselves, so bootstrapping is a pretty good test too.

Another reason is that compilers simply must* work for software development to continue, so people have spend the necessary amount of energy to get implementation and tests "right".

(*) There are always exceptions, like when a compiler auto-parallelizes code and introduces a race condition that is rarely triggered. But those cases are blessedly rare.

Testing was the hardest thing I came across.

You have on your hands a compiler that you can no longer think of a program for, that would produce an incorrect result. You're happy.

Then your friend comes along and the first thing they try behaves incorrectly.

The problem isn't even that the compiler would crash and burn, it lovingly compiles the input program into something that does the wrong thing!

What did you write your compiler in? Writing compilers in, say, raw C is indeed a complex endeavour. But using, say, OCaml or Haskell (which is secretly a DSL for compiler writing) should make it much easier to not fail silently.
We used Java and a bunch of professor supplied code to speed us along. The input language was a subset of Pascal.
The poor compilers do the best with what they have. And by "what they have", I mean the things they can't make assumptions about. Which turns out to be a crapload. Until that happens, very highly-tuned assembly will continue to outperform the best compilers.

Of course, a more typical scenario is hand-tuning a few loops where 99% of the clock cycles occur and letting the compiler take care of the rest.

(Also, I was attempting to send a Morse code message by flashing the vote counter between up and down, but I don't think anyone got it :( )

I saw the flashing vote counter, and was just thinking that SO was getting funky.
I will meet you at said coordinates and bring the pineapple you've requested.
I used to work on a compiler for an embedded system. One fun trick we used while writing the run-time libraries was to write them in C, then optimise the generated assembly (possibly by rewriting it from scratch), then fix the compiler so it generated that assembly :). Sometimes that did require using (and occasionally adding) new intrinsics.
How stable where those fixes? I.e. if you made slight changes to the C code, did the optimizations still kick in?
I worked in the same company (Hey Andrew!). It would definitely depend on the specific instructions/optimisations involved but I believe they were generally pretty robust to changes. Some would require the user to supply pragmas (i.e. to specify data alignment, etc) but obviously the compiler intrinsics would always generate the expected instructions.
There are some magic keywords, like const, which definitely help the compiler. Unfortunately these kinds of optimisations are far too numerous, and soon become tedious. After a certain point, more structured languages could allow much more rigid optimisation. These days JIT seems to have taken over though, which isn't really a bad thing.
Const doesn't actually help compilers (at least in C/C++ based languages). Since it can be const_cast away and still work in a standards compliant way, any optimisation assuming const values never change is a bug. Instead the compiler will use other techniques, e.g. finding variables that are only written to on initialisation, and those don't even need to be marked const.
If an object is defined as const, casting away its constness and modifying the object causes the program's behavior to be undefined. Compilers are free to take advantage of that.
Do you have a spec reference for that? I was under the impression you could safely const_cast and modify pretty much anything. Perhaps it was just primitives like ints, or const member functions.
That is true, but it's extremely rare to be able to take advantage of that. When people think of const as a potential optimization aid, it's almost always in the context of const pointers, which actually do nothing at all for optimization.
I've seen gcc turn a const bool& into a direct pass of a bool by value. Of course, I noticed this because it was the implementation of a web service binding, and the wrapper was going to pass me a bool& (as a pointer) whether I liked it or not. Instant segfault...but not always :(
Oh God. Don't get me started on const.

    const char * const fuck_this(const char *shit) const;
Thing #1: In C++ the word "const" can mean many things depending on position and inflection: declaring a symbol an actual constant; a pointer argument has in (as opposed to in-out) semantics; a function has no side effects. I keep forgetting which use of const does what.

Thing #2: Each use of const, regardless of meaning, induces a different type. Which makes API design a pain in the ass since you can't pass in stuff that wasn't declared with the same constness if the procedure expects const parameters without casting the parameters. I actually worked on a codebase where a guy broke much of our code by checking in a "fix" for our APIs to make them comply with what he considered best practice regarding constness.

Thing #3: Passed-in pointers and references are not 'const' by default. You should have to declare intent to clobber their referents.

Thing #4: And as someone said downthread, you can cast around it in most cases anyways.

This is why I say, if you're thinking of using C++, reach for Ada instead. Ada's reputation has been necessarily tainted by whiners complaining about its verbosity. But I swear that figuring out a page of Ada code is easier than figuring out a few lines of sufficiently complicated C++. For one thing, in Ada, function/procedure parameters are 'in' (i.e., const) by default, and you must declare intent to modify parameters in side effects by declaring them 'in out'.

Most of all, the compiler can't change the layout of your data. Many of the use cases for hand-crafted assembly involve SIMD instructions, which perform several operations in parallel. These vector instructions can be incredibly fast, but their limitations often mean that you need to carefully design the data structures of the whole program around the optimization of one single critical loop.
I've written lots of code that either GCC has autovectorized into SIMD instructions, or that I've represented using GCC's vector types which produce SIMD instructions. While it is true that a poor choice of data structure will preclude SIMD optimizations, use of a compiler does not preclude the same.
At the same time I have seen autovectorization to fail on things that would look like obvious candidates or to generate still sub-optimal code. I would prefer autovectorization over hand-written SIMD code everyday but that key here is reliability. If I cannot guarantee that the performance is going to stay the same across different compiler releases (which is often that case with autovectorization) it is much more convenient to just write the optimization myself and be sure that it is going to happen regardless of the environment.
> the compiler can't change the layout of your data

Sure it can, this is the most promising optimization avenue currently. Not just on the micro level to make data layout more SIMD-friendly, but more cache friendly object layout etc.

Modern systems are primarily memory bound, not ALU bound, so squeezing out clock cycles from computations is pretty far in the dimishing returns territory.

C/C++ have forbidden these kinds of optimizations but it's a the future (tm) in high level languages.

As someone who is working on a project where the CTO demands more LOC, this makes me warm inside.
Yes, from that comment I think I can infer what CTO means in this context

You can easily go creative on this

That should be hard to believe, save for my honed cynicism. Could you please elaborate?
I'm working on a project where the CTO of this huge company is criticizing the lack of code I'm writing. Doesn't matter the fact that my code meets every criteria. No functionality is being left out. But, he wants more code. It has been very difficult for me to deal with this, because its the first time I have ever faced such idiocy.
Am I the only one just enjoying watching the upvotes rocketing up on SO?
(comment deleted)
I upvoted when the counter was 520. Now it is 1500! (or more, by the time you read this :)

EDIT: Looks like it's locked at 1788!

This is the first time I see the vote count grow by 10 in real time. Impressive stuff.
Are they pushing those realtime vote counts with websockets? Pretty slick. Beats polling by far.

Looks like IE is holding it back as usual:

https://developer.mozilla.org/en-US/docs/WebSockets#Browser_...

Unless my eyes are strange that page says it's supported on IE.
This chart is easier to read:

http://caniuse.com/#feat=websockets

Only IE10 and above. And IE Mobile would be dubious.

Even older safari 5.1 has partial support but not IE.

Surprised to see android mobile does not have support - is that chart correct?

IE10 came out around the same time as Firefox 16 didn't it?
Yes that’s websockets it seems. Must be quite a overhead, they use it on all answers.
But it's awfully cool when you see it going up or down :)
Yes, it's websockets. You can check it in Chrome by keeping the console open and refreshing the page. Would be interesting to test in IE.

BTW, as much as I am amazed to see websockets in action, the real time updating of vote count feels creepy and distracting at the same time :-)

Yeah, I guess we're going to see a lot more bad UX abuse of this in the near future. It's very distracting.
It makes me feel more connected though.

As long as it's not abused I think it's a clever use.

Have to research how to setup websocket server.

This looks like an impressive project http://socket.io/

We currently have ~ 128k open sessions for sockets (They all go through HAProxy).

They socket server process runs on 9 web servers, and each service is using less than 1% CPU at the moment.

So very efficient from a sysadmin perspective (We did some tuning with conntrack so only the outside is tracked on the load balancers).

Devs could give a lot more detail.

Cute. Although I think my compiler has different things to say.

Hello, I'm a C compiler that still can't handle C99. I hope you're wearing waterproof clothing because I'm gonna throw up on you. Also, I've been drinking heavily so your C++ code is going to take a while to compile and when it's done, it's gonna smell funny.

Visual C++ ? :)
C++ compiler != C compiler
Visual C++ is a C compiler - it compiles C90. The issue is that they still haven't added support for C99. You can compile your C code as C++, but then you're restricted to the common subset of C and C++.
No it is not. It is two compilers bundled together and called by the same driver application.

Microsoft will not update the C compiler and will focus only on the C++ one.

As explained by their main architect:

http://herbsutter.com/2012/05/03/reader-qa-what-about-vc-and...

Bundling C and C++ compilers together was a way for C++ vendors to ease the migration into C++ land, specially in the early days. There is no law that C++ compiler vendors are required to offer a C compiler as well.

Given that on Build 2012 it was mentioned that the Windows team is making their code compilable under C++ and the actual position on C++ vs C at Microsoft, the C compiler might even be dropped from Visual Studio.

I think you're in violent agreement with the GP.
Regardless of all that, there still remains a C90 compiler in Visual Studio 2012.
(comment deleted)
:D iyi deneme.
(comment deleted)
what about me a.q.!? what is my deficient! nick:dictummeumpactum
Isn't Steve Gibson ( http://www.grc.com/stevegibson.htm ) still coding large, complex programs in pure assembly?

His work on spinrite is legendary, for those born before IDE hard drives were invented.

From his podcasts I hear that it is pure assembly. He's borderline machine, though.
It is funny how people want to believe in tools. In fact, the optimizations compiler does are incomparable with those programmer could do by choosing an appropriate data-structure with corresponding algorithms and by being aware of strengths and weakness of a particular CPU architecture.

JVM, which is nothing but a stack-based byte-code interpreter is the most famous case.) People seems to believe it can do wonders, especially in memory management and data throughput.

It is so strange to see how people are trying to create a whole world inside a JVM. What it is called when people are building models of ships inside a bottle?)

btw, now, it seems, they are trying to build a whole world inside a V8 bottle.)

My experience in the industry is just the opposite; people will do anything to avoid admitting that the tools can do better than they than. I've had senior programmers sneeringly declare that anyone who uses a debugger must be an inferior programmer, and then watched them spend a full day figuring out a bug that could be found in half an hour with the appropriate tool.

You know why it's worth recreating the world inside a JVM? Because its behaviour is so much more thoroughly specified and predictable. Prior to Java, C++ didn't even have a memory model; every new release of GCC breaks a whole raft of C programs that didn't realise they were invoking undefined behaviour by having integer overflow. By the C standard, even a single instance of undefined behaviour invalidates your whole program, making it virtually impossible to predict the behaviour of any nontrivial-sized codebase.

In my opinion it is a computer architecture that has a memory model, not Java or C++.

For some strange reasons nginx - a mere C program - works for millions. So does postgresql or redis or whatever.

I half agree. C++ directly exposes the underlying computer architecture's memory model. Java abstracts it reasonably well and essentially results in a different model with different advantages and disadvantages (e.g. garbage collection and garbage collection :))
In my opinion it is a computer architecture that has a memory model, not Java or C++.

Unfortunately that opinion is by definition incompatible with portable computer languages.

What is wrong with Schemes or Lisps?)

Well, even Python (cpython) is more portable than Java. All it needs is working C compiler. It is ported to Plan9 and Android.)

Python has a memory model. It's just too bad that so much of the python ecosystem relies on bindings to C libraries, so you go to resize an image and then you get a segfault that brings down your whole program (real example).
Schemes and Lisps have memory model, it's just one that's radically different enough from processor memory models that no-one realizes it's a memory model and thus no-one gripes about it being different from processor X's memory model.

If you're wondering what the memory model is, you should ask yourself: What happens when I mutate a cell? are those changes visible in references to that cell? are those changes visible across thread boundaries? What happens when I dereference a cell? Does it continue to take up memory or is it garbage-collected? What if it's part of a cycle?

But I digress; your point was actually about languages that don't talk about memory, such as the lambda calculus. A degenerate memory model is still a memory model, and an inherently portable one at that. My point is, for languages which do talk about memory, it's necessary that they specify how that memory works in order to be a portable language.

It's even better when you read what the question was.
Compiler got AI human language capabilities?
Now I can't wait to get a message from the kernel :D
Anytime I read about the topic of assembly language, I can't help but think of Michael Abrash. For example, check out Chapter 22 [1] from his Graphics Programming Black Book entitled Zenning and the Flexible Mind for a pleasant stroll down Optimization Lane.

You might also enjoy his book entitled The Zen of Assembly Language which features the Zen Timer (a timing tool for performance measuring).

[1] http://downloads.gamedev.net/pdf/gpbb/gpbb22.pdf

Hello, I am a programmer.

I have little idea what modern day compilers are doing, or what the CPU, or the operating system is doing for that matter. Often, way too often, compilers fail, hardware fails, operating systems fail, lots of things fail. I am not going to read the millions of lines of code written by other programmers (in f-ing emacs no less) in the any number of differing complex beasts, the compilers. It seems crazy-making to me, that other programmers would create compilers that would use millions of possibilities of optimizing a single line of mine using hundreds of different optimization techniques based on a vast amount of academic research that I won't be spending years getting at. I do feel embarrassed, yes very icky, that I have little to no idea what a three-line loop will be compiled as, but bloat would be my guess. There is risk in going to great lengths of optimization or doing the dirtiest tricks. And if I don't want the compiler to do this, I have no idea how to stop this behavior, nor do I want to invest in the specific knowledge of the nuances any particular compiler. The compiler does not allow me easy access because the compiler itself is an overly complex piece of software written by other programmers. I could care less about how a compiler would make my code would look in assembly, on different processor architectures and different operating systems and in different assembly conventions. Transformation comes with how we as programmers write code, not in compiler-fu.

P.S. Oh, and by the way if I really wasn't using half of the code I wrote, I would throw the source code away.

You seem to be saying that you're at the same time completely clueless about how programs get built and executed and yet you know better that the compiler what needs to be done.

I've found that in the general case Compilers Know Better. It might not be true for very simple and limiter architecture such as small microcontrolers, but modern CPUs are so much complex and "quirky" that most of the time the compiler will beat you.

These days I only use assembly for very low level stuff where I need complete control of the execution flow (dealing with cache invalidation, MMU etc...) or some very specific and aggressive optimisation (like implementing <string.h> in ASM).

But hey, if you want to ditch C and write everything in ASM, be my guest (as long as we don't work together).

The reverse is actually true. On simple orthogonal architectures the compiler is much more able to take advantage of all the features, while on x86 there are many instructions a compiler will never generate because of limitations on when they can be used. A human can occasionally do better then the necessarily limited algorithm used for scheduling and instruction selection.
My rationale was that it takes a much bigger knowledge base to optimize code for more complex architectures because of all the factors you have to take into account.

On simple architectures it's often very straightforward and you can sometimes save CPU cycles/memory space by doing some refactoring the compiler can't/is not allowed to do.

You can for instance "stash" certain important values in CPU registers across functions, disregarding the ABI to avoid pushing/popping the stack or moving stuff around in registers. Well, that's not a very good example because you can tell GCC to do exactly that, but it's not a standard C feature and the compiler cannot do that on its own across translation units. So it's one of those situations where you can "outsmart" the compiler, even if the compiler would probably tell you it's not fair game :)

It's not orthogonal vs. crazy x86-y instruction sets, it's in-order vs. superscalar processing. The compiler knows the intimate details about each architecture's pipeline latency to a degree that most programmers don't.
> I have little to no idea what a three-line loop will be compiled as, but bloat would be my guess.

This is unfortunately too often true. Some compilers are tuned too much for looking good on artificial benchmarks, in which turning 3-line loops into thousands of instructions sometimes helps, even if it hurts on most real-world code.

> And if I don't want the compiler to do this, I have no idea how to stop this behavior, nor do I want to invest in the specific knowledge of the nuances any particular compiler.

The -O0 option, or its equivalent, is pretty easy to find in many compilers. If you're happy with the performance of your code without all those fancy techniques being applied, feel free to use it. Most people aren't ;-).

> P.S. Oh, and by the way if I really wasn't using half of the code I wrote, I would throw the source code away.

Only if you were aware of it ;-). I wish that compilers would focus a little more on helping me make my code better, rather than so much on magically making things better under the covers.

If you want your compiler to do more to help you improve your source, you might like Go, which offers a lot of (sometimes unwelcome) mandatory suggestions that force you to do the right thing even when you don't want to. (Ada and Pascal do the same thing according to a very different philosophy.)
I have come to love the strong typing of VHDL (very similar to Ada but for hardware design). After using it for a while, in my uninformed opinion, I think it can drastically reduce bugs because it assumes nothing and makes the programmer define exactly what they mean.
Even better for him, -O0 is the default (for most compiler's I've worked with). You need to opt-in to optimizations most of the time.
I never noticed that the Stackoverflow js pulls updates for vote tallies in real-time. Browsing this answer while HN is sending lots of traffic there is almost like watching a car odometer.
Really? HN is now including witty posts in Stackoverflow as news?
I have never seen so many stupid, misinformed comments by people who have never touched assembly in my life. But this is the internet.
Ah, the irony of Knuth being the proponent of Literate Programming, and at the same time the last man standing in general purpose assembly.
And on the Fourth Day, God proclaimed "Thou shalt have the ability to use inline assembly in thy C/C++ code for performance-critical tasks".

I can think of absolutely zero reason to write an entire program in x86 assembly, let alone any other kind of assembly (GCC spits out some pretty optimized code for my little Atmel MCU)... It's a lot nicer to write everything in a high-level, and then write any performance specifics in inline assembly.

The really cool thing to see is how other newer languages have adopted this scheme (e.g. PyASM for Python, or the ability to edit the instructions for interpreted languages that run in their own VM). And as always, great power comes with great responsibility ;)

"I can think of absolutely zero reason to write an entire program in x86 assembly,"

I can think of 2 reasons: study and fun.

For x86 I'd say study but I don't think there's any fun to be had there. Something like MIPS32 would be pretty fun because that instruction set actually makes sense to a human.
I'm in a class using MIPS, and I don't find it fun.
Oh, come on, the ModR/M byte, opcode extensions, variable length instructions, opcode prefixes, what's not to love </sarcasm>
Funny. x86 was designed to be understandable to humans. MIPS32 was designed to be more suitable for compilers.
8086, maybe, but I don't think we can say that modern x86 was "designed" for any one thing at all. Modern x86 is an excellent example of what you get when you evolve something for decades with backwards compatibility as a paramount requirement and little other consistent guidance, for all the good and bad that implies.
The LOADALL instruction is certainly fun to get working though!
writing 4096 byte demos and similar, back in the day, I can assure you I had fun coding x86 asm :)

maybe if the Asphyxia tutorials hadn't been written for Turbo Pascal (+inline asm) and the C-compilers (back in '97) were really that good at optimizing as comments here suggest, I'd have gone a different route. but still, that's just performance. I doubt a compiler can beat a human at size optimization, cramming as much audio-visual power into as little bytes as possible--although executable-packers have come a loooong loong way since then (and impressively, afaik mostly by research and not so much Moore's law).

Now a days, compiler writers sees zero reason to write inline assembly.

First of all, it throws a wrench in high level optimizer's analysis. Plus, compilers and processors are getting smarter day by day while inline assembly in shipping code becomes more and more untouchable everyday.

You have never written embedded code, or code to deal with low level hardware in drivers?

I haven't either, but I imagine ASM would be required here.

I've written code for GameBoy Advance which has no OS, just magic memory addresses, and didn't need any assembly. Even hblank interrupts could be implemented in C.
A typical reason to use assembly these days is for instructions the compiler doesn't output (for instance specialized instructions which are only useful for a kernel).

GCC's extended assembly at least (which clang/LLVM also support), allows one to specify constraints for asm() statements that let the compiler respect dependencies etc.

Hello. I'm an assembly programmer. I used a compiler to generate the majority of code, and can hand-craft any assembly that comes out of it. I understand how compilers auto-generate SIMD instructions can be more easily compiler-generated if I make a "struct of arrays" instead of "an array of structs".

TLDR: Real performance programmers need to understand the assembly a compiler generates if they hope to tune the compiler to generate optimal assembly. Also, GCC -O3 is prone to removing too much code and reordering it, causing memory barrier issues and the like. All multi-threaded programmers need to understand how the compiler generates assembly (ie: by reordering your code), and how it can generate new bugs if you don't use the right compiler flags.

Also, GCC -O3 is prone to removing too much code and reordering it, causing memory barrier issues and the like.

Whoah, that's what __sync_synchronize() and volatile are for. If you're trying to write order-dependent multithreaded code without those, the bug's in your code, not in compiler flag juju.