Closed kito-cheng closed 1 year ago
Why is this a new directive rather than just a .option
? We already have .option push
/.option pop
, all you need is a .option to change the arch string like now we already have rvc/norvc. Perhaps that should just be generalised to (no)rv$arch?
i.e.:
.attribute arch, "rv64imafdc"
memcpy_general:
add a5,a1,a2
beq a1,a5,.L2
add a2,a0,a2
mv a5,a0
.L3:
addi a1,a1,1
addi a5,a5,1
lbu a4,-1(a1)
sb a4,-1(a5)
bne a5,a2,.L3
.L2:
ret
.option push
.option rvv
memcpy_vec:
mv a3, a0
.Lloop:
vsetvli t0, a2, e8, m8, ta, ma
vle8.v v0, (a1)
add a1, a1, t0
sub a2, a2, t0
vse8.v v0, (a3)
add a3, a3, t0
bnez a2, .Lloop
ret
.option pop # Restore the enabled ISA extension status to imafdc.
This is cleaner, more consistent and avoids adding more than one way to enable/disable RVC.
Looks OK with some English improvements. Only useful if both clang and GNU as support it at roughly the same time, and will require configure checks in GNU tools before using, and whatever the clang equivalent is.
The assembler is integrated (well, it doesn't even bother to serialise and re-parse textual assembly) so normally no such concern exists. When there is enough interest in supporting old GNU assemblers with the integrated assembler turned off there's -fbinutils-version that has to be supplied by the user. But configure-time does not make sense for Clang as there's very little distinction between native and cross-compilation beyond the fact it picks a default triple, and every build contains all backends by default, and you're not going to have an assembler for every possible supported target present when you build Clang.
Why is this a new directive rather than just a .option? We already have .option push/.option pop, all you need is a .option to change the arch string like now we already have rvc/norvc. Perhaps that should just be generalised to (no)rv$arch?
Reason why define new directive rather than extend rvc
/norvc
scheme.
.option
implementation.Here is an another issue there: should we have negative option for .push_arch
/.pop_arch
?
e.g. .push_arch -c
, .push_arch -v
Why is this a new directive rather than just a .option? We already have .option push/.option pop, all you need is a .option to change the arch string like now we already have rvc/norvc. Perhaps that should just be generalised to (no)rv$arch?
Reason why define new directive rather than extend
rvc
/norvc
scheme.
- Able to included the version info in the option.
.option rvv1p0
- Able to enable more than one extension at a time.
.option rvv1p0, rvb0p93
, or I guess you can .option rvb0p93_v1p0
etc and allow an arch "substring", both work. But even without those options, having to have multiple lines is hardly a big deal... how often do you need to enable more than one extension? And how often is that being done by hand rather than just auto-generated by a loop in the compiler? It's a non-issue.
- Implementation is simpler, it won't mixed with existing
.option
implementation.
Disagree. Uniformity is simpler. Parsing this is trivial and generalises the code that's already there. Having two ways to do the same thing confuses users, looks ugly and means you have multiple copies of similar code in your assembler.
Here is an another issue there: should we have negative option for
.push_arch
/.pop_arch
? e.g..push_arch -c
,.push_arch -v
Yes. My solution supports that.
Other than aesthetics and arguments about simplicity/consistency, there is a very real concern I have about having two different push/pop mechanisms. What does:
.attribute arch, rv32i2p0
.push_arch m
.option rvc
.pop_arch
mean? Is RVC enabled or disabled at the end of that? Or:
.attribute arch, rv32i2p0
.option push
.push_arch m
.option pop
Does that have RVM enabled or disabled at the end? If you make the push and pop parts of .push_arch
and .pop_arch
be the same as .option
then they are completely redundant and should not exist beyond the "set the arch string" part (i.e. pop_arch goes away and push_arch only modifies the current arch string), but then push_arch is a bad name for that part. If you don't make them equivalent and try and maintain two separate stacks then that becomes a complete tangled nightmare both in the implementation and in the conceptual model. Thus, whatever you name the thing, it needs to ultimately be equivalent to .option (no)rv$arch
, and so might as well be called that for consistency with (no)rvc rather than some kind of .modify_arch
.
@jrtc27 thanks your example, that's good point, let me write down second version for this proposal.
I already have the first version of .push_arch and .pop_arch in GNU binutils, but haven't written the test cases yet. Nelson1225/riscv-binutils-gdb@8e2483f
The implementation and assembly syntax of .option rvc; .option norvc; and .push_arch c2p0; .pop_arch are different, though they all need to be stored in the stack. I agree with @jrtc27 that we should use the same format and way to do this stuff, so seems that there are some issues as follows,
.attribute arch, rv32i2p0
.option push /* backup rv32i2p0. */
.option rvc2p0 /* added c2p0, rv32i2p0_c2p0. */
.option rvc3p0 /* updated c3p0, rv32i2p0_c3p0. */
.option norvc /* removed c, rv32i2p0. */
.option pop /* restored rv32i2p0. */
So the format `.option rv<extension><version>` is good, but `.option norv<extension><version>` will complicate the usage, so I suggest do not use versions in the `.option norv<extension>`
2. Not only the standard extensions can be pushed and popped, so according to the above formats.
.option rv
.attribute arch, rv32i2p0_m2p0 .option push / backup rv32i2p0. / .option rvc2p0 / added c2p0, rv32i2p0_c2p0. / .option rvzfh0p1 / added zfh0p1, rv32i2p0_c2p0_zfh0p1. / .option rvxvendor1p0 / added xvendor1p0, rv32i2p0_c2p0_zfh0p1_xvendor1p0. / .option pop / restored rv32i2p0. /
Although `rv` prefix looks redundant, but we need to consider the compatibility of rvc and norvc.
3. Should we still support the following format?
.option rv
Changes:
.option
rather than .push_arch
/.pop_arch
Why is this still introducing a new way of doing things, .option arch <foo>
, rather than reusing and extending the existing syntax? This still results in two different ways to enable/disable RVC. We should not be adding new syntax unless absolutely necessary.
IMO this is the right way to go: having .option arch +c
mean the same thing as .option rvc
is fine, it's just a more general way of doing things. It's way cleaner than trying to have a million ad-hoc '.option noZba` for every flavor of extension we want to flip on/off. I'd go a bit farther and suggest a handful of additions:
=
op (or just let it be blank). This would let users write something like .option arch rv64gc
when they want to control exactly the arch they're based on..option arch
lines. This prevents us from getting screwed when our separator (IIUC a ,
?) becomes a valid character in extensions.-march=rv64g -march+c
. We can deal with that later, though, as I'm sure it'll require a lot of sorting out.int func() __attribute__(("arch", "-c"))
or whatever the syntax usually looks like over there. We can also argue about this one later.IMO this is the right way to go: having
.option arch +c
mean the same thing as.option rvc
is fine, it's just a more general way of doing things. It's way cleaner than trying to have a million ad-hoc '.option noZba` for every flavor of extension we want to flip on/off. I'd go a bit farther and suggest a handful of additions:
Just as you wouldn't implement this by having a million ad-hoc -Zba options for .option arch, you wouldn't implement my proposal that way either, you'd parse (no)rv and then parse an extension name.
- Add an
=
op (or just let it be blank). This would let users write something like.option arch rv64gc
when they want to control exactly the arch they're based on.- Drop the extension list, and just make users insert multiple
.option arch
lines. This prevents us from getting screwed when our separator (IIUC a,
?) becomes a valid character in extensions.- Add this as command-line syntax. Something like
-march=rv64g -march+c
. We can deal with that later, though, as I'm sure it'll require a lot of sorting out.- Add this as a function attribute. So something like
int func() __attribute__(("arch", "-c"))
or whatever the syntax usually looks like over there. We can also argue about this one later.
That's __attribute__((target(...)))
as an architecture-independent attribute (with architecture-dependent arguments), and __attribute__((target("-c")))
etc already work today for LLVM (in as much as it can without assembly syntax to toggle things on and off; for C in particular it won't work well, or at least not if you round-trip through assembly, might work fine if you don't, but for something like M or F it'll just (not) emit the instructions).
IMO this is the right way to go: having .option arch +c mean the same thing as .option rvc is fine, it's just a more general way of doing things. It's way cleaner than trying to have a million ad-hoc '.option noZba` for every flavor of extension we want to flip on/off. I'd go a bit farther and suggest a handful of additions:
Just as you wouldn't implement this by having a million ad-hoc -Zba options for .option arch, you wouldn't implement my proposal that way either, you'd parse (no)rv and then parse an extension name.
To me, both are extending stuffs, and now we have chance to implement one scheme more clear / better, so I would prefer the new one. (although that's subjective I know.)
Add an = op (or just let it be blank). This would let users write something like .option arch rv64gc when they want to control exactly the arch they're based on.
Sound good idea.
Drop the extension list, and just make users insert multiple .option arch lines. This prevents us from getting screwed when our separator (IIUC a ,?) becomes a valid character in extensions.
Hmmm, make sense to me...
Add this as command-line syntax. Something like -march=rv64g -march+c. We can deal with that later, though, as I'm sure it'll require a lot of sorting out.
Yeah, I guess we need that to deal with the RISC-V profile
...although I prefer use -march as the only option for control the ISA.
Add this as a function attribute. So something like int func() attribute(("arch", "-c")) or whatever the syntax usually looks like over there. We can also argue about this one later.
Like @jrtc27 said, LLVM having some level of support for that, write down that into to https://github.com/riscv/riscv-c-api-doc is my next step, but for GNU toolchain site, we need this to implement that.
IMO this is the right way to go: having
.option arch +c
mean the same thing as.option rvc
is fine, it's just a more general way of doing things. It's way cleaner than trying to have a million ad-hoc '.option noZba` for every flavor of extension we want to flip on/off. I'd go a bit farther and suggest a handful of additions:Just as you wouldn't implement this by having a million ad-hoc -Zba options for .option arch, you wouldn't implement my proposal that way either, you'd parse (no)rv and then parse an extension name.
IMO that's pretty ad-hoc: by removing the explicit name-spacing provided by Kito's proposal we end up with these options all at the top level, which makes them harder to describe. That said, I don't really care that much about syntax.
- Add an
=
op (or just let it be blank). This would let users write something like.option arch rv64gc
when they want to control exactly the arch they're based on.- Drop the extension list, and just make users insert multiple
.option arch
lines. This prevents us from getting screwed when our separator (IIUC a,
?) becomes a valid character in extensions.- Add this as command-line syntax. Something like
-march=rv64g -march+c
. We can deal with that later, though, as I'm sure it'll require a lot of sorting out.- Add this as a function attribute. So something like
int func() __attribute__(("arch", "-c"))
or whatever the syntax usually looks like over there. We can also argue about this one later.That's
__attribute__((target(...)))
as an architecture-independent attribute (with architecture-dependent arguments), and__attribute__((target("-c")))
etc already work today for LLVM (in as much as it can without assembly syntax to toggle things on and off; for C in particular it won't work well, or at least not if you round-trip through assembly, might work fine if you don't, but for something like M or F it'll just (not) emit the instructions).
Sounds like that should be in some spec somewhere, as I don't remember having seen it before. I also very much question the value of providing options that generate broken code.
IMO this is the right way to go: having
.option arch +c
mean the same thing as.option rvc
is fine, it's just a more general way of doing things. It's way cleaner than trying to have a million ad-hoc '.option noZba` for every flavor of extension we want to flip on/off. I'd go a bit farther and suggest a handful of additions:Just as you wouldn't implement this by having a million ad-hoc -Zba options for .option arch, you wouldn't implement my proposal that way either, you'd parse (no)rv and then parse an extension name.
IMO that's pretty ad-hoc: by removing the explicit name-spacing provided by Kito's proposal we end up with these options all at the top level, which makes them harder to describe. That said, I don't really care that much about syntax.
- Add an
=
op (or just let it be blank). This would let users write something like.option arch rv64gc
when they want to control exactly the arch they're based on.- Drop the extension list, and just make users insert multiple
.option arch
lines. This prevents us from getting screwed when our separator (IIUC a,
?) becomes a valid character in extensions.- Add this as command-line syntax. Something like
-march=rv64g -march+c
. We can deal with that later, though, as I'm sure it'll require a lot of sorting out.- Add this as a function attribute. So something like
int func() __attribute__(("arch", "-c"))
or whatever the syntax usually looks like over there. We can also argue about this one later.That's
__attribute__((target(...)))
as an architecture-independent attribute (with architecture-dependent arguments), and__attribute__((target("-c")))
etc already work today for LLVM (in as much as it can without assembly syntax to toggle things on and off; for C in particular it won't work well, or at least not if you round-trip through assembly, might work fine if you don't, but for something like M or F it'll just (not) emit the instructions).Sounds like that should be in some spec somewhere, as I don't remember having seen it before. I also very much question the value of providing options that generate broken code.
https://clang.llvm.org/docs/AttributeReference.html#target https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html (scroll way down)
It works just fine for everything but C. For C it'll still mess with the subtarget internally (which can affect codegen for relative costs of instructions as it looks at whether they're compressible) but we fail to omit the necessary .option (no)rvc
to stop post-isel compression, and it seems that does affect using the integrated assembler too (not sure how though, bit strange). There's nothing wrong with the option, just a bug in its implementation for one specific case (that's a rather weird one).
IMO this is the right way to go: having
.option arch +c
mean the same thing as.option rvc
is fine, it's just a more general way of doing things. It's way cleaner than trying to have a million ad-hoc '.option noZba` for every flavor of extension we want to flip on/off. I'd go a bit farther and suggest a handful of additions:Just as you wouldn't implement this by having a million ad-hoc -Zba options for .option arch, you wouldn't implement my proposal that way either, you'd parse (no)rv and then parse an extension name.
IMO that's pretty ad-hoc: by removing the explicit name-spacing provided by Kito's proposal we end up with these options all at the top level, which makes them harder to describe. That said, I don't really care that much about syntax.
I agree that, if I could go back in time, I would stop the (no)rvc syntax from being adopted by GNU as and pick something more like this proposal. However, my personal opinion is that there should be a very good reason for introducing new syntax for something that can be done by generalising existing syntax, but .option arch
is certainly better than .push_arch
. I think the way forward is to bring it up with both GNU and LLVM developers to see if there's a consensus for which of the two current proposals they feel is best.
NB: I would personally put a comma after .option arch
, as is done for .attribute arch
, if that is the proposal that ends up being adopted.
Changes:
,
after arch.=
operator to set arch to specific configuration. I agree that .option arch
is just a more general way to specify things, and I prefer keeping things namespaced there.
We discussed somewhat on the LLVM sync-up call and there were diverging opinions on whether it was desirable to later deprecate .option [no]rvc
(either just documenting it's no longer the preferred way, or even moving towards emitting warnings). But I don't think that's a discussion that needs to be had here and now.
Hi Guys, Is there any further concern about this issue? If no, then I think maybe it is time to merge this pr, and then we could proceed to the next issues, including add mapping symbols with ISA string to these .option arch directives. Thanks.
Hi Guys, Is there any further concern about this issue? If no, then I think maybe it is time to merge this pr, and then we could proceed to the next issues, including add mapping symbols with ISA string to these .option arch directives. Thanks.
Mapping symbols are not dependent on this; .option (no)rvc
already exists and could make use of them, even if not really necessary. As could files compiled with different -march= strings.
Changes:
rvc/norvc
sectionChanges:
ifunc
example to note.EF_RISCV_RVC
won't updated by .option arch
rvc
/norvc
in future.rvc
/norvc
option.Hi, @kito-cheng . I have a question that since D extension will imply F extension, should '.option arch, -d' also disable F extension at the same time?
Why wouldn't that just leave you with F? The only weird thing is that .option arch, =rv32i, +d, -d
will give you rv32if, but I think that's the least bad semantics and hard to oddities like that.
I have a question that since D extension will imply F extension, should '.option arch, -d' also disable F extension at the same time?
No, since that means we also need to disable zicsr due to F imply zicsr :( But thanks for point out that I think we should add NOTE to mention that.
The only weird thing is that .option arch, =rv32i, +d, -d will give you rv32if, but I think that's the least bad semantics and hard to oddities like that.
@jrtc27 I guess we should add a NOTE to recommend user use push
/pop
rather than -
, consider =rv32i, +v, -v, will result rv32ifd_zve32x_zve32f_zve64x_zve64f_zve64d_zvl32b_zvl64b_zvl128b
.
Changes:
Changes:
@luismarques thanks!
@luismarques @asb do you mind take a review for this? this has been verified on binutils for a while and here also a LLVM implementation already under review: https://reviews.llvm.org/D123515
We've binutils support on upstream and a patch on LLVM (https://reviews.llvm.org/D123515), so I think it's time to merge this, before merge this, I would like wait one more week to make sure no objection or further comment from LLVM community @asb @luismarques @jrtc27 @MaskRay.
Thanks everyone! We have the last necessary element of the function multi-versioning now!
Changes:
.option
rather than.push_arch
/.pop_arch
.This commit extend .option diretive with new keyword:
Enable and/or disable specific ISA extensions for following code regions, but without changing the arch attribute, that means it won't raise the minimal execution environment requirement, so the user should take care to protect execution of the code regions around
.option push
/.option arch
/.option pop
. A typical use case is is withifunc
, e.g. the libc is built withrv64gc
, but a few functions like memcpy provide two versions, one built withrv64gc
and one built withrv64gcv
, and then select between them by ifunc mechanism at run-time. However we don't want to change the minimal execution environment requirement torv64gcv
, since therv64gcv
version will be invoked only if the execution environment supports the vector extension, so the minimal execution environment requirement still isrv64gc
.Example:
Notes: