14 ms·
I have a theory that CPU architectures implicitly have something I call the "architectural weirdness budget", which is the extent to which you can get away with
by pm215 4y ago
I have a theory that CPU architectures implicitly have something I call the "architectural weirdness budget", which is the extent to which you can get away with design decisions in the architecture or ABI that differ from the existing established consensus. Any time you do something a bit odd that means that existing software has to do awkward things or might not be no-changes portable to your new architecture, you're spending a bit of your weirdness budget. Some examples:
+ HPPA's upwards-growing stack
+ SPARC register windows
+ PowerPC's slightly oddball varargs ABI
+ CHERI capabilities are massively spending weirdness budget
+ these days, being big-endian is spending weirdness budget
Doing a few odd things is fine, but if you blow your weirdness budget entirely then your new architecture is in danger of failing because you've cumulatively made adoption of it too expensive for the existing software ecosystem. So you need to be careful that you're spending it on things that really matter; if something's not a big deal, do it the same way everybody else does. (Certainly some of the things in the list above are deliberate choices for things that are, or at least seemed at the time, important. But nobody tried to do all of them at once!)
Of course if you're a pre-existing dominant architecture like x86 then you get a lot more freedom to do weird things :-)
- KptMarchewa 4y agoWhat does ARM and RISC-V spend their weirdness budget on?
- qikInNdOutReply 4y agowasnt there also the long jump limitation weirdness that forced it to create little hopping points, were the instructions were stored to hop to the next point, all of that to get to some memory whos pointer it could not fit into loadInstructions Register? Sorry, its been a while, but i found the idea, to generate those instruction isles into the code quite weird.
- jmgao 4y agoARM spends it on pc being wrong: when you mov from it, it's off by 8 in ARM mode, and off by 4 in Thumb mode, and if you're using it for pc-relative loads (and stores, if you're crazy), it uses a word aligned value. edit: oh, and softfloat vs softfp vs hardfp vs vfp edit: oh, and how they have two incompatible assembly language dialects that are mostly the same, but in non-trivial code, incompatible
- danachow 4y ago> ARM spends it on pc being wrong. Heh, having dealt with x86 for years, this is comparatively such a nothing burger. It's always a simple known fixed offset. > softfloat vs softfp vs hardfp vs vfp That's something not really unique to ARM per se. Any architecture with options for hardware FPU are going to practically need ABI specs for the soft and hard cases (you don't absolutely need anything more than hardfp since you can always emulate but it will be slow as shit) - and ARM is certainly not unique in having multiple hardware floating point implementations either. > two incompatible assembly language dialects Curious what you're referring to here - but I personally wouldn't consider assembly language dialects to be part of a CPU architecture.
- curling_grad 4y agoBy pc you mean "program counter"?
- deleted 4y ago[deleted]
- snvzz 4y agoAs far as I am aware, RISC-V spends it on not being weird (which is itself weird).
- TNorthover 4y agoThe hoops they had to go through to get PIC address calculations to work make it quite weird. Because `auipc` adds an offset from its `pc`, the corresponding `add` or `lw` relocation needs refer back to that instruction rather than the symbol it's actually looking for. The poor ELF specification ends up quite tortured by this, IMO.
- brucehoult 4y agoThat affects ELF relocations but not the code. Arm64 is even worse! There is almost exactly the same instruction, but it also zeroes the low bits of the target address, so as you relocate code you also have to change the offset in the 2nd instruction even if the distance between the reference and the target stays the same.
- rwmj 4y agoProbably on copying Arm too much :-) I hit "char is unsigned" (not really architectural, more of a toolchain issue) only this morning. RISC-V was originally going to implement a hypervisor mode which would only have worked with Xen-like hypervisors. Luckily we were able to head that off early and the actual hypervisor extension we got can run KVM efficiently.
- exikyut 4y agoNot sure if you'll see this - going through old tabs - but I was curious, and just in case: what are the practical differences between Xen and KVM here?
- kryptiskt 4y agoIt doesn't have a condition code register, which scores it plenty of weirdness points.
- pjc50 4y agoRISC-V spends it on the "R": either not having single instructions to do certain stuff, or that those instructions are in one of the extension blocks so you have to customize your binaries to a particular RISC-V subset. Most architectures only do this for the high-performance SIMD numeric instructions. ARM endianness is switchable at runtime.
- rwmj 4y agoYou keep saying this about RISC-V and it keeps not being true. Instruction sequences that fuse are standardized. RISC-V defines various profiles (like "Unix server") which mandate a minimum set of extensions. Extensions beyond the mandated ones will be detected at runtime, just like on x86.
- gchadwick 4y ago> Instruction sequences that fuse are standardized They are? Care to point to a ratified RISC-V standard that lists said instruction sequences?
- rwmj 4y agoGo to the user spec here: https://riscv.org/technical/specifications/ https://riscv.org/technical/specifications/ and search for "fusion", "macro-op", "hint", "two-instruction sequences". A lot of it is through register choice. For other proposals (not standards yet) see https://en.wikichip.org/wiki/macro-operation_fusion#Proposed_fusion_operations https://en.wikichip.org/wiki/macro-operation_fusion#Proposed...
- Annatar 4y agojust one example of weird insanity from that table: slli rd, rs1, {1,2,3} add rd, rd, rs2 Fused into a load effective address ...this is so insane. Whoever thought that this is okay and good, has, in my opinion, severe psychological and psychiatric problems and would do well to seek professional help. If this gets "fused" into a lea, why just not implement a hex code for lea? I'm just completely at a loss as to how messed up that is. You know what, I'd like to know what a person who thinks that this is okay looks and behaves like.
- pm215 4y agoYou could argue that Arm mostly doesn't get too weird and that that's part of why it succeeded, but some things include: + 'char' being unsigned + handling of unaligned accesses (in early architecture versions a value is read from the aligned address and rotated, which is useless behaviour that falls out of the original implementation because of how it dealt with byte loads; subsequently it was at least made to fault, but it wasn't until I think v6 that unaligned accesses were made to Just Work) + the weak memory model
- bpye 4y agoI’m pretty sure it’s x86 that is weird in having a strong memory model, most other architectures (including ARM) are weak.
- renox 4y agoIn RISC-V with the C-extension 32bit instructions are 16bit aligned. Far from x86-level of weirdness but my must be quite annoying for those who want to make 'high performance' CPUs..
- rwmj 4y agoRISC-V instructions are variable length, from 16 bits up to 192 bits[0]. The instruction stream is self-synchronising though so from a hardware decode point of view it's not a problem, unlike x86. [0] See "Expanded Instruction-Length Encoding" in the user spec.
- monocasa 4y agoI don't think the instruction stream is self synchronizing; if you jump to the middle of an instruction there's no guarantee you'll ever get back to not parsing garbage.
- rwmj 4y agoI didn't put that very well. I didn't mean it was self-synchronising when executing, but that you can (I think?!) always find the next instruction boundary by looking at the bottom bits. At least, that's my understanding from reading that part of the user spec.
- pm215 4y agoIt can still get you into some extra corner cases for the insn fetch hardware to have to handle when an insn crosses a cache line boundary, though...
- brucehoult 4y agoRISC-V instructions longer than 32 bits are just a theoretical possibility at this point. An extension escape hatch for the future. No one has done it, no one seems to be keen to be the first to do it, and even how the instruction length encodings work is not a ratified part of the spec -- it's just a proposal at the moment, even for the next step of 48 bit instructions. There has been discussion of encodings better than the one proposed in the current spec, especially around instruction length encoding schemes that would make more opcode bits available in 80 bit instructions than in the scheme in the spec, so as to have a possibility of encoding 64 bit literals in an 80 bit instruction. https://github.com/riscv/riscv-isa-manual/issues/280 https://github.com/riscv/riscv-isa-manual/issues/280
- cesarb 4y agoFor traditional 32-bit ARM, off the top of my head: - Every instruction being conditional (all instructions have a four-bit condition field, with one of the 16 possible modes being "always"); - The barrel shifter, which can be used on nearly every data processing instruction; - The program counter being one of the general-purpose registers (and on the original ARM, the same register also containing the flags), so that any register move can alter the program flow; - The load-multiple/store-multiple instructions, which can load or store up to 16 registers, plus incrementing or decrementing the base register; and since the program counter is one of these registers, it can restore several registers from the stack, update the stack pointer, change the program counter, and switch to Thumb mode (stored on the least significant bit of the program counter), all in a single instruction.
- Annatar 4y agoLoading and storing multiple registers is by no means weird: the MC68000 family has the movem.(b|w|l) instructions which do exactly that, and it's one of the best things since sliced bread because performance can be gained when used cleverly. Being able to manipulate the program counter in the ARM processors directly is just being honest, simple and straightforward, rather then having it always done implicitly. Seems very intuitive to me now that I think about it.
- brucehoult 4y agoBeing able to manipulate the program counter directly plays hell with a superscalar and especially OoO processor where you want to be able to predict what the program counter does very accurately so the instruction fetch and decode can run far ahead of the execution. There are four kinds of instructions that play hell with pipeline and OoO design: - instructions that might cause traps, dependent on the values processed - instructions that you don't know whether they will change the control flow - instructions that you don't know where the control flow is going to go to - instructions where you don't know how long they will take to execute RISC-V, for example, bans the first category entirely other than load/store, and carefully separates the other three so any one instruction only had at most one of those problems. ARM load multiple has all of those problems. At least you can examine the register mask at instruction decode time and know whether it will change the PC or not and tag the instruction in the pipeline as being a Jump or not. Imagine if there was a version that took the bitmap from a register instead of being hard-coded... Load/store multiple don't increase performance much if at all on a CPU with an instruction cache and/or an instruction prefetch buffer. On an original 68000 or ARM without any cache, sure, a series of load or store instructions requires interleaving reading the opcodes with reading or writing the data, while load/store multiple eliminates the opcode reads. An instruction cache also eliminates them, leaving only the code size benefits. But load/store multiple is a perfect candidate for using a simple runtime function instead, at least if you have lightweight function call/return as RISC designs usually do.
- pjc50 4y agoMIPS delay slots were another example of this. Arguably Itanium's failure was due to exceeding the weirdness budget with VLIW nonsense, leading to the default PC 64-bit architecture being AMD's "x86 with longer registers" instead. What happened to the Mill "unlimited weirdness budget" CPU guys anyway?
- voldacar 4y agoThe mill guys post one or two updates per year on their forum site. Apparently covid messed up their timeline a lot, but they aren't bankrupt or anything.
- DSingularity 4y agoWhat is up with those guys?
- gumby 4y agoI don't think they know how to move a project forward. What's it been, 20 years?
- voldacar 4y agoI think they just have a small team. Most recent work has been on their software stack (emulator, compiler etc), which I think is fairly close to release, but I could be wrong about that.
- mhh__ 4y agoI think they don't have a rich enough VC friend, and they need a kick up the arse before (to be blunt) they get too old. Ivan was saying that they weren't sure about how to get money, and then someone quite rightfully pointed out that this is probably the most liquid time in years for funding startups. Mill team if you're reading this: Get your IP sorted out then open source everything, then start talking to VCs aggressively. Not the other way round because everyone thinks you're either a joke or a group of fantasists. Cool ISA, hopeless execution. Where's the FPGA model?
- planede 4y agoYou also have to distinguish between the architecture, and an ABI targeting a specific architecture. I believe x86 exception handling is nothing like this on gcc/clang.
- gumby 4y ago> CPU architectures implicitly have something I call the "architectural weirdness budget" The point of designing a new architecture is you have a point to make (generally, "doing X will lead to faster execution"). So by definition you are adding unfamiliar architectural weirdness, else why get involved. The big problem is that the pervasiveness of the C model has fossilized design decisions of the PDP-11 that still haunt us to this day. For example a lot of transistors are devoted to hiding the effects of the micromachine (superscalar implementation, OOO execution etc). Newer paradigms (even trivial older ones like vector instructions) don't get used enough because of higher level language constraints (e.g. C's memory aliasing model). There's a lot of innovation going on but it's all stick in one small bay of a large lake.
- someguydave 4y ago> C's memory aliasing model does this mean that because you can’t be sure if two vectors don’t overlap in C you therefore can’t auto-vectorize loops?
- gumby 4y agoThat's an example. It also constrains some optimizations like reordering.
- titzer 4y ago> It also constrains some optimizations like reordering. Ha! As if C compilers really cared about correctness. This is why type-punning and aliasing memory through different typed pointers is fraught with peril, often UB. It's so C compilers can cheat and use type-based alias analysis, breaking programs that have "UB" but would work absolutely fine if the compiler wasn't so aggressive. In general, almost all arguments between language design and optimization for C/C++ are settled with "let's not think too hard about how to help users; go ahead and optimize this and make it their fault (UB) when they observe the hard cases". It's so rude.
- pornel 4y ago
- twoodfin 4y agoThis article isn’t really about x86’s weirdness as an architecture so much as it’s about Windows’ unusual implementation choices particular to that architecture.
- eadmund 4y ago> + HPPA's upwards-growing stack To be honest, I never really understood why more architectures don't have upwards-growing stacks. Visually, one adds things to the top of a stack, after all, so it makes sense to increment the stack pointer. I suppose it's a relic of the old days when folks just set the start of the stack to some remote part of memory and hoped it never grew down into the code or the heap? > + these days, being big-endian is spending weirdness budget Hard disagree, big-endian is right and little-endian is wrong. At least, unless you think this year is 2202. I don't know how Intel got this so badly incorrect. And remember that network byte order is big-endian. Any protocol which emits little-endian bytes on the wire is broken by design.
- silon42 4y agoStack grows down because it can then potentially use the same as unused heap (which grows from bottom) But then again, HPPA makes it more obvious that stack should be limited size because the above only works for single-threaded processes Worse things about HPPA is delayed jumps... no wonder they were the ones that partnered with Intel on Itanium. Network has no natural order (do you start with the last bit?)... for new stuff I'd do the little-endian any way if I cared to bother.
- rhn_mk1 4y agoNetwork does have a natural order. You can make a routing decision faster when you get the most significant units first. If you get the least first, you have to wait for the entire address before you can route to it.
- mech422 4y agoOh cool - I never knew this was the reason why... Thanks!
- xenadu02 4y agoThis is mostly irrelevant today though; the hardware is so much faster and memory so much more plentiful that handling is done by reading the full header (and often full packet) then making the routing or forwarding decision. You don't need to squeeze out every single cycle or save every single byte possible. You have so much headroom saving cycles or bytes makes no difference and you can't optimize enough to make significant BOM reductions by choosing cheaper chips while still offering features considered standard. Even if you could you'd be selling into an ultra-ultra-cheap market segment no one cares about (congrats, you made a $2 10Mbps router that can run on a coin cell battery).
- titzer 4y ago+ MSP430 holes in the addressing mode encoding space I don't know of any new architecture that is choosing big-endian. Almost all of the ones that I can think of that are/were big-endian have added a little-endian mode. Thank god for that! In Wasm we just decreed little-endian, and I think this was one of our better calls.
- nneonneo 4y agoI mean, people did try to do everything all at once, and the results are therefore dead and forgotten (cough Itanium cough).
- jayd16 4y agoYou can generalize this to a developer/user friction budget.
- gotaquestion 4y agoAs a former microarchitect, the contortions designs take on is due to a combination of factors, usually stemming from routing/timing problems in the design or backwards compatibility, and every now and then, compiler team requests. For example, endian-ness looks like weirdness to a programmer, but not to a chip designer that needs to read in lower-order bytes first to decode an instruction quickly. Why not just change the instruction decoder? Because it needs to be backwards compatible to what was once a byte-sized ISA. But for programmers who don't understand the history, it seems insane.
- Annatar 4y agoThat's because it is insane: how come most processors are big endian, how did they manage just fine?
- gotaquestion 4y agoFirst off, most processors are not BE. Arm and X86 are LE and cover "most processors". Second, processors like the Motorola 68000 were 32-bit, so there was no need to read just the first byte. Refer to my point about instruction fetch. Like I said, if you have an ISA that came from byte-sized opcodes, and then expanded later, you need to fetch bytes first. However, if your opcodes are 32-bit, then the code is bigger. (In the old days, CISC code size was a selling point compared to RISC, this opcode compression was one of the reasons.) This is what you learn in first-year computer architecture. However the world has changed a lot since the 80's. Single bytes aren't fetched in x86, 256-byte cachelines are, and the decode happens on that.
- Annatar 4y agoARM and x86 are only two out of many processors: you are purposely choosing to confuse market dominance with what exists, and I fault you for it, because by behaving in this way, you are helping perpetuate the monoculture. The moment you help perpetuate a monoculture rather than subvert it and fight it at every turn and opportunity, you become part of the problem.
- CalChris 4y ago+ SPARC tagged integers + MIPS branch delay slot + Everything about VLIW + Everything about Mill + iAPX 432 bit variable length instructions
- Annatar 4y agoHPPA upwards-growing stack: far more logical when one thinks about it, because in an upwards growing stack, the limit of the stack is the available memory, rather than some arbitrary size decided by someone arbitrarily. SPARC register windows: once one gr0ks them, they are a feature of wonder! The register windows in an UltraSPARC processor effectively provide 256 virtual registers in a processor with only 32 physical ones, giving one increased performance.