Live data from Hacker News

ARM immediate value encoding

alisdair.mcdiarmid.org

41–50 of 71 posts

Re: ARM immediate value encoding

#41

Earlier quoted context omitted.

In the ARM instruction encoding, every arithmetic and logical instruction is "conditional". The destination register is either updated or not depending on the four bit condition field and the state of the condition flags in the processor. As a simple contrived example, consider the following C code: int a[100], b[100], count; ... for (int i=0; i b[i]) count++; } without conditional execution, one might compile this t…

That's a beautiful explanation. It's one of my favorite things about the ARM instruction set. That said, it also means debugging becomes a bit more painful. Let's say you want your (cheap) JTAG debugger to halt on the count++ instruction. You can hard break on that particular address in code, but you will always hit that address whether the condition was met or not.

Knowing nothing about the tools, why can't you set a breakpoint based on a bitmask of the instruction pointer?

I'm new to the assembly world, I've been working my way down and have gotten as far as Forth.

Re: ARM immediate value encoding

#42
post #11

Very cool and clever scheme. But what happens to immediates that can't be encoded that way?

Here's what you can do to add a "complicated" constant stored elsewhere, in hand-crafted assembler: add_something: ; function starts here (argument r0 == some number) ldr r1, __tmp ; get complicated constant, store in r1 add r0, r0, r1 ; do the addition r0 = r0 + r1 bx lr ; == return result (in r0) __tmp: .word 0x12345678 ; store complicated constant here You can play with your compiler, if you call gcc as "gcc -Os -…

In at least the ADT assembler and gas a few years back, the assembler provided syntactic sugar:

    ldr r0,=0x123456578
assembles to

    ldr r0,pc+xxx
    ... and then somewhere later ...
    .word 0x12345678
The assembler had some default places it would put constant pools (end of a module?), or you could explicitly tell it to generate a constant pool if the default place would be outside the limit of the pc-relative addressing mode.

Re: ARM immediate value encoding

#43
post #22

I was left with one question after reading the article: the purpose of the condition field in the instruction.

In the ARM instruction encoding, every arithmetic and logical instruction is "conditional". The destination register is either updated or not depending on the four bit condition field and the state of the condition flags in the processor. As a simple contrived example, consider the following C code: int a[100], b[100], count; ... for (int i=0; i b[i]) count++; } without conditional execution, one might compile this t…

This was part of the beauty of ARM when I learned it as a teenager back in the early 90s. Very simple and elegant, and writing ARM code by hand was enjoyable. Coming back to ARM now, though, in this form of Cortex-M microcontrollers, I see that things have become muddied with things like if-then-else instructions and mixed 16-bit/32-bit Thumb-2 code.

Re: ARM immediate value encoding

#45
post #36

The Tensilica guys took this thing an extra step. ie- profile real code to find out what constants are most typically used, enumerate the top n constants, encode the constant with 0..n-1 in the immediate instruction - the immediate value is a hardware based lookup. You can still do arbitrary immediates with longer instructions but you can apparently get some nice code size reductions using this technique.

The flipside of that is that the scheme described here will take less silicon, fewer transistors and thus . . . use less power, if you happen to optimise the code appropriately.

Code size reductions are good, but for power purposes it is a case of balancing them against decoding complexity.

Re: ARM immediate value encoding

#46
post #3

So arm compilers must prefer to, for example, XOR with 0x10000000 rather than AND with 0xEFFFFFFF?

Aside from this kind of trick, I have not worked with a ton of ARM assembly but what I find is very frequently compilers will just put values in the text section close to where they are used and refer to them with some PC-relative thing, rather than using immediate values as often as they might on x86. I have seen this on other RISC platforms as well.

Wouldn't that require the pc-relative address to fit into this immediate scheme?

Re: ARM immediate value encoding

#47

Earlier quoted context omitted.

Aside from this kind of trick, I have not worked with a ton of ARM assembly but what I find is very frequently compilers will just put values in the text section close to where they are used and refer to them with some PC-relative thing, rather than using immediate values as often as they might on x86. I have seen this on other RISC platforms as well.

Wouldn't that require the pc-relative address to fit into this immediate scheme?

In order to have a single-instruction PR-relative load the offset needs to be small (though it uses a different immediate scheme for the offset). So in practice you usually tuck small constant islands between blocks of executable code when you adopt this approach.

Re: ARM immediate value encoding

#48

Earlier quoted context omitted.

In the ARM instruction encoding, every arithmetic and logical instruction is "conditional". The destination register is either updated or not depending on the four bit condition field and the state of the condition flags in the processor. As a simple contrived example, consider the following C code: int a[100], b[100], count; ... for (int i=0; i b[i]) count++; } without conditional execution, one might compile this t…

I remember there was a "never" condition, which was present just for completeness; it turns out ARM eventually found that having 2^28 different NOPs would not be a good use of opcode space, so it's now a special extension for newer instructions...

I seem to recall from my ARM Assembler coding days that there was also a noop instruction, which of course could be conditional itself, so if you didn't actually want to do the NOOP, you could do NOOP-NE, which wouldn't do anything twice over.

Re: ARM immediate value encoding

#49

Earlier quoted context omitted.

In the ARM instruction encoding, every arithmetic and logical instruction is "conditional". The destination register is either updated or not depending on the four bit condition field and the state of the condition flags in the processor. As a simple contrived example, consider the following C code: int a[100], b[100], count; ... for (int i=0; i b[i]) count++; } without conditional execution, one might compile this t…

This was part of the beauty of ARM when I learned it as a teenager back in the early 90s. Very simple and elegant, and writing ARM code by hand was enjoyable. Coming back to ARM now, though, in this form of Cortex-M microcontrollers, I see that things have become muddied with things like if-then-else instructions and mixed 16-bit/32-bit Thumb-2 code.

Simple, elegant, and it eats an astonishing 12.5% of instruction bandwidth (4 bits out of 32). A branch will require less space as soon as you want to conditionally execute over 8 instructions. On top of that, for that is executed unconditionally (in practice, maybe not most of the instructions if you look at the binary, but almost certainly most of the instructions if you count ones executed multiple times)

So, a neat idea, but not for the long term, and certainly not for all CPUs. For example, ARM 64 ditches this feature (https://www.mikeash.com/pyblog/friday-qa-2013-09-27-arm64-an...)

Re: ARM immediate value encoding

#50

Earlier quoted context omitted.

Wouldn't that require the pc-relative address to fit into this immediate scheme?

In order to have a single-instruction PR-relative load the offset needs to be small (though it uses a different immediate scheme for the offset). So in practice you usually tuck small constant islands between blocks of executable code when you adopt this approach.

That's what I was thinking. I also started wondering how a large structure might be packed, when you can relatively address every byte in the nearest 256 bytes but only every 4 bytes in the next KB and so on. It could sort of upend the way you might normally think about packing a struct.
Post reply on HN