Live data from Hacker News

Things I learned while writing an x86 emulator (2023)

timdbg.com

111–120 of 135 posts

Re: Things I learned while writing an x86 emulator (2023)

#111
post #104

Earlier quoted context omitted.

If Terry A. Davis is to be trusted, as long as you ignore the legacy stuff, x64 assembly is nice to work with.

Where did he say this? In any case, I can confirm it from personal experience. x86 isn't that annoying if you ignore most of it. The worst thing is the edge cases with how some instructions can only use some registers, like shifting/rotating using cl.

There was a video of him talking about it, but I can't recall the exact words or the name of the video.

But his operating system, TempleOS, was based on HolyC which was compiled to pure x64, and had support for inline x64 assembly.

Re: Things I learned while writing an x86 emulator (2023)

#112

Earlier quoted context omitted.

I'm not following: as long as you are introducing a new, incompatible instruction for leading zero counting, you'd definitely choose LZCNT over BSR as LZCNT has definitely won in retrospect over BSR as the primitive for this use case. BSR is just a historical anomaly which has a zero-input problem for no benefit. What would be the point of offering a new variation BSR with different input semantics?

When it comes to TZCNT vs BSF, they are just compatible enough for a new compiler to use unconditionally (if we assume that BSF with a zero input leaves its output register unchanged, as it has for decades, and as documented by AMD who defined LZCNT): the instruction sequence MOV ECX, 32 TZCNT ECX, EAX ; i.e. REP BSF ECX, EAX behaves identically on everything from the original 80386 up and is better on superscalars w…

TZCNT and BSF are not completely identical even for non-zero input: BSF sets the ZF when the input is zero, TZCNT sets ZF when the output is zero (i.e., the least significant bit is set).

Re: Things I learned while writing an x86 emulator (2023)

#113
post #19

Earlier quoted context omitted.

> I blame Intel for why so many folks avoid assembly language. x86 (the worst assembly of any of the top 50 most popular ISAs by a massive margin) and tricky MIPS branch delay slots trivia questions at university have done more to turn off programmers from learning assembly than anything else and it's not even close. This is one reason I'm hoping that RISC-V kills off x86. It actually has a chance of once again allow…

I think that's putting the cart before the horse. I think it wouldn't matter which architecture you choose as there will always be deep performance considerations that must be understood in order to write efficient software. Otherwise your statement might amount down to "I hope there is an ISA that intentionally wastes performance and energy in deference to human standards of beauty." It's why the annals of expertise…

x86 has a parity flag. It only takes the parity of the lowest 8 bits though. Why is it there? Because it was in the 8086 because it was in the 8080 because it was in the 8008 because Intel was trying to win a contract for the Datapoint 2200.

Sometimes the short instruction variant is correct, but not if it makes a single instruction break down into many uops as the microcode is 1000x slower.

Oh, but you need to use those longer variants without extra uops to align functions to cache boundaries because they perform better than NOP.

Floats and SIMD are a mess with x87, AMX (with incompatible variants), SSE1-4 (with incompatible variants), AVX, AVX2, and AVX512 (with incompatible variants) among others.

The segment and offset was off dealing with memory is painful.

What about the weird rules about which registers are reserved for multiply and divide? Half the “general purpose” registers are actually locked in at the ISA level.

Now APX is coming up and you get to choose between shorter instructions with 16 registers and 2 registers syntax or long instructions with 32 registers ands 3 registers instructions.

And this just scratches the surface.

RISCV is better in every way. The instruction density is significantly higher. The instructions are more simple and easier to understand while being just as powerful. Optimizing compilers are easier to write because there’s generally just one way to do things and is guaranteed to be optimized.

Re: Things I learned while writing an x86 emulator (2023)

#114
post #74

Earlier quoted context omitted.

Yes, it's like someone looked at TZCNT and thought "let's encode LZCNT the same way", but it makes no sense.

LZCNT and TZCNT are corrections (originally introduced by AMD) for the serious mistake done by the designers of Intel 80386 when they have defined BSF and BSR. Because on the very slow 80386 the wrong definition for the null input did not matter much, they have failed to foresee how bad it will become for the future pipelined and superscalar CPUs, where having to insert a test for null input can slow down a program m…

LZCNT was introduced by Intel in BMI1, while TZCNT was introduced by AMD.

Re: Things I learned while writing an x86 emulator (2023)

#115
post #52

Earlier quoted context omitted.

Another bonus quirk, from the 486 and Pentium area.. BSWAP EAX converts from little endian to big endian and vice versa. It was a 32 bit instruction to begin with. However, we have the 0x66 prefix that switches between 16 and 32 bit mode. If you apply that to BSWAP EAX undefined funky things happen. On some CPU architectures (Intel vs. AMD) the prefix was just ignored. On others it did something that I call an "inner…

Also known as "bswap ax", and research shows that it does something surprising but consistent on almost all hardware: It zeros the register. https://www.ragestorm.net/blogs/?p=141 https://gynvael.coldwind.pl/?id=268 However, this page, now gone, suggests that some CPUs (early 486s?) did something different: http://web.archive.org/web/20071231192014/http://www.df.lth.... Unfortunately I have not found any evidence nor…

[deleted]

Re: Things I learned while writing an x86 emulator (2023)

#116

Earlier quoted context omitted.

I suspect the biggest issue is that courses like to talk about how instructions are encoded, and that can be difficult with x86 considering how complex the encoding scheme is. Personally, I don't think x86 is all that bad as long as you look at a small useful subset of instructions and ignore legacy and encoding.

True, encoding is one thing that really sets x86 apart. But as you say, the assembly itself doesn't seem that uniquely horrible (at least not since the 32-bit era), which is why I found the sentiment confusing as it was phrased. Maybe it's the haphazard SIMD instruction set, with every extension adding various subtly-different ways to permute bytes and whatnot? But that would hardly seem like a beginner's issue. The…

An ordinary developer cannot write performant x86 without a massive optimizing compiler.

Actual instruction encoding is horrible. If you’re arguing that you can write a high-level assembly over the top, then you aren’t so much writing assembly as you are writing something in between.

When you need to start caring about the actual assembly (padding a cache line, avoiding instructions with too many uops, or choosing between using APX 32 registers and more normal shorter instructions, etc) rather than some high level abstraction, the experience is worse than any other popular ISA.

Re: Things I learned while writing an x86 emulator (2023)

#118

Check out Justine Tunney and her emulator. https://justine.lol/blinkenlights/ The docs are an amazing tour of how the cpu works.

That name, Tunney. Remember it from around 2014, being homeless, bumming around, and shit posting on Twitter about Occupy lol

Re: Things I learned while writing an x86 emulator (2023)

#119
post #116

Earlier quoted context omitted.

True, encoding is one thing that really sets x86 apart. But as you say, the assembly itself doesn't seem that uniquely horrible (at least not since the 32-bit era), which is why I found the sentiment confusing as it was phrased. Maybe it's the haphazard SIMD instruction set, with every extension adding various subtly-different ways to permute bytes and whatnot? But that would hardly seem like a beginner's issue. The…

An ordinary developer cannot write performant x86 without a massive optimizing compiler. Actual instruction encoding is horrible. If you’re arguing that you can write a high-level assembly over the top, then you aren’t so much writing assembly as you are writing something in between. When you need to start caring about the actual assembly (padding a cache line, avoiding instructions with too many uops, or choosing be…

> Actual instruction encoding is horrible. If you’re arguing that you can write a high-level assembly over the top, then you aren’t so much writing assembly as you are writing something in between.

One instruction in x86 assembly is one instruction in the machine code, and one instruction as recognized by the processor. And except for legacy instructions that we shouldn't teach people to use, each of these is not much higher-level than an instruction in any other assembly language. So I still don't see what the issue is, apart from "the byte encoding is wacky".

(There are μops beneath it of course, but these are reordered and placed into execution units in a very implementation-dependent manner that can't easily be optimized until runtime. Recall how VLIW failed at exposing this to the programmer/compiler.)

> padding a cache line, avoiding instructions with too many uops

Any realistic ARM or RISC-V processor these days also supports out-of-order execution with an instruction cache. The Cortex processors even have μops to support this! The classic 5-stage pipeline is obsolete outside the classroom. So if you're aiming for maximum performance, I don't see how these are concerns that arise far less in other assembly languages. E.g., you'll always have to be worried about register dependencies, execution units, optimal loop unrolling, etc. It's not like a typical program will be blocked on the μop cache in any case.

> APX 32 registers and more normal shorter instructions

APX doesn't exist yet, and I'd wager there's a good chance it will never reach consumer CPUs.

Re: Things I learned while writing an x86 emulator (2023)

#120

Bonus quirk: there's BSF/BSR, for which the Intel SDM states that on zero input, the destination has an undefined value. (AMD documents that the destination is not modified in that case.) And then there's glibc, which happily uses the undocumented fact that the destination is also unmodified on Intel [1]. It took me quite some time to track down the issue in my binary translator. (There's also TZCNT/LZCNT, which is B…

Can you imagine having to make all this logic work faithfully, let alone fast , in silicon? X86 used to be Intel's moat, but what a nightmarish burden to carry.

Intel is coming out with an improved x86 instruction set that removes a lot of the cruft, called ‘APX’ for advanced performance extensions.
Post reply on HN