Wikipedia:Reference desk/Archives/Computing/2020 August 27

= August 27 =

8086 assembly: inc-then-dec why?
I've been peeking at some disassembled source code of very old 1970s, early-1980s PC games to get an understanding of other programmers' approaches to assembly, and how they did things efficiently for such low-powered computers back then, so that I myself may learn some things.

Something odd I noticed a lot in one project I'm looking at, is that this pattern is very common:


 * mov al,X
 * inc al
 * dec al
 * (then do whatever with al)

(X is any byte value at all. Register is not necessarily always AL, just in this example)

What is the purpose of incrementing and then immediately decrementing the register?

(One guess I had was that perhaps INC/DEC trigger Flags such as Carry/Zero/etc/whatever, which then influence conditional jumps. But more often than not, in this source, the value loaded into AL with the MOV is something nowhere near the 0-or-255 bounds of what a byte could be)  — Preceding unsigned comment added by 67.168.7.154 (talk) 15:40, 27 August 2020 (UTC)


 * There are two possibilities that I can think of:
 * DEC AL is the target of a jump or loop. The INC AL instruction is there to negate the decrement on the first pass.
 * The other option is as you suggest for setting flags. MOV AL,x doesn't set any flags whilst DEC AL sets AF, OF, PF, SF and ZF.  SF is set if the result of the DEC is 80-FF, ZF is set if the result of the DEC is 00.
 * HTH, Martin of Sheffield (talk) 20:18, 27 August 2020 (UTC)


 * If the next instruction is a conditional jump, then I think Martin of Sheffield's second idea is the likely case. See #6 "eliminate unnecessary compare instructions" (and the inc makes sure that, after the pair of instructions, AL is still X, and not X-1). -- Finlay McWalter··–·Talk 12:24, 28 August 2020 (UTC)


 * The only problem is that it is less efficient. INC AL, DEC AL codes as FE C0 FE C8 and takes 6 clock cycles.  Using TEST AL,#FF codes as A8 FF which is only 2 bytes and 4 clocks.  The TEST instruction sets SF, ZF and PF so would be more efficient unless you actually needed AF or OF. Martin of Sheffield (talk) 13:27, 28 August 2020 (UTC)
 * Yes indeed (unless there is some ancient variant of the microarchitecture where this isn't true). We'd really have to see more of the specific code the OP is talking about. In any event, this kind of micro-optimisation is very microarchitecture specific, and is more the domain of software archaeology than up-to-date best practice. -- Finlay McWalter··–·Talk 13:33, 28 August 2020 (UTC)
 * Well given that the OP referred to "very old 1970s, early-1980s PC games" and we are discussing an 8086 which was released in 1979 and discontinued in 1998 then I'd agree that "up-to-date best practice" is not relevant. Counting cycles and minimising byte counts was best practice in the 1980s.  And yes, it is chip specific, that's why I'm using a 1983 programming manual which precisely defines the instructions an 8086 implements.  Martin of Sheffield (talk) 13:54, 28 August 2020 (UTC)


 * If you're really interested in this kind of thing, I recommend Michael Abrash's Black Book (which is available free, from a link on that article) which goes into great detail about x86 assembly and efficient programming. It's mostly centred about rather later microarchitecture versions (a lot is 386 and 486 stuff), but I imagine you'll still find it interesting (if of a rather daunting size). -- Finlay McWalter··–·Talk 17:24, 28 August 2020 (UTC)
 * Interesting. My machine code experience started on 4004, then 8080 and onto Z80.  I started to look at 8086, but then moved on to Macro-32 for VAXes and later Alphas.  That was 20-odd years ago, since then I was in System Management/Admin until being made redundant and having to retire.  The usual problem; anyone over the age of 40 is too old to be worth training and management never believes you can mug up on a language yourself without training.  Martin of Sheffield (talk) 17:53, 28 August 2020 (UTC)
 * Which is particularly sad, because many of us spent our entire careers mugging up on languages without training. That's what manuals are for. But management tends to be full of people who don't understand the pleasure of reading manuals. --jpgordon&#x1d122;&#x1d106; &#x1D110;&#x1d107; 03:55, 29 August 2020 (UTC)
 * Another possibility is that the code needs to take a known exact time to execute, in which case, it might need to be padded with time-wasting instructions. Graeme Bartlett (talk) 22:40, 28 August 2020 (UTC)
 * take a known exact time to execute — possible, but if that were the case I would expect to see NOP, which is much safer. Both NOP and INC/DEC 8-bit-register take 3 clock cycles, and the former uses less memory (1 byte vs 2). Mitch Ames (talk) 07:42, 30 August 2020 (UTC)