Code in ARM Assembly: Registers Explained
eclecticlight.co
eclecticlight.co
Interesting. I wonder why that particular one. It's not exactly in the middle of the range. Maybe they searched for typical existing use and decided that was the least likely to have some conflict?
https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aap...
https://developer.apple.com/documentation/xcode/writing-arm6...
Note that small structures will be passed in registers. Here's an example: https://godbolt.org/z/rsGEbefcv. a and b are 32 bits and passed packed in x0, and c is a long passed in x1.
'Reference' doesn't mean C++'s reference, it means that you pass where the data is, not the data itself. Even Visual Basic had this concept.
Unlike C++, C does not support pass-by-reference (ignoring preprocessor silliness). Passing a pointer by value is not the same thing. edit To be clear, C++ supports both pass-by-value and pass-by-reference.
This topic cropped up a year ago: https://news.ycombinator.com/item?id=23553574
It's not a C++ concept, I only used C++ in that example simply because godbolt.org makes it really easy to show how the language treats the two concepts differently even though they compile to the same thing.
In that case perhaps the response should have been "pass-by-reference doesn't exist on machine level", not "pass-by-reference is something different", as the latter would seem to be a category error.
Which would barely make any sense.
A typical CPU deals with abstractions like jumps and copies, and has no real concept of a function call. It seems fair to say that, at the level of a typical assembly language/machine language, there is no argument passing, and therefore no evaluation strategy. Same goes for a Turing machine.
> I'm reluctant to bikeshed
This is the kind of topic where precise phrasing is important, so I wouldn't chalk it up as pedantry. It doesn't help that Java muddied the waters with its use of the word reference.
[0] Here's the link again: https://news.ycombinator.com/item?id=23553574
Kinda, but that difference is important. We can say that C allows us to simulate pass-by-reference by using pointers. It's still true that the C language does not support pass-by-reference semantics.
Taking the address of a variable is an operation that the C language permits us to do, yielding a new value (a pointer value). This isn't part of C's argument-passing functionality, though.
> What does the 'ref' keyword change about how C# passes the argument to the function?
The internals of C# compilers aren't really the point, but I believe .Net does it the copy-intensive way, copying to pass in and copying again to pass the new value back out. I don't think this a real performance problem though, unless you overuse the feature.
Wasn't there, but pretty sure in 70s, the notion of pointer and reference (and 'handle', etc) were pretty much interchangeable, since AFAIK there wasn't any compiler capable of creating a compiler-checked 'reference' construct.
so, if this is true, in the relm of asm, since really we are just dealing with bits in a register that could be interpreted as data or addresses, it makes sense to treat pointer and reference interchangably, since there is no such thing as a higher-order 'reference' anyway.
[0] Amir M. Ben-Amram and Zvi Galil. 1992. On pointers versus addresses. J. ACM 39, 3 (July 1992), 617–648. DOI:https://doi.org/10.1145/146637.146666
* Java: Java spec says "pass by value"
* C: pass by value
* C++: pass by value and reference(with ref qualifier)
* C#: pass by value and reference(with ref keyword)
Do you know a language that defines "pass by reference" in a very different way?
> but they define reference and value passing similarly
Well, If all of them have been derived from C++ or designed by people trying to improve on C++, they would be very likely to have the notion defined similarly regardless of how anyone else would use the term, so there's not much surprise there.
BTW the page you've linked seems to contradict some of your statements:
> so they are typically described as call by value even though implementations frequently use call by reference internally for the efficiency benefits
As you seem to be arguing that this is not call by reference you should probably correct the page.
EDIT: It also seems that there IS some amount of language specificity anyway, since in another place of the page it says:
> "In particular it is not call by value because mutations of arguments performed by the called routine will be visible to the caller. And it is not call by reference because access is not given to the variables of the caller, but merely to certain objects"
I'm reasonably sure that the first part would be called "call by value" in C++ even if in context of CLU it wasn't if the usual way of doing the same in C++, namely passing a pointer to an object, were to be used.
Source: the Procedure Call Standard for the Arm 64-bit Architecture https://github.com/ARM-software/abi-aa/blob/2021Q1/aapcs64/a...
There is a lot of other HW crud that leaks into sw for dubious reasons. For example, although 'wasteful' if every memory location had tag bits -- hardware enforced -- capabilities would layer naturally. More sophisticated memory protection would be possible.
Instead, we have these von Neumann archs hellbent on winning some synthetic benchmark. Will the computer-using community ever demand some sacrifice in overall potential "adds-per-second" to enable better security and to support better abstractions? Sadly, I doubt it. Even Risc-V is a baby step.
ARM has various mechanisms in flight for tagging; there's already PAC shipping on certain chips and MTE seems like it might be on the horizon. More advanced efforts like Morello are being evaluated, too.
Registers are unavoidable. Even if you could directly address the whole memory space on every instruction, even if it was all "really fast", the hardware would still need to read the input operands from memory into internal registers, and store the result into an internal register before writing to memory.
I can never remember which names are mapped to the same register. I've had that issue on x86 and I'll have that issue on ARM.
I loved how Motorola 68000 made it simple. Each command had a dot-letter suffix indicating the length: move.b d0, d1
It doesn't seem to be as confusing as the x86 situation anyway: none of the registers are _really_ special purpose on ARM.
Here's a link to the details in the ARM64 APCS: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aap...
Also, on 68k you can only address the least significant word or byte of a register that way. Some CPUs have, say, 8 8-bit registers that can alternatively be treated as 4 16-bit registers (https://en.wikipedia.org/wiki/Intel_8080#Registers). On such a CPU, one can write to the top half of a register in a single instruction by writing to the 8-bit register that shares its storage (some RISC CPUs support that by having a separate instruction “load top half of register”)
For 32-bit Arm, unfortunately, things are different: D0 is the bottom half of Q0, and D1 the top half; similarly S0 is the bottom half of D0 and S1 is the top half (and so Q0 is S0 S1 S2 S3, with S3 its most significant 32 bits). This is why "just indicate the length on the insn" wouldn't have worked for 32-bit: there is more than one 32-bit register in each 64-bit register (and some kind of 'high/low' notation would have been annoying when you really do want to just think of it as a collection of 32-bit registers sometimes, especially if your hardware doesn't even have double-precision support!). The 64-bit transition fixed up the awkward overlaid mapping, but retains the notation for the benefit of all the people who were already familiar with the Arm notational conventions for things.
For general purpose registers: X=long (64-bit), W=word (32-bit)