-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose target cpu to conditional compilation #44036
Comments
As far as I am aware, for most targets the "CPU" setting is just a shorthand for a rough baseline of features (e.g., whether certain ISA extensions are present) and as guidance for certain heuristics in the compiler (e.g., scheduling). Anything sane that user code might do with that information can more reliably be achieved with |
cc @japaric |
@rkruppe Thanks for the ping. @dylanmckay I have written my thoughts (more or less) on the topic of device specific APIs, which seems to be what you are after with this change, here. You may want to check that out. The TL;DR is that we haven't picked up a solution but that comment lists some of the possible solutions. With respect to the issue at hand, I don't think It seems to me that what you want here is actually a To me, it also feels overkill to have one target (specification) per device / microcontroller -- I'm assuming this is what you are after: one target per device where the specification is mostly the same except for Finally, what you want to achieve here can be done without modifying the compiler, and thus you can experiment today, and without having one target per device: you can append the [target.thumbv7m-none-eabi]
rustflags = ["--cfg", "target_device=stm32f100"]
[build]
target = "thumbv7m-none-eabi" This setting will affect the conditional compilation ( Messing with the Just my two cents :-). |
I believe that AVR is special compared to ARM in that is is not enough to know what peripherals are supported - we also need to know where they are exposed in memory via IO registers. For example, Here is a sample of the generated microcontroller files that contain
Note that these devices are in the same family (Tiny), and yet even then we have IO registers in different locations. Because of this, we have to use conditional compilation per microcontroller. The "pack" files (analguous to SVD AFAIK) provided by Atmel (see here) do no attempt at grouping into families. All registers, their locations, the supported peripherals, the supported interrupts, are all specified in whole for every individual device. AVR-GCC also uses the same methodology, having header files per device rather than family (for example,
Thinking about it your way, I completely agree with this here. The different microcontrollers themselves may have the same CPU, but the difference is the locations of the IO registers that the CPU itself uses. In this regard, using AVR-GCC actually does something similar to what you suggest with When I think about this more, I'm fairly certain that the AVR-LLVM backend (which I maintain) does use the CPU to distinguish different microcontrollers. This is because LLVM provides the a consistent interface for the creation of targets (AVRMCTargetDesc.cpp:51, this function must have this signature to compile). In order to separate the concept of CPU and device in LLVM, it would require changing LLVM itself, and even then I don't think that Atmel themselves make a distinction between CPUs as I've never seen it in a datasheet (ATmega328 wiki). I believe that because we don't know what CPU is actually in the package, the only thing we can do is use the device instead. Because of this, I think that our only choice is to treat different microcontrollers as different CPUs.
I had not considered this. I'm not too worried about this personally because AVR at the moment only supports
That's true, we can definitely achieve the same thing without modifying the compiler, but because the information is already there in the target specification, I don't want my downstream users to have to worry passing the MCU again in a separate argument it as they don't really need to. |
I've looked at AVR-GCC a little bit more, and I believe that it doesn't actually make a distinction between CPU and MCU. It looks like GCC does not provide any target-independent arguments to set the CPU - if a target wants to support something like this, it needs to create a target-specific argument. Note that X86 provides its own AVR does not support specifying a CPU, only an MCU. In that regard, AVR gcc does the same thing my patch currently does in that you only ever specify one. |
If we come to a consensus and find that for AVR, we do need to support conditional compilation based on CPU, then it might be a good idea to make it a flag that is only turned on for backends that opt-in. On top of this, a lint could be written to warn about usage of target-specific attributes that aren't guarded by a If we decided that though, there'd be no point merging it until we actually have an in-tree backend that opts in to the feature, so I'd be tempted to hold off until the day the fork converges into mainline. |
I find it a bit surprising that the LLVM backend apparently needs detailed information about the device. Does each device have a subtly different ISA? Does the backend need to know about peripherals? Or why do you want the LLVM backend to know when it's targeting, for example, "atmega328"? |
tl;dr Sometimes, yes In general, all devices can be more or less grouped into families. For example, You can find the AVR backend's definition of these families in AVRDevices.td. You can see that in general, the families build up on top of each other in terms of supported instructions/features. The problem is that not every realised ISA can be cleanly separated into a family. For example, the ATtiny26 is a part of the Another example is the ATMega8515, which almost implements all of
No
Solely for deciding what subset of the ISA is supported.All device-specific information required (or used) by the backend can be found inside AVRDevices.td. |
Thanks for the explanation. I can't shake the feeling that it might be cleaner for the backend to just know about the various ISA subsets/features, and target specs for different devices setting the right features (as opposed to the backend knowing about all devices out there and which features they imply). But since I know nothing of the topic other than what you've written down here, and this implementation has been accepted upstream, I'll chalk it up to my personal ignorance or taste. |
When you say "target specs", do you mean on the Rust side? I worry that would cause every single AVR LLVM frontend to have to know about every single AVR, and when new ones come up we would need to add the MCUs to N frontends. At the moment, the device families (avr1, avr2, ..) and the specific devices (atmega328p, ..) under the hood are actually the same thing. That means that you can use That means that at the moment, it is possible for a frontend to specify families and support features if they desire. |
Is there a PR or an RFC for this ? What remains to be done ? I have a proc macro that should have different logic if Having to scan RUSTFLAGS, |
I don't believe there's anything beyond this issue (and the living implementation of it over in avr-rust). I don't want to speak too much for @dylanmckay, but I believe they've been pretty busy with other things recently and might not have the bandwidth to drive an RFC through. |
We could build a library that can be used in |
Is there any progress on this feature? Seems odd this is still missing after two years. I'm running into some situations where specialized instructions on AMD are slower than their naive implementations. e.g. Ideally, I could just exclude |
Coming up on the 3rd anniversary of this. Has there been any progress on this issue? |
I've recently created a crate that provides IO/microcontroller specific constants to Rust programs written for the AVR architecture.
avrd on GitHub
avrd on Docs.rs
I've made it so that there is always a
current
module in the crate root that reexports all items from a microcontroller-specific crate, depending on what CPU is being targeted.In order to achieve this, I needed to add a
target_cpu
conditional compilation flag to my fork of the Rust compileravr-rust@1f5f6bd
I would like to upstream this (with cleanups like more documentation), as it seems generally useful, but it also would make it easier to merge the fork into mainline if that were to ever happen in the future. On top of this, it would be quite a useful feature to other people who fork Rust for more esoteric architectures.
The in-tree targets don't seem to specify CPUs most of the time - looking in the
librustc_back
module, it looks like some targets set CPU tocortex-a8
, some to a CPU name used by Sparc, but almost everything else is left blank, generic, or "x86_64", etc.Before I file a PR, are there any glaring objections to this?
The text was updated successfully, but these errors were encountered: