Hi Richard, Thanks! I can confirm that changing VAR_DECL's type and calling relayout_decl fixes my problem.
On 2020-01-28 4:35 a.m., Richard Biener wrote: > On Mon, Jan 27, 2020 at 6:41 PM Erick Ochoa > <erick.oc...@theobroma-systems.com> wrote: >> >> Hello, >> >> I have a problem with a transformation I'm working on and I would appreciate >> some help. The transformation I am working on removes fields in structs early >> during link-time. For the purposes of development and this example, my >> transformation deletes the field identified as "delete_me" from the struct >> identified as "astruct_s". These identifiers are hard coded in the >> transformation at the moment. >> >> For example: >> >> ```c >> int >> main() >> { >> struct astruct_s { _Bool a; _Bool delete_me; _Bool c;}; >> // more >> } >> ``` >> >> should be equivalent to >> >> ```c >> int >> main() >> { >> struct astruct_s { _Bool a; _Bool c;}; >> // more >> } >> ``` >> >> as long as no instruction accesses field "delete me". >> >> I have succeeded in eliminating field "delete_me" from struct "astruct_s" and >> at the same time successfully calculating field offsets and array offsets for >> a subset of the C syntax. I am working on expanding the allowed syntax and at >> the same time creating tests to verify my assumptions/work is still producing >> correct results. >> >> I was starting work on supporting arrays of multiple dimensions, when I found >> an interesting edge case in my transformation. I was able to transform >> structs >> of size 2, 3, (but not 4), 5, 6, 7, (but not 8), 9, 10... This was the stack >> trace when the error was triggered: >> >> ``` >> a.c: In function ‘main’: >> a.c:11:19: internal compiler error: in convert_move, at expr.c:219 >> 11 | struct astruct_s b = a[argc][argc]; >> | ^ >> 0xb8bac3 convert_move(rtx_def*, rtx_def*, int) >> /home/eochoa/code/gcc/gcc/expr.c:219 >> 0xb9f5cf store_expr(tree_node*, rtx_def*, int, bool, bool) >> /home/eochoa/code/gcc/gcc/expr.c:5825 >> 0xb9d913 expand_assignment(tree_node*, tree_node*, bool) >> /home/eochoa/code/gcc/gcc/expr.c:5509 >> 0xa08bfb expand_gimple_stmt_1 >> /home/eochoa/code/gcc/gcc/cfgexpand.c:3746 >> 0xa09047 expand_gimple_stmt >> /home/eochoa/code/gcc/gcc/cfgexpand.c:3844 >> 0xa1170f expand_gimple_basic_block >> /home/eochoa/code/gcc/gcc/cfgexpand.c:5884 >> 0xa134b7 execute >> /home/eochoa/code/gcc/gcc/cfgexpand.c:6539 >> Please submit a full bug report, >> ``` >> >> Looking at expr.c:219 I found the following assertions >> >> ```c >> /* Copy data from FROM to TO, where the machine modes are not the same. >> Both modes may be integer, or both may be floating, or both may be >> fixed-point. >> UNSIGNEDP should be nonzero if FROM is an unsigned type. >> This causes zero-extension instead of sign-extension. */ >> >> void >> convert_move (rtx to, rtx from, int unsignedp) >> { >> machine_mode to_mode = GET_MODE (to); >> machine_mode from_mode = GET_MODE (from); >> >> gcc_assert (to_mode != BLKmode); >> gcc_assert (from_mode != BLKmode); <-- crashes here >> ``` >> >> I started reading the gcc internals around machine modes: >> https://gcc.gnu.org/onlinedocs/gccint/Machine-Modes.html >> and tried the experiment where I first compiled a struct of size 2 (and >> delete >> field "delete_me"), then of size 3 and so on, and so on. I noticed that the >> TYPE_MODE for matches the machine mode. And that it varies with the size of >> the >> struct. (Which agrees with the definition of machine mode.) >> >> I originally thought that I needed to set TYPE_MODE myself, but if >> layout_type >> is called after deleting the field (which it is), then TYPE_MODE is correctly >> set somewhere within layout_type: >> https://github.com/gcc-mirror/gcc/blob/68697710fdd35077e8617f493044b0ea717fc01a/gcc/stor-layout.c#L2203 >> I verified that layout_type is setting the correct values for TYPE_MODE when >> transforming struct "astruct_s" by comparing the TYPE_MODE of different sizes >> without the transformation applied. When transforming structs, layout_type >> always returned a TYPE_MODE which matched the TYPE_MODE for unmodified >> structs >> with the same size as the transformed struct (post transformation). >> >> In other words: >> >> For variable "struct not_transformed b" without transformation I obtain >> the following relationship. Without transformation: >> >> | size | typemode | >> |------|----------| >> | 1 | 13 | >> | 2 | 14 | >> | 3 | 1 | >> | 4 | 15 | >> | 5 | 1 | >> | 6 | 1 | >> | 7 | 1 | >> | 8 | 16 | >> | 9 | 1 | >> >> With transformation (i.e. astruct_s b with a field named "delete_me") >> >> | size before | size after | typemode | >> |-------------|------------|----------| >> | 2 | 1 | 13 | >> | 3 | 2 | 14 | >> | 4 | 3 | 1 | >> | 5 | 4 | 15 | >> | 6 | 5 | 1 | >> | 7 | 6 | 1 | >> | 8 | 7 | 1 | >> | 9 | 8 | 16 | >> >> I have a similar result for variable >> "struct astructs b[]". Without modifications: >> >> | size | type_mode | >> |------|-----------| >> | 1 | 14 | >> | 2 | 15 | >> | 3 | 1 | >> | 4 | 16 | >> | 5 | 1 | >> | 6 | 1 | >> >> With deletion of a field: >> >> | old size | size | type_mode| >> |----------|------|----------| >> | 2 | 1 | 14 | >> | 3 | 2 | 15 | >> | 4 | 3 | 1 | >> | 5 | 4 | 16 | >> |6 | 5 | 1 | >> | 8 | 7 | 1 | >> | 9 | 8 | 17 | >> | 10 | 9 | 1 | >> >> >> >> So, going back to the error and the information that I had collected, I found >> out that for structs of size 3 (and arrays holding structs of size 3) the >> assigned TYPE_MODE for my machine should be BLKmode. E.g. >> >> ```c >> int >> main() >> { >> struct untransformed { _Bool a; _Bool c; _Bool d;}; >> struct untransformed b; // TYPE_MODE == BLKmode >> struct untransformed a[2]; // TYPE_MODE == BLKmode >> b = a[0]; >> } >> ``` >> >> So, when transforming structs of size 4, initially: >> >> ```c >> int >> main() >> { >> struct astruct_s { _Bool a; _Bool c; _Bool delete_me; _Bool d;}; >> struct astruct_s b; // TYPE_MODE != BLKmode >> struct astruct_s a[2]; // TYPE_MODE != BLKmode >> b = a[0]; >> } >> ``` >> >> However, after the struct is transformed, the TYPE_MODE becomes BLKmode. >> This means, that the assertion that gets triggered is correct. `from_mode` is >> indeed BLKmode and therefore the assertion gets triggered. "from_mode" should >> be BLKmode, that's something I want and expect. And the assertion that is >> not triggered >> `to_mode` is incorrect and should be triggered. This means to me that >> somehow we are >> triggering a different execution path and hitting an assertion that we should >> not have encountered in the first place. >> >> This leads me to believe that I have not changed a TYPE_MODE somewhere in the >> gimple code. Maybe specifically the variable "b" (since this is where the >> "to" >> of the expression `b = a[0]` should be. However, printing the gimple code >> after >> the transformation, shows that b is the new variable type with the correct >> TYPE_MODE: >> >> Before transformation >> ``` >> Executing structreorg >> main (int argc, char * * argv) >> { >> struct astruct_s a[2]; >> struct astruct_s b; >> int D.10221; >> >> <bb 2> : >> b = a[0]; >> b ={v} {CLOBBER}; >> a ={v} {CLOBBER}; >> _5 = 0; >> >> <bb 3> : >> <L0>: >> return _5; >> >> } >> ``` >> >> Some output of my pass: >> ``` >> modifying,astruct_s >> offset,astruct_reorged,a,0 >> offset,astruct_reorged,c,1 >> offset,astruct_reorged,d,2 >> old type_mode 15 >> new type_mode 1 // This is BLKmode >> new type,astruct_reorged >> >> modifying,astruct_s[] >> old type_mode 16 >> new type_mode 1 // This is BLKmode >> new type,astruct_reorged[] >> ``` >> >> We can also look at the offending expression more indepth. >> The type_mode's are unchanged here, but they are changed at the end. >> >> ``` >> b = a[0]; >> <rewrite_expr "b"> >> < type = astruct_s type_mode = 15> >> <rewrite_var_decl "b"> >> < type = astruct_s type_mode = 15> >> </ type = astruct_s type_mode = 15> >> </rewrite_var_decl "b"> >> </ type = astruct_s type_mode = 15> >> </rewrite_expr "b"> >> >> <rewrite_expr "a[0]"> >> < type = astruct_s type_mode = 15> >> <rewrite_array_ref "a[0]"> >> < type = astruct_s type_mode = 15> >> >> <rewrite_expr "a"> >> < type = astruct_s[] type_mode = 16> >> <rewrite_var_decl "a"> >> < type = astruct_s[] type_mode = 16> >> </ type = astruct_s[] type_mode = 16> >> </ type = astruct_s[] type_mode = 16> >> </rewrite_expr "a"> >> >> <rewrite_expr "0"> >> < type = integer_cst type_mode = 15> >> </ type = integer_cst type_mode = 15> >> </rewrite_expr "0"> >> >> </ type = astruct_reorged type_mode = 1> >> </rewrite_array_ref "a[0]"> >> >> </ type = astruct_reorged type_mode = 1> >> </rewrite_expr "a[0]"> >> >> // ...SNIP... >> >> <rewrite_expr "{CLOBBER}"> >> < type = astruct_s type_mode = 15> >> <rewrite_constructor "{CLOBBER}"> >> < type = astruct_s type_mode = 15> >> </ type = astruct_reorged type_mode = 1> >> </rewrite_constructor "{CLOBBER}"> >> </ type = astruct_reorged type_mode = 1> >> </rewrite_expr "{CLOBBER}"> >> >> // ...SNIP... >> >> // Here is where the type mode are definitely modified for >> // local variables >> rewriting,local_decl struct astruct_s a[2];, struct astruct_reorged a[2]; >> rewriting,local_decl struct astruct_s b;, struct astruct_reorged b; >> >> ``` >> >> After the pass finishes this is the gimple I see. >> >> ``` >> >> main (int argc, char * * argv) >> { >> struct astruct_reorged a[2]; >> struct astruct_reorged b; >> int D.10221; >> >> <bb 2> : >> b = a[0]; >> b ={v} {CLOBBER}; >> a ={v} {CLOBBER}; >> _5 = 0; >> >> <bb 3> : >> <L0>: >> return _5; >> >> } >> ``` >> >> So just to summarize, things changed include: >> * Variable's Type b >> * Variable's Type a >> * Expression's Type a[0] >> * {CLOBBER} expression's type >> >> I have also tried using GDB to get a better grasp on how to fix the problem. >> I use the following command to explore gcc's run time state in gdb. >> $HOME/code/gcc-inst/bin/gcc -flto -fipa-typelist -fdump-ipa-typelist a.c >> -wrapper gdb,--args >> I am able to see that the IPA passes are successfully executed, however, I am >> never able to trigger a breakpoint during RTL generation. This is how I use >> gdb: >> >> * I go to the third gdb instance to look at the linker in gdb >> * set catchpoints for fork and vfork >> * and look at the inferior process #5 which is where LTO is applied. >> * I've tried to set a breakpoint for symbols "execute" and I mostly just see >> all IPA passes, but I do not see pass_expand::execute. >> * I've also looked other inferior processes but I cannot set a >> breakpoint before the assertion is hit. GCC just exists normally. >> >> Can anyone help me understand what could possibly be happening? >> Some possibilities: >> * Another LTO uses summary information and changes the type back to >> non-BLKmode? (However, I also tried passing -flto-partition=none to >> avoid summaries.) >> * I am missing setting something in gimple which I do not know what that >> could be? (Printing gimple doesn't show all information, but I did try >> to set everything correctly). >> * I am failing to communicate this change to other link time opts? >> (I am changing the definition of this function as opposed to creating >> a clone and then dropping the previous definition). >> * Some other thing? > > My first guess would be that you need to re-layout all decls that refer to the > re-layouted type. > > Richard. > >> Any help would be appreciated! >> Thanks >> >> -Erick