News for hackers. Stuff that matters.
Re:The x86 architecture is the weirdo, part 2 by gumby on Friday April 22, 2022 @08:18AM (#31120695)
> 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.

Re:The x86 architecture is the weirdo, part 2 by agalunar on Friday April 22, 2022 @01:07PM (#31124544)
> the pervasiveness of the C model has fossilized design decisions of the PDP-11

This is tangential and somewhat pedantic, but I want to point out an oft-repeated mischaracterization.

C is essentially a refinement of B with some additions [1], and B was written for the PDP-7, which was a very different machine.

For example, the increment and decrement operators in C were inherited from B; they could not have been modelled after the PDP-11. From Dennis Ritchie himself [2]:

> Thompson went a step further by inventing the ++ and -- operators, which increment or decrement; their prefix or postfix position determines whether the alteration occurs before or after noting the value of the operand. They were not in the earliest versions of B, but appeared along the way. People often guess that they were created to use the auto-increment and auto-decrement address modes provided by the DEC PDP-11 on which C and Unix first became popular. This is historically impossible, since there was no PDP-11 when B was developed. The PDP-7, however, did have a few "auto-increment" memory cells, with the property that an indirect memory reference through them incremented the cell. This feature probably suggested such operators to Thompson; the generalization to make them both prefix and postfix was his own.

Another person puts it this way [3]:

> It's a myth to suggest C's design is based on the PDP-11. People often quote, for example, the increment and decrement operators because they have an analogue in the PDP-11 instruction set. This is, however, a coincidence. Those operators were invented before the language [i.e. B] was ported to the PDP-11.

[1] Notably, the char type, since the PDP-11 was byte addressable but the PDP-7 was not.

[2] https://www.bell-labs.com/usr/dmr/www/chist.html

[3] https://retrocomputing.stackexchange.com/questions/8869/have...

Re:The x86 architecture is the weirdo, part 2 by brucehoult on Friday April 22, 2022 @06:08PM (#31128834)
>[1] Notably, the char type, since the PDP-11 was byte addressable but the PDP-7 was not.

"char" is a useful type for the program's problem domain regardless of whether the machine is byte-addressed or not. Pascal was developed on machines that were not byte-addressable but always had a char type. This is easily visible in the PACK and UNPACK standard functions and the PACKED keyword for arrays and records. It is slow to do access to a random char from an array packed several to a word, so there are standard functions to copy everything from a packed array to an array that uses one word per item for easier processing, and back again.

If anything, you need the compiler to support the char type more if you don't have a byte-addressed machine because it's such a pain for the programmer to deal with themselves.

Standard Algol 60 didn't have "char" but some manufacturers added it non-standard. Algol 68 had char. These ran on primarily word-addressed machines too, as was the fashion in those days.

Re:The x86 architecture is the weirdo, part 2 by gumby on Friday April 22, 2022 @08:28PM (#31130005)
Yet all these languages were limited to the 8-bit byte. C on the PDP-10 and -20 only had an 8-bit byte while all other languages on those machines Al had native access to bytes of width 1-36 bits — yes, std::vector<bool> in hardware, but more powerful.

Though a general purpose machine it had instructions specifically designed for low cost Lisp implementation, arbitrary numbers of stacks etc…all inaccessible to C

Re:The x86 architecture is the weirdo, part 2 by brucehoult on Friday April 22, 2022 @11:26PM (#31131088)
There is no requirement in C for char to be 8 bits. Even in modern C it's allowed to be bigger than that. For sure it is a bit limiting that in C everything else has to be a multiple (possibly x1) of the size of char. Other languages don't have that restriction.

Algol68 allowed char to be as small as 6 bits, the size on the ICL 1900 it was first developed on (with a 24 bit word size).

Pascal was first implemented on the CDC 6600, with 60 bit words and characters again 6 bits. The first other machine Pascal was ported to was, again, the ICL 1900.

Re:The x86 architecture is the weirdo, part 2 by pm215 on Friday April 22, 2022 @10:17AM (#31121837)
Yes, absolutely you should have a point to make with your new architecture, and that's likely to involve at least some weirdness. What I'm trying to get at is that the weirdness budget isn't infinite, and therefore you want to be careful to spend it on making your point, not frittering it away on incidentals.
Re:The x86 architecture is the weirdo, part 2 by gumby on Friday April 22, 2022 @12:25PM (#31123762)
Oh I agree, I was mainly commenting that the size of that “budget” is smaller than it should be, because of the malign influence of C.
Re:The x86 architecture is the weirdo, part 2 by someguydave on Friday April 22, 2022 @08:53AM (#31121004)
> 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?

Re:The x86 architecture is the weirdo, part 2 by gumby on Friday April 22, 2022 @09:06AM (#31121120)
That's an example. It also constrains some optimizations like reordering.
Re:The x86 architecture is the weirdo, part 2 by titzer on Friday April 22, 2022 @09:35AM (#31121364)
> 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.

Re:The x86 architecture is the weirdo, part 2 by pornel on Friday April 22, 2022 @10:56AM (#31122353)
This is roughly what happens, but you shouldn't attribute this to rudeness. Compiler users also demand performance. They compare implementations (and languages) and point out when such-and-such is X% slower. They file bugs about "missed" optimizations and "unnecessary" instructions.

C is especially awkward here, because compilers are expected to precisely conform the C specification, but at the same time C users don't actually want to program for the abstract machine from the C specification (the one that can't overflow signed integers or shift by a full int width). C users expect their programs to actually behave like programs for a particular hardware they target, without any overhead or discrepancy from "emulating" the imaginary C-spec machine. In face of such conflicting requirements, C compilers will always be forced to balance performance, predictability, conformance, and compatibility.

Re:The x86 architecture is the weirdo, part 2 by titzer on Friday April 22, 2022 @11:34AM (#31122893)
You make some good points. C was often used in the situation where "Hey, we just built this enormous supercomputer for LLNL, let's make this C program run as fast as possible on this one machine. Compiler team, please do everything possible to get the maximum performane out of this machine." I feel like a lot has followed from this repeating dozens of times over the past few decades. Performance has been the #1 priority, above all else, and it shows.
Re:The x86 architecture is the weirdo, part 2 by gumby on Friday April 22, 2022 @12:31PM (#31123877)
Not sure if the S-1 is a good example — IIRC it still had a 36-bit word and was mainly intended for pl1 and lisp (I only really saw it from the S-1 Lisp side). Was there evening a C for it? It would have been as bad as running C on a Cray YMP (which I mention above)
Re:The x86 architecture is the weirdo, part 2 by Slighted on Friday April 22, 2022 @04:18PM (#31127498)
What exactly do you mean by the "C model"? Computers have followed the Von Neumann architecture for quite a long time. That PDP-11 is fundamentally the same as a modern computer, albeit millions of times slower. And I'm curious as well what "new paradigms" you have in mind.
Re:The x86 architecture is the weirdo, part 2 by brucehoult on Monday April 25, 2022 @08:43AM (#31153619)
The C language and portable C programs do not in any way require a Von Neumann architecture. In fact with the modern trend for phone/tablet/desktop/server OSes to use W^X memory permissions they effectively mandate programs written in Harvard-compatible style even if they technically have code and data in the same address space.

Once instruction sets got features such as index (or base) registers and register indirect addressing (including stack addressing) instead of absolute addressing (including for indirect jumps/subroutine calls) there was no longer any need to support self-modifying code during execution of the program itself, and Von Neumann architecture is not required except for initial loading of the program code into memory by the OS.

I'd think most modern instruction sets are easily capable of running with code and data in truly different address spaces.

The only real difficulty is in loading constant data and especially constant tables from program space. Microcontroller ISAs such as AVR have special instructions for program space loads. Any ISA where the PC is a GPR (PDP-11, VAX, arm32) or that has an explicit PC-relative addressing mode (preferably indexed) such as 68000 make it easy to detect that a memory reference is PC-relative and do it in the program space instead of the data space.

Arm64 with ADR and ADRP and RISC-V with AUIPC make it tricky because hardware would have to track that a GPR contains a pointer derived from the PC. x86 and PowerPC make it even more difficult, because the only way to get the PC value is to do a fake function call to the next instruction (or to keep return stack prediction happy, to a real function that just saves the return address then returns). On these ISAs you're probably better off assembling all constants using load immediate and shifts, and arrays or tables of constants using computed jumps to load immediate instructions.

In short, using a conventional modern ISA with Harvard architecture is doable if you want to.

Re:The x86 architecture is the weirdo, part 2 by gumby on Friday April 22, 2022 @05:10PM (#31128182)
Harvard architecture machines are still not just being used but still being designed these days.

Examples of non-pdp-11 things are discussed in various comments in this thread.

Re:The x86 architecture is the weirdo, part 2 by colejohnson66 on Sunday April 24, 2022 @11:21AM (#31144878)
Case in point: many microcontrollers. The AVR ISA (made famous in Arduinos) is a modified Harvard architecture.
Re:The x86 architecture is the weirdo, part 2 by someguydave on Friday April 22, 2022 @10:26PM (#31130814)
personally I would like a memory access model that makes buffer overflow impossible
Re:The x86 architecture is the weirdo, part 2 by notacoward on Friday April 22, 2022 @08:46AM (#31120947)
So which language has handled ILP, OOO, delay slots, cache hints, etc. particularly well? Anything that's ergonomic and actually used (i.e. not awkward and academic)?
Re:The x86 architecture is the weirdo, part 2 by gumby on Friday April 22, 2022 @09:13AM (#31121174)
But that's my point: the dominance of a C monoculture has relegated alternatives to being "awkward and academic".

When you're in a C straightjacket it's hard to take advantages of other architectures like transputer, connection machine, or cell. Ever run bsd unix on a Cray? It was dog slow because the CPU assumed very deep pipelining and always had to continually resynchronize because of the frequent branches in the C code.

GPGPU is the sole recent exception, and even then it's still at the margins. And we have CUDA which is an attempt to, yes, get back to the C model.

These modern CPUs benchmark pretty well, but in practice little code can really take advantage. For example the M1 is a multicore screamer, yet most apps are still restricted to a single one.

Re:The x86 architecture is the weirdo, part 2 by my123 on Friday April 22, 2022 @09:36AM (#31121370)
> And we have CUDA which is an attempt to, yes, get back to the C model

CUDA allows different programming models, it's the point of having the PTX virtual machine as the exposed programming model.

CUDA C++ is popular, but is far from the only option people have.

(and it can go very deep, https://www.ibm.com/docs/en/sdk-java-technology/8?topic=egpu... for example)

Re:The x86 architecture is the weirdo, part 2 by paulmd on Friday April 22, 2022 @11:50AM (#31123165)
It's far less popular than the C/C++ bindings (at least at an end-user level), but NVIDIA actually has official support for FORTRAN on CUDA as well. iirc you can mix and match at the linker level, and there's a fair amount of library code that uses FORTRAN for performance reasons.

FORTRAN has tighter restrictions around what you can do in terms of aliasing/etc, which allows compilers to be more aggressive about optimizations without as much undefined-behavior "this looks correct and will run fine until we add another optimization and it doesn't" shenanigans. So in practice it can be faster than C, and it's actually quite popular among the HPC community and other performance-sensitive segments.

It's not like C has to be this way, with all the "undefined behavior" nonsense, it just is an artifact of a programming language written in the early 70s. C makes a lot of sense when a compiler looks a lot more like an assembler with a bit of optimization sprinkled in, and isn't performing super deep introspection and deciding that this entire function can be optimized away because of some arcane "undefined behavior" rule.

Re:The x86 architecture is the weirdo, part 2 by my123 on Friday April 22, 2022 @12:40PM (#31124035)
> at least at an end-user level

I'd say that the most popular option at the end-user level today is a whole level of abstraction above: using Python w/ PyTorch (or less frequently, TensorFlow).

Combined with CuPy and cuNumeric, which is available at https://developer.nvidia.com/cunumeric and handles scaling to multiple machines with Python-written code, through the Legate runtime (https://nv-legate.github.io/legate.core/README.html). This covers a huge amount of what the CUDA userbase uses.

Re:The x86 architecture is the weirdo, part 2 by titzer on Friday April 22, 2022 @09:39AM (#31121400)
These are all microarchitectural things that should not be surfaced in language, IMHO. This is why compilers exist, to raise the level of abstraction. For example, other than sidechannels (i.e. Spectre), OOO is not observable, nor is ILP or cache hints. Delay slots are observable at the ISA level but typically compilers do the work of dealing with them. Thank god delay slots didn't make it into programming languages; they were a wart of ISA design surfaced because of a lack of decent branch prediction. Can you imagine if you had a bizarre feature where the next line of code after a branch still executed even if the branch was taken? That'd be bonkers.
Re:The x86 architecture is the weirdo, part 2 by SuchAnonMuchWow on Friday April 22, 2022 @10:06AM (#31121693)
OOO is definitely observable when dealing with multithreading.

That's why you have things like memory order constraints on atomic operations in C, and why you need to be extremely careful with how you place things like memory fences when doing anything fine-grained between several threads.

Re:The x86 architecture is the weirdo, part 2 by titzer on Friday April 22, 2022 @10:54AM (#31122326)
Fair point, but I'd qualify that OOO is only observable for racy programs. In languages with shared memory concurrency, but safety, races are either statically disallowed (Rust), or their results are constrained by a (weak) memory model. Java, e.g. only makes rough guarantees that you don't see out-of-thin air values and that you can't violate the type system. Java also is a little stricter around volatile memory access (they are sequentially consistent, iirc). Also worth noting, some reorderings that you see are not due to hardware, but due to compiler optimizations. Compilers have to obey the memory model, too.

Generally, most programmers shouldn't need to be reasoning about OOO or memory order and be using fences. Rather, they should use libraries that are written by experts that use extra-lingual mechanisms (like compare-swap or fences) to guarantee a higher contract.

Re:The x86 architecture is the weirdo, part 2 by toast0 on Friday April 22, 2022 @12:08PM (#31123444)
> Fair point, but I'd qualify that OOO is only observable for racy programs.

I mean, you're basically saying that it's only observable if you care to observe it.

Re:The x86 architecture is the weirdo, part 2 by zozbot234 on Friday April 22, 2022 @11:16AM (#31122641)
Rust has atomic types that can observe races. Such "racy" code is useful because some concurrent code doesn't need the strictest guarantees (sequential consistency). Though, compared to C, Rust does not use the "Consume" memory ordering because so far it has turned out to be ill-defined.
Re:The x86 architecture is the weirdo, part 2 by titzer on Friday April 22, 2022 @11:39AM (#31122967)
AFAICT those can't observe OOO of CPUs, just nondeterminism from interleavings different threads. I.e. they will give you sequential consistency unless you have other, worse races.
Re:The x86 architecture is the weirdo, part 2 by zozbot234 on Friday April 22, 2022 @11:53AM (#31123213)
Sequential consistency is absolutely optional, there are several other possible memory orderings that are far weaker. When programs involve multiple atomic locations concurrently, atomicity is only preserved at each separate location.
Re:The x86 architecture is the weirdo, part 2 by gumby on Friday April 22, 2022 @10:28AM (#31121987)
Think about it the other way around: if the language were sufficiently high level that the compiler could give the CPU more opportunities for OOO. C incorporates too many assumptions about the PDP-11. Sometimes they are harmless (the ++ operator) and sometimes disastrous (memory model).
Re:The x86 architecture is the weirdo, part 2 by AnimalMuppet on Friday April 22, 2022 @01:01PM (#31124445)
> Can you imagine if you had a bizarre feature where the next line of code after a branch still executed even if the branch was taken?

I seem to recall that there was a mainframe back in the 1970s that actually did that. Univac 1108 or 1100, maybe? Maybe only in some particular mode?

Re:The x86 architecture is the weirdo, part 2 by notacoward on Friday April 22, 2022 @08:26PM (#31129993)
I once worked on the MC88K which had this behavior at the instruction level, and I think other contemporary RISC processors did as well. Never saw it in a higher-level language, though. Maybe some variant of SNOBOL (which already had success/failure branches for every line)?
Re:The x86 architecture is the weirdo, part 2 by Annatar on Friday April 22, 2022 @01:42PM (#31125226)
Fortran. This essay sums it up rather well: https://news.ycombinator.com/item?id=31123165