4 ms·
I have very mixed opinions about the custom syntax. IMO the correct asm syntax, with very few exceptions, is the one in the manual. This is why Intel syntax is
by amluto 2mo ago
I have very mixed opinions about the custom syntax. IMO the correct asm syntax, with very few exceptions, is the one in the manual. This is why Intel syntax is right and AT&T syntax is wrong: the ISA comes from Intel, the docs are from Intel and AMD, and those docs use Intel syntax.
So I was kind of hoping that the custom syntax would at least result in a very, very strong checker, at least as good as Fil-C’s. Maybe with an escape hatch to say something like “I know it looks like I clobbered xyz, but I promise I really didn’t.
Sadly, the CPUID example in the article apparently compiles, but IMO it shouldn’t have: CPUID takes two inputs, in EAX and ECX, and the example forgot to bind ECX as an input. One might argue that CPUID takes even more inputs if you’re on a VM and doing something special, but ECX is really quite unambiguous.
- CBLT 2mo ago> the CPUID example in the article [...] forgot to bind ECX as an input. I'm not really familiar with this stuff, but the example uses what it calls a "pin" (which in their docs is a type of "binding") on ECX before calling CPUID.
- tialaramex 2mo agoYou don't really need to be familiar with either "this stuff" or Odin to spot that this clearly takes a single parameter named "leaf" and that's the input, which goes in EAX. However CPUID may care about ECX as input and that's only used as an output in this uh, "template". Here's Rust implementing this same feature: https://doc.rust-lang.org/src/core/stdarch/crates/core_arch/src/x86/cpuid.rs.html#61-100 https://doc.rust-lang.org/src/core/stdarch/crates/core_arch/... Rust provides this for both x86-64 and the original 32-bit x86 and this is a function, not an Odin-style "template" but hopefully this helps show what you're supposed to do. [Edited to add the Rust example]
- tpmoney 2mo agoI'm not sure the example template was supposed to be canonical, vs demonstrating multiple output destructuring. Certainly the actual instruction definition in the checker library seems to understand that there could be two possible inputs: https://github.com/odin-lang/Odin/blob/4247507dd5e31c9fd87166f53fd67b007ecca86c/core/rexcode/isa/x86/tablegen/instruction_table.odin https://github.com/odin-lang/Odin/blob/4247507dd5e31c9fd8716... But I'm also not entirely sure why the example should not have compiled. It seems to me that the idea here is to be able to define a typed set of something equivalent to a function that inlines some assembly, but nothing about that inherently requires that the number of input or output parameters to the template match the parameters in the underlying assembly calls. There's no reason (in my mind anyway) why this shouldn't be a perfectly valid template: // Returns the extended feature flags obtained by calling CPUID // with EAX=7 and ECX=1 cpu_extended_feature_flags :: asm() -> (a, b, c, d: u32) [ a = %eax, b = %ebx, c = %ecx, d = %edx, ] { mov %eax 0x7 mov %ecx 0x1 cpuid }
- tialaramex 2mo ago> But I'm also not entirely sure why the example should not have compiled The source you presented seems fine - it's explicitly setting the register. The trouble with the cpuid definition in the article is that it just doesn't set ECX at all It does actually seem as though Odin is intended to notice this problem but maybe is fooled that the register is pinned (because we want its result value) and so the diagnostic doesn't trigger. Reading this code reminded me that my annual summer leave ends this weekend because it would get so much review feedback if he worked with me. "Commenting out" blocks of code is NOT OK and neither are "if (false)" blocks.
- tpmoney 2mo agoSure, I agree that if you're making a CPUID inline assembly template that isn't setting the register value, and it accepts any values for EAX that would also cause it to read ECX then the behavior is going to be undefined and likely unexpected, but that doesn't seem to be a reason for this not to compile. For one, requiring an input parameter when it isn't mandatory would mean that you're spending cycles setting a register with a value that you don't need and is just going to be overwritten anyway. A good number of the CPUID calls never read from ECX, and if you're going to call any of them, then the value in ECX is irrelevant. And sure, it's only an extra instruction or two, but presumably if you're dropping down to inline assembly, you kind of care about every wasted instruction. Again, this seems to me like it should be a perfectly valid assembly template (based on https://www.felixcloutier.com/x86/cpuid https://www.felixcloutier.com/x86/cpuid): // Returns the maximum input value for basic CPUID information cpu_extended_feature_flags :: asm() -> (a, b, c, d: u32) [ a = %eax, b = %ebx, c = %ecx, d = %edx, ] { mov %eax 0x0 cpuid } I admit I never touch inline assembly or really assembly at all save for the occasional microcontroller project, so maybe I'm missing something that's obvious to people more familiar with this. But to me the article seems to be sayin that the Odin templates will type check and validate that IF you have inputs from Odin types that are being put into registers or used as operands to your assembly, or are mapping registers and outputs from your assembly back to Odin types, that those mappings will be type compatible, and when you get those mappings wrong, you'll get a more useful error. But I didn't read it as saying that it will prevent you from writing assembly that does something completely unrelated to those inputs or outputs.
- applfanboysbgon 2mo agoThe syntax in the manual is embarrassingly outdated. Like, it's actually a disgrace and shameful for our profession that assembly languages and tooling are stuck in the previous century. There is absolutely zero logical reason we should be constrained to such primitiveness.
- adrian_b 2mo agoFollowing the vendor syntax may be useful if you only ever program in assembly for only a single target ISA. Otherwise, all the vendor syntaxes are different and all of them have many ugly quirks, for various historical reasons. If you ever have to write assembly for at least 2 ISAs, e.g. x86-64 and Aarch64, then it is much more productive to use a unified, and better syntax, like the one described in TFA. Nothing makes more likely the appearance of bugs than having to alternate frequently between two or more slightly different syntaxes. Even with only one target ISA, if you frequently intersperse inline assembly within a high-level language source code, it is better to have harmonized syntaxes, as explained in TFA.
- pjmlp 2mo agoAnd that is how you end up with Plan 9 Assembly, that requires mapping to every single ISA.
- MrBuddyCasino 2mo agoIt is better to put this burden on a small team of language developers than putting the burden on every future user of the language
- deleted 2mo ago[deleted]
- inkyoto 2mo agoThe correct assembly syntax is a matter of convention and personal preference – not a category error. Historically, some ISA's have adopted the «src, dst» convention, whilst others have preferred «dst, src». We should be grateful that no engineer, in a moment of excessive creativity, attempted boustrophedon – a conceptual device solely appropriate to the likes of INTERCAL. Then we have 3 operand RISC instructions. As with so many technical orthodoxies, the first convention one encounters tends thereafter to acquire the status of natural law. The consistent application of the same convention is useful nevertheless. It reduces the unnecessary cognitive overload once one starts jumping across multiple hardware architectures.