[HN Gopher] New inline assembly syntax available in Rust nightly ___________________________________________________________________ New inline assembly syntax available in Rust nightly Author : dagenix Score : 370 points Date : 2020-06-09 14:10 UTC (8 hours ago) (HTM) web link (blog.rust-lang.org) (TXT) w3m dump (blog.rust-lang.org) | m0zg wrote: | Is there anything like https://github.com/herumi/xbyak on the | Rust side? I like this approach a lot for non-tivial high | performance work since it lets you tweak your assembly for | particular hardware at runtime. | jfkebwjsbx wrote: | Anybody that knows about the RFC and other implementations in C | compilers, why are always "string literal parameters" (quoted | strings) used? | | Wouldn't be nice to have a way to embed other languages without | the need for those quotes everywhere? | | I guess it is meant to avoid complicating the syntax/grammar | reusing the existing macro one? | dathinab wrote: | Yes it adds a lot of complexity on the tokenization level (and | others), potentially requiring some form of contextual | tokenization. | | Scala originally supported "inline" XML but moved it into some | form of compiler plugin you can opt-in to as just having it | enabled had drawbacks even if you don't use any XML... (I don't | remember the exact drawbacks anymore). | Sharlin wrote: | For maximum generality and compatibility, likely. Also note | that this is "just" a macro, not first-class language syntax, | so any non-quoted arguments would have to be valid Rust token | trees. | est31 wrote: | > any non-quoted arguments would have to be valid Rust token | trees. | | Token trees allow a very wide set of syntaxes. rust-c for | example allows you to embed inline C code as token tree via a | macro: https://github.com/lemonrock/rust-c | [deleted] | kevincox wrote: | Yes, Rust macros have certain syntax requirements that allow | the code to parse without knowing what a macro does (and to | find out where a macro ends). Don't quote me but there are some | token requirements as well as balanced parenthesis. If you | allow another language to be inserted raw you risk that it | requires syntax that would break these requirements. | | Buy using a raw string literal you have a well defined quoting | syntax mediating the two languages. | geofft wrote: | It means that a parser for Rust doesn't also have to be a | parser for every embedded language - which is particularly | important for things like syntax highlighters in text editors | or HTML renderers or whatever. | | For example, in most languages including Rust, parentheses are | balanced as a rule, but they might not be in some inner | language. So if you want to define a syntax where you can say | inner_language!( smiley = :-) ); | | while you can certainly write a parser that understands what's | going on there, any existing Rust parser will get very | confused. So, unless you're confident the inner language is | syntactically compatible (even if it's meaningless) with the | outer language, you'd need to protect it somehow. | | Making the inner language quoted means that existing parsers | that already know how to handle the outer language's string | syntax (where to find the close quote, how close quotes might | be escape, etc.) work seamlessly. You could also define some | other syntax for it, but it's fundamentally the same | requirement - it's a well-defined open and close syntax - and | most other syntaxes end up uglier (think of <script>//<!-- ... | //--></script or <script>//<![CDATA[ ... //]]></script> in | HTML/XHTML.) | | And there's nothing preventing a particularly clever parser | from recognizing the asm! macro specifically and syntax- | highlighting (or otherwise tokenizing/processing/etc.) the text | inside, if it wants to. | [deleted] | klyrs wrote: | Zig has a nice solution for that: | | https://ziglang.org/documentation/master/#Global-Assembly | | The "magic" being that lines beginning with double-backslashes | are string literals. | masklinn wrote: | That's a solution in none of the ways GP asks about. It's | just a different syntax for a string literal, the entire | point of the original comment is _why string literals_. | | > The "magic" being that lines beginning with double- | backslashes are string literals. | | So... strictly worse than rust which allows linebreaks inside | string literals, and thus only require a dquote before and | one after the entire block instead of a two-char prefix | before each line? | jcranmer wrote: | In principle, you can embed languages without the need for | strings. However, when you do so, you need to worry about the | tokenization of languages to see that a) they combine in a | sensible way and b) tools won't get confused if they don't | understand the sub-language (this is a real issue that cropped | with XHTML and JS). | | In practice, inline assembly has pretty much been seen as a | "paste this text into the generated assembly of the program, | after substituting some values determined by register | allocation"--in other words, it's a pretty natural string | formatting problem, and describing the language like you would | a formatted string is a natural step to take. | | Another point to make is that assembly languages are wildly | divergent in their actual syntax. ARM uses # to denote | literals, x86 (Intel syntax) uses # to denote comments. | mhh__ wrote: | It saves time (there also isn't a single ground truth for | parsing assembler) | | https://dlang.org/spec/iasm.html | | No quotes required | mhh__ wrote: | I don't understand (I do actually but it's not that much work) | why so few languages do what D does and actually have inline | assembly as a fully supported (no quotes) syntactic construct | within the language | cowboysauce wrote: | > I do actually but it's not that much work | | It apparently is, given that D only supports x86 assembly, | doesn't support all instructions and has idiosyncrasies like | requiring prefixes to be written as separate instructions. | mhh__ wrote: | D only has about <20 people working on it at a given time. | Some languages probably have at least a hundred times that | number. | artursapek wrote: | If I wanted to learn assembly language in 2020, what's the best | book or resource people would recommend? | thomspoon wrote: | Imo there's not really a best book or resource other than | buying a microcontroller and doing it yourself! Pick up a ARM | Cortex-M4 development board either from TI or STM and | reimplement their example code or driver code in assembly! You | can look at the ISA to see what assembly instructions are | supported, or the disassembly of a running program (probably | with no optimizations so you can see what they are doing) | jagger27 wrote: | There's definitely something to be said about poking a | physical pin in assembly. It makes me feel like I actually | have control of the computer, and that I'm not just along for | the ride. | ethagnawl wrote: | https://famicom.party features the best, most accessible 6502 | assembly crash course I've yet to come across. | | It does strike me as weird that there aren't any popular | resources that sit between something as high-level as the | linked e-book and something as low-level as "buy some hardware | and figure it out". | mywittyname wrote: | I suspect this has to do with Intel architecture not being | very beginner friendly. When I tried learning x86 assembly, I | found it to be incredibly overwhelming. | | There are simulators for teaching assembly, but I don't think | those are nearly as fulfilling as hacking on real hardware. | And since it's difficult to hack on your computer's hardware, | you're left pickup up something more simple. | adamnemecek wrote: | I really like "Introduction to 64 Bit Assembly Programming for | Linux and OS X: For Linux and OS X" by Ray Seyfarth. It's short | and you actually implement something interesting like the | correlation function or basic data structures, like linked | list. | JoeAltmaier wrote: | Always tricky. I avoid inline assembler, except in cases where | the compiler cannot generate some special instruction. This can | occur in drivers and kernel code, where there's no other language | feature to manipulate processor architecture (special registers | or machine state manipulation). | | It can be fun to try and hand-optimize code in regular | applications. I can't help but feel, there's more juice in | teaching the compiler to recognize the case and generate better | code instead. But few know how to go down that road. | [deleted] | Bedon292 wrote: | I am super new to Rust and maybe not the best place to ask, but | why would you want to use inline assembly in Rust at all? Does | that not invalidate a lot of the safety features built into the | language? | oconnor663 wrote: | There are some places where you have to use assembly | instructions: | | - Operating systems. For example, the voodoo that happens | during early boot, where you need to walk the CPU through | different modes. And also fundamental kernel stuff like mapping | memory. | | - Cryptography. Crypto code is often hand-written in assembly | for efficiency. (Sometimes it's even the other way around: | crypto algorithms may be designed with specific machine | instructions in mind.) Also there are places where you have to | guarantee that some operation happens in constant time, which | is hard to do when a compiler may choose to insert branches or | jumps without telling you. | | To compete with C in those spaces, Rust will need inline | assembly features. | | As far as safety is concerned, yes, inline assembly is | completely unsafe. In that sense, it's not so different from | calling functions in the C standard library (or any other C | library), which might do absolutely anything with your memory. | In all of these cases, the Rust programmer has to use the | `unsafe` keyword, and it's up to them to make sure that Rust's | rules are still respected after the unsafe code has run. Doing | this properly, and wrapping it all in a safe Rust API, means | that other safe code can then use your library without the | `unsafe` keyword and without any risk of triggering undefined | behavior. | mywittyname wrote: | > - Operating systems. For example, the voodoo that happens | during early boot, | | Isn't every system call an assembly instruction? Not just the | voodoo stuff? | | My only experience with "real" assembly was my OS class in | college, in which a project we had involved adding system | calls to Linux, and they were all snippets of assembly code | called in C. | DSMan195276 wrote: | Yes, generally speaking you need inline assembly to execute | whatever architecture-specific instruction is used to enter | the kernel (`int 0x80`, `syscall`, `swi`, etc.). And in the | kernel you need inline assembly for other various | architecture-specific instructions so you can execute them | as part of your regular code instead of having to write | them in a separate assembly file. | | For the weirder cases like right after boot or handling an | interrupt you generally just have to go full assembly for | that, since in general you're not started out in a state | where you can just start running your typical C/Rust/etc. | code. It depends heavily on your platform at that point | though. | codys wrote: | "safely abstracting `unsafe`" is the important concept with | respect to rust and it's use of `unsafe`. | | `unsafe` occurs in rust source code where the author of some | code needs to do things in a way that can't be directly proven | to the compiler to be safe. These include things like calling C | functions and ASM code (both cases where we can't infer all the | information necessary to ensure safety). The author of the | unsafe code then provides an "safe" abstraction around the | unsafety that ensures that when one uses the "safe" interface, | no undefined behavior occurs. | | At the lowest level there is always some unsafety: system | calls, libc function invocations, asm, modifying various memory | mapped registers. What rust provides vs C or C++ is effective | isolation of the unsafety. | [deleted] | metalliqaz wrote: | If you have a large-ish project that is otherwise coded in | Rust, but you have to do some low-level coding because of | special I/O, or special intrinsic features for multimedia, or | even just flat-out performance, then this allows you to do so | without falling back on linking against ASM or C. | learc83 wrote: | Rust wants to be a serious contender for low level and embedded | code. In those spaces sometimes you don't have much of a choice | but to drop down into assembly. | woodruffw wrote: | Rust has lots of unsafe features; they all require explicit | `unsafe {}` blocks. | | As the post mentions, inline assembly comes in handy in a | number of low level contexts (e.g. dealing with memory-mapped | devices, working on microcontrollers, using processor features | that aren't exposed by the kernel or standard library). | masklinn wrote: | > e.g. dealing with memory-mapped devices, working on | microcontrollers, using processor features that aren't | exposed by the kernel or standard library | | Or kernel features not exposed by the libc. | gizmo385 wrote: | > using processor features that aren't exposed by the kernel | or standard library). | | As someone who doesn't do any low-level work, could you give | an example of these kinds of features? I'd like to read into | some of them :) | neutronicus wrote: | Some processors implement "Instruction Level Parallelism" | where you can do arithmetic on many values simultaneously | with special assembly instructions. | | The most widespread cases of this (SSE, AVX2) came from | Intel trying to get lock-in in the high-performance | computing market. So it took a while for AMD to sell chips | that implemented these instructions and even Intel's | catalog doesn't uniformly offer them. | | It's also tough to get the compiler to emit these | instructions where you want even if it knows they're | available (unsurprisingly, since you're asking it to auto | parallelize a computation), so in the high-performance | space a lot of people just have to resort to inline | assembly. | jlokier wrote: | Just a minor terminology point. Instruction Level | Parallelism (ILP) means something else. | | What you are describing, with special instructions, is | called Single Instruction Multiple Data (SIMD), or simply | vector instructions. | | ILP means the execution of multiple separate instructions | in parallel per clock cycle, though techniques like | superscalar, out-of-order and speculative execution. ILP | is sometimes used as a measure: How many instructions per | cycle can be issued. It does not require special | instructions, it's just the hardware being clever about | running existing instructions faster. | neutronicus wrote: | Ah, we used that wrong in my old group then. | | We talked about Instruction Level Parallelism vs. Thread | Level Parallelism vs. Node Level Parallelism since | generally if you are working on a problem with some data | dependency you will really have to think about each | separately to get the best performance. | masklinn wrote: | This sort of instructions you often have intrinsics for | though. | neutronicus wrote: | Ah, yeah, in my head I tend to conflate intrinsics and | inline assembly | woodruffw wrote: | My go-to example of this is CPU-level virtualization | support, like AMD-V or VT-x. | | Some C/C++ compilers will expose these instructions as | intrinsics, but AFAIK Rust doesn't. | JoshTriplett wrote: | Moving into or out of a control register, such as to enable | a processor feature. Disabling or enabling interrupts. | Reading or writing model-specific registers. Saving | registers, switching stacks, and calling another function, | then switching back and restoring registers when the | function returns. Initializing and using hardware | virtualization features (e.g. Intel VT). Using features | like SMAP (preventing accidental access from the kernel to | user memory through a wild pointer, temporary enabling it | in careful dedicated routines like copy_from_user and | copy_to_user). Making raw system calls from userspace. | fluffything wrote: | Just take any operating systems course and try to implement | your own. | | Or try to program a micro-controler "hello world" that | actuates an LED ? | masklinn wrote: | Aren't those _usually_ MMIO? | AndrewGaspar wrote: | I used inline assembly once when playing around with Rust | on GPUs to get Cuda's implicit thread ID and grid ID: | https://docs.nvidia.com/cuda/parallel-thread- | execution/index... | dmytrish wrote: | Embedded/systems programming is not possible without dropping | to assembly at times. Also, it can unlock some hardware- | specific performance optimizations. | | Rust already has unsafe blocks (explicitly marked `unsafe`) for | this kind of situations. Inline assembly obviously is allowed | only in unsafe contexts and should be used very carefully. | jfkebwjsbx wrote: | Yes, but low-level programming implies direct access to memory | and instructions. | | Rust is not designed for memory safety _only_. If you only want | that, there are other simpler options, like any functional, | scripting or managed language. Instead, Rust is designed to | bring as much memory safety as possible (but not more!) to the | low-level and performance fields. | neutronicus wrote: | Because ultimately Rust wants to be a C++ replacement and you | can't do that if you don't let people who know what they're | doing opt into inline assembly and raw pointers. | amluto wrote: | Rust folks, thank you so much for making this far, far better | than GCC's asm syntax for C. Also, thank you for using Intel x86 | syntax instead of AT&T. | | It would be delightful if GCC were to adopt something similar | after this stabilizes in Rust. | pjmlp wrote: | Still fails short of asm code blocks of PC based languages. | FpUser wrote: | Second that. Very simple example: function | MultiplyBy2Reg(aInput: int64): int64 assembler | register; asm SHL RAX, 1; end; | function MultiplyBy2(aInput: int64): int64 assembler; | asm mov RAX, aInput; SHL RAX, 1; end; | simias wrote: | Now I need to port that code to MIPS, what do? | | This is a very nice feature to have if you know your | environment is overwhelmingly tied to a certain | architecture and you want to make it easy to target this | architecture in particular. | | This might actually be a somewhat reasonable, if short- | sighted approach if we were in 2005 and you could make the | point that anything that's not x86 is effectively legacy or | niche but nowadays you need to at the very least support | x86-64, ARM32 and AARCH64. Baking all these flavors of | assembly into a language would be very heavy handed and a | maintenance nightmare. | | Beyond that we're not in the 90's anymore, ASM is not | routinely used outside of very low level code these days. | Even for performance people often opt for intrinsics | instead. Compilers got massively better at optimizing code | while humans got worse due to ever more complex | architectures. | | Being able to seamlessly blend ASM with normal code isn't | that much of a killer feature anymore IMO. It would be a | costly gimmick to implement. | FpUser wrote: | ifdef is your friend. used everywhere | pjmlp wrote: | It is Assembly after all, just use conditional | compilation. | systems wrote: | what are PC based languages ? what is PC short for in this | context | pjmlp wrote: | MS-DOS/Windows heritage. | | Modula-2, Pascal, C, C++, Basic based compilers with inline | Assembly parsers or intrisics that interact with host | language type system instead of manually dealing with | strings UNIX style. | dathinab wrote: | But in rust asm! _does_ interact with the type system. | | The asm macro does know about what group of registers (or | what specific register) a input/output is stored/loaded | from and compilation will fail if the input isn't | compatible with the register. | | Then it's delegating to a assembler for the rest. | | Sure it could also have a list of all asm commands the | given target does support and parameters/registers it can | be used with but this means keeping track of all | supported targets and all commands for all potential | featuresets of all targets and all way they can be | called. This is a lot of work. Even more such support can | be added later one, too. For now it's more important to | support asm on stable. | | Also with proc-macros you can implement this as a library | on top of `asm`! | | Also with a more "knowledgeable" asm any support for a | new platform would need to manually add support for all | asm of that language so having a standard stringly | interface is a good think anyway. | jfkebwjsbx wrote: | What you describe is how it works in GCC/LLVM and is | required in any inline asm system. Otherwise it is not | really inline. | | Saying that fits with the type system is a stretch... it | is like any other FFI. | Rusky wrote: | The use of strings in Rust's implementation is limited to | the assembly template and the operand constraints. | Functionally speaking, moving those out of strings gains | you absolutely nothing and can make parsing more | difficult. | | The important part, type system integration, is already | there. Sizes must match, move and borrow checking still | happens, etc. This avoids the typical failure modes of | unix-like stringly-typed systems. In fact if you read the | announcement and RFC, you'll see that this was a primary | goal of the new design! | simias wrote: | I've followed the discussion regarding how ASM should be | integrated in Rust over the past few years, the idea of | integrating the ASM syntax more tightly with Rust has been | brought up. Basically one could treat assembly as an ad-hoc | domain specific language with its own parsing rules that | would make it more like a first class citizen instead of a | magical character string. I've actually implemented a very | simplistic MIPS assembler in a similar way for emulation | purposes: https://github.com/simias/rustation/blob/master/src | /parallel... | | I think they were absolutely right not to go down that route, | because then you have to basically specify this syntax for | every possible architecture targeted by Rust. Integrating ASM | in the language syntax is fine if you only care about x86, | but it's going to be a mess if you want to support MIPS, | ARM32, AARCH64, Sparc and whatnot because the ASM dialects | for each of these architectures have special bespoke syntax | to deal with various quirks of the underlying ISA. MIPS has | special syntax to load the top and bottom half of an address | as well as dealing with delay slots (.noreorder), ARM has | special sugar for PC-relative addressing etc... | | Importing that baggage into Rust would be a fool's errand | IMO. It would also make it harder both to port Rust to new | architectures _and_ to transfer existing assembly code into | Rust since it would require adjusting the syntax. | | I'm very happy with Rust's current approach, it's a good | middle ground IMO. | JoshTriplett wrote: | > Also, thank you for using Intel x86 syntax instead of AT&T. | | Thank you for helping to validate that decision; this is the | kind of feedback we needed. | | (And note that you can still choose to use AT&T syntax, it just | isn't the default.) | mzs wrote: | I prefer AT&T, thank you for the option. | jdright wrote: | Yes, thank you for the Intel syntax. It is by far the most | frequent syntax you'll find anywhere somewhat recent (1990+) | and it is by far the most straightforward to learn by being | clean. I did learn both in the 90s, but I've always struggled | with AT&T symbols and different offerings which to me was | hard to switch to when learning from different material | sources. | exmadscientist wrote: | If you're ever in doubt on which syntax to implement first or | make default, just look at the processor manual (TRM). Match | it, and you'll have an ironclad defense :) | JoshTriplett wrote: | That was one of our primary justifications. The tradeoff | was between that and what's currently widely used with GCC | and clang; the latter (along with people porting from | what's now called llvm_asm!) motivated us adding the | att_syntax option. | binarycrusader wrote: | Yes, this is great, but I have to disagree on the Intel x86 | syntax assertion by the original poster. Perhaps it's because | of the era I grew up in and how I first learned machine | language and then assembly language, but I've always | preferred AT&T syntax. Regardless thanks for supporting the | saner syntax even if it's not by default ;) | josephcsible wrote: | Is AT&T syntax really that bad? In particular, it's way nicer | for specifying operand sizes. I'd prefer "andl $3, (%eax)" any | day over "and DWORD PTR [eax], 3". | dmytrish wrote: | I subjectively like AT&T syntax more (as a more familiar to | me and having more "machine" vibe). | | However, I recognize that it's objectively worse for a human | coder and contains some syntactic footguns which shoot even a | experienced coder regularly: | | - `number` (memory displacement/pointer) used instead of | literal `$number`. It's an easy automatic mistake even for a | person who knows this very well. | | - the SIB clauses for x86 (memory addressing with constant | Displacement and Scale and Index, Base in registers) look | like `D(B, I, S)`: it's possible to remember this, but | reading/writing it is not as obvious as `[D + B + I * S]`. | | - Intel syntax in general is more similar to high-level | languages, even though it's more verbose. | | - AT&T syntax has syntactic redundancies like '%' before each | register which make code much noisier than needed. | pwdisswordfish2 wrote: | % before register names isn't redundant: it allows you to | refer to symbols that would otherwise have the same | spelling as register names. | dmytrish wrote: | Yes, that's where AT&T is more logical. | | In practice, though, naming a symbol with a register name | is error-prone and confusing. I'd rather have a way to | escape a symbol when it's really needed than to pay the | price of noise for an admittedly bad idea. | cesarb wrote: | New registers are added all the time (for instance, the | %zmm registers), so even if a symbol name doesn't | conflict now, it might conflict in the future. Having | separate namespaces for symbols and registers is a good | idea. | hyperman1 wrote: | The intel syntax has some nice gotchas though as the scale | can be 1. I believe there is [eax+ebp] which uses the ds | segment, but [ebp+eax] uses ss. | exmadscientist wrote: | The really fun bit is when you explicitly want to force | one form or other, for some reason. Usually this is | related to instruction length, but occasionally you used | to run into times when one form could help avoid a stall. | | Keeping tricks like that stable and clearly documented | is, uh, not for the faint of heart. | fluffything wrote: | The problem is not whether its bad or not, but rather, having | to learn a completely-different second syntax for one | architecture. | | Most Rust code is quite portable, targeting ARM, x86, MIPS, | PPC, WASM, Sparc, s390x, riscv, ... That means, that for many | snippets of inline assembly, you might encounter ~8 of them, | one for each architecture, all using different syntaxes. | | Intel syntax is quite similar to that of other popular | architectures `op dst, args...`. | | Adding another second syntax for x86 just doesn't add that | much value IMO, and adds quite a bit of cost: now everybody | dealing with x86 assembly needs to learn 2 syntaxes... and | everybody dealing with portable code now needs to be at least | able to read 2 syntaxes for x86... Without talking about the | cost of implementing a second syntax in the compiler, etc. | | If you prefer AT&T, you can always write a proc macro that | translates it to Intel, and use that in your projects. | | If I ever need to deal with such code, I'd just expand the | macro to read the actual Intel syntax, modify that, and | either fork the project, or submit a patch with a fix using | Intel syntax. | amluto wrote: | I have two big reasons for preferring Intel syntax: | | 1. It's the syntax in the manual. The last thing I want to | do when reading or writing asm is to mentally translate | from the manual to AT&T syntax. | | 2. Addressing like (%rax) is tolerably. But the AT&T scale | * index + offset syntax is inexcusable. Give me the verbose | Intel addressing syntax any day, please. | | (As a kernel programmer, I'm more familiar with AT&T. I | _still_ hate it. I'm morbidly curious how Intel syntax | ought to handle things like SGDT. Maybe SGDT SIXBYTE PTR | [address]? The fact that four bytes is called a DWORD isn't | great.) | jlebar wrote: | > 1. It's the syntax in the manual. The last thing I want | to do when reading or writing asm is to mentally | translate from the manual to AT&T syntax. | | Right! I worked on C++ compilers for years and I don't | even know where is the canonical book of AT&T mnemonics. | At the rate that Intel is adding new instructions, using | anything other than their official docs (and thus their | official names) seems nuts. | jfkebwjsbx wrote: | AT&T syntax is actually the common one in most low-level | programming if you count by architectures and most likely | also by code size produced, if only because GCC has/had | been the de facto compiler for new chip uarchs for more | than a decade (helped by the fact that everyone wants their | chips to run Linux). | | Nowadays GCC and LLVM support both styles and archs pick | whatever they prefer and nobody cares, really. | | > either fork the project, or submit a patch with a fix | using Intel syntax. | | That sounds a bit extreme? Reading/writing in both styles | is not an issue for anyone that has dealt with x86 | professionally. | oblio wrote: | And apparently Rust already supports both. | exmadscientist wrote: | >AT&T syntax is actually the common one in most low-level | programming | | Is this actually true? Admittedly I've done mostly x86 | and ARM for the past several years (almost entirely | Cortex-M, so v6-M and v7-M profiles, using ARM's GCC | builds for embedded) and the only toolchain that prefers | AT&T syntax is x86 GCC and those explicitly trying to be | compatible with it. All the ARM inline assembly I've | written, targetting GCC backends, has been ARM syntax, | and likewise for all the disassembly output. | | The DSPs and DSP-likes are... always weird. So I try to | stay away from them and make them someone else's problem. | But I don't think they use AT&T syntax either. It doesn't | work so well for truly strange processors anyway. | | I'm one of those guys who tends to have the makefiles | output the disassembly, and have it open on the other | monitor while I'm working, so I'd notice if it were | different.... | JoshTriplett wrote: | > If you prefer AT&T, you can always write a proc macro | that translates it to Intel, and use that in your projects. | | If you prefer AT&T (or you have a large body of existing | AT&T code you don't want to have to translate all at once), | use asm!("...", options(att_syntax)) and it'll Just Work. | rectang wrote: | They're both terrible. :( I yearn for a more ergonomic | assembler. | | That's not to say that the Rust team should have tried to | find (or create) an alternative; it's outside their core | mission, and choosing between popular existing alternatives | is the right framing. | simias wrote: | I agree. They took their time but was worth it. I really missed | not having had ASM is stable Rust the past few years but since | it means not having to deal with something as horrendous as | GCC's __asm__ syntax I'm glad they took their time. | bobly_today wrote: | As someone who only knows at&t syntax I guess I should view | this is an opportunity to learn intel syntax | Teknoman117 wrote: | To be honest, I still like the explicit cobber syntax of | rusty_asm. | | Last year I had some fun getting a rust program to run on some | old 386 DOS SBC I had hanging around. Was terrible in terms of | code density (basically a bunch of 32 bit instructions prefixed | with the "execute 32 bit op in real mode" prefix). | | This was a wrapper around the DOS string print function (where s | is a &str). rusty_asm! { | let ptr: in("{dx}") = s.as_ptr(); let len: | in("{cx}") = s.len(); clobber("ah"); | clobber("al"); clobber("bx"); | asm("volatile", "intel") { "mov ah, 0x40 | xor bx, bx int 21h" } | } | JoshTriplett wrote: | In the new syntax, a direct translation of that would look | something like this: asm!(" mov | ah, 0x40 xor bx, bx int 21h | ", in("dx") s.as_ptr(), in("cx") | s.len(), out("ax") _, out("bx") _, | ) | | However, I'd personally write that like this instead: | asm!( "int 21h", inout("ax") 0x4000 => | _, inout("bx") 0 => _, inout("cx") | s.len() => _, inout("dx") s.as_ptr() => _, | ) | | That lets the compiler handle filling in ax and bx, and also | avoids trusting that the interrupt routine leaves ax/bx/cx/dx | untouched. (I might also write clobbers for every other | general-purpose register, too. Take a look at Linux | arch/x86/boot/bioscall.S and the "Glove box" for BIOS calls, | due to misbehaving BIOSes that clobber registers they | shouldn't.) | Teknoman117 wrote: | Thanks! The latter of the two is definitely nice. Yeah, I | should've let the compiler setup ax and bx. Again, this was a | hack :) | livre wrote: | I may be the only one but I feel like this (and the old) asm | syntax is too complex and not very user friendly. It looks | heavily inspired GCC. I'm sorry for the upcoming German (you can | ignore it and just read the examples), I feel like a smarter | compiler could have a friendlier asm syntax, similar to the one | used by FreeBASIC[1]. | | I hope you can see why I prefer that. Even though the FB compiler | is not very smart and just pushes and pops all important regs to | and from the stack its asm syntax is a joy to write. I don't have | to specify clobber registers, in, out and variables and functions | are in scope by default. Also the asm code is not a string and | doesn't need to be quoted, it's doesn't look like something | foreign at all. | | I know that something like that is currently not possible in Rust | but I'd love to see it some day. | | [1] https://www.freebasic-portal.de/befehlsreferenz/inline- | assem... | jcranmer wrote: | You can track some of the history of the proposals here: | https://github.com/rust-lang/rust/issues/29722. | | A lot of the improvements you've suggested have been suggested | in the past, but there's some reasons why they aren't being | proposed. In short, sufficiently smart compilers can probably | guess at a lot of constraints automatically, but building that | level of smarts is very daunting, and for most use cases, the | user probably wants/needs the fine-grained control anyways. | | For example, take the call instruction. Which registers should | the compiler mark that as using and/or clobbering? It depends | on the ABI of the function being called--and the user might not | even be calling a function at all (say, using a call as a | gadget to get the current program counter). Saving a register | is another common technique in inline assembly, and you don't | want the compiler to infer that the register is clobbered-- | indeed you're saving it to explicitly not clobber it. | fluffything wrote: | > I don't have to specify clobber registers, | | So how does the compiler know that these are clobbered then ? | masklinn wrote: | I expect the entire assembly is encoded into the language. | livre wrote: | Not really, the other reply is right. Most registers are | clobbered. FreeBASIC only passes the asm code inside the | asm block directly to GAS (using the .intel_syntax noprefix | directive). As I said, the compiler is too dumb to figure | out what registers are being used so as a safety measure it | clobbers almost all of them (see Register Preservation | here[1]). | | [1] https://documentation.help/FreeBASIC/KeyPgAsm.html | int_19h wrote: | That doesn't really help - the compiler doesn't know what | could be clobbered by any given (sys)call. | cesarb wrote: | Since the parent comment said "just pushes and pops all | important regs", it probably assumes that all registers are | clobbered. | zozbot234 wrote: | > I feel like a smarter compiler could have a friendlier asm | syntax, similar to the one used by FreeBASIC[1]. | | Feel free to propose a better syntax, then. This feature is not | yet part of Stable Rust, so syntax improvements are very much | possible. | | The FreeBASIC syntax seems problematic though, since it would | require architecture-specific smarts in the compiler and make | it hard to port it to different architectures or add support | for newer asm features. It might be better to have these | additional features as separate tooling or crates, that might | even wrap the asm! syntax itself via proc macros. | livre wrote: | Sadly I think Rust's way is the best one in the long term | even if it's not very user friendly. There are a lot of | problems with the FreeBASIC syntax, my comment was mostly | wishful thinking. As other user has said in a reply to my | comment, you can't beat the level of control Rust's syntax | provides and that's what most people writing assembly would | want. You are also right that a proper asm parser would be | difficult to maintain due to the amount of architectures Rust | has to support. | dathinab wrote: | Yes, I mean we shouldn't forget that asm today is a last | resort escape hatch which should be avoided if possible. | | EDIT: Just to be clear it's still important. But it's | mainly used for a view "very high control" use cases. | fluffything wrote: | Notice that you can quite easily implement a Rust proc | macro that takes whatever DSL you want to use for inline | assembly, and generates an `asm!` expression from it. | | So better syntaxes are possible, as long as they can be | built on top of the proposed inline-assembly feature. | | They can, however, just be implemented as normal Rust | libraries, and do not need to be part of the compiler. | rwmj wrote: | The problem with baking the asm syntax into the language is | that it can make it really hard to use new / obscure | instructions. And yet that is often the only reason to use | inline asm in the first place, because you need some specific | CPU feature which the language you're using doesn't expose. | MintelIE wrote: | Is Rust ever going to go for standardization? Seems like the | language has been in a state of flux with heavy changes all the | time. When's it going to settle down a bit? | sedatk wrote: | As long as it's backwards compatible, why should that be a | problem? | simias wrote: | Keep in mind that the changes since 1.0 have been with very few | exceptions completely backward compatible. I write a | significant amount of Rust and I don't follow the development | of the language ultra closely anymore, yet it doesn't feel like | I'm coding for a moving target. | | Basically from my point of view the changes are about adding | features (inline ASM in this case, async I/O previously) but it | doesn't really change the way you code, it's just an other tool | in your belt that you may decide to use later. If you didn't | have a need for inline ASM before you still won't be using it, | if you couldn't use Rust previously because of bad ASM support | it opens up new use cases. | mkchoi212 wrote: | This looks a lot better than GCC's asm. However, I can't think of | a good reason why one should use asm in their code instead of | letting the compiler write the far superior asm for you. | fluffything wrote: | Because compilers almost never write better code than humans ? | | There are literally tens of thousands of bugs in the GCC and | LLVM/Clang bug trackers about that. | | I don't remember the last time I read some compiler-generated | asm and thought "wow, that's great code". | yoshuaw wrote: | One example is authoring USDT probes. This is done by writing | inline assembly comments [1] that the kernel can then trace | when instructed to. | | Also people doing cryptography things occasionally need access | to specific ASM instructions for their work. I believe AES has | specialized instructions, but there are more cases. | | You're not wrong that writing inline ASM is a fairly | specialized need, but for those who require it this will come | in incredibly useful. | | [1]: I still need to try using this, so I might be wrong. I was | waiting on inline assembly to be available before trying tho, | so quite excited it's now available. | mkchoi212 wrote: | Yeah true. But doesn't Rust provide an equivalent to C's | intrinsic functions like popcount? | MaulingMonkey wrote: | Yes: | | https://doc.rust-lang.org/core/intrinsics/fn.ctpop.html | | https://doc.rust-lang.org/std/?search=count_ones | | There are still use cases for raw assembly untouched by the | optimizer - e.g. constant time cryptography functions | designed to thwart timing attacks might desire control over | the _exact_ instruction stream. Although, most of that can | be tackled with out-of-line assembly - as one must do with | x64 MSVC for example. | ratww wrote: | Most application developers don't need assembly, but it's still | necessary for the people writing Rust and its stdlib itself, | embedded developers, people writing libraries that use very | specialised optimisations, SIMD, etc. | Twirrim wrote: | Compilers are great, but they don't always produce optimal | code. You can quite often produce faster code if you're | prepared to hand roll the assembly code, but it's rarely | something most people will need to do. The time it takes to | produce often outweighs any advantage you'd get, but having it | as an option is going to be very important. | | Just within the rust world, | https://www.nickwilcox.com/blog/autovec2/ from a few weeks ago | talks about the limitations with the compiler around | vectorisation, demonstrating that with hand-rolled assembly | they were able to cut the runtime in half, vs what the compiler | was able to produce. | | Outside of the rust world, you'll often see hand-rolled | assembly in performance critical code across a spectrum of | uses, e.g. OpenSSL uses it extensively for performance reasons, | Go has it in a number of places in their libraries, with a pure | go fall-back, and so on. | mkchoi212 wrote: | Ah gotcha. I guess I just haven't come across a situation | that calls for hand written ASM yet :p | Twirrim wrote: | I definitely haven't for the things I'm working on. Good | enough is good enough. | | edit: Thinking about it, that's not true. I was dealing | with some hot code running on some MIPS architecture stuff | a while back and the compiler's generated ASM was merely | "okay", for the standard library. Alternative libraries | with hand-rolled ASM ran significantly faster and we were | going to leverage those, when another team came up with | architectural changes that allowed us to take that away | from the MIPS part of the stack. | SAI_Peregrinus wrote: | Sometimes the compiler generates worse ASM (rarely, but it can | happen, especially with vector instructions). Sometimes you | want to use ASM instructions there are no intrinsics for. | Sometimes you want to write some extremely low-level startup | code for an OS or microcontroller and simply need assembly | since the C/Rust/whatever runtime can't operate yet (eg main | memory needs to be initialized). | adwn wrote: | One niche case where you need assembly is if you write a green | threads library. At the yield points, you need to save all | necessary registers of the current thread, and restore the | registers of the thread you're switching to. There's no way you | can do this without assembly, because you a) you need to | control exactly which machine instructions are emitted in which | order, and b) you need to read and write actual registers, not | variables or memory locations. | palmtree3000 wrote: | It's not always superior! | | For example, I've been working on a big integer library. | Addition is a bit annoying, because you need to add 3 numbers | (the prior carry bit, and the two digits you're adding) and get | out a new carry bit and a resulting digit. This is a bit | cumbersome: let (res, carry1) = | target_digit.overflowing_add(carry as u64); let | (res, carry2) = res.overflowing_add(other_digit); | *target_digit = res; carry = carry1 || carry2; | | The resulting assembly is a fairly literal translation. We | perform the addition using an add instruction, and extract the | carry flag into a register using setb. | addq (%rdi,%rsi,8), %rcx setb %r10b | addq (%rdx,%rsi,8), %rcx setb %al | movq %rcx, (%rdi,%rsi,8) orb %r10b, %al | movzbl %al, %eax | | But there's a dedicated instruction for this, adc. adc adds two | operands and the carry flag, while itself setting a carry flag. | Manually unrolling the loop a bit, I wrote this assembly: | shlb $8, {carry} adcq 0x00({y0}), {x0} | adcq 0x08({y0}), {x1} adcq 0x10({y0}), {x2} | adcq 0x18({y0}), {x3} adcq 0x20({y0}), {x4} | adcq 0x28({y0}), {x5} setb {carry} | | And got a 3x speedup. | sethhochberg wrote: | Thanks for this - its been many years since I've done | anything touching assembly, and never outside of an academic | context, so when I read conversations like this I'm always | curious for concrete examples of how people are actually | _using_ this stuff beyond something vague like interacting | with VT-x or working on an experimental OS. | jeffdavis wrote: | The article here: | | https://news.ycombinator.com/item?id=23351007 | | specifically recommends against the carry variants of | addition, because the instructions are still dependent on | each other and don't pipeline well. In other words, it's | using the same algorithm, just buried in a single | instruction, and that doesn't necessarily make it faster. | | Have you considered using a strategy similar to what the | article suggests? I think the HN comments also had some | additional suggestions. | adwn wrote: | > _that doesn 't necessarily make it faster_ | | Did you miss the "And got a 3x speedup" part of the post | you were replying to? Actual benchmarks of real code always | trump theoretical deliberations. | jeffdavis wrote: | Yikes. I was just trying to link to a relevant technique | that the author might find helpful. | | A big integer library may have many use cases; a | benchmark only shows one data point. It's possible that | by deferring carry work across more operations he'd see | an even bigger improvement. | palmtree3000 wrote: | I was briefly very excited when I read that article, | actually. But as devit points out in a sibling comment, | that technique is only relevant to cases where you're | adding more than 2 numbers. | | Multiplication initially seemed like a very promising use | case, since it's basically repeated addition. But I'm not | super optimistic about that, because I think it's dominated | by the alternate optimization of noticing that the product | of two 64 bit numbers cannot saturate the high 64 bits of | the resulting 128 bit number, which causes carries to be | bounded [1]. | | [1] https://github.com/rocurley/bignum/blob/b45448a156fb910 | 0ab06... | devit wrote: | The dependency is unavoidable due to the way addition | works. | | The approach in the article only works if you are adding a | lot of numbers together, and then indeed doing carry | propagation once at the end is obviously faster. | | But of course there is no way that doing the carry | propagation yourself on one addition can possibly be faster | on a decent CPU that implements add-with-carry efficienly. | jeffdavis wrote: | Maybe it's worth considering an interface to a big int | library that can defer carry work across many operations, | and then normalizing at the end? | | That certainly sounds useful for, e.g., totaling an array | of big integers. | secondcoming wrote: | What is Rust's policy for signed/unsigned int overflow? I | assume that it's not modulo or else the complier should have | generated ADC for you. | | I assume you've been using Compiler Explorer a lot? | masklinn wrote: | > What is Rust's policy for signed/unsigned int overflow? | | Defined, by default checked in debug mode and unchecked in | release, unsigned wraps and signed wraps as two's | complement. This can be overridden by explicitly setting | overflow-checks in the relevant profile. | | It also, separately, has explicitly wrapping, saturating | and checking versions of basic arithmetic operations. | palmtree3000 wrote: | overflowing_add, like I was using above, is explicitly | wrapping. | | I've found it very difficult to provoke rustc into emitting | an ADC: the only case where it does so AFAICT is when | adding u128s, which are implemented using u64s. Not sure | why, except that the shortest function I could think of to | emulate ADC is kind of baroque, and it's possible the | compiler can't figure it out. | | I've mostly been using cpuprofiler[1] and Vtune to | simultaneously profile my code and show the assembly. In | theory they both provide timing information per- | instruction, but I don't really trust it. For the 6 adc | instructions above, it shows the number of clock ticks as | ranging from 22 million to 3 billion, which doesn't make | sense to me. But at least it shows me the assembly! | | [1] | https://docs.rs/cpuprofiler/0.0.4/cpuprofiler/index.html | secondcoming wrote: | This will change your life! | | https://godbolt.org/z/fntvYa | xyproto wrote: | You can't explore undocumented CPU instructions, like this guy | is doing: https://youtu.be/jmTwlEh8L7g | open-paren wrote: | I'm new to Rust, so there may be precedent that I don't know, and | I'm kinda spoiled because I'm a front-end dev mainly, where the | rule is "don't break the web", but doesn't changing the syntax of | a macro like that break backwards compatibility? | knome wrote: | > syntax was highly unlikely to ever graduate from nightly to | stable Rust, despite being one of the most requested features. | | I think it's safe to infer from this line that there was not | yet a guarantee of stability in the interface, and that | breaking backwards compatibility was therefore fine. | | >We renamed the existing asm! to llvm_asm! | | They also kept the existing functionality under a different | name to ease transition. Current users will need only update | the macro name and then transition to the better syntax at | their own pace. | SAI_Peregrinus wrote: | Rust has two ways of ensuring forwards compatibility (or | incompatibility): | | The first is the `stable`/`nightly` system. Anything in | `stable` gets compatibility guarantees, anything in `nightly` | can change or be removed at any time. | | Nightly also has feature-gates: using an unstable feature | requires an opt-in to enable it. The old `asm!` syntax which | got renamed was only ever in `nightly`. | | The compatibility guarantees for `stable` are based on | editions: each year there's an edition, your project's | `cargo.toml` specifies which edition your code is for, and | compilers will continue to support old edition code. New | editions might require changes to existing code, but as long as | you don't update the edition in your `cargo.toml` you can | freely update your compiler (to a new stable version) without | worrying about it breaking. You can use crates (packages) from | any edition with any other edition, as long as the compiler is | new enough to support the latest edition used. | amalcon wrote: | To clarify, "unstable" in rust-speak means "You can use this, | but it might completely change or go away, and therefore break | your code." | | You need to deliberately opt in to unstable features, so you | are unlikely to use something like this by accident. | brandur wrote: | Also worth noting that the old syntax was renamed from `asm!` | to `llvm_asm!`. It'll still disappear at some point, but | existing users of the former on nightly have a very easy way | of fixing their build in the meantime. | SpaceNugget wrote: | "don't break the web" type issues are not really applicable to | releases of precompiled languages or applications that ship | their own interpreters and don't load third party content. | | Let's say you are browsing my website. Suddenly, your browser | gets an update and prompts you to re-open the window. My site | no longer displays correctly due to a backward incompatible | change. | | My site is the web and your browser broke it. | | If you use a native app or service I write in rust 1.35 or | whatever and there is a backwards incompatible change in a new | version of rust it has no impact on your use of that app at | all. | dtech wrote: | backwards compatibility is still highly valued. Code no | longer compiling in newer versions of the languages can | create huge churn. | | It's one of the reasons Java is so widely used, you can still | use Java 1.4 libraries in Java 13 and most 1.4 code will keep | working and compiling. | coding_lobster wrote: | >I'm a front-end dev mainly, where the rule is "don't break the | web" | | left-pad flashbacks intensify | whatshisface wrote: | `asm!` never made it out of the nightly builds, so nothing | that's being changed has been released. | dralley wrote: | The important thing in this case is that the previous syntax | was never actually stabilized, and was only available in | nightly releases of the compiler. | | So technically it does break some code, but only code which was | deliberately opting into unstable features with the knowledge | that it may break in the future. | jcranmer wrote: | asm! has been an unstable feature for years, which means a) | it's available only in nightly builds, and b) there is no | guarantee that it will remain backwards-compatible. | | Actually, with regards to asm!, it's been known for a long time | that it was unlikely to be stabilized as-is (being originally a | very thin wrapper around LLVM's inline asm functionality). | Probably nearly everyone who's been relying on inline asm to | make their code work has already been following the effort to | replace asm! with a better version. | twic wrote: | > Probably nearly everyone who's been relying on inline asm | to make their code work has already been following the effort | to replace asm! with a better version | | Except for my colleague who basically says "nah, they'll | never be able to move off the LLVM syntax, the code i'm | writing now will be supported forever". | | Fortunately, we only have a small amount of assembly, so if | we ever do want to upgrade to a version of the compiler which | has dropped support, it won't be a lot of work. | dathinab wrote: | Support will likely not be dropped anytime soon, maybe | never. You just need to rename it to `llvm_asm!`. Through | with `asm!` likely going to be stabilized while `llvm_asm` | never going to be stabilized it might be worthwhile to | switch to the new asm to get of nightly in the future ;=) | gpm wrote: | c) Even on nightly builds you need to put #![feature(asm)] at | the root of your crate to use it. (Likewise for all unstable | features, just replace asm with feature_name.) | trufas wrote: | Every couple years they'll define an edition of a language | (e.g. rust 2015, rust 2018), the idea being that if you choose | to stick to one of them, the latest rust will still compile | your code as long as you tell it what version you're | targetting. | JoshTriplett wrote: | This isn't related to editions; asm was never stable syntax | and couldn't be used in the stable compiler; you could _only_ | use it on nightly and only if you opted in. This new syntax | is something we hope to stabilize eventually. | dathinab wrote: | I recommend reading the RFC. It explains pretty well how it works | and it's readable even for people with only very minimal asm | experience: | | https://github.com/Amanieu/rfcs/blob/inline-asm/text/0000-in... | whatshisface wrote: | Hopefully this will help us get better numerical libraries for | scientific computing. | Q6T46nT668w6i3m wrote: | I hope so too but I'm skeptical. In my opinion, Rust still | needs ergonomic multi-dimensional index expressions and | standardized multi-dimension array traits. I'd love to see (or | join) a scientific working group to help with this. | whatshisface wrote: | That would be amazing, but I would also be satisfied with a | numpy clone. Of course language-level support would be far | better! | Q6T46nT668w6i3m wrote: | I can envision something between the two, e.g. a situation | similar to the Future trait and the various async backends. | adrianN wrote: | The lack of such features did not prevent numerical libraries | in C. | Q6T46nT668w6i3m wrote: | Or Rust (I don't understand your point) | adrianN wrote: | As the topic was inline assembly, I interpreted "better" | as "faster", not "more ergonomic". | devit wrote: | You can use a[(i, j, k)], and also a[i][j][k] for some data | layouts. | | As for multidimensional array traits, you can use | Index<(usize, usize, usize), Output = f32>. | kzrdude wrote: | you can use the syntax `a[[i, j, k]]` too, just for another | example. | jcranmer wrote: | For that sort of code, the value of inline assembly over | compiler intrinsics (and Rust already has stabilized arch- | specific intrinsics for the platforms listed in the current | inline asm proposal) is likely minimal or nonexistent. | pjmlp wrote: | Sadly it is yet another language that follows the UNIX tradition | of not having a proper Assembly parser instead forcing us to play | with strings. | | I guess it leaves PC based languages to have actual inline | Assembly parsers or intrisics. | jerf wrote: | I'm sure someone will be along to provide a wrapper macro or | macros to address that shortly. | | I can see why they would not want to bless a particular syntax | tree or whatever into the core compiler. | gpm wrote: | (Once this is stable) haven't they blessed a particular | syntax tree anyways, since the contents of the "" string is | parsed to a specific syntax tree that will have to remain | stable. The only difference is that that syntax tree is | delimited "<contents>" instead of asm!(<contents>). | Someone1234 wrote: | If you want the outer language to be cross platform (e.g. x64, | ARM64, etc), then you'd either need a parser for every | potential platform (even ones you aren't currently using!) OR | you just settle for strings. | | Don't get me wrong: Parsed assembly is superior because you can | have certain parser guarantees/checks. But it will definitely | limit the scope of your language or at least slow its adoption | to new platforms. | pjmlp wrote: | Productivity of language users vs compiler developers. | Someone1234 wrote: | Productivity of a niche area. | | But related: There's no reason parsers cannot be | externalized and inject the resultant assembly strings into | the Rust solution. If that's really what people want. The | nice thing about external parsers is that they become | optional in every sense. | | If the Rust team builds them in, then every supported | platform needs support, every development environment needs | every parser, and tooling also has to support it (e.g. | IDEs, code checkers, etc). | | It isn't simply just adding it once and leaving it forever, | the work is repeated several times over and the maintenance | will be time-consuming for what is: A niche feature. | pjmlp wrote: | Better not starting talking about niche in regards to | Rust, unless adoption of a niche systems language isn't | something to care about. | | Productivity matters everywhere, systems languages that | care about happy programmers have better chances of long | term adoption. | yazaddaruvala wrote: | It seems reasonable, but we need to not conflate niche | with lacking-popularity (i.e. low usage). | | Niche is about the environment, i.e. the problem domain. | | Analogy to biology/ecology, grazing on mountain tops is a | niche that is also unpopular (i.e. low usage), meanwhile | pollination is a niche that is popular. | | The problem domain for Rust to be useful is very large, | across the programming ecosystem and across the | programming ecosystem effort is put into increase | accessibility for the less and less experienced (e.g. | embedded, wasm, webservers, clis, etc). However, Rust | _might_ currently lack popularity (i.e. low usage). | | The problem domain for Inline Asm to be useful is very | small, typically by experts in narrow domains and across | the programming ecosystem effort is put into decrease the | need for inline asm (e.g. crypto, firmware, drivers, | etc). It also happens to be unpopular, and is avoided as | much as possible. | | Summary, Rust is pragmatically niche, rather than | theoretically niche, Inline Asm is theoretically niche, | and also pragmatically niche. | Someone1234 wrote: | That's a pretty shallow argument, one that can literally | be re-used verbatim to argue for any and every | feature/philosophy. Particularly when "happy" is as | subjective as this. | | It also ignores the reality that the Rust team's time is | finite, and if they invest it into three or more assembly | parsers then they aren't investing it into other areas of | the language that could _also_ be productivity | multipliers. Areas that more programmers actually use. | | Ultimately how much is unsafe assembly in Rust going to | be used? And how large are those code sections? And are | you better off creating Assembly in existing dedicated | tooling and importing it, even if Rust had native parsers | (e.g. due to better debugging/visualization elsewhere)? | | Honestly if Rust code outside of standard libraries ends | up with a ton of assembly anyway then that's a weakness | of Rust. You should be using as little as possible. Even | unsafe Rust is superior to assembly because it is | platform agnostic. I'd go as far as to call it a "last | resort." | alharith wrote: | There are infinitely more language users. I'd rather throw | a bone to the compiler developers. | AnIdiotOnTheNet wrote: | Then that means there is infinitely more productivity to | be gained catering to the language users. | pjmlp wrote: | One more reason to actually care about the productivity | of language users. | | They are free to go elsewhere more welcoming. | zamalek wrote: | I really don't like the strings (because Rust is so good at | avoiding things like this), but your explanation makes tons | of sense. | | That being said, it wouldn't be hard to create an asm_x86! | macro that hides the string. | kzrdude wrote: | Strings can be parsed. The rust compiler parses format strings, | for example. | newacct583 wrote: | It's not "PC based" that's the magic you want, it's the | assumption of x86 (and, very recently, sorta, ARM, in a few | compilers). | | Architectures are weird, assembly is crazy. There just isn't | going to be a single set of semantics around what you want. | | This Rust thing isn't revolutionary, it's indeed just a | prettier way of writing the model GCC invented a few decades | back: | | + "Assembly" is a black box for the code author. | | + The compiler's job is generating code _around_ the assembly, | not the code itself. | | + So the fundamental model is "constraints": the rules the | compiler needs to follow before and after the assembly, and how | to emit an appropriate string to represent the | register/address/immediate/whatever requested by the assembly | code. | | And like it or not, this works. It works really well. | Generations of OSes have been written in this model without | much complaint (beyond the general ugliness of the gcc syntax, | which Rust is trying to fix). | | I think this is fine. I agree it's not going to bring a | revolution, but we really don't want one in this space. | pjmlp wrote: | GCC did not invent anything, that dumb approach to inline | Assembly is traditional in UNIX environments. | | Amiga and Atari also had similar inline Assembly support. | not2b wrote: | GCC doesn't implement the "dumb approach" that existed | before it, and that Amiga and Atari originally had. The GCC | approach provides enough information to the compiler that | code can be optimized in the presence of inline assembly; | the compiler is informed of what the assembler code reads | and writes, and can allocate registers for it. It was much | more flexible than the implementation in the original Unix | compiler. | newacct583 wrote: | I still think you're missing the point. GCC indeed didn't | invent "inline assembly as a string", no. | | GCC invented "constraint metalanguage as the foundation for | inline assembly generation", which is the model here that | enables one compiler and one syntax to work the same way | for basically every architecture over decades. Modelling | the interior of the assembly code as a black box (which in | this implementation means "string") is just a side effect | of this important design choice. | | Again, the stuff you're imagining isn't a general purpose | assembly language model, it's an _x86-specific hack_ that | works only on the specific compilers and architectures for | which it was targeted. | pjmlp wrote: | Except that compilers with inline Assembly also don't | have dumb backends that just dump Assembly for as, like | on UNIX. | | They interact with the backend. | | They weren't specific of x86, although I mentioned only | PC, they were available across all 8 and 16 bit home | computers and several embedded targets support it as | well. | patrec wrote: | Are you aware of PeachPy? It's the only (Intel) assembler I | have ever seen I liked. | jcranmer wrote: | Microsoft declined to extend its inline assembly syntax to | support x64 or ARM-based processors. | | If you want to use a single specific instruction or two, it's | usually better to just use the compiler's intrinsics (Rust has | already stabilized the x86 SSE and AVX intrinsics) than inline | assembly. When you go to more complex assembly fragments, you | tend to need more control over how the inline assembly fragment | interacts with scheduling and the register allocator, and | making that control work ergonomically is that much more | challenging. | [deleted] ___________________________________________________________________ (page generated 2020-06-09 23:00 UTC)