All of lore.kernel.org
 help / color / mirror / Atom feed
* [cocci] How do you add a function argument when an identifier exists in the function?
@ 2022-03-05 21:35 Eric Wheeler
  2022-03-05 21:47 ` Julia Lawall
  2022-03-06 15:43 ` Markus Elfring
  0 siblings, 2 replies; 6+ messages in thread
From: Eric Wheeler @ 2022-03-05 21:35 UTC (permalink / raw)
  To: cocci

Hello,

I'm trying to convert an existing global typedef struct to be the first 
function parameter whenever it is used so we can move away from global 
varaiables and make the code more flexible and thread-safe.

If I have functions like this:

	void f(int i) {
		nec->x = i;
	}

	int g(int i) {
		return i+1;
	}

Then I want to prepend an argument only if the existing global
`nec_t *nec` is used in the function.  Thus `g` is unmodified and `f` 
would become:

	void f(nec_t *nec, int i) {
		nec->x = i;
	}

This is the patch I'm trying and it doesn't seem to be matching nec->j:
	@ rule1 @
	type T;
	identifier F, j;
	typedef nec_t;
	parameter list PL;
	@@

	T F(
	-PL
	+nec_t *nec, PL
	 )
	{
	...
	nec->j
	...
	}

If I remove `nec->j` from the patch so it is just this:
	T F(
	-PL
	+nec_t *nec, PL
	 )
	{
	...
	}

then the parameter list is correctly modified (in all functions), but how 
do I properly check and only add the parameter when `nec` is used in the 
function?

A couple notes:
    *  `nec` is currently global, it is already used in the function.  
       I'm trying to change it to a parameter so I can drop the globals.

    * The acutal use of `nec` can be quite complex.  For example:
        curd= CCJ * v/(( log(2.0 * nec->dataj.s/ nec->data.bi[is])-1.0)) ...
      so we want to match if `nec` is used in any form. 

Thanks for your help!


--
Eric Wheeler

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [cocci] How do you add a function argument when an identifier exists in the function?
  2022-03-05 21:35 [cocci] How do you add a function argument when an identifier exists in the function? Eric Wheeler
@ 2022-03-05 21:47 ` Julia Lawall
  2022-03-06 13:43   ` Markus Elfring
  2022-03-06 15:43 ` Markus Elfring
  1 sibling, 1 reply; 6+ messages in thread
From: Julia Lawall @ 2022-03-05 21:47 UTC (permalink / raw)
  To: Eric Wheeler; +Cc: cocci



On Sat, 5 Mar 2022, Eric Wheeler wrote:

> Hello,
>
> I'm trying to convert an existing global typedef struct to be the first
> function parameter whenever it is used so we can move away from global
> varaiables and make the code more flexible and thread-safe.
>
> If I have functions like this:
>
> 	void f(int i) {
> 		nec->x = i;
> 	}
>
> 	int g(int i) {
> 		return i+1;
> 	}
>
> Then I want to prepend an argument only if the existing global
> `nec_t *nec` is used in the function.  Thus `g` is unmodified and `f`
> would become:
>
> 	void f(nec_t *nec, int i) {
> 		nec->x = i;
> 	}
>
> This is the patch I'm trying and it doesn't seem to be matching nec->j:
> 	@ rule1 @
> 	type T;
> 	identifier F, j;
> 	typedef nec_t;
> 	parameter list PL;
> 	@@
>
> 	T F(
> 	-PL
> 	+nec_t *nec, PL
> 	 )
> 	{
> 	...
> 	nec->j
> 	...
> 	}

This doesn't work because it requires that nec->j appears exactly once (ie
not in the part matched by ...) along every control-flow path of the
function.  You can do the following:

       T F(
       -PL
       +nec_t *nec, PL
        )
       {
       ... when exists
           when any
       nec->j
       ... when exists
           when any
       }

The when exists requires that only (ie at least) one path have the
property and the when allows other occurrences of nec->j

julia

>
> If I remove `nec->j` from the patch so it is just this:
> 	T F(
> 	-PL
> 	+nec_t *nec, PL
> 	 )
> 	{
> 	...
> 	}
>
> then the parameter list is correctly modified (in all functions), but how
> do I properly check and only add the parameter when `nec` is used in the
> function?
>
> A couple notes:
>     *  `nec` is currently global, it is already used in the function.
>        I'm trying to change it to a parameter so I can drop the globals.
>
>     * The acutal use of `nec` can be quite complex.  For example:
>         curd= CCJ * v/(( log(2.0 * nec->dataj.s/ nec->data.bi[is])-1.0)) ...
>       so we want to match if `nec` is used in any form.
>
> Thanks for your help!
>
>
> --
> Eric Wheeler
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [cocci] How do you add a function argument when an identifier exists in the function?
  2022-03-05 21:47 ` Julia Lawall
@ 2022-03-06 13:43   ` Markus Elfring
  2022-03-06 14:01     ` Julia Lawall
  0 siblings, 1 reply; 6+ messages in thread
From: Markus Elfring @ 2022-03-06 13:43 UTC (permalink / raw)
  To: Eric Wheeler, Julia Lawall; +Cc: cocci


> You can do the following:
>
>         T F(
>         -PL
>         +nec_t *nec, PL
>          )
>         {
>         ... when exists
>             when any
>         nec->j
>         ... when exists
>             when any
>         }
>
> The when exists requires that only (ie at least) one path have the
> property and the when allows other occurrences of nec->j


How do you think about to work with the following SmPL script variant?


@add_first_function_argument@
type rt;
identifier func, member;
typedef td;
parameter list pl;
@@
  rt func(
+        td* nec,
          pl
         )
  {
  ... when exists
      when any
  nec->member
  ... when exists
      when any
  }


Would you eventually like to use another SmPL ellipsis instead of the
explicit specification
for the parameter list variable?

Regards,
Markus


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [cocci] How do you add a function argument when an identifier exists in the function?
  2022-03-06 13:43   ` Markus Elfring
@ 2022-03-06 14:01     ` Julia Lawall
  0 siblings, 0 replies; 6+ messages in thread
From: Julia Lawall @ 2022-03-06 14:01 UTC (permalink / raw)
  To: Markus Elfring; +Cc: Eric Wheeler, cocci

[-- Attachment #1: Type: text/plain, Size: 992 bytes --]



On Sun, 6 Mar 2022, Markus Elfring wrote:

>
> > You can do the following:
> >
> >         T F(
> >         -PL
> >         +nec_t *nec, PL
> >          )
> >         {
> >         ... when exists
> >             when any
> >         nec->j
> >         ... when exists
> >             when any
> >         }
> >
> > The when exists requires that only (ie at least) one path have the
> > property and the when allows other occurrences of nec->j
>
>
> How do you think about to work with the following SmPL script variant?
>
>
> @add_first_function_argument@
> type rt;
> identifier func, member;
> typedef td;
> parameter list pl;
> @@
>  rt func(
> +        td* nec,
>          pl
>         )
>  {
>  ... when exists
>      when any
>  nec->member
>  ... when exists
>      when any
>  }
>
>
> Would you eventually like to use another SmPL ellipsis instead of the
> explicit specification
> for the parameter list variable?

This should also work.

julia

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [cocci] How do you add a function argument when an identifier exists in the function?
  2022-03-05 21:35 [cocci] How do you add a function argument when an identifier exists in the function? Eric Wheeler
  2022-03-05 21:47 ` Julia Lawall
@ 2022-03-06 15:43 ` Markus Elfring
  2022-03-06 23:53   ` Eric Wheeler
  1 sibling, 1 reply; 6+ messages in thread
From: Markus Elfring @ 2022-03-06 15:43 UTC (permalink / raw)
  To: Eric Wheeler; +Cc: cocci


> I'm trying to convert an existing global typedef struct


Would you become interested in any more source code transformations
where data from global variables with selected types should be passed
by additional function arguments?


> to be the first function parameter whenever it is used so we can move away
> from global varaiables and make the code more flexible and thread-safe.


How much does the parameter position matter for your software adjustments?


Regards,
Markus


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [cocci] How do you add a function argument when an identifier exists in the function?
  2022-03-06 15:43 ` Markus Elfring
@ 2022-03-06 23:53   ` Eric Wheeler
  0 siblings, 0 replies; 6+ messages in thread
From: Eric Wheeler @ 2022-03-06 23:53 UTC (permalink / raw)
  To: Markus Elfring; +Cc: cocci

On Sun, 6 Mar 2022, Markus Elfring wrote: 
> > I'm trying to convert an existing global typedef struct
> 
> Would you become interested in any more source code transformations
> where data from global variables with selected types should be passed
> by additional function arguments?

In our use case there were a bunch of global structs that defined the 
program state.  The first transform was to move all of these global 
structs into a single global struct `nec` which looked like this (thanks 
Julia!):

	@ rule1 @
	global idexpression I = {cm,cmag,crnt,ct1m,ct2m,data,dataj,fpat,ggrid,gnd,gwav,impedance_data,incom,matpar,near_field,netcx,save,segj,smat,calc_data,zload,vsorc};
	identifier j;
	@@
	-I@j
	+nec->j

The `nec` variable is still a global after this transpose, which gives me 
a chance to build the program (www.xnec2c.org) and make sure it still 
works as expected:

	nec_t _nec, *nec = &_nec;

Coccinelle is amazing: This first patch hit ~3300 replacements and the 
code still works.


Since many global values were moved into a single global struct, I don't 
have many other use cases for moving globals into parameters, just `nec`.

Now that `nec` is global and encapsulates each state, the next step is to 
pass it by parameter as noted earlier in this email thread so different 
"struct objects" can be passed down the stack in different threads.  Then 
I can delete the temporary `*nec = &_nec` storage.

There might be other global state stored in static local function 
variables (or static global variables in their own .c file) that I haven't 
discovered yet: see the "How can I find all static variable declarations?" 
thread from a few days ago that is having spatch trouble.

As I find those statics (if any) they will be moved into the `nec` struct 
somewhere so all shared state can be passed down the stack.

> > to be the first function parameter whenever it is used so we can move away
> > from global varaiables and make the code more flexible and thread-safe.
> 
> How much does the parameter position matter for your software adjustments?

To me it matters, but just as a matter of preference.  I've done a lot of 
Perl programming where the first variable in the input list to a function 
is the class object.  Here is a Perl example where $self is akin to "this" 
in C++:

	sub foo
	{
		my ($self, $arg1, $arg2, @other_args_list) = @_;

		return $self->bar($arg1+$arg2, @other_args_list);
	}

	$obj->foo(1, 2, 'a', 'b');


So I put `nec` as the first parameter since the NEC2 code is still written 
in C but is becoming "struct (object) oriented".  


--
Eric Wheeler



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-03-06 23:54 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-05 21:35 [cocci] How do you add a function argument when an identifier exists in the function? Eric Wheeler
2022-03-05 21:47 ` Julia Lawall
2022-03-06 13:43   ` Markus Elfring
2022-03-06 14:01     ` Julia Lawall
2022-03-06 15:43 ` Markus Elfring
2022-03-06 23:53   ` Eric Wheeler

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.