Re: [PATCH V2 2/8] bpf: new GCC port
> +(define_insn "*branch_on_di" > + [(set (pc) > + (if_then_else (match_operator 3 "ordered_comparison_operator" > + [(match_operand:DI 0 "register_operand" "r") > + (match_operand:DI 1 "reg_or_imm_operand" "rI")]) > + (label_ref (match_operand 2 "" "")) > + (pc)))] > + "" > +{ > + int code = GET_CODE (operands[3]); > + > + switch (code) > + { > + case EQ: return "jeq\t%0,%1,%2"; break; > + case NE: return "jne\t%0,%1,%2"; break; > + case LT: return "jslt\t%0,%1,%2"; break; > + case LE: return "jsle\t%0,%1,%2"; break; > + case GT: return "jsgt\t%0,%1,%2"; break; > + case GE: return "jsge\t%0,%1,%2"; break; > + case LTU: return "jlt\t%0,%1,%2"; break; > + case LEU: return "jle\t%0,%1,%2"; break; > + case GTU: return "jgt\t%0,%1,%2"; break; > + case GEU: return "jge\t%0,%1,%2"; break; > + default: > +error ("unknown comparison code %d in *branch_on_di\n", code); This error message isn't written in terms meaningful to users (that is, saying what is wrong with their source code). Calls to error () should only be for errors meaningful to users (and shouldn't appear in .md files at all, because exgettext doesn't extract messages from .md files for translation, and any error that late in compilation is liable not to have a very meaningful location either). Internal errors - errors indicating a bug in the compiler rather than a problem with the user's program - need to use other functions such as internal_error. Yeah that's actually a gcc_unreachable, or fatal error. Thanks for noticing!
Re: [PATCH V2 2/8] bpf: new GCC port
On Sat, 17 Aug 2019, Jose E. Marchesi wrote: > +(define_insn "*branch_on_di" > + [(set (pc) > + (if_then_else (match_operator 3 "ordered_comparison_operator" > + [(match_operand:DI 0 "register_operand" "r") > + (match_operand:DI 1 "reg_or_imm_operand" "rI")]) > + (label_ref (match_operand 2 "" "")) > + (pc)))] > + "" > +{ > + int code = GET_CODE (operands[3]); > + > + switch (code) > + { > + case EQ: return "jeq\t%0,%1,%2"; break; > + case NE: return "jne\t%0,%1,%2"; break; > + case LT: return "jslt\t%0,%1,%2"; break; > + case LE: return "jsle\t%0,%1,%2"; break; > + case GT: return "jsgt\t%0,%1,%2"; break; > + case GE: return "jsge\t%0,%1,%2"; break; > + case LTU: return "jlt\t%0,%1,%2"; break; > + case LEU: return "jle\t%0,%1,%2"; break; > + case GTU: return "jgt\t%0,%1,%2"; break; > + case GEU: return "jge\t%0,%1,%2"; break; > + default: > +error ("unknown comparison code %d in *branch_on_di\n", code); This error message isn't written in terms meaningful to users (that is, saying what is wrong with their source code). Calls to error () should only be for errors meaningful to users (and shouldn't appear in .md files at all, because exgettext doesn't extract messages from .md files for translation, and any error that late in compilation is liable not to have a very meaningful location either). Internal errors - errors indicating a bug in the compiler rather than a problem with the user's program - need to use other functions such as internal_error. -- Joseph S. Myers jos...@codesourcery.com
Re: [PATCH V2 2/8] bpf: new GCC port
jose.march...@oracle.com (Jose E. Marchesi) writes: > > +#undef TARGET_PASS_BY_REFERENCE > > +#define TARGET_PASS_BY_REFERENCE bpf_pass_by_reference > > I might have misunderstood, but I thought from an earlier (IRC?) > message, it wasn't possible for the callee to access the caller's > frame, which was why you had the error about running out of argument > registers. If so, won't passing by reference make the argument > inaccessible in practice? I don't see what you gain by defining > the hook, since I'd have assumed (at least after the fix above) > that it would be better to pass by value and get an error about > having no argument registers left. > > Yes. I added that hook before I had the restriction of number of > arguments in place. Removing it. > > Happy auto correction :) > > A colleague (who actually _uses_ eBPF extensively, ahem) tells me that > the kernel verifier allows to pass addresses of the caller's stack > frame, tracking that it is a ptr to a stack location, and it knows which > stack it came from. So it is indeed possible for the callee to access > the caller's frame, and therefore to pass arguments by reference. > > On the downside, it is not possible for a callee to access the caller's > frame applying an offset to its frame pointer, because the stacks are > disjoint. This means that most probably I will have to dedicate a real, > not eliminable register to act as the arg pointer, if I want to get rid > of the annoying limitation on the number of arguments... and in order > to keep ABI compatibility with llvm built objects, this register is > gonna have to be %r5, i.e. the last register usable to pass arguments, > but it should be only used for that purpose if the function gets more > than 5 arguments... sounds messy, but there is hope, yay! > > However, unless someone comes with a magical macro to define or an > existing target doing the same thing, I am deferring attacking this > problem for later (TM) and for the time being I will keep both the > ability of passing aggregates and other big arguments by reference, and > the limit on number of arguments (this is what clang does.) > > I hope that's ok for you people. Sounds good :-)
Re: [PATCH V2 2/8] bpf: new GCC port
Hi! On Thu, Aug 22, 2019 at 04:11:46AM +0200, Jose E. Marchesi wrote: > A colleague (who actually _uses_ eBPF extensively, ahem) tells me that > the kernel verifier allows to pass addresses of the caller's stack > frame, tracking that it is a ptr to a stack location, and it knows which > stack it came from. So it is indeed possible for the callee to access > the caller's frame, and therefore to pass arguments by reference. Good news for testability of the GCC port, and also good news for users, who will have one less (HUGE) arbitrary restriction to deal with :-) > On the downside, it is not possible for a callee to access the caller's > frame applying an offset to its frame pointer, That is true for many targets. > because the stacks are disjoint. And even that sometimes. > This means that most probably I will have to dedicate a real, > not eliminable register to act as the arg pointer, if I want to get rid > of the annoying limitation on the number of arguments... and in order > to keep ABI compatibility with llvm built objects, this register is > gonna have to be %r5, i.e. the last register usable to pass arguments, > but it should be only used for that purpose if the function gets more > than 5 arguments... sounds messy, but there is hope, yay! At *function entry* it is in %r5, but you can immediately copy that elsewhere, at function start; there is no need to dedicate a hard register to it. Segher
Re: [PATCH V2 2/8] bpf: new GCC port
> +#undef TARGET_PASS_BY_REFERENCE > +#define TARGET_PASS_BY_REFERENCE bpf_pass_by_reference I might have misunderstood, but I thought from an earlier (IRC?) message, it wasn't possible for the callee to access the caller's frame, which was why you had the error about running out of argument registers. If so, won't passing by reference make the argument inaccessible in practice? I don't see what you gain by defining the hook, since I'd have assumed (at least after the fix above) that it would be better to pass by value and get an error about having no argument registers left. Yes. I added that hook before I had the restriction of number of arguments in place. Removing it. Happy auto correction :) A colleague (who actually _uses_ eBPF extensively, ahem) tells me that the kernel verifier allows to pass addresses of the caller's stack frame, tracking that it is a ptr to a stack location, and it knows which stack it came from. So it is indeed possible for the callee to access the caller's frame, and therefore to pass arguments by reference. On the downside, it is not possible for a callee to access the caller's frame applying an offset to its frame pointer, because the stacks are disjoint. This means that most probably I will have to dedicate a real, not eliminable register to act as the arg pointer, if I want to get rid of the annoying limitation on the number of arguments... and in order to keep ABI compatibility with llvm built objects, this register is gonna have to be %r5, i.e. the last register usable to pass arguments, but it should be only used for that purpose if the function gets more than 5 arguments... sounds messy, but there is hope, yay! However, unless someone comes with a magical macro to define or an existing target doing the same thing, I am deferring attacking this problem for later (TM) and for the time being I will keep both the ability of passing aggregates and other big arguments by reference, and the limit on number of arguments (this is what clang does.) I hope that's ok for you people. Salud!
Re: [PATCH V2 2/8] bpf: new GCC port
On Tue, 20 Aug 2019 23:14:35 +0200 jose.march...@oracle.com (Jose E. Marchesi) wrote: > The kernel verifier doesn't allow backward jumps. > > This may change at some point. There is much discussion among the > kernel hackers in whether it is possible to allow bounded loops in a > safe way. In that case, some of the restrictions may be lifted. Actually, bounded loops are supported and allowed in the 5.3 kernel. https://lwn.net/Articles/794934/ jon
Re: [PATCH V2 2/8] bpf: new GCC port
On Tue, Aug 20, 2019 at 03:42:53PM -0600, Jeff Law wrote: > > I have been thinking about Segher's suggestion on providing options to > > lift some of the limitations, for compiler testing. Unfortunately, many > > of the restrictions are deeply rooted in the design of the > > architecture... or the other way around. Finding sane ways to implement > > these extensions will be fun :) > Hell, it's a virtual architecture. I'd just make up new instructions > for the missing functionality, make them dependent on an flag. I think > the PRU is in a similar position and uses that approach. PTX might have > as well. This approach works well for simulators for physical architectures, too. > > This may change at some point. There is much discussion among the > > kernel hackers in whether it is possible to allow bounded loops in a > > safe way. In that case, some of the restrictions may be lifted. > ACK. It's an interesting problem. Would it help if we could annotate > loops with bound information? Not sure how to preserve that from gimple > down to assembly, but it's worth pondering. You probably should have machine insns that iterate a loop some number of times given when you first start the loop (and cannot be changed later, except maybe exiting from the loop). Like "doloop" in GCC. Maybe only allow a constant number of times, if the verifier want to see that? The only thing the verifier should be concerned with is how long the code takes to run, or am I missing something? Segher
Re: [PATCH V2 2/8] bpf: new GCC port
On Tue, Aug 20, 2019 at 11:14:35PM +0200, Jose E. Marchesi wrote: > The kernel verifier doesn't allow backward jumps. > > This may change at some point. There is much discussion among the > kernel hackers in whether it is possible to allow bounded loops in a > safe way. In that case, some of the restrictions may be lifted. > > For now, only loops that can be peeled/massaged and then fully unrolled > are supported. You can also generate code like x5: call x4 jump x1 x4: call x2 x2: call x1 x1: do things once here ret to do fixed number of iteration loops. Disgusting? You decide :-) (Or is something in that not allowed by the verifier?) Segher
Re: [PATCH V2 2/8] bpf: new GCC port
On 8/20/19 3:14 PM, Jose E. Marchesi wrote: > > Hi Jeff. > > > This patch adds a port for the Linux kernel eBPF architecture to GCC. > > > > ChangeLog: > > > > * configure.ac: Support for bpf-*-* targets. > > * configure: Regenerate. > > > > contrib/ChangeLog: > > > > * config-list.mk (LIST): Disable go in bpf-*-* targets. > > > > gcc/ChangeLog: > > > > * config.gcc: Support for bpf-*-* targets. > > * common/config/bpf/bpf-common.c: New file. > > * config/bpf/t-bpf: Likewise. > > * config/bpf/predicates.md: Likewise. > > * config/bpf/constraints.md: Likewise. > > * config/bpf/bpf.opt: Likewise. > > * config/bpf/bpf.md: Likewise. > > * config/bpf/bpf.h: Likewise. > > * config/bpf/bpf.c: Likewise. > > * config/bpf/bpf-protos.h: Likewise. > > * config/bpf/bpf-opts.h: Likewise. > > * config/bpf/bpf-helpers.h: Likewise. > > * config/bpf/bpf-helpers.def: Likewise. > So I think various folks have already mentioned the configure rebuild > issues, formatting and other stuff. I'm going to try to keep them all > in mind so that I don't duplicate anything. If I do duplicate someone's > comment, apologies in advance. > > At a high level I realize there's lots of things not supported due to > the restricted environment it'll ultimately be used in. However, you > might want to consider extensions that would allow larger portions of > the gcc testsuite to run and some kind of user mode simulator so that > you can reasonably test the target. Not a requirement, but could be > useful (from experience :-) > > I agree to both regards. > > I have been thinking about Segher's suggestion on providing options to > lift some of the limitations, for compiler testing. Unfortunately, many > of the restrictions are deeply rooted in the design of the > architecture... or the other way around. Finding sane ways to implement > these extensions will be fun :) Hell, it's a virtual architecture. I'd just make up new instructions for the missing functionality, make them dependent on an flag. I think the PRU is in a similar position and uses that approach. PTX might have as well. > > As for the simulator, I have one, along with an initial GDB port... but > it doesn't work very well due to a particularly nasty bug in CGEN. I > have a patch that seems to fix it but, as everything that touches cgen's > ifield handling code, it is difficult to be 100% sure about that, and I > also need to adapt some of the other existing cgen-based ports... so it > will take a while before I have something that can run the GCC > testsuite. ACK. > Curious about the motivation on the loop unrolling stuff. In general we > discourage targets from mucking around with the default > flags/optimizations, but it is sometimes the right thing to do. > > The kernel verifier doesn't allow backward jumps. Oh yea, I should have remembered that. I think it came up in a systemtap and/or ebpf+systemtap discussion at some point. > > This may change at some point. There is much discussion among the > kernel hackers in whether it is possible to allow bounded loops in a > safe way. In that case, some of the restrictions may be lifted. ACK. It's an interesting problem. Would it help if we could annotate loops with bound information? Not sure how to preserve that from gimple down to assembly, but it's worth pondering. > Does this get called often? If so the linear search could end up being > expensive from a compile-time standpoint. > > It gets called per function call to a symbol with the form > __builtin_bpf_helper_*... you think it is worth of a hash? Hard to tell. Maybe leave it for now and revisit post integration and real world feedback. > Is the stack limit likely to change? Would a param work better here > which would allow us to accommodate such a change without having to > re-release GCC? > > It will probably be increased at some point. Using a param sounds like > a good idea. However... > > The stack limit is associated with kernel version. I guess we can just > set the appropriate defaults in bpf_option_override if we make it > variable, in case the user didn't specify a --param for it, so no > problem. > > Also, if we allow the user to specify a stack frame bigger than 0x7fff, > bpf_expand_prologue will break. Probably in that case we want to detect > this, warn and truncate to the -mkernel's default, also in > bpf_option_override. > > Does that sound reasonable? It does. I think PARAMS have the ability to enforce a min/max and specify a default. So set a default to 512 since that's what works everywhere and if the kernel bumps up, folks can just use the param to allow more stack space. > > > diff --git a/gcc/config/bpf/bpf.h b/gcc/config/bpf/bpf.h > > + > > +/ Debugging Info / > > + >
Re: [PATCH V2 2/8] bpf: new GCC port
Hi Jeff. > This patch adds a port for the Linux kernel eBPF architecture to GCC. > > ChangeLog: > > * configure.ac: Support for bpf-*-* targets. > * configure: Regenerate. > > contrib/ChangeLog: > > * config-list.mk (LIST): Disable go in bpf-*-* targets. > > gcc/ChangeLog: > > * config.gcc: Support for bpf-*-* targets. > * common/config/bpf/bpf-common.c: New file. > * config/bpf/t-bpf: Likewise. > * config/bpf/predicates.md: Likewise. > * config/bpf/constraints.md: Likewise. > * config/bpf/bpf.opt: Likewise. > * config/bpf/bpf.md: Likewise. > * config/bpf/bpf.h: Likewise. > * config/bpf/bpf.c: Likewise. > * config/bpf/bpf-protos.h: Likewise. > * config/bpf/bpf-opts.h: Likewise. > * config/bpf/bpf-helpers.h: Likewise. > * config/bpf/bpf-helpers.def: Likewise. So I think various folks have already mentioned the configure rebuild issues, formatting and other stuff. I'm going to try to keep them all in mind so that I don't duplicate anything. If I do duplicate someone's comment, apologies in advance. At a high level I realize there's lots of things not supported due to the restricted environment it'll ultimately be used in. However, you might want to consider extensions that would allow larger portions of the gcc testsuite to run and some kind of user mode simulator so that you can reasonably test the target. Not a requirement, but could be useful (from experience :-) I agree to both regards. I have been thinking about Segher's suggestion on providing options to lift some of the limitations, for compiler testing. Unfortunately, many of the restrictions are deeply rooted in the design of the architecture... or the other way around. Finding sane ways to implement these extensions will be fun :) As for the simulator, I have one, along with an initial GDB port... but it doesn't work very well due to a particularly nasty bug in CGEN. I have a patch that seems to fix it but, as everything that touches cgen's ifield handling code, it is difficult to be 100% sure about that, and I also need to adapt some of the other existing cgen-based ports... so it will take a while before I have something that can run the GCC testsuite. > diff --git a/gcc/common/config/bpf/bpf-common.c b/gcc/common/config/bpf/bpf-common.c > new file mode 100644 > index 000..a68feb62897 > --- /dev/null > +++ b/gcc/common/config/bpf/bpf-common.c [ snip ] > +/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */ > +static const struct default_options bpf_option_optimization_table[] = > + { > +/* Enable -funroll-all-loops by default. */ > +{ OPT_LEVELS_ALL, OPT_funroll_all_loops, NULL, 1 }, > +/* Disable -fomit-frame-pointer by default. */ > +{ OPT_LEVELS_ALL, OPT_fomit_frame_pointer, NULL, 0 }, > +{ OPT_LEVELS_NONE, 0, NULL, 0 } > + }; Curious about the motivation on the loop unrolling stuff. In general we discourage targets from mucking around with the default flags/optimizations, but it is sometimes the right thing to do. The kernel verifier doesn't allow backward jumps. This may change at some point. There is much discussion among the kernel hackers in whether it is possible to allow bounded loops in a safe way. In that case, some of the restrictions may be lifted. For now, only loops that can be peeled/massaged and then fully unrolled are supported. Rather than -fomit-frame-pointer, I think you can use the FRAME_POINTER_REQUIRED hook if you always want a frame pointer. Oh so specifying -fomit-frame-pointer there is redundant... good to know. Will remove it. > diff --git a/gcc/config/bpf/bpf-helpers.h b/gcc/config/bpf/bpf-helpers.h > new file mode 100644 > index 000..2fe96be7637 > --- /dev/null > +++ b/gcc/config/bpf/bpf-helpers.h I can't remember, is this an installed header that consumers are expected to use? If so you might want to be careful with polluting user code with BPF #defines such as BPF_ANY, BPF_NOEXIST, BPF_EXIST, etc. The #defines for mapping to the builtins are probably OK though. Yes, it is a header file for consumers. Unfortunately, the whole purpose of the header is to provide an interface that is compatible with the kernel's bpf_helpers.h (which at the moment is llvm-specific). The API is given :( This is a point I plan to raise with the eBPF developers in a few weeks, at the Linux Plumbers conference in Lisbon. > diff --git a/gcc/config/bpf/bpf.c b/gcc/config/bpf/bpf.c > new file mode 100644 > index 000..4a42259a9c3 > --- /dev/null > +++ b/gcc/config/bpf/bpf.c > @@ -0,0 +1,1136 @@ [ ... ] > + > +/* Return the builtin code corresponding to the kernel helper builtin > + __builtin_NAME, or 0 if the na
Re: [PATCH V2 2/8] bpf: new GCC port
On 8/16/19 6:59 PM, Jose E. Marchesi wrote: > This patch adds a port for the Linux kernel eBPF architecture to GCC. > > ChangeLog: > > * configure.ac: Support for bpf-*-* targets. > * configure: Regenerate. > > contrib/ChangeLog: > > * config-list.mk (LIST): Disable go in bpf-*-* targets. > > gcc/ChangeLog: > > * config.gcc: Support for bpf-*-* targets. > * common/config/bpf/bpf-common.c: New file. > * config/bpf/t-bpf: Likewise. > * config/bpf/predicates.md: Likewise. > * config/bpf/constraints.md: Likewise. > * config/bpf/bpf.opt: Likewise. > * config/bpf/bpf.md: Likewise. > * config/bpf/bpf.h: Likewise. > * config/bpf/bpf.c: Likewise. > * config/bpf/bpf-protos.h: Likewise. > * config/bpf/bpf-opts.h: Likewise. > * config/bpf/bpf-helpers.h: Likewise. > * config/bpf/bpf-helpers.def: Likewise. So I think various folks have already mentioned the configure rebuild issues, formatting and other stuff. I'm going to try to keep them all in mind so that I don't duplicate anything. If I do duplicate someone's comment, apologies in advance. At a high level I realize there's lots of things not supported due to the restricted environment it'll ultimately be used in. However, you might want to consider extensions that would allow larger portions of the gcc testsuite to run and some kind of user mode simulator so that you can reasonably test the target. Not a requirement, but could be useful (from experience :-) > --- > diff --git a/contrib/config-list.mk b/contrib/config-list.mk > index 69c826e649a..aa9fdb64eaf 100644 > --- a/contrib/config-list.mk > +++ b/contrib/config-list.mk > @@ -123,7 +123,7 @@ $(LIST): make-log-dir > TGT=`echo $@ | awk 'BEGIN { FS = "OPT" }; { print $$1 }'` && > \ > TGT=`$(GCC_SRC_DIR)/config.sub $$TGT` && > \ > case $$TGT in > \ > - *-*-darwin* | *-*-cygwin* | *-*-mingw* | *-*-aix*) > \ > + *-*-darwin* | *-*-cygwin* | *-*-mingw* | *-*-aix* | > bpf-*-* ) \ > ADDITIONAL_LANGUAGES=""; > \ > ;; > \ > *) > \ So I've got no problem disabling Go for BFD, but I don't see bpf added to LIST, which it should be. > diff --git a/gcc/common/config/bpf/bpf-common.c > b/gcc/common/config/bpf/bpf-common.c > new file mode 100644 > index 000..a68feb62897 > --- /dev/null > +++ b/gcc/common/config/bpf/bpf-common.c [ snip ] > +/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */ > +static const struct default_options bpf_option_optimization_table[] = > + { > +/* Enable -funroll-all-loops by default. */ > +{ OPT_LEVELS_ALL, OPT_funroll_all_loops, NULL, 1 }, > +/* Disable -fomit-frame-pointer by default. */ > +{ OPT_LEVELS_ALL, OPT_fomit_frame_pointer, NULL, 0 }, > +{ OPT_LEVELS_NONE, 0, NULL, 0 } > + }; Curious about the motivation on the loop unrolling stuff. In general we discourage targets from mucking around with the default flags/optimizations, but it is sometimes the right thing to do. Rather than -fomit-frame-pointer, I think you can use the FRAME_POINTER_REQUIRED hook if you always want a frame pointer. > + > +#undef TARGET_OPTION_OPTIMIZATION_TABLE > +#define TARGET_OPTION_OPTIMIZATION_TABLE bpf_option_optimization_table > + > +/* Implement TARGET_OPTION_DEFAULT_PARAMS. */ > + > +static void > +bpf_option_default_params (void) > +{ > + /* XXX large-stack-frame = 512 bytes */ > + /* XXX max-unrolled-insns */ > + /* XXX max-unroll-times */ > +} > + > +#undef TARGET_OPTION_DEFAULT_PARAMS > +#define TARGET_OPTION_DEFAULT_PARAMS bpf_option_default_params I'd generally discourage twiddling the params like this, at least the ones for the unroller. > diff --git a/gcc/config/bpf/bpf-helpers.h b/gcc/config/bpf/bpf-helpers.h > new file mode 100644 > index 000..2fe96be7637 > --- /dev/null > +++ b/gcc/config/bpf/bpf-helpers.h I can't remember, is this an installed header that consumers are expected to use? If so you might want to be careful with polluting user code with BPF #defines such as BPF_ANY, BPF_NOEXIST, BPF_EXIST, etc. The #defines for mapping to the builtins are probably OK though. > diff --git a/gcc/config/bpf/bpf.c b/gcc/config/bpf/bpf.c > new file mode 100644 > index 000..4a42259a9c3 > --- /dev/null > +++ b/gcc/config/bpf/bpf.c > @@ -0,0 +1,1136 @@ [ ... ] > + > +/* Return the builtin code corresponding to the kernel helper builtin > + __builtin_NAME, or 0 if the name doesn't correspond to a kernel > + helper builtin. */ > + > +static inline int > +bpf_helper_code (const char *name) > +{ > + int i;
Re: [PATCH V2 2/8] bpf: new GCC port
jose.march...@oracle.com (Jose E. Marchesi) writes: > Hi Richard! > > Many thanks for the deep review. I'm addressing some of your questions > below. > > > [...] > > +/* Override options and do some other initialization. */ > > + > > +static void > > +bpf_option_override (void) > > +{ > > + /* Set the default target kernel if no -mkernel was specified. */ > > + if (!global_options_set.x_bpf_kernel) > > +bpf_kernel = LINUX_LATEST; > > LINUX_LATEST is the default in the .opt file, so when is this needed? > > It is an idiom I got from sparc.c: > > /* Set the default CPU if no -mcpu option was specified. */ > if (!global_options_set.x_sparc_cpu_and_features) > { > ... > } > > Maybe the code in sparc.c predates the Init() directive in sparc.opt > file? Might be wrong, but it looks like the SPARC code is overriding the .opt default with the configure-time one. I don't think it's needed when the default is fixed. > > [...] > > +/* Return a RTX indicating whether a function argument is passed in a > > + register and if so, which register. */ > > + > > +static rtx > > +bpf_function_arg (cumulative_args_t ca, enum machine_mode mode > ATTRIBUTE_UNUSED, > > + const_tree type ATTRIBUTE_UNUSED, bool named > ATTRIBUTE_UNUSED) > > +{ > > + CUMULATIVE_ARGS *cum = get_cumulative_args (ca); > > + > > + if (*cum < 5) > > +return gen_rtx_REG (mode, *cum + 1); > > + else > > +/* An error have been emitted for this in > > + bpf_function_arg_advance. */ > > +return NULL_RTX; > > This hook is called first, so "will be" rather than "has been". > > (BTW, I just submitted a series of patches to change this interface, > but it should be a trivial change for whichever of us gets to make it.) > > I see your interface change was approved yesterday, so I will just adapt > in my next rebase :) Thanks! Richard
Re: [PATCH V2 2/8] bpf: new GCC port
On Tue, Aug 20, 2019 at 04:20:03PM +0200, Jose E. Marchesi wrote: > > + (PLUS ADDR_BASE CONST_INT) > > + (PLUS CONST_INT ADDR_BASE) > > The second one isn't canonical rtl, so you shouldn't (need to) handle it. > Please raise a bug if you find a case where it's being generated. :-) > > Oooh, didn't know that, that's actually very handy :) > > Do you know if this is documented anywhere? I don't recall seeing this > in the internals manual, but maybe I missed it. @node Insn Canonicalizations ... @itemize @bullet @item For commutative and comparison operators, a constant is always made the second operand. If a machine only supports a constant as the second operand, only patterns that match a constant in the second operand need be supplied. The whole section is worth reading :-) Segher
Re: [PATCH V2 2/8] bpf: new GCC port
> > +/*** Order of Allocation of Registers. */ > > + > > +/* We generally want to put call-clobbered registers ahead of > > + call-saved ones. (IRA expects this.) */ > > +#define REG_ALLOC_ORDER\ > > + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} > > Do you gain much by defining this? I would have expected better > code without, given the architecture is so regular. It does exactly the same as not defining REG_ALLOC_ORDER, just a tiny bit less efficient. Yeah I just removed the definition from the port.
Re: [PATCH V2 2/8] bpf: new GCC port
> [...] > +;; Division > +(define_insn "div3" > + [(set (match_operand:AM 0 "register_operand" "=r,r") > +(div:AM (match_operand:AM 1 "register_operand" " 0,0") > +(match_operand:AM 2 "reg_or_imm_operand" "r,I")))] > + "" > + "div\t%0,%2" > + [(set_attr "type" "")]) > + > +(define_insn "udiv3" > + [(set (match_operand:AM 0 "register_operand" "=r,r") > +(div:AM (match_operand:AM 1 "register_operand" " 0,0") > +(match_operand:AM 2 "reg_or_imm_operand" "r,I")))] > + "" > + "div\t%0,%2" > + [(set_attr "type" "")]) div and udiv are two different operations. I don't see how we can use the same eBPF instruction for both. The rtl for udiv should also use the udiv rtx code. > +;;; Modulus > +(define_insn "mod3" > + [(set (match_operand:AM 0 "register_operand" "=r,r") > +(mod:AM (match_operand:AM 1 "register_operand" " 0,0") > +(match_operand:AM 2 "reg_or_imm_operand" "r,I")))] > + "" > + "mod\t%0,%2" > + [(set_attr "type" "")]) > + > +(define_insn "umod3" > + [(set (match_operand:AM 0 "register_operand" "=r,r") > +(mod:AM (match_operand:AM 1 "register_operand" " 0,0") > +(match_operand:AM 2 "reg_or_imm_operand" "r,I")))] > + "" > + "mod\t%0,%2" > + [(set_attr "type" "")]) Same here, with umod for the rtx code. Oh dear the signed division... during development I just made both signed and unsigned flavors to use the same instructions, then forgot to change it. Why did I do that? Because eBPF does not provide instructions for doing _signed_ division, nor signed remainder: both `div' and `mod' perform unsigned arithmetic. clang/llvm ICEs whenever it finds signed division in a C program: $ clang -target bpf foo.c Error: Unsupport signed division for DAG: t17: i64 = sdiv t15, t16Please convert to unsigned div/mod. fatal error: error in backend: Cannot select: t17: i64 = sdiv t15, t16 For GCC I much prefer for the compiler to generate funcalls instead, to __divdi3/__divsi3/__moddi3/__modsi3 or the like, even if nothing is providing implementations for these functions (yet.) So I just defined the u{div,mod}MODE3 patterns in bpf.md (yes this time using the right rtl opcode :P) and removed the insns for signed operations. Thanks for noticing this!
Re: [PATCH V2 2/8] bpf: new GCC port
On Mon, Aug 19, 2019 at 08:57:22PM +0100, Richard Sandiford wrote: > > +/*** Order of Allocation of Registers. */ > > + > > +/* We generally want to put call-clobbered registers ahead of > > + call-saved ones. (IRA expects this.) */ > > +#define REG_ALLOC_ORDER\ > > + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} > > Do you gain much by defining this? I would have expected better > code without, given the architecture is so regular. It does exactly the same as not defining REG_ALLOC_ORDER, just a tiny bit less efficient. > > +#define REG_CLASS_CONTENTS \ > > +{ \ > > + 0x, /* NO_REGS */ \ > > + 0x07ff, /* GR_REGS */ \ > > + 0x07ff, /* ALL_REGS */ \ > > +} > > + > > +/* A C expression whose value is a register class containing hard > > + register REGNO. In general there is more that one such class; > > + choose a class which is "minimal", meaning that no smaller class > > + also contains the register. */ > > +#define REGNO_REG_CLASS(REGNO) ((REGNO) < 11 ? GR_REGS : ALL_REGS) > > Did you mean to include register 11 in ALL_REGS in REG_CLASS_CONTENTS? > If not, then there doesn't seem to be any distinction between ALL_REGS > and GR_REGS, and it'd be better to make one the alias of the other > (and make REGNO_REG_CLASS return NO_REGS for 11). ALL_REGS is required to contain all (hard) registers, too. I wonder what will go wrong this way... Well nothing too obvious, apparently! :-) > > +(define_insn "*mulsi3_extended" > > + [(set (match_operand:DI 0 "register_operand" "=r,r") > > +(sign_extend:DI > > + (mult:SI (match_operand:SI 1 "register_operand" "0,0") > > + (match_operand:SI 2 "reg_or_imm_operand" "r,I"] > > + "" > > + "mul32\t%0,%2" > > + [(set_attr "type" "alu32")]) > > There's a named pattern for this: mulsidi3. You might get better > code by using that name instead. mulsidi3 is something else (it extends the operands before the mult). > > +(define_expand "extendsidi2" > > + [(set (match_operand:DI 0 "register_operand" "=r") > > + (sign_extend:DI (match_operand:SI 1 "register_operand" "r")))] > > define_expands shouldn't have constraints. (Same for the rest of the file.) > > > [...] > > +(define_expand "mov" > > + [(set (match_operand:AMM 0 "general_operand" "") > > +(match_operand:AMM 1 "general_operand" ""))] Not empty constraints, either... That is, you do not need to write them, and internally it will be the same thing. Segher
Re: [PATCH V2 2/8] bpf: new GCC port
Hi Richard! Many thanks for the deep review. I'm addressing some of your questions below. > [...] > +/* Override options and do some other initialization. */ > + > +static void > +bpf_option_override (void) > +{ > + /* Set the default target kernel if no -mkernel was specified. */ > + if (!global_options_set.x_bpf_kernel) > +bpf_kernel = LINUX_LATEST; LINUX_LATEST is the default in the .opt file, so when is this needed? It is an idiom I got from sparc.c: /* Set the default CPU if no -mcpu option was specified. */ if (!global_options_set.x_sparc_cpu_and_features) { ... } Maybe the code in sparc.c predates the Init() directive in sparc.opt file? > +/* Determine whether the port is prepared to handle insns involving > + scalar mode MODE. For a scalar mode to be considered supported, > + all the basic arithmetic and comparisons must work. */ > + > +static bool > +bpf_scalar_mode_supported_p (scalar_mode mode) > +{ > + switch (mode) > +{ > +case E_QImode: > +case E_HImode: > +case E_SImode: > +case E_DImode: > +case E_TImode: > + return true; > + > +default: > + return false; > +} > + > + return false; > +} Are you overriding this just to exclude floating-point modes? If so, what specifically doesn't work? Would be worth a comment. Reminiscence of not having support for TImodes at some stage. I'm removing the target hook. > [...] > +/* Return true if a value of mode MODE1 is accessible in mode MODE2 > + without copying. */ > + > +static bool > +bpf_modes_tieable_p (enum machine_mode mode1, > + enum machine_mode mode2) > +{ > + return (mode1 == mode2 > + || GET_MODE_CLASS (mode1) == GET_MODE_CLASS (mode2)); > +} The second part makes the first part redundant. But why do you need to restrict it based on classes? It seems like eBPF is an example of an architecture where any modes are tieable, so using the default would be better if possible. If the restriction is needed, it would be worth having a comment explaining which case you're excluding and why. Hm yes, you are right. TARGET_HARD_REGNO_MODE_OK (R,MODE1) == TARGET_HARD_REGNO_MODE_OK (R,MODE2) for all supported modes... I'm removing the target hook. > [...] > +case PLUS: > + { > + /* The valid patterns here are: > + > +(PLUS ADDR_BASE CONST_INT) > +(PLUS CONST_INT ADDR_BASE) The second one isn't canonical rtl, so you shouldn't (need to) handle it. Please raise a bug if you find a case where it's being generated. :-) Oooh, didn't know that, that's actually very handy :) Do you know if this is documented anywhere? I don't recall seeing this in the internals manual, but maybe I missed it. > [...] > +/* Split an out-of-range address displacement into hi and lo parts. > + The hi part will have to be loaded into a register separately, but > + the low part will be folded into the memory operand. */ > + > +static bool > +bpf_legitimize_address_displacement (rtx *off1, rtx *off2, > + poly_int64 poly_offset, machine_mode) > +{ > + HOST_WIDE_INT orig_offset = poly_offset; > + > + /* Our case is very easy: the REG part of an indirect address is > + 64-bit wide, so it can hold any address. This always leads to > + REG+0 */ > + > + *off1 = GEN_INT (orig_offset); > + *off2 = GEN_INT (0); > + return true; > +} > + > +#undef TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT > +#define TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT bpf_legitimize_address_displacement But then do you need to define the hook at all? I think this is what LRA does by default. The hook is only really there to get better spill code (via common anchor points) on targets with limited offset ranges. Hm I think I wrote this hook to fix some invalid addresses being generated at some point... but I don't recall the details. It looks like this hook is no longer necessary with the current implementation of addresses (legitimize etc) so I'm removing it. > [...] > +/* Return true if memory address ADDR in address space AS can have > + different meanings depending on the machine mode of the memory > + reference it is used for or if the address is valid for some modes > + but not others. */ > + > +static bool > +bpf_mode_dependent_address_p (const_rtx addr ATTRIBUTE_UNUSED, > + addr_space_t as ATTRIBUTE_UNUSED) > +{ > + return true; > +} > + > +#undef TARGET_MODE_DEPENDENT_ADDRESS_P > +#define TARGET_MODE_DEPENDENT_ADDRESS_P bpf_mode_dependent_address_p
Re: [PATCH V2 2/8] bpf: new GCC port
In addition to Segher's comments: jema...@gnu.org (Jose E. Marchesi) writes: > [...] > +/* This file contains the definition of the kernel helpers that are > + available to eBPF programs. > + > + The primary source for information on kernel helpers is the > + linux/include/uapi/linux/bpf.h file in the Linux source tree. > + Please keep this database in sync. > + > + The first column is the first kernel version featuring the helper > + function. This should be an enumerate from bpf_kernel_version, > + defined in bpf-opts.h. Note that the backend assumes that helpers > + never get deprecated in the kernel. If that eventually happens, > + then we will need to use a bitmask here instead of an enumerate. > + > + The second column is the constant-name for the helper. > + The third column is the program-name of the helper. > + > + The fourth column is a list of names describing the types of the > + values returned and accepted by the helper, in one of these forms: > + > + TYPES (type1, type2, ..., 0) > + VTYPES (type1, type2, ..., 0) > + > + VTYPES should be used should the helper accept a variable number of > + arguments, TYPES otherwise. The valid type names are: > + > + `vt' for void. > + `it' for signed int. > + `ut' for unsigned int. > + `pt' for *void. > + `cpt' for const *void. "*" after "void" in both cases. > + `st' for short int. > + `ust' for unsigned short int. > + `cst' for const char *. Very minor, but it might be less confusing to pick something other than "s" for "cst" given the above. > [...] > +/* Functions to emit BPF_LD_ABS and BPF_LD_IND instructions. We > + provide the "standard" names as synonyms of the corresponding GCC > + builtins. Note how the SKB argument is ignored. */ > + > +static inline long long > +load_byte (void *skb, unsigned long long off) > +{ > + return __builtin_bpf_load_byte (off); > +} > [etc] It might be worth adding __attribute__((unused)) to them, in case anyone compiles with -Wsystem-headers. > [...] > +/* Supported versions of the Linux kernel. */ > +enum bpf_kernel_version > +{ > + /* Linux 4.x */ > + LINUX_V4_0, > [etc.] The contents should be indented by two spaces. > [...] > +enum bpf_builtins > +{ > + BPF_BUILTIN_UNUSED = 0, > + /* Built-ins for kernel helpers. */ > +#define DEF_HELPER(V,D,N,T) BPF_BUILTIN_HELPER_##D, > +# include "bpf-helpers.def" > +#undef DEF_HELPER > + BPF_BUILTIN_HELPER_MAX, > + /* Built-ins for non-generic loads and stores. */ > + BPF_BUILTIN_LOAD_BYTE = BPF_BUILTIN_HELPER_MAX, > + BPF_BUILTIN_LOAD_HALF, > + BPF_BUILTIN_LOAD_WORD, > + BPF_BUILTIN_MAX, > +}; > + > +/* This table is indexed by an enum bpf_builtin. */ > +static const char *bpf_helper_names[] = > +{ > + NULL, > +#define DEF_HELPER(V,D,N,T) #N, > +# include "bpf-helpers.def" > +#undef DEF_HELPER > + NULL, > + NULL, > + NULL, > + NULL > +}; Same for these two. > [...] > +#define INCLUDE_STRING You didn't seem to rely on this (i.e. std::string). > [...] > +/* Override options and do some other initialization. */ > + > +static void > +bpf_option_override (void) > +{ > + /* Set the default target kernel if no -mkernel was specified. */ > + if (!global_options_set.x_bpf_kernel) > +bpf_kernel = LINUX_LATEST; LINUX_LATEST is the default in the .opt file, so when is this needed? > [...] > + /* Define BPF_KERNEL_VERSION_CODE */ > + { > +const char *version_code; > +char *kernel_version_code; > + > +switch (bpf_kernel) > + { > + case LINUX_V4_0: version_code = "0x4"; break; > + case LINUX_V4_1: version_code = "0x40100"; break; > + case LINUX_V4_2: version_code = "0x40200"; break; > + case LINUX_V4_3: version_code = "0x40300"; break; > + case LINUX_V4_4: version_code = "0x40400"; break; > + case LINUX_V4_5: version_code = "0x40500"; break; > + case LINUX_V4_6: version_code = "0x40600"; break; > + case LINUX_V4_7: version_code = "0x40700"; break; > + case LINUX_V4_8: version_code = "0x40800"; break; > + case LINUX_V4_9: version_code = "0x40900"; break; > + case LINUX_V4_10: version_code = "0x40a00"; break; > + case LINUX_V4_11: version_code = "0x40b00"; break; > + case LINUX_V4_12: version_code = "0x40c00"; break; > + case LINUX_V4_13: version_code = "0x40d00"; break; > + case LINUX_V4_14: version_code = "0x40e00"; break; > + case LINUX_V4_15: version_code = "0x40f00"; break; > + case LINUX_V4_16: version_code = "0x41000"; break; > + case LINUX_V4_17: version_code = "0x42000"; break; > + case LINUX_V4_18: version_code = "0x43000"; break; > + case LINUX_V4_19: version_code = "0x44000"; break; > + case LINUX_V4_20: version_code = "0x45000"; break; > + case LINUX_V5_0: version_code = "0x5"; break; > + case LINUX_V5_1: version_code = "0x50100"; break; > + case LINUX_V5_2: version_code = "0x50200"; break; > + default: > + gcc_unreac
[PATCH V2 2/8] bpf: new GCC port
This patch adds a port for the Linux kernel eBPF architecture to GCC. ChangeLog: * configure.ac: Support for bpf-*-* targets. * configure: Regenerate. contrib/ChangeLog: * config-list.mk (LIST): Disable go in bpf-*-* targets. gcc/ChangeLog: * config.gcc: Support for bpf-*-* targets. * common/config/bpf/bpf-common.c: New file. * config/bpf/t-bpf: Likewise. * config/bpf/predicates.md: Likewise. * config/bpf/constraints.md: Likewise. * config/bpf/bpf.opt: Likewise. * config/bpf/bpf.md: Likewise. * config/bpf/bpf.h: Likewise. * config/bpf/bpf.c: Likewise. * config/bpf/bpf-protos.h: Likewise. * config/bpf/bpf-opts.h: Likewise. * config/bpf/bpf-helpers.h: Likewise. * config/bpf/bpf-helpers.def: Likewise. --- ChangeLog |5 + configure | 68 ++- configure.ac | 54 +- contrib/ChangeLog |4 + contrib/config-list.mk |2 +- gcc/ChangeLog | 16 + gcc/common/config/bpf/bpf-common.c | 57 ++ gcc/config.gcc |9 + gcc/config/bpf/bpf-helpers.def | 194 ++ gcc/config/bpf/bpf-helpers.h | 324 ++ gcc/config/bpf/bpf-opts.h | 56 ++ gcc/config/bpf/bpf-protos.h| 33 ++ gcc/config/bpf/bpf.c | 1136 gcc/config/bpf/bpf.h | 565 ++ gcc/config/bpf/bpf.md | 528 + gcc/config/bpf/bpf.opt | 119 gcc/config/bpf/constraints.md | 29 + gcc/config/bpf/predicates.md | 105 gcc/config/bpf/t-bpf |0 19 files changed, 3300 insertions(+), 4 deletions(-) create mode 100644 gcc/common/config/bpf/bpf-common.c create mode 100644 gcc/config/bpf/bpf-helpers.def create mode 100644 gcc/config/bpf/bpf-helpers.h create mode 100644 gcc/config/bpf/bpf-opts.h create mode 100644 gcc/config/bpf/bpf-protos.h create mode 100644 gcc/config/bpf/bpf.c create mode 100644 gcc/config/bpf/bpf.h create mode 100644 gcc/config/bpf/bpf.md create mode 100644 gcc/config/bpf/bpf.opt create mode 100644 gcc/config/bpf/constraints.md create mode 100644 gcc/config/bpf/predicates.md create mode 100644 gcc/config/bpf/t-bpf diff --git a/configure b/configure index 63b1e33f41c..4f8e68a4085 100755 --- a/configure +++ b/configure @@ -754,6 +754,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -919,6 +920,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' @@ -1171,6 +1173,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) +ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) +runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1308,7 +1319,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1468,6 +1479,7 @@ Fine tuning of the installation directories: --sysconfdir=DIRread-only single-machine data [PREFIX/etc] --sharedstatedir=DIRmodifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIRobject code libraries [EPREFIX/lib] --includedir=DIRC header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -3353,6 +3365,9 @@ case "${target}" in # No hosted I/O support. noconfigdirs="$noconfigdirs target-libssp" ;; + bpf-*-*) +noconfigdirs="$noconfigdirs target-libssp" +;; powerpc-*-aix* | rs6000-*-aix*) noconfigdirs="$noconfigdirs target-libssp" ;; @@ -3387,12 +3402,43 @@ if test "${ENABLE_LIBSTDCXX}" = "default" ; then avr-*-*) noconfigdirs="$noconfigdirs target-libstdc++-v3" ;; +bpf-*-*) + noconfigdirs="$noconfigdirs target-libstdc++-v3" + ;; ft32-*-*) noconfigdirs="$noconfigdirs target-libstdc++-v3"