From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 126499 invoked by alias); 27 Jan 2020 17:41:51 -0000 Mailing-List: contact gcc-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-owner@gcc.gnu.org Received: (qmail 126487 invoked by uid 89); 27 Jan 2020 17:41:51 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-6.5 required=5.0 tests=AWL,BAYES_00,KAM_SHORT,SPF_PASS autolearn=ham version=3.3.1 spammy=H*r:sk:DHE_RSA, HOME, snip, gccmirror X-HELO: mail.theobroma-systems.com Received: from vegas.theobroma-systems.com (HELO mail.theobroma-systems.com) (144.76.126.164) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 27 Jan 2020 17:41:49 +0000 Received: from cablelink-187-161-146-42.pcs.intercable.net ([187.161.146.42]:45159 helo=[192.168.0.9]) by mail.theobroma-systems.com with esmtpsa (TLS1.2:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.80) (envelope-from ) id 1iw8OP-0000fj-SZ; Mon, 27 Jan 2020 18:41:46 +0100 From: Erick Ochoa Subject: Question about changing {machine,type} modes during LTO To: GCC Development , =?UTF-8?Q?Christoph_M=c3=bcllner?= , "Dr. Philipp Tomsich" Message-ID: Date: Tue, 28 Jan 2020 09:35:00 -0000 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:68.0) Gecko/20100101 Thunderbird/68.4.1 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-SW-Source: 2020-01/txt/msg00475.txt.bz2 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; : b = a[0]; b ={v} {CLOBBER}; a ={v} {CLOBBER}; _5 = 0; : : 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]; < type = astruct_s type_mode = 15> < type = astruct_s type_mode = 15> < type = astruct_s type_mode = 15> < type = astruct_s type_mode = 15> < type = astruct_s[] type_mode = 16> < type = astruct_s[] type_mode = 16> < type = integer_cst type_mode = 15> // ...SNIP... < type = astruct_s type_mode = 15> < type = astruct_s type_mode = 15> // ...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; : b = a[0]; b ={v} {CLOBBER}; a ={v} {CLOBBER}; _5 = 0; : : 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? Any help would be appreciated! Thanks -Erick