Live data from Hacker News

Does a compiler use all x86 instructions? (2010)

pepijndevos.nl

171–180 of 198 posts

Re: Does a compiler use all x86 instructions? (2010)

#171
post #170
post #2

It doesn't, because there are lots of special-purpose x86 instructions that would be more trouble than they're worth to teach a compiler about. For example, instructions for accessing particular CPU features that the C and C++ languages have no concept of (cryptographic acceleration and instructions used for OS kernel code spring to mind). Some of these the compiler might know about via intrinsic functions, but won't…

is there any point in multiplying by 1 ?

It might be used to avoid a conditional.

Re: Does a compiler use all x86 instructions? (2010)

#172

Earlier quoted context omitted.

> What you're describing is a GPU I would say I'm describing something halfway between a CPU and a GPU. It's not just an ALU, it's a complete microprocessor, with pipelining, caches, etc. The main difference is that the instruction set is optimized, backward compatibility is no longer a requirement, and redundancy of the architecture is eliminated.

What you are looking for is called the Mill: https://millcomputing.com/

I don't think that is quite what he's looking for, the Mill is not exactly RISC.

Though it is an awesome architecture and I recommend anyone to check it out.

Re: Does a compiler use all x86 instructions? (2010)

#173

Earlier quoted context omitted.

IIRC, when a new version of OSX stops working on older hardware, it's usually because Apple started using a "new" version of SSE that's not supported on a given CPU. For handcoded assembly, it's not uncommon for code to check a CPU's capabilities at runtime (e.g. OpenSSL checks at runtime if it can use the really fast AES-NI instructions,. If not, it fall backs to other assembly or C implementations). That way you do…

The Intel compiler (used to?) do runtime CPUID checks. If your CPU came back "GenuineIntel" (and only Intel), it took the fast SSE path. Theres more here: http://www.agner.org/optimize/blog/read.php?i=49#49

Wow... And I thought Microsoft used questionable business practices...

Re: Does a compiler use all x86 instructions? (2010)

#174
post #38

There are instructions that would almost never be useful. See Linus's rant on cmov http://yarchive.net/comp/linux/cmov.html The tl;dr is that it would only be useful if you are trying to optimize the size of a binary.

It is _very_ useful when hand optimizing loops in assembly. But for the compiler, the newer processors have such incredible branch predictors it is usually a bad idea for the compiler assume a branch is poorly predicted. Now if you are using profile guided optimizations (--prof-gen/prof-use) AND you use the processor's performance counters as part of the feedback to the compiler _then_ I could see the compiler correc…

I have a mixed feeling about that incredible progress in modern CPUs branch prediction. Don't they just use idle execution units and run both branches in parallel behind the scenes? It looks great on microbenchmarks when there's a bunch of idle execution units to use, a memory bus and caches are underused. It may not perform so well on real load when there's no idle execution units available to use for free, and memory bus and cache lines are choking on load.

Is it somewhat similar to these two examples?

> If it owns that line then CAS is extremely fast - core doesn't need to notify other cores to do that operation. If core doesn't own it, the situation is very different - core has to send request to fetch cache line in exclusive mode and such request requires communication with all other cores. Such negotiation is not fast, but on Ivy Bridge it is much faster than on Nehalem. And because it is faster on Ivy Bride, core has less time to perform a set of fast local CAS operations while it owns cacheline, therefore total throughput is less. I suppose, a very good lesson learned here - microbenchmarking can be very tricky and not easy to do properly. Also results can be easily interpreted in a wrong way

http://stas-blogspot.blogspot.com/2013/02/evil-of-microbench...

> On current processors, POPCNT runs on a single execution port and counts the bits in 4B per cycle. The AVX2 implementation requires more instructions, but spreads the work out across more ports. My fastest unrolled version takes 2.5 cycles per 32B vector, or .078 cycles/byte (2.5/32). This is 1.6x faster (4 cycles per 32B /2.5 cycles per 32B) than scalar popcnt(). Whether this is worth doing depends on the rest of the workload. If the rest of the work is being done on scalar 64-bit registers, those other scalar operations can often fit between the popcnts() "for free", and the cost of moving data back and forth between vector and scalar registers usually overwhelms the advantage.

https://news.ycombinator.com/item?id=11279047

Re: Does a compiler use all x86 instructions? (2010)

#175
post #82

Earlier quoted context omitted.

According to [1], on recent Intel CPUs, each instruction is translated by hardware decoder to up to four micro-ops: either trivial micro-ops like addition, subtraction, bitwise and/or/xor, or a special "microcode assist" micro-op which is essentially a function call into the CPU microcode table. According to the same source, CPU microcode table is believed to consist roughly of 20,000 micro-ops which handle edge case…

The new slides for AMD Zen say explicitly that it has hardware sha256 support.

Careful. Do they mean an ISA extension to support fast SHA-256 implementations in your code, or do they have a SHA-256 implementation in their microcode for CPU-internal use?

Re: Does a compiler use all x86 instructions? (2010)

#176
post #70
post #42

My question is if compilers use "new" x86 instructions, as then the program won't work at all on old systems. For example, if Intel decided today that CPUs need a new "fast" hashing opcode (I don't know if they actually do), a compiler can't compiles to it, as programs won't work on older computers. Is it like the API cruft in Android, where "new" Lollipop APIs are introduced for 10 years from now, when no one uses a…

In addition to what others have said, sometimes stuff gets added in a backwards compatible way. For example, Intel added two new instruction prefixes for their hardware lock elision extension. Actually, they reused existing instruction prefixes which were valid but did nothing on older CPUs when used on the instructions where the HLE prefixes apply. The semantics are such that "do nothing" is valid, but CPUs which un…

Certainly the Borland 8087 emulation code used to have an interrupt call followed by the 8087 opcodes, the interrupt call got replaced at run time by NOPs if there was a co-processor present.

Re: Does a compiler use all x86 instructions? (2010)

#177
post #172

Earlier quoted context omitted.

What you are looking for is called the Mill: https://millcomputing.com/

I don't think that is quite what he's looking for, the Mill is not exactly RISC. Though it is an awesome architecture and I recommend anyone to check it out.

I mean, it's a cleanroom design unconstrained by backwards compatibility, and aspects of its design can be described as elegantly simple. You're right that it doesn't try to be RISC though.

Re: Does a compiler use all x86 instructions? (2010)

#178
post #130
post #19

Earlier quoted context omitted.

LEA (load effective address) can perform computations of the form BASE + SCALE * INDEX + OFFSET, where scale can be 1, 2, 4 or 8. This allows optimisation of multiplications and additions into a single instruction, and the compiler takes advantage of that. So if you write: a = 4 * b + c + 10; It will be optimised to a single instruction like: lea 0xa(%rsi,%rdi,4),%rax Rather than the more naive: imul $0x4,%rdi,%rax a…

Right, that's what I mean by pointer arithmetic -- specialized instruction for calculating memory addresses. It seems it can be co-opted to do math and other calculations as well. But at least that was its intended use? Also Zen of Assembly mentions that LEA can store its result in any register and doesn't alter flags.

Yes, I think it was designed in particular for determining addresses of fields within structures and variables on the stack, for example if you had:

    struct foo
    {
       int field1;
       int field2[10];
    }
Then an access like:

    fooptr->field2[index]
Would compile to:

    fooptr + sizeof(int) * index + offsetof(struct foo, field2)
Which is:

    lea $4(fooptr,index,4)

Re: Does a compiler use all x86 instructions? (2010)

#179
post #125

Earlier quoted context omitted.

The AS/400 is more like an AOT than a JIT compiler. When I hear JIT I think opportunistically compiling portions of a program, but falling back to an interpreter. The way AS/400 works, IIUC, is that the compiler compiles to an intermediate byte code, which has remained stable for decades. When the program is first loaded, the entire program is compiled to the native architecture, cached, and then executed like any ot…

I would disagree with almost everything you said here. JIT compilers can beat equivalent AOT compilers by about 20%, or at least, that's the kind of loss you get in HotSpot from not doing profile guided compilation and doing it all AOT instead. So that point seems wrong. If you're comparing Java and C++ well, that is affected by many things and you can quite easily construct microbenchmarks where Java beats C++. In r…

> I would disagree with almost everything you said here.

reality seems to agree with the parent. Case in point there are no production level JIT compilers for C/C++.

The fact that a java AOT compiler is not competitive with HotSpot might have more to do to the maturity of HotSpot and the amenability of Java to AOT compilation.

> JIT compilers tend to be better at unguided vectorisation than AOT compilers because they know what CPU features are available to them at compile time.

runtime dispatching to specialized functions makes this a moot point point. I'm not aware of the state of the art, but last I heard HotSpot wasn't particularly great at vectorization.

Re: Does a compiler use all x86 instructions? (2010)

#180
post #174
post #38

Earlier quoted context omitted.

It is _very_ useful when hand optimizing loops in assembly. But for the compiler, the newer processors have such incredible branch predictors it is usually a bad idea for the compiler assume a branch is poorly predicted. Now if you are using profile guided optimizations (--prof-gen/prof-use) AND you use the processor's performance counters as part of the feedback to the compiler _then_ I could see the compiler correc…

I have a mixed feeling about that incredible progress in modern CPUs branch prediction. Don't they just use idle execution units and run both branches in parallel behind the scenes? It looks great on microbenchmarks when there's a bunch of idle execution units to use, a memory bus and caches are underused. It may not perform so well on real load when there's no idle execution units available to use for free, and memo…

> I have a mixed feeling about that incredible progress in modern CPUs branch prediction. Don't they just use idle execution units and run both branches in parallel behind the scenes?

No, I do not know of any production CPU that does it; Branch predictor accuracy today is ~98-99% so it would be a waste of power and execution capability to speculate both paths of a branch.

Also, I think code in average executes 1 jump every 5 instructions and an OoO core can speculate hundreds of instructions in advance, so the number of possible code paths would explode very quickly.

Post reply on HN