-
Notifications
You must be signed in to change notification settings - Fork 452
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
Rework riscv -march and -mabi detection #796
base: main
Are you sure you want to change the base?
Conversation
src/lib.rs
Outdated
|
||
// If riscv32gc-* or riscv64gc-* then double-float ABI, | ||
// otherwise use soft-float ABI. | ||
let float_abi = if arch.contains("g") { "d" } else { "" }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks fragile to me, maybe we could use arch.ends_with("gc")
or contains("gc")
at least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My reasoning is that g
means imafd_zifencei_zicsr
, so it implies d
for double
, which is required for double float ABI. Currently it seems (see table in top post) that rustc does use lp64d
/ilp32d
for all targets with d
ouble. Maybe I can change the code to detect d
or g
and/or change the comment to reflect this reasoning better?
I guess I'll also change it so that it handles e.g. riscv64imac_zsomething
with a multi-letter extension tha happens to contain g
. Not sure if something other than an ISA/-march
string appears here though tbh.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the RISC-V Unprivileged Specification RISC-V ISA can be decided from ISA string, which indicates that if it has D inside, the target must support double length floating points; and G means that it has IMAFD and Zifencei (F indicates Zicsr). Using C here would not cover this case correctly, as that C doesn't imply G or D.
It is possible to have an RVD implementation without RVC, for example disabling C instruction set on RV64GC platform (which is sometimes common on embedded SoC or developing new SoCs); detecting GC for D will not be correct in those cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added a bunch of comments explaining the logic, and also updated the detection logic to handle the possible future existence of multi-letter extensions, so it won't get confused by e.g. riscv64imac_zsomething
containing a g
.
23303fc
to
6a1aff2
Compare
Additional justification for inferring the ABI: https://github.com/riscv-non-isa/riscv-toolchain-conventions#specifying-the-target-isa-with--march
Since the Rust target implies I can add a comment linking to it, if the maintainers are okay with this logic in general. |
Can this be revived? As it stands, cc-rs is sort-of useless for embedded RISCV*GC targets (at least without target-specific workarounds similar to mentioned in #795). |
I think it needs to resolve merge conflicts and rebase against main, then I can do another review pass on it |
As original author of this PR I'm interested in reviving this |
6a1aff2
to
0526b06
Compare
Aaaand, rebased, hope this works. I haven't added the toolchain convention reference, because it has been removed and it's now only a de facto standard. Honestly, we should just get the information from rustc itself once it's available... |
0526b06
to
6019801
Compare
Instead of adding cases for all the operating systems, Use target architecture directly as ISA string, replacing "riscv" with "rv", and detect floating point ABI based on support for the D and F extensions. Fixes rust-lang#795
6019801
to
0fed19a
Compare
} | ||
|
||
cmd.args.push("-mcmodel=medany".into()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This flag is pushed unconditionally now and it was conditional before.
Can you please add a comment explain why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that there was no reason to make this conditional in the first place and everything uses medium
/medany
(same thing). But I'll verify it later.
.split(['_', 'z', 's']) | ||
.next() | ||
// The arch string starts with 32 or 64 | ||
.expect("arch string cannot be empty"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm bit confused on this, I checked the riscv targets rust supported and doesn't find any z, s or underscore in after the prefix "riscv" .
What is this trying to detect?
Is there any new target which contains z, s or underscore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't know how else to address the fact that isa string parsing is "fragile" #796 (comment)
in case in the future we add extensions like zsomething
the arch string could look like riscv64imaczsomething
or riscv64imac_zsomething
and we don't want to match on the g
of zsomething
i don't think there's any easy way to say how the rust project will decide to name future riscv architectures, but if you're okay with this being "fragile" i can remove this part
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just to chim in here, to give an idea about how for example the riscv-esp-elf-gcc sees target definitions, it looks something like the following:
*multilib_defaults:
march=rv32imafdc_zicsr_zifencei mabi=ilp32
*multilib_extra:
*multilib_matches:
march=rv32i_zicsr_zifencei march=rv32i_zicsr_zifencei;march=rv32iac_zicsr_zifencei march=rv32iac_zicsr_zifencei;march=rv32ic_zicsr_zifencei march=rv32ic_zicsr_zifencei;march=rv32im_zicsr_zifencei march=rv32im_zicsr_zifencei;march=rv32imc_zicsr_zifencei march=rv32imc_zicsr_zifencei;march=rv32imac_zicsr_zifencei march=rv32imac_zicsr_zifencei;march=rv32imafc_zicsr_zifencei march=rv32imafc_zicsr_zifencei;march=rv32imafdc_zicsr_zifencei march=rv32imafdc_zicsr_zifencei;march=rv32imafdc_zicsr_zifencei_xesppie march=rv32imafdc_zicsr_zifencei_xesppie;mabi=ilp32 mabi=ilp32;mabi=ilp32f mabi=ilp32f;fno-rtti fno-rtti;
this above is part of the output of ./riscv32-esp-elf-gcc -dumpspecs
and presumably it looks similar on other gcc based variants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh so it's non-standard rust target used in riscv-esp-elf-gcc?
If it is non-standard then it would indeed makes more sense to pass them as environment variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure what you mean by non-standard rust target, but our target descriptions are similar on how the other riscv targets on the rust site are being expressed.
But as dramforever mentions downstream gcc & clang is more complicated matter. Mapping to thouse means that there are possible different ISA versions that can be associated with. Rust target names in its current form lag that expressiveness if i see it correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure what you mean by non-standard rust target, but our target descriptions are similar on how the other riscv targets on the rust site are being expressed.
I consider any target not in rustup or maintainer by the rust officially to be a non-standard one.
I heard of cargo plugins for esp and I think it sets the cflags and etc to work?
Would it makes sense here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it might make sense to summarize the situation:
- Rust targets lists the instruction extensions after
riscv{32,64}
.f
means hardware f32,d
means hardware f64, andg
is abbreviation ofimafd
- Currently there are only single letters there so we can detect it based on just looking for
g
/d
orf
- Previously a maintainer complained that it was fragile... but with no real way to predict future target names IMO it will never be not fragile
- There's no way to get the target ABI used by rustc here, IIUC. If there was this whole detection would be obsolete for everyone.
- The de facto standard for
-mabi
is to use the "maximum" supported hard float ABI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no way to get the target ABI used by rustc here, IIUC. If there was this whole detection would be obsolete for everyone.
We do have a crate to extract some riscv target information from nightly rust.
I wonder if we could get this from it as well?
https://github.com/rust-lang/cc-rs/blob/main/dev-tools/gen-target-info/src/main.rs
@NobodyXu I just thought of another solution, can we just delete this section of the altogether and rely on the user to have configured the toolchain correctly or add the options for themselves? |
If it is optional flags that's there to improve performance, then maybe we can do it. If it is required for it to compile, then I think we should keep it |
Unfortunately it is required for correctness :( (Edit I mean, required for compilation to go through. The linker will catch (most) mistakes.) |
What is preventing this PR from being merged as is? Would it introduce any regressions? It might not be perfect, it might be fragile for some obscure corner cases, but right now cc-rs can't even handle the bog-standard riscv64gc arch on non-standard OSes! In particular, it blocks introducing risc-v support on Redox, at least without forking this crate which is pretty much a non-starter. Maybe the PR could be merged in (to move the needle in the right direction), and then you guys could continue perfecting it? |
we were previously discussing about getting the flags from rustc codebase at build time.
I've posted this on zulip asking for a final review from someone understands riscv before merging in, I'm not very familiar with riscv so I don't know if it'd work/break something. It would be great if it has CI running for riscv, with that I can merge in with confidence. |
I'm still interested in working on this, although I would like some input on what kind of detection is expected here before trying to make up some logic without evidence to back it |
cc-rs has an infrastructure to extract information from https://github.com/rust-lang/cc-rs/blob/main/dev-tools/gen-target-info/src/main.rs Basically you need to modify the Once you've done that, you'd need to run You'd also need to stage and commit |
I'd like to understand a state of things a little better. To give a concrete example, I'm targeting riscv64gc-unknown-redox. This is a non-standard target, using patched Rust, and it uses lp64d abi. cc-rs, as it stands now, instructs gcc to use soft-float abi so everything breaks. The PR, as it stands now, fixes that. Now, I saw several comments here what seems to be quite differing in nature.
That should work for us I think, and for any non-standard target, including custom json target definitions. But then the very last comment:
Seem to indicate an idea of hardcoding options inside cc-rs code, so that wouldn't exactly work for anything not known by stock Rust at the time of generation. So, assuming we are left to fend for ourselves so to speak... More specifically
How one would go about doing it? IIUC right now it is impossible to do because cc-rs would override it unconditionally. Let's say that is changed, so we'd provide If so, it would probably be almost fine... Not exactly frictionless, as it would have to be put in bunch of places to make things like CI work; and also they have to be only present for riscv and not other targets. But that should be more manageable than the current approach of adding patches to all those Cargo.toml files. |
What I was describing is our build time rustc target info extraction. In the gen-target-info workspace, we get the flags from rustc, we have a workspace which run rustc and exteact target info to files that are included in cc. We run this in CI once a week. however, there's a better option now. @madsmtm is working on #1225 which would enable cc-rs to use information from cargo environment if present, thus it should fix the custom target use cases. |
Currently all the riscv*gc targets use the 'd' double-float ABI, and
soft-float otherwise. There's no need to detect the operating system
type. Fixes #795.
I'm not sure how correct this is. I've checked all the targets on version
1.69.0-nightly (ef934d9b6 2023-02-08)
with this script:Which gives:
Also I'm not sure whether to add tests or not. Please advise on this.