8 ms·
Notes on Type Layouts and ABIs in Rust
- zozbot234 7y agoI'm somewhat surprised to learn that there's no plan to have Rust support non-byte-addressable architectures, such as are found in DSP's (that is, architectures where the addressable word is something other than 8 bits). It shouldn't be too hard to add such support, at least for no_std use.
- quotemstr 7y agoRust seems to be targeting a development environment that's a bit more constrained than C and C++. C++ is general enough to work everywhere. Rust seems specialized to, well, the kinds of systems that run Firefox. Embedded into the shape of the language isn't only byte addressing, but also this idea that memory is practically unlimited and that allocation failure recovery isn't important. Rust may be perfectly fine in its domain, but my position is that these baked-in assumptions make its domain a subset of C++'s.
- Ar-Curunir 7y agoNothing in the language assumes unfailing allocation. It's only the current standard library APIs that don't support failable allocation, but there is work underway to remedy this.
- quotemstr 7y agoThe fundamental mistake in the Rust programming language is avoiding the use of exceptions for reporting errors. It's because the Rust designers eschewed exceptions that lots of standard library functions that need to allocate memory are also no-fail. If we reported allocation failure with Result, we'd have Result _everywhere_, which would have an ergonomic disaster, especially before the "?" operator appeared. If Rust had been designed to use exceptions from the start, this problem wouldn't exist, and it'd be a much nicer language besides. Some people seem to just have a philosophical or aesthetic aversion to exceptions, which is a shame, because exceptions work wonderfully in practice. Rust's development path is especially unfortunate because when you return Result everywhere and use the "?" operator consistently, what you end up writing looks just like exceptional code, but with weird warts and limitations from the language essentially implementing exceptions with return codes instead of first-class affordances built into the language itself. It's because Rust got error handling wrong that I still prefer C++ despite Rust's advantages in variable lifetime reificiation. Exceptions turn out to be so useful in general-purpose programming that Rust had to add them in a hacky way after the fact using macros and special operators. I understand that my position is controversial, but it's still my opinion and it's going to inform my language choice.
- nixpulvis 7y agoI disagree. In fact, I'd go a step further the opposite direction and say that the inclusion of panics was a mistake in the language design, though we're stuck with it now. To be fair, they do allow much better diagnostics when things fail, so this is more of a matter of simplicity vs developer economics, unless I'm missing something.
- quotemstr 7y agoI agree that supporting panics was a mistake as long as exceptions aren't really supported. Panics force everyone to pay for the possibility of unwinding without getting to use unwinding for exceptions. It's unfortunate. If you're going to have to consider the possibility unwinding, running destructors, and so on, just add exceptions! You don't need the panic mechanism to get good stack traces. You can get good stack traces in plain C with abort(): walking the stack does not require unwinding the stack! Confusing these two concepts is just another example of the unfixable confusion baked into the core of Rust that ruins an otherwise-interesting language.
- steveklabnik 7y agoIf you don’t want to pay for landing pads, you can compile your program with panic=abort, and you won’t get them. As you say, you can still get stack traces. The only reason that this is feasible is precisely because panics are not used for recoverable error handing in Rust; libraries don’t break if you turn this option on.
- nixpulvis 7y agoWell, panics should not be used for recoverable error handing in Rust. There's no guarantee turning off panics in favor of aborts wont break the assumptions of some library. That library should probably break tho, since as you said, panics aren't meant to emulate application logic exceptions. use std::panic::catch_unwind; fn main() { let err = catch_unwind(|| { panic!("B") }); println!("Look ma, recoverable error handing! {:?}", err); }
- chubot 7y agoDoes Rust support 16-bit architectures? I think I read recently that D doesn't on purpose. But of course C and C++ do. Found this comment, which makes it seem like support is intended but maybe not ready to use: https://news.ycombinator.com/item?id=15270502 https://news.ycombinator.com/item?id=15270502 not sure if related: https://github.com/rust-osdev/bootloader/issues/24 https://github.com/rust-osdev/bootloader/issues/24
- steveklabnik 7y agoThere’s been ongoing work to support AVR, which as I understand is a 16 (or was it 8?) bit architecture. It hasn’t landed in tree yet due to codegen bugs in LLVM, last I checked.
- monocasa 7y agoIt's basically a 16 bit arch. 8 bit registers, but they can be paired pretty easily and uniformly across the ISA MSP430 is probably the best supported 16 bit arch for Rust.
- ohazi 7y ago> the kinds of systems that run Firefox What gave you this idea? Rust today will run on 1 MHz microcontrollers with 4k sram.
- jcranmer 7y agoRust relies on LLVM for architecture support, and LLVM itself doesn't support non-8-bit-byte architectures very well. (Similarly, LLVM's poor support for IEEE 754 sticky bits, FP exceptions, and rounding mode is one factor in Rust's lack of support for these features).
- Mathnerd314 7y agoIs there any point in supporting DSPs? They seem to be getting phased out in favor of FPGAs or chips with more standardized architectures. And LLVM has a little support for some higher-end DSPs like Hexagon, but most toolchains are based on a modified GCC or an in-house C compiler like TI's compiler: http://processors.wiki.ti.com/index.php/TI_Compiler_Information http://processors.wiki.ti.com/index.php/TI_Compiler_Informat...
- monocasa 7y agoI don't think they're getting phased out. They're very hard to beat in their perf/watt gate count niche. Those little TI DSPs are everywhere.
- hsivonen 7y agoPersonally, I think it's great that Rust places radical limits on ISA and C ABI like octet addressing, two's complement integers, and size of bool being 1. What non-octet-addressing DSPs do you find to be important these days and why don't octet-addressing DSPs work for the use cases?
- quotemstr 7y agoRust's ABI needs a lot of work before it's frozen. They're leaving performance on the table. Consider this code: https://rust.godbolt.org/z/jN2AA_ https://rust.godbolt.org/z/jN2AA_ pub fn square(num: i64) -> i64 { return num * num; } // mov rax, rdi // imul rax, rdi // ret pub fn square2(num: i64) -> Result<i64, Box<dyn std::error::Error>> { Ok(num * num) } // mov rax, rdi // imul rsi, rsi // mov qword ptr [rdi + 8], rsi // mov qword ptr [rdi], 0 // ret In square(), we multiply the input by itself and return the result in rax. In square2(), we call the function with an extra hidden pointer argument and store the output Result via that pointer. That's really bad considering how central this fat-return-value model is to Rust programming. x86_64 has nine caller-saved registers. We should be using all of those to return function return values. Yes, I know that we'e returning by pointer because the Box has a non-trivial destructor. That's irrelevant, a holdover from the bad old C++ ABI. Rust should be returning from square2() via two registers, and I hope that it implements this optimization before freezing its ABI. In C++, we can address this ABI wart using the [[clang::trivial_abi]] attribute: see https://quuxplusone.github.io/blog/2018/05/02/trivial-abi-101/ https://quuxplusone.github.io/blog/2018/05/02/trivial-abi-10... There's no reason Rust can't do the same thing.
- ComputerGuru 7y agoYou’re completely right. But AFAIK there isn’t much of a push to cement the ABI as no one believes we’re “there” with what we have. That’s one of the things I like about rust (although a certain class of developers have a problem with that), the emphasis on trying to get things right rather than merely on time.
- zozbot234 7y ago> That's irrelevant, a holdover from the bad old C++ ABI. It's not irrelevant, it's doing whatever's most convenient given that the caller is to drop the Result<> later. As mentioned in the blogpost you link to, the [[clang::trivial_abi]] attribute changes how these things happen, such that it's no longer clear whether the caller or callee is responsible for a value that's passed via trivial_abi. I don't think it would make sense for Rust to adopt this, especially not in all cases. > That's really bad considering how central this fat-return-value model is to Rust programming. It's not 'fat return values' that lead to this, it's just boxed return values. Or more generally, values with non-trivial drop implementations.
- mwcampbell 7y agoRegarding systems with segmented memory models, I think it would be kind of cool if a language like Rust, with its emphasis on both safety and zero-overhead abstractions, could be cross-compiled for my first computer, the Apple IIGS, with its 65C816 processor. But I admit I don't want it enough to put any serious work into making it happen. Probably time to let that nostalgia go.
- zozbot234 7y agoYou'd need to get the architecture supported by LLVM first. This can be a hurdle, because LLVM backends need to be actively maintained to keep up with the rest of the code. The MC68K (far more popular than the 65C816) is still not supported for example, and work on it is really just starting. Segmented memory can be supported by C itself in a quasi-standard way, because the "Embedded C" technical report has a proviso for "multiple address spaces". Loosely speaking, this means that a "fully general" pointer type, encompassing all possible address spaces, still has to exist; but address-space specific pointers are also made possible.
- pshc 7y agoWould it work to compile rust code to WebAssembly first and translate that to 65C816 opcodes?
- zozbot234 7y agoIt would be quite inefficient. And you'd still need to write a JIT from WASM to the 65C816.
- johnsoft 7y agoAnother possible avenue is mrustc, an alternative Rust compiler which compiles Rust code to C code. Every platform has a C compiler (though maybe not C11, which is what mrustc targets). https://github.com/thepowersgang/mrustc https://github.com/thepowersgang/mrustc
- davidgerard 7y ago> To my knowledge the last great bastion of these properties being violated is some DSPs (Digital Signal Processors), because they really don't like 8-bit bytes. Now, there's definitely a tangent to be explored there. Anyone know more about this?
- steveklabnik 7y agoThe C spec has a concept called CHAR_BIT that specifies how many bits are in a byte. Looking for systems where it’s not 8 will give examples. I always link to https://stackoverflow.com/questions/32091992/is-char-bit-ever-8/38360262 https://stackoverflow.com/questions/32091992/is-char-bit-eve... which has a TI DSP as the first answer, for example.