Hacker Timesnew | past | comments | ask | show | jobs | submitlogin

The author is less than enthusiastic about Apple and Microsoft pivoting to ARM. Considering the perf of the M1, this is virtually inevitable. And once most developer tool chains start supporting ARM as a first class citizen, I see no reason why we wouldn’t start running our applications on ARM in the cloud. A world with 2 architectures for mainstream use cases is the future, there’s no point fighting it.

(Unless you’re Intel/AMD in which case please fight it by giving us faster, more power-efficient chips for cheaper. Thanks!)



We achieved a near ubiquitous consensus with the x86 PC. Then APPLE said, Behold, the programmers are one, and they can build portable binaries with one machine language; and this they begin to do: and now nothing will be restrained from them, which they have imagined to do. Go to, let us go down, and there confound their machine code, that they may not run each other apps across platforms. So APPLE scattered them abroad with M1 processors from thence upon the face of all the Internet: and they left off to rebuild their open source.


Just because it's ubiquitous doesn't mean that it's good. Also, to be clear, x86 then became x86_64/amd64 which isn't the same architecture either. There will always be iterations and oddball architectures where something new can be learned and even reapplied to update x86. POWER, Sparc, etc. all taught new lessons.

Apple isn't scattering anything by running processors that run the same architecture as android and ios on phones. Most open source software can already be compiled for x86, arm, sparc, etc.


Except ARM CPUs have been vastly outselling x86 CPUs for a very long time, long before the M1 entered the scene. In just Q4 2020, 6.7 billion ARM-based devices shipped, while 275 million PCs shipped in all of 2020. Desktop PCs are only a small fraction of the total computing ecosystem.

The stuck-in-the-'90s "desktop is all there is" mindset is a weird holdover from the early growth of PCs in developed countries. If you look at emerging markets, mobile is completely dominant.


Raw sales numbers are going to be biased because ARM is like Zerg and x86 is Protoss. In the ARM world there isn't the same concept of a central processor so normally lots of chips get built into each individual device.

ARM has also been historically used most often on proprietary systems you need authorization to develop for. So it's made less sense as a target for open source tooling hack projects like this one.

ARM also has so many sub-targets that it's almost like a coalition of ISAs rather than a unified one like x86. So adding ARM support to Actually Portable Executable might not be as simple as including an ARM build in the binary. We might need to have multiple ARM builds for its microarchitectures. Because ARM users want resource efficiency and they're not going to be happy with a generalized build that broadly targets ARM; they want code that's narrowly targeted to the specific revisions of the processor that they're using.

In other words, we can't give ARM users portable binaries because ARM users do not want them.

I also always thought that code for other architectures was the kind of thing that mostly got contributed by the people who build those architectures. Things like how IBM always graces our GitHub issues with patches each time our code doesn't work on s390x mainframes. I like that they do it by contributing patches rather than the feedback of why don't you support this? Why don't you support that? Oh I didn't say I actually needed it.


> We might need to have multiple ARM builds for its microarchitectures.

Nitpick: it is by definition not needed to have different build for different microarchitectures (except maybe for performance). If the same code doesn't work on different chips, it's because they have different ('versions of') instruction set architectures.

Edit: nevermind, on rereading, you were already complaining about that. You should probably stick scare-quotes on "'need'", though.


> they're not going to be happy with a generalized build that broadly targets ARM; they want code that's narrowly targeted to the specific revisions of the processor that they're using.

Apple already does this for x86: macOS contains duplicates of all operating system binaries & libraries compiled for pre- vs. post-Haswell processors.


Hahaha, I love the StarCraft analogy!


I really want to know how we can work Banelings into a hilariously extended metaphor here. :P

(Rule 5: if you haven't played SC2, Banelings were a super in-character addition to the zerg unit tree. Zerglings are able to morph into a variant called the "baneling" that's a fairly powerful suicide bomb. Rather like the "scourge" air units in SC1, except a ground-only attack. Fairly good at rushing bunkers, but die pretty fast to siege tanks.

Really loved the design though - fit the zerg ethos really well.)


How do PC sales get tracked when a lot of builds are put together from parts at mom-and-pop stores or by the customers themselves?


There's only two vendors selling CPUs for build your own PCs. Track their sales, and there's your PC numbers.


I'm not sure bursting in with an "EXCEPT!" is quite the correct response to a satirical bible quote.


Lol this made my morning


I read that in the voice of Cecil B. DeMille narrating in The Ten Commandments. Well done.


Near consensus on x86? But aren’t most computers in this world actually smartphones?


I'm not sure what you're saying, but I appreciate that you put more effort into saying it than ten other HN posts combined.


It's an adapted Bible quote. Genesis 11:6, about the tower of Babel.


Cool, thanks for the explanation. It sounded Biblical, but I wasn't sure.


I think it was an allusion to the tower of Babel.


> A world with 2 architectures for mainstream use cases is the future

And the past, I mean PowerPC was a thing for a long time on both Apple desktop systems and servers.

Glad that the compiler toolchains make this transition a lot easier, and Apple has been a major contributor to that. It helped ease the transition from 32 bit ARM to 64 bit ARM, it enabled easy cross-platform apps (Mac Catalyst) and now from x86 to ARM for desktop apps.

And of course it's not particularly new; 25 years ago (ish) Java came out that promised the same thing, one codebase that runs on all architectures. Scripting languages, too.


PowerPC was also the dominant embedded platform for two decades (the rover that just landed on Mars is PPC). Point being, ARM's presence in highly vertical markets like embedded or phones means very little to desktops and servers outside of Apple.


Only 2 architectures? Hah! I remember when there was X86, Sparc, MIPS, PowerPC, M68K, and Alpha, all in relatively common use. There were a few Itanium, S390x, and other weird things floating around too. (MIPS, PowerPC, and S390x are still hanging around in niche applications today.)

Portability is not hard. If you write standard C/C++ that does not depend on undefined behavior (like wild-ass pointer casts, etc.) you will be fine 99% of the time. Use newer languages like Go and Rust or higher-level languages and you won't even notice.

The only hard areas where labor intensive porting is needed are hand rolled ASM or the use of CPU-specific extensions like vector code (e.g. __m128i and friends). That's a tiny fraction of code written and is generally confined to things like codecs, graphics engines, crypto, and math kernels.


The problem with C/C++ and "newer" languages is that programs need to be individually compiled or have an interpreter installed to execute them - the main problem the author is solving.

The author precisely realises that there used to be multiple architectures, just like you, but also notices that we have converges on x86-64 - what she terms the lingua franca.

I also completely follows her sentiment, that we should not switch ISA unless there is a very real computation per power unit benefit of doing so.


> Portability is not hard. If you write standard C/C++ that does not depend on undefined behavior (like wild-ass pointer casts, etc.) you will be fine 99% of the time.

This is not my area of expertise, so I'm not the one to write the rebuttal, but it seems that "---- is not hard" is never anything more than an invitation to someone who fully understands ---- to explain why it is hard.

Succinctly, serving 99% of the use cases with no effort mainly seems to be a recipe for making sure that, when one hits those 1% problems, one has no idea how to deal with them. I suspect that portability is one of those things where it's easy to do a mediocre job but hard to do a good/robust job.


Does ARM really have a performance advantage? Or is it the specific Apple customizations tailored to their use case?

Apple doesn't have to worry about 35 years of legacy architecture to support.


> Or is it the specific Apple customizations tailored to their use case?

Apple's use case is "run applications". It's not like there's any magic or they have some sort of ultra specific workload they improved by 10x while the rest sat there.

Apple's customisations are largely "throw hardware at the problem", which I'm reasonably sure Intel would do if that worked for x86. So sounds like something you can do with ARM, which you can't with x86.

The more magical customisations are workload specific, but then they would only trigger for these workloads, both of which are pretty much opt-in: running emulated x64 code on ARM, and performing matrix computations (which AFAIK will only be used through the Accelerate framework).


As far as I understood, some of the reasons M1 is fast are in fact specific to ARM. For Instance, the advantages given by the width of the decode depend partly on the uniformity of AMR instruction size, and M1 also benefits from looser ordering of memory operations


Intel would do that if they could shrink their transistors. But because they are still at 14NM they are heavily constrained. It's actually amazing they are competitive at all given they are now 3 generations behind in manufacturing.


> So sounds like something you can do with ARM, which you can't with x86.

There's not reason why Intel couldn't, but they don't have the incentive to hyper-optimize frequently used Apple workloads like Final Cut Pro.


> There's not reason why Intel couldn't

If Intel could they would, for years now they’ve been spending billions to get fraction of a pc improvements on benchmarks. You really think if they could increase die size by 10% and get 30% better perfs they’d say no? Come on.

> they don't have the incentive to hyper-optimize frequently used Apple workloads like Final Cut Pro.

Except M1’s performance improvements show up across the board including software which has no relation to Apple, so this is just complete nonsense.


Performance is agnostic of ISA. Apple's custom designed cores do indeed have a massive performance/Watt advantage over x86 based designs and happen to be using ARM. However, it's not impossible for an x86 CPU to be designed in a similar way. It does, however, get more difficult to do so due to x86's variable length instruction encoding, to which ARM does not have.


x86’s instruction decoder suffers from its inability to parallelize some things. Because instructions have no fixed boundary,[a] something has to process the bytes sequentially. Even if they can be read from memory in massive amounts, something still has to sit there going byte by byte to find the boundaries.

The good news is, once those boundaries are found, uops can be generated. But that ~5% or so of die space is always running full tilt (provided there’s no pipeline stalls).

I’m sure Intel and AMD have put a massive amount of work into theirs to make it as quick as possible,[b] but it’s still ultimately a sequential operation.

With RISC-like architectures like ARM and RISC-V, you don’t need that boundary detector. Just feed the 2 or 4 bytes straight into the decoders.

[a]: Unlike ARM and RISC-V which have fixed 2 or 4 byte encodings (depending on processor mode), x86’s instructions can be anywhere from 1 through 15 bytes.

[b]: Take the EVEX prefix for example. It is always 4 bytes long with the first one being 0x62. So, once you see that 0x62 byte after the optional “legacy prefixes”, you can skip 3 bytes and go to the opcode. But then you need to decode that opcode to see if it has a ModR/M byte, decode that (partially) to see if there’s an SIB byte, decode that to see if there’s a displacement (of 1, 2, or 4 bytes), etc. And then, don’t forget about the immediate (which can be 1, 2, 4, or (in one case of MOV) 8 bytes).


Something has been bugging me about x86’s lack of boundaries...could the boundaries be computed ahead-of-time and passed to the processor?


Not that I’m aware of. The decoding of an instruction is complicated and also dependent on the current operating mode and a few other things. So, for an OS to pass those lengths before hand, it’d have to know everything about the current state of the processor at that instruction. For example, in 16 and 32 bit modes, opcodes 0x40 through 0x4F are single byte INC and DEC (one for each register). In 64 bit mode, those are the single byte REX prefixes; The actual opcode follows. See also: the halting problem.

As for why it became an issue, instruction sets need to be designed from the beginning to be forward expandable. Intel has historically not done that with x86. Take AVX for example. Originally, it was just 128 bit (XMM) vectors encoded as an opcode with various prefix bytes being used in ways they weren’t intended. Later, 256 bit vectors were needed. So they made the VEX prefix. But it only had 1 bit for vector length. This allowed 128 bit (XMM) and 256 bit (YMM) vectors, but nothing else. So when AVX-512 came along, Intel had to ditch it and create the EVEX prefix and allow both to be used. But EVEX only has 2 bits for vector length. So, should something past AVX-512 come out (AVX-768 or AVX-1024?), it’ll probably use the reserved bit pattern 11, and they’ll be stuck again if they want to go past that.

For an example of this being done right, ForwardCom[0] (started by the great Agner Fog) took the “forward compatibility” (hence the name) issue into mind and used 2 bits to signal the instruction length. It’ll probably never reach silicon, but it and RISC-V (which is in silicon form) are good examples of attempting to keep things forward compatible.

[0]: https://forwardcom.info/


> Not that I’m aware of. The decoding of an instruction is complicated and also dependent on the current operating mode and a few other things. So, for an OS to pass those lengths before hand, it’d have to know everything about the current state of the processor at that instruction

The compiler would know the instruction boundaries. It could store that information in a read-only section in the executable. The OS would then just pass that section to the CPU somehow.

I don't think there is anything impossible about this. Would there be sufficient performance benefit to justify the added complexity? I don't know, quite possibly not.


This sounds like a potential attack vector.


I'm not sure why it would be. If the boundary information were wrong, the CPU instruction decode would fail, but that should just be an invalid instruction exception, which operating systems already know how to handle.


"Performance is agnostic of ISA" is too strong a statement. The variable length instruction encoding is a significant performance disadvantage, as is the strict memory ordering requirement of X86/X64.

X64 decoders are indeed only ~5% of the die on a modern CPU, but it's 5% that is always at 100% utilization. That's a non-trivial amount of extra power. X64 decode parallelism is also limited. I've heard four instructions at once as a magic number beyond which it becomes really hard. This is why hyperthreading (SMT) is so common on X64 chips. It's a "cheat" to keep the pipeline full by decoding two different streams in parallel (allowing 8X parallelism). SMT isn't free though. It drags in a lot of complexity at the register file, pipeline, and scheduler levels, and is a bit of a security minefield due to spectre-style attacks. All that complexity adds more overhead and therefore more power consumption as well as taking up die space that could be used for more cores, wider cores, more cache, etc.

ARM is just a lot easier to optimize and crank up performance than X86. The M1 apparently has 8X wide instruction decode, and with fixed length instructions it would be trivial to take it to 16X or 32X if there was benefit to that. I could definitely imagine something like a 16X wide ARM64 core at 3nm capable of achieving up to 16X instruction level parallelism as well as supporting really wide vector operations at really high throughput. Put like 16 of those on a die and we're really far beyond X64 performance in every category.

This is also why SMT/hyperthreading doesn't really exist in the ARM world. There's less to be gained from it. Better to have a simpler core and more of them.

IMHO X86/X64 has hit a performance wall at least in terms of power/performance, and this time it might be insurmountable due to variable length instructions and associated overhead. It matters in the data center as well as for mobile and laptops. There's a reason AWS is pricing to steer people toward Graviton: it costs less to run. Power is the largest component of most data center costs.


While it’s absolutely true that fixed width instructions make parallel decoding vastly easier, there’s a cost in terms of binary footprint size. x86 generally has an advantage in instruction cache and TLB performance for this reason, which can be significant depending on the workload.


Not true. This is a common myth that comes from some old Linus posts in the 32-bit Pentium 4 days and still won't die. I've done comparisons to test this. Compare sizes of modern x86-64 Linux binaries to their counterparts on AArch64. You'll find that they're extremely close.

The biggest problem is all the REX prefixes. The inefficient encoding of registers in x86-64 squandered all the advantages that x86 had.


Is true. They said:

> > x86 generally has an advantage [empahsis added, not "x86-64"]

Obviously if you take the worst of both worlds (bloated and variable-width instructions), you can squander that advantage, but the advantage is in fact real.


Is this still really relevant? I can understood that it can be a problem 20 years ago, but with current processor with huge L1 cache and memory bandwidth, I am starting to think that 4 bytes (or variable 4/8 bytes) is not a bad tradeoff for density Vs superscalar.


L1 size in 1999: 32 kB

L1 size in 2021: 64 kB


The L1 size is yet another place where the x86 legacy hinders things. To avoid aliasing in a virtually indexed L1 cache (which is what you want for performance in a L1 cache, since a physically indexed cache would have to wait for the TLB lookup), the size of each way is limited to the page size, which on x86 is 4096 bytes. To get a 64 KiB L1 cache, it would have to be a 16-way cache, and increasing that too much makes the cache slower and more power-hungry. It's no wonder Apple decided to use a 16 KiB page size instead of a 4 KiB page size; a 64 KiB VIPT L1 cache with 16 KiB page size needs only 4 ways.

For the L1 instruction cache, aliasing shouldn't be a problem (since it's never written to), but this is once again another place where the x86 legacy hinders things: instead of requiring an explicit instruction to invalidate a virtual address in the instruction cache, it's implicitly invalidated when writing to that address.


Apple M1 big core cache sizes:

256KB L1I/128KB L1D

Little cores: 128KB L1I/64KB L1D


Wow. Didn't know that. That should more than compensate for a very slight increase in code size for ARM64 vs X64.

When I use M1, AWS Graviton, or even older Cavium ThunderX chips I can't help but think that X86 is on its way out. The advantage is something you can subjectively see and feel. It's obvious, especially when it comes to power consumption.

Process node has something to do with it, but it's not the whole story. I'm typing on a 10nm Ice Lake MacBook Air and while this chip is better than older 14nm Intel laptops it's still just shockingly crushed by the M1 on every metric. 10nm -> 5nm is not enough to explain that, especially since apparently Intel is more conservative with its numbering and Intel 10nm is more comparable to TSMC 7nm. So it's more like TSMC 7nm vs TSMC 5nm, which is not a large enough gap to account for what seems to be at least 1.5X better performance and 3X better power efficiency.

Some of the X86/X64 apologists remind me of old school aerospace companies dissing not only SpaceX and Blue Origin but the whole idea of reusable rockets, trying to convince us that there's little economic advantage in reusing a $100M rocket stage that consumes ~$100-200K in fuel per launch.

"That's not much of a meteorite. It's no big deal." - Dinosaurs


Que? Look at VLIW ISA's for five minutes and tell me how you've arrived at "agnostic".


Agnostic is a little strong, although it is true that M1 is extremely wide especially for a laptop chip, and wide in ways beyond the decoder which could be applied to an X86 part.

Ultimately these discussions are quite hard because AMD aren't on exactly the same density, and Intel are quite a way behind at the moment.


It currently has a performance per watt advantage because of a fundamental design difference (smaller, simpler, many cores) which works great for mobile and can be scaled up to desktop/server rather than trying to scale down x86.


It seems we are finally going back to the ecosystem of the 90's with multiple processors. This was the genesis of Java at the time and the promise of Write Once Run Anywhere was quite appealing to many developers at the time.

Back then IBM Mainframes still had as strong foothold in large corporate IT departments. Sun had a dominant position as well for most newer companies. If you wanted multiple CPU's with redundant fail over and gigs of RAM Sun was your huckleberry back in the day.


It seems like the current iteration is that modern build systems provide the “write once run anywhere” rather than virtual machines, which have their own compatibility and performance issues.

It’s trivial nowadays to write a program in Go or Rust and deploy it to whatever architecture you want, without any arcane knowledge of the build process


> It’s trivial nowadays to write a program in Go or Rust and deploy it to whatever architecture you want

According to rust docs [1] and go wikipedia page [2] both have mainly support for x86, while go recently added support for macos/arm and in 2019 windows/arm, rust only has tier 1 ("guaranteed to work") support for arm-linux and x86.

Am I misreading this? It does not seem "trivial" to me for arbitrary platforms.

[1] https://doc.rust-lang.org/nightly/rustc/platform-support.htm...

[2] https://en.wikipedia.org/wiki/Go_(programming_language)#Vers...


A significant barrier to getting platforms to Tier 1 support for Rust is actual hardware to run CI on. Tier 1 is an extremely high bar for support.

I do my job at work every day on a Tier 2 ARM target, and in practice, don't notice any difference from the Tier 1 targets. YMMV of course.


Thank you, that helped me put it into perspective!


I'm not sure about Go, but Rust should work on everything LLVM can emit native code for. While ARM may not be listed as "tier 1", Rust worked on M1's on launch day because of LLVM portability.


I very definitely read that tongue-in-cheek. Her project targets everything, so long as it's using AMD64, therefore anything _not_ AMD64 is useless, as it can't run her project.


How many toolchains do not have Arm64 support? Cross-compiling is ancient and most tools predate x86 being useful.




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: