Problem with init of structure bit fields
Hi, I'm doing a port of gcc 4.3.3 on a custom architecture and I'm having trouble when initializing the bit fields of a structure. The testcase is based on a modified gcc torture testcase, the natural registers are 16 bits, and long long is defined to be 64 bit wide: struct itmp { long long int pad : 30; long long int field : 34; }; struct itmp itmp = {0x123LL, 0x123456LL}; int main(void) { itmp.field = 0x42; return 1; } Running the above example gives (compiled with -O0...): 12itmp.field = 0x42; (gdb) p/x itmp $1 = {pad = 0x123, field = 0x123456} (gdb) n 13return 1; (gdb) p/x itmp $2 = {pad = 0x123, field = 0x0} If I use 32 bits for pad and 32 bits for field, the result is correct. Also, if I use 'long' instead of 'long long' (and change the bit lengths of course), it works too. Looking at the RTL shows the problem right from the beginning, in the expand pass (there is no reference to the constant 66 = 0x42 in the RTL below): ;; itmp.field = 66 (insn 5 4 6 991118-1.c:12 (set (reg/f:HI 25) (symbol_ref:HI (itmp) [flags 0x2] var_decl 0xb7c460b0 itmp)) -1 (nil)) (insn 6 5 7 991118-1.c:12 (set (reg:HI 26) (reg/f:HI 25)) -1 (nil)) (insn 7 6 8 991118-1.c:12 (set (reg/f:HI 27) (plus:HI (reg/f:HI 25) (const_int 6 [0x6]))) -1 (nil)) (insn 8 7 9 991118-1.c:12 (set (reg:HI 28) (const_int 0 [0x0])) -1 (nil)) (insn 9 8 10 991118-1.c:12 (set (mem/s/j/c:HI (reg/f:HI 27) [0+6 S2 A16]) (reg:HI 28)) -1 (nil)) (insn 10 9 11 991118-1.c:12 (set (reg:HI 29) (reg/f:HI 25)) -1 (nil)) (insn 11 10 12 991118-1.c:12 (set (reg/f:HI 30) (plus:HI (reg/f:HI 25) (const_int 4 [0x4]))) -1 (nil)) (insn 12 11 13 991118-1.c:12 (set (reg:HI 31) (const_int 0 [0x0])) -1 (nil)) (insn 13 12 14 991118-1.c:12 (set (mem/s/j/c:HI (reg/f:HI 30) [0+4 S2 A16]) (reg:HI 31)) -1 (nil)) (insn 14 13 15 991118-1.c:12 (set (reg:HI 32) (reg/f:HI 25)) -1 (nil)) (insn 15 14 16 991118-1.c:12 (set (reg/f:HI 33) (plus:HI (reg/f:HI 25) (const_int 2 [0x2]))) -1 (nil)) (insn 16 15 17 991118-1.c:12 (set (reg:HI 34) (mem/s/j/c:HI (reg/f:HI 33) [0+2 S2 A16])) -1 (nil)) (insn 17 16 18 991118-1.c:12 (set (reg:HI 36) (const_int -4 [0xfffc])) -1 (nil)) (insn 18 17 19 991118-1.c:12 (set (reg:HI 35) (and:HI (reg:HI 34) (reg:HI 36))) -1 (nil)) (insn 19 18 0 991118-1.c:12 (set (mem/s/j/c:HI (reg/f:HI 33) [0+2 S2 A16]) (reg:HI 35)) -1 (nil)) Any idea on what is happenning here ? Am I missing some standard patterns in my .md file ? Thanks ! -- Stelian Pop stel...@popies.net
Re: Problem with init of structure bit fields
On Wed, Jun 03, 2009 at 07:49:29PM +0200, Stelian Pop wrote: I'm doing a port of gcc 4.3.3 on a custom architecture and I'm having trouble when initializing the bit fields of a structure. Ok, after further analysis, it looks like a genuine bug in gcc, in store_bit_field_1(): when a field is bigger than a word, the rvalue is splitted in several words, after being placed in a smallest_mode_for_size() operand. But the logic for adressing the words of this operand is buggy in the WORDS_BIG_ENDIAN case, the most signficant words being used instead of the least significant ones. The following patch corrects this, and makes the gcc.c-torture/execute/991118-1.c testcase work correctly on my platform. Stelian. diff --git a/gcc/expmed.c b/gcc/expmed.c index dc61de7..03c60a8 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -582,7 +582,10 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, { /* If I is 0, use the low-order word in both field and target; if I is 1, use the next to lowest word; and so on. */ - unsigned int wordnum = (backwards ? nwords - i - 1 : i); + unsigned int wordnum = (backwards + ? GET_MODE_SIZE(fieldmode) / UNITS_PER_WORD + - i - 1 + : i); unsigned int bit_offset = (backwards ? MAX ((int) bitsize - ((int) i + 1) * BITS_PER_WORD, -- Stelian Pop stel...@popies.net
Re: Problem with init of structure bit fields
On Wed, Jun 03, 2009 at 01:07:08PM -0700, Ian Lance Taylor wrote: - unsigned int wordnum = (backwards ? nwords - i - 1 : i); + unsigned int wordnum = (backwards + ? GET_MODE_SIZE(fieldmode) / UNITS_PER_WORD + - i - 1 + : i); unsigned int bit_offset = (backwards ? MAX ((int) bitsize - ((int) i + 1) * BITS_PER_WORD, Your patch looks correct. However, it makes me wonder how the test case passes on existing big-endian platforms, such as the PowerPC. Can you explain how that works? I'm not sure, but it is related to the smaller word size on my platform and the size of the field (a 64 bit long long). The 991118-1.c test case passes ok on my platform when the word size is 32 or 16 bits (my processor has configurable word sizes). The only configuration that fails is when the word size is 8 bits... When I tried to simplify the testcase I obtained the simple assignment problem I posted in the original mail. And that problem was visible in both 8 and 16 bits configurations. So I suspect the problem won't be seen on PowerPC unless someone does TI or OI bit fields... -- Stelian Pop stel...@popies.net
Issues with testsuite on constant pointer arithmetics
Hi all, I'm reaching the final stages of my port of gcc to a custom microcontroller and at this point real world examples seem to work, I only have a few dozen tests of the testsuite which give me trouble. All those tests involve arithmetics on pointers (or labels), and I'm not sure if the tests show a real problem in my port or if the tests are not relevant given the specifics of my microcontroller (size of pointers not being a long, int not being a natural register etc). Before going further, a bit of background: this microcontroller is special in that it can be configured to work in 4 different modes: 8 bit wide, 16 bit, 16 bit wide and 32 bits. The code below speaks for itself: #define BITS_PER_UNIT 8 #define UNITS_PER_WORD (TARGET_8W ? 1 : (TARGET_16 || TARGET_16W) ? 2 : 4) #define SHORT_TYPE_SIZE 16 #define INT_TYPE_SIZE 16 #define LONG_TYPE_SIZE 32 #define LONG_LONG_TYPE_SIZE 64 #define FLOAT_TYPE_SIZE 32 #define DOUBLE_TYPE_SIZE64 #define LONG_DOUBLE_TYPE_SIZE 64 #define SIZE_TYPE unsigned int #define PTRDIFF_TYPE_SIZE ((TARGET_8W || TARGET_16) ? int : long int) #define Pmode ((TARGET_8W || TARGET_16) ? HImode : SImode) #define POINTER_SIZE((TARGET_8W || TARGET_16) ? 16 : 32) Now, back to my problems: the following tests fail with error: initializer element is not constant: on TARGET_8W and TARGET_16: 920928-1.c: 1 struct{int c;}v; 2 static long i=((char*)(v.c)-(char*)v) 930326-1.c: 1 struct 2 { 3 char a, b, f[3]; 4 } s; 5 6 long i = s.f-s.b; labels-3.c: 9 int foo (int a) 10 { 11 static const short ar[] = { l1 - l1, l2 - l1 }; 12 void *p = l1 + ar[a]; 13 goto *p; 14 l1: 15 return 1; 16 l2: 17 return 2; 18 } on TARGET_16W and TARGET_32: 2004-1.c: 1 extern void _text; 2 static __SIZE_TYPE__ x = (__SIZE_TYPE__) _text - 0x1000L - 1; Are those tests expected to fail on my port or is that something I've obviously done wrong ? Thanks. Stelian. -- Stelian Pop stel...@popies.net
Re: Issues with testsuite on constant pointer arithmetics
On Wed, May 06, 2009 at 12:19:55PM -0700, Ian Lance Taylor wrote: Stelian Pop stel...@popies.net writes: on TARGET_8W and TARGET_16: 920928-1.c: 1 struct{int c;}v; 2 static long i=((char*)(v.c)-(char*)v) 930326-1.c: 1 struct 2 { 3 char a, b, f[3]; 4 } s; 5 6 long i = s.f-s.b; labels-3.c: 9 int foo (int a) 10 { 11 static const short ar[] = { l1 - l1, l2 - l1 }; 12 void *p = l1 + ar[a]; 13 goto *p; 14 l1: 15 return 1; 16 l2: 17 return 2; 18 } on TARGET_16W and TARGET_32: 2004-1.c: 1 extern void _text; 2 static __SIZE_TYPE__ x = (__SIZE_TYPE__) _text - 0x1000L - 1; Are those tests expected to fail on my port or is that something I've obviously done wrong ? I don't see any particular reason that these tests should fail. I hasten to add that these tests are not very important and it is unlikely that a failure to pass these tests will affect any actual program. You didn't mention which version of gcc you are based on. Do you have these patches? If not, that may be your problem. Sorry, fergot to say that I was using gcc 4.3.3, so yes, the patches you mention are already in. Even if you do have those patches, that code is where I would start looking. Your initializers are constant, but something in that area thinks that they are not constant. I did spent a few hours looking but haven't had much luck. I tried tracing this one: 6 long i = s.f-s.b; and noticed that the pointers gets casted to 'long' (so they become integers and no longer pointers) before the actual substraction is made. Of course, replacing the 'long' with 'int' (on the incriminated targets, where the real size of the pointer is 16 bit, the size of an 'int') makes the code compile as a charm. Stelian. -- Stelian Pop stel...@popies.net
Re: Issues with testsuite on constant pointer arithmetics
On Wed, May 06, 2009 at 01:23:57PM -0700, Ian Lance Taylor wrote: Stelian Pop stel...@popies.net writes: I did spent a few hours looking but haven't had much luck. I tried tracing this one: 6 long i = s.f-s.b; and noticed that the pointers gets casted to 'long' (so they become integers and no longer pointers) before the actual substraction is made. Of course, replacing the 'long' with 'int' (on the incriminated targets, where the real size of the pointer is 16 bit, the size of an 'int') makes the code compile as a charm. I took a quick look at a similar case for x86, and the key step seems to be a call to ptr_difference_const. It converts the difference of two ADDR_EXPRs to a constant. in my case ptr_difference_const doesn't get called at all, because the operands are no longer ADDR_EXPRs: (gdb) p debug_tree(op0) nop_expr 0xb7cfd120 type integer_type 0xb7c9d3a8 long int public SI size integer_cst 0xb7c904b4 constant invariant 32 unit size integer_cst 0xb7c90230 constant invariant 4 align 8 symtab 0 alias set -1 canonical type 0xb7c9d3a8 precision 32 min integer_cst 0xb7c90460 -2147483648 max integer_cst 0xb7c9047c 2147483647 pointer_to_this pointer_type 0xb7ca7478 constant invariant arg 0 convert_expr 0xb7cfd100 type integer_type 0xb7c9d2d8 int public HI size integer_cst 0xb7c9039c constant invariant 16 unit size integer_cst 0xb7c903b8 constant invariant 2 align 8 symtab 0 alias set -1 canonical type 0xb7c9d2d8 precision 16 min integer_cst 0xb7c903f0 -32768 max integer_cst 0xb7c9040c 32767 pointer_to_this pointer_type 0xb7ca4680 constant invariant arg 0 addr_expr 0xb7cfd080 type pointer_type 0xb7cfa7b8 constant invariant arg 0 component_ref 0xb7c99050 type array_type 0xb7cfa750 arg 0 var_decl 0xb7c980b0 s arg 1 field_decl 0xb7d050b8 f (gdb) p debug_tree(op1) nop_expr 0xb7cfd0e0 type integer_type 0xb7c9d3a8 long int public SI size integer_cst 0xb7c904b4 constant invariant 32 unit size integer_cst 0xb7c90230 constant invariant 4 align 8 symtab 0 alias set -1 canonical type 0xb7c9d3a8 precision 32 min integer_cst 0xb7c90460 -2147483648 max integer_cst 0xb7c9047c 2147483647 pointer_to_this pointer_type 0xb7ca7478 constant invariant arg 0 convert_expr 0xb7cfd0c0 type integer_type 0xb7c9d2d8 int public HI size integer_cst 0xb7c9039c constant invariant 16 unit size integer_cst 0xb7c903b8 constant invariant 2 align 8 symtab 0 alias set -1 canonical type 0xb7c9d2d8 precision 16 min integer_cst 0xb7c903f0 -32768 max integer_cst 0xb7c9040c 32767 pointer_to_this pointer_type 0xb7ca4680 constant invariant arg 0 addr_expr 0xb7cfd060 type pointer_type 0xb7ca6f70 constant invariant arg 0 component_ref 0xb7c99078 type integer_type 0xb7c9d1a0 char arg 0 var_decl 0xb7c980b0 s arg 1 field_decl 0xb7d0505c b -- Stelian Pop stel...@popies.net
Re: Issues with testsuite on constant pointer arithmetics
On Wed, May 06, 2009 at 03:42:47PM -0700, Ian Lance Taylor wrote: Stelian Pop stel...@popies.net writes: There is something strange in your trees. Why did it convert the pointers to long int? Why did it not simply convert them to int? The fact that they are going to be assigned to a long int variable should not have caused them to convert to long int. Oh, I see it comes from PTRDIFF_TYPE, which defaults to long int. Try doing #define PTRDIFF_TYPE int in your CPU.h file. Of course, and I thought I did: On Wed, May 06, 2009 at 06:15:40PM +0200, Stelian Pop wrote: #define PTRDIFF_TYPE_SIZE ((TARGET_8W || TARGET_16) ? int : long int) ... except that there's a typo in there. Once corrected, all things are back to normal. Thanks, and sorry for the noise. Now, where's that brown paper bag... Stelian. -- Stelian Pop stel...@popies.net
question on 16 bit registers with 32 bit pointers
Hi, I'm (still) porting GCC to a 16 bit microcontroller, and I'm having a few issues with the way it handles memory accesses: this microcontroller can function in two modes: in one of them the pointers are on 16 bit (a full register), in the second one the pointers are on 32 bit and are stored in two following registers (N and N+1). I did implement a GCC option to select between the two modes, and I'm using this option to select the size of the pointers and Pmode: #define Pmode ((TARGET_16) ? HImode : SImode) #define POINTER_SIZE((TARGET_16) ? 16 : 32) Do I need to define movsi3(), addsi3() etc. patterns manually or should GCC figure those by itself ? Is there something special I need to do to express the relationship between the two registers N and N+1 composing a pointer, or does GCC automatically allocate two subsequent HI registers when it needs a SI one ? Thanks. -- Stelian Pop stel...@popies.net
Re: question on 16 bit registers with 32 bit pointers
On Fri, Apr 10, 2009 at 06:29:06PM +0100, Dave Korn wrote: Stelian Pop wrote: Hi, I'm (still) porting GCC to a 16 bit microcontroller, and I'm having a few issues with the way it handles memory accesses: this microcontroller can function in two modes: in one of them the pointers are on 16 bit (a full register), in the second one the pointers are on 32 bit and are stored in two following registers (N and N+1). I did implement a GCC option to select between the two modes, and I'm using this option to select the size of the pointers and Pmode: #define Pmode ((TARGET_16) ? HImode : SImode) #define POINTER_SIZE ((TARGET_16) ? 16 : 32) Do I need to define movsi3(), addsi3() etc. patterns manually or should GCC figure those by itself ? Not sure I understand you. You always need to define movMM3 etc. GCC will correctly select between movhi3 and movsi3 based on your Pmode macro when handling pointers, but you still need to write the patterns. The thing is that this CPU does not have any real 32 bit registers, or instructions to do assignments/additions/etc to 32 bit registers. So the 32 bit operations (on pointers) need to be emulated using the 16 bit components, and I thought that GCC can do this automatically for me ... Is there something special I need to do to express the relationship between the two registers N and N+1 composing a pointer, or does GCC automatically allocate two subsequent HI registers when it needs a SI one ? GCC always uses consecutive hard regs when doing multi-reg data sizes. See HARD_REGNO_MODE_OK in the internals docs. Great, thanks ! Stelian. -- Stelian Pop stel...@popies.net
Re: How to use a scratch register in jump pattern ?
On Wed, Mar 11, 2009 at 03:33:28PM +0100, Ulrich Weigand wrote: It doesn't work. It causes a loop somewhere in gcc. I can get a gdb trace if needed. Yes, this does not work. Jumps are special; the CFG logic makes a lot of assumptions how jump patterns look. [...] The s390 back-end globally reserves a register for the purpose of holding the target of long branches (well, the register is also used as link register for calls). Ok, so I'll reserve a register for indirect jumps too then. I was hoping to be able to avoid this. Thanks ! Stelian. -- Stelian Pop stel...@popies.net
Re: How to use a scratch register in jump pattern ?
On Wed, Mar 11, 2009 at 08:33:34AM +0100, Georg-Johann Lay wrote: Stelian Pop schrieb: On Tue, Mar 10, 2009 at 10:18:10PM +0100, Georg-Johann Lay wrote: Note that no one is generating an insn that looks like *jump. Maybe insn combine and peep2 would try to build such a pattern, but that is not what helpd you out here. Write the expander as parallel of a (set (pc) ...) and a (clobber (match_scratch ...)) so that an appropriate insn is expanded. Like this ? (define_expand jump [(parallel [(set (pc) (label_ref (match_operand 0 ))) (clobber (match_scratch:QI 1 =r))])] ) Constraints are useless in expanders. Of course, copy'n'paste error. You really need a QI scratch? Your insn looks as if HI was needed as you load hi and lo part of the scratch. Yes, QI is correct: my microcontroller is a bit special in that in has 16 bit bytes (BITS_PER_UNIT=16). [...] So you have just one alternative =r, and in the case of rjmp the scratch is unused. Ok, so I ended up with (omitting the jump lengths for now): (define_insn *jump [(set (pc) (label_ref (match_operand 0 ))) (clobber (match_scratch:QI 1 =r))] { return ldih %1,hi(%l0)\n\t\n\tldil %1,lo(%l0)\n\tijmp (%1); } ) (define_expand jump [(parallel [(set (pc) (label_ref (match_operand 0 ))) (clobber (match_scratch:QI 1 ))])] ) It doesn't work. It causes a loop somewhere in gcc. I can get a gdb trace if needed. Note that you emit up to three instructions, so the -2048/2047 may crash in corner cases. Right, thanks ! You can have a look at avr, it computes jump lengths as well but afaIr without needing a scratch for long jumps. I'll do. I'm trying now first to get the indirect jump to work, and I'll put the test for the jumps lenghts later. Thanks, -- Stelian Pop stel...@popies.net
How to use a scratch register in jump pattern ?
Hi, I need to use a scratch register in the jump pattern and I can't figure out how to do it properly. My problem is that the microcontroller I'm porting gcc onto does not permit far jumps, those must be done using an indirect adressing. So I wrote this: -8--8- (define_attr length (const_int 2)) (define_insn *jump [(set (pc) (label_ref (match_operand 0 ))) (clobber (match_scratch:QI 1 =r))] { if (get_attr_length (insn) == 1) return rjmp %0; else return ldih %1,hi(%l0)\n\t\n\tldil %%1,lo(%l0)\n\tijmp %(%1); } [(set (attr length) (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048)) (le (minus (match_dup 0) (pc)) (const_int 2047))) (const_int 1) (const_int 2)))] ) (define_expand jump [(set (pc) (label_ref (match_operand 0 )))] ) -8--8- But it doesn't work: ... (jump_insn 44 266 45 6 /tmp/src/gcc-4.3.1/libgcc/../gcc/libgcov.c:137 (set (pc) (label_ref 119)) -1 (nil)) /tmp/src/gcc-4.3.1/libgcc/../gcc/libgcov.c:577: internal compiler error: in extract_insn, at recog.c:1990 Please submit a full bug report, with preprocessed source if appropriate. Any idea ? Side question regarding the length attribute. It seems to work ok, but if I change the default value (first line in my example) to be 'const_int 1', I later get 'operand out of range' from the assembler because the 'rjmp' instruction was used for deplacements bigger than 2048. How can this happen, since my '(set (attr length)' code explicitly sets the correct value each time ? Thanks, -- Stelian Pop stel...@popies.net
Re: How to use a scratch register in jump pattern ?
On Tue, Mar 10, 2009 at 05:20:28PM +, Dave Korn wrote: Stelian Pop wrote: I need to use a scratch register in the jump pattern and I can't figure out how to do it properly. My problem is that the microcontroller I'm porting gcc onto does not permit far jumps, those must be done using an indirect adressing. (define_insn *jump Any idea ? You should be able to define/use the indirect_jump pattern instead? Take a look at the last paragraph of the the docs for the call pattern as well. I already do have an indirect_jump pattern in my md file: (define_insn indirect_jump [(set (pc) (match_operand:QI 0 register_operand r))] ijmp (%0) [(set_attr cc none)] ) However, I didn't find a way to say to gcc that it cannot use the direct jump in some cases, and force it to use the indirect_jump instead. I don't think it'll work to have a jump insn that is sometimes direct, sometimes indirect. Looking at how the rs6000 backend handles direct and indirect calls and jumps might give you some inspiration too. Well, I already did look at all the backends, but didn't find the answer (although the answer probably is hidden somewhere inside those files...). As for the rs6000 backend I see a simple direct call pattern, not sure what you want me to look at: in rs6000.md: (define_insn jump [(set (pc) (label_ref (match_operand 0 )))] b %l0 [(set_attr type branch)]) Thanks, Stelian. -- Stelian Pop stel...@popies.net
Re: How to use a scratch register in jump pattern ?
On Tue, Mar 10, 2009 at 10:18:10PM +0100, Georg-Johann Lay wrote: Note that no one is generating an insn that looks like *jump. Maybe insn combine and peep2 would try to build such a pattern, but that is not what helpd you out here. Write the expander as parallel of a (set (pc) ...) and a (clobber (match_scratch ...)) so that an appropriate insn is expanded. Like this ? (define_expand jump [(parallel [(set (pc) (label_ref (match_operand 0 ))) (clobber (match_scratch:QI 1 =r))])] ) Also note that *jump is an (implicit) parallel. As constraint for the *jump insn use an X in the case you do not need the clobber reg and sth. like =r in the case you really need it. Ok, but the decision on if I need the clobber reg or not is based on the 'length' attribute. So if I could write the following, but where I can put the calculation and the test of the 'length' attribute: (define_insn *jump_internal [(set (pc) (label_ref (match_operand 0 ))) (clobber (match_scratch:QI 1 X,=r))] @ rjmp %0 ldih %1,hi(%l0)\n\t\n\tldil %1,lo(%l0)\n\tijmp (%1) ) Side question regarding the length attribute. It seems to work ok, but if I change the default value (first line in my example) to be 'const_int 1', I later get 'operand out of range' from the assembler because the 'rjmp' instruction was used for deplacements bigger than 2048. How can this happen, since my '(set (attr length)' code explicitly sets the correct value each time ? You set the length explicitely, so the default does not matter. Yes, this was exactly my point. It shouldn't matter, but it does, because it does different things when I change the default value. Stelian. -- Stelian Pop stel...@popies.net
Re: Scratch register in jump instruction ?
Le lundi 21 juillet 2008 à 15:37 +0200, Stelian Pop a écrit : I have a problem with the jump instructions: my direct jumps are very limited in displacements, and I want to always generate indirect jumps instead. Ok, no answer yet. Does this mean that my question is really dumb ? Or does this mean that it should work just fine and I need to debug deeper to see what happens here ? Thanks, -- Stelian Pop [EMAIL PROTECTED]
Scratch register in jump instruction ?
Hi, (I finally resumed the work on my microcontroller I posted about 3 months ago...) I have a problem with the jump instructions: my direct jumps are very limited in displacements, and I want to always generate indirect jumps instead. So I wrote this: (define_insn jump [(set (pc) (label_ref (match_operand 0 ))) (clobber (match_scratch:QI 1 =w))] ldih %1,hi(%l0)\n\tldil %1,lo(%l0)\n\tijmp (%1) [(set_attr cc none)] ) gcc and libgcc get compiled ok, but several testsuite tests fail because gcc is eating all the virtual memory when compiling the file. One of those is for example gcc.c-torture/compile/2120-2.c . The problem is coming from the usage of 'match_scratch' here, because removing it makes the problem go away. Before going deeper and trying to see if I'm hitting a bug in gcc, can someone please advice whether my define_insn is correct ? I'm using gcc-4.3.1. A stack trace from gdb seems to show that gcc is looping around here: #0 0x080f70df in df_insn_rescan (insn=0x80951c08) at /wip/src/gcc-4.3.1/gcc/df-scan.c:1078 #1 0x0811b5ad in add_insn_after (insn=0x80951c08, after=0x80951be0, bb=0xb7c17924) at /wip/src/gcc-4.3.1/gcc/emit-rtl.c:3495 #2 0x0811b870 in emit_jump_insn_after_noloc (x=0x80950c58, after=0x80951be0) at /wip/src/gcc-4.3.1/gcc/emit-rtl.c:4085 #3 0x080da84c in try_redirect_by_replacing_jump (e=0xb7c26460, target=0xb7c179d8, in_cfglayout=0 '\0') at /wip/src/gcc-4.3.1/gcc/cfgrtl.c:822 #4 0x08360a08 in cleanup_cfg (mode=1) [...] Thanks, -- Stelian Pop [EMAIL PROTECTED]
Re: Problem with reloading in a new backend...
Le lundi 14 avril 2008 à 18:27 -0700, Jim Wilson a écrit : On Tue, 2008-04-15 at 00:06 +0200, Stelian Pop wrote: - I had to add a PLUS case in PREFERRED_RELOAD_CLASS() or else reload kept generating incorrect insn (putting constants into EVEN_REGS for example). I'm not sure this is correct or if it hides something else... It does sound odd, but I can't really say it is wrong, as you have an odd set of requirements here. At least it is working which is good. Ok, thanks again. Stelian. -- Stelian Pop [EMAIL PROTECTED]
Re: Problem with reloading in a new backend...
Le vendredi 11 avril 2008 à 11:14 -0700, Jim Wilson a écrit : Stelian Pop wrote: #define PREFERRED_RELOAD_CLASS(X, CLASS)\ ((CONSTANT_P(X)) ? EIGHT_REGS : \ (MEM_P(X)) ? EVEN_REGS : CLASS) #define PREFERRED_OUTPUT_RELOAD_CLASS(X, CLASS) \ ((CONSTANT_P(X)) ? EIGHT_REGS : \ (MEM_P(X)) ? EVEN_REGS : CLASS) I think most of your trouble is here. Suppose we are trying to reload a constant into an even-reg. We call PREFERRED_RELOAD_CLASS, which says to use eight_regs instead, and you get a fatal_insn error because you didn't get the even-reg that the instruction needed. [...] I've tried the suggestion above and it did indeed help. However, I had a few additional issues: - the stack pointer and the frame pointer MUST be placed into an even-reg, or else reload will generate (mem (plus (reg) (const))) insn (when eliminating the pointers). - I had to add a PLUS case in PREFERRED_RELOAD_CLASS() or else reload kept generating incorrect insn (putting constants into EVEN_REGS for example). I'm not sure this is correct or if it hides something else... #define STACK_POINTER_REGNUM 30 #define FRAME_POINTER_REGNUM 28 #define PREFERRED_RELOAD_CLASS(X, CLASS) ardac_preferred_reload_class(X, CLASS) #define PREFERRED_OUTPUT_RELOAD_CLASS(X, CLASS) ardac_preferred_reload_class(X, CLASS) enum reg_class ardac_preferred_reload_class(rtx x, enum reg_class class) { if (CONSTANT_P(x)) { switch (class) { case NO_REGS: case STACK_REGS: return NO_REGS; case EVEN_REGS: case EIGHTEVEN_REGS: return EIGHTEVEN_REGS; case EIGHT_REGS: case GENERAL_REGS: return EIGHT_REGS; default: gcc_unreachable (); } } else if (MEM_P(x)) { switch (class) { case NO_REGS: case STACK_REGS: return NO_REGS; case EIGHT_REGS: case EIGHTEVEN_REGS: return EIGHTEVEN_REGS; case EVEN_REGS: case GENERAL_REGS: return EVEN_REGS; default: gcc_unreachable (); } } else { if (GET_CODE (x) == PLUS GET_CODE (XEXP (x, 0)) == REG GET_CODE (XEXP (x, 1)) == CONST_INT) { return EIGHTEVEN_REGS; } return class; } } Now it compiler 100+ files from libgcc without error so I guess the register assignment problem is solved. It now fails later: /home/tiniou/LTD/LTD/aRDAC/wip/src/gcc-4.3.0/libgcc/../gcc/unwind-dw2-fde.c: In function ‘frame_heapsort’: /home/tiniou/LTD/LTD/aRDAC/wip/src/gcc-4.3.0/libgcc/../gcc/unwind-dw2-fde.c:521: internal compiler error: in expand_call, at calls.c:3149 I haven't investigated why yet, but this is probably not related to the above. Thanks, -- Stelian Pop [EMAIL PROTECTED]
Re: Problem with reloading in a new backend...
Le vendredi 11 avril 2008 à 11:14 -0700, Jim Wilson a écrit : Stelian Pop wrote: #define PREFERRED_RELOAD_CLASS(X, CLASS)\ ((CONSTANT_P(X)) ? EIGHT_REGS : \ (MEM_P(X)) ? EVEN_REGS : CLASS) #define PREFERRED_OUTPUT_RELOAD_CLASS(X, CLASS) \ ((CONSTANT_P(X)) ? EIGHT_REGS : \ (MEM_P(X)) ? EVEN_REGS : CLASS) I think most of your trouble is here. Suppose we are trying to reload a constant into an even-reg. We call PREFERRED_RELOAD_CLASS, which says to use eight_regs instead, and you get a fatal_insn error because you didn't get the even-reg that the instruction needed. PREFERRED_RELOAD_CLASS must always return a class that is a strict subset of the class that was passed in. So define another register class which is the intersection of eight regs and even regs, and when we call PREFERRED_RELOAD_CLASS with a constant and even regs, then return the eight/even intersection class. Ah thanks, this does indeed seem to solve a lot of problems I had ! Likewise in all of the other cases you are trying to handle. Fix this problem, and you probably don't need most of the other changes you have made recently. I will still have the problems with the fact that my indirect addressing doesn't allow displacements, no ? (so I would need to implement LEGITIMIZE_RELOAD_ADDRESS, in which I'll need a special reserved register to compute the full address by adding the base and the displacement). Or do you imply that I won't need this anymore ? Thanks, -- Stelian Pop [EMAIL PROTECTED]
Re: Problem with reloading in a new backend...
Le mercredi 09 avril 2008 à 18:21 -0400, DJ Delorie a écrit : Maybe I should reserve a special register for this usage (say r0). That might be the only way, yes. Ok, I reserved r0 (BP_REGNUM) for such reloads, and I'm generating new instructions in LEGITIMIZE_RELOAD_ADDRESS to calculate the memory address: if (GET_CODE (*x) == PLUS GET_CODE (XEXP (*x, 0)) == REG GET_CODE (XEXP (*x, 1)) == CONST_INT) { rtx reginsn, setinsn, plusinsn; reginsn = gen_rtx_REG(Pmode, BP_REGNUM); setinsn = gen_rtx_SET(Pmode, reginsn, XEXP (*x, 1)); plusinsn = gen_rtx_SET(Pmode, reginsn, gen_rtx_PLUS(Pmode, reginsn, XEXP (*x, 0))); emit_insn_before(setinsn, insn); emit_insn_before(plusinsn, insn); *x = reginsn; return 1; } Does this sound ok ? Note that I needed to use emit_insn_before() in order to insert the instructions, and emit_insn_before() needs the current 'insn', which is not passed by LEGITIMIZE_RELOAD_ADDRESS(), so I needed to modify the macro. Is there something I miss here ? Note that reload also assumes that such adds don't change the flags (i.e. a compare/jump pair must not have a flag-modifying add between them). I think this won't happen because I emit the compare/conditional branch insn at the same time, in beq/bne/bgt... etc define_insn() (like many other targets). Thanks. -- Stelian Pop [EMAIL PROTECTED]
Re: Problem with reloading in a new backend...
Le jeudi 10 avril 2008 à 15:48 +0200, Stelian Pop a écrit : Le mercredi 09 avril 2008 à 18:21 -0400, DJ Delorie a écrit : Maybe I should reserve a special register for this usage (say r0). That might be the only way, yes. Ok, I reserved r0 (BP_REGNUM) for such reloads, and I'm generating new instructions in LEGITIMIZE_RELOAD_ADDRESS to calculate the memory address: [...] Now it seems that the register moves are correctly dealt with, but I'm still having the same problem on calls: just like indirect addressing, indirect calls are allowed only on even registers. My patterns look like: (define_insn *icall_value [(set (match_operand 0 register_operand =r) (call (mem:QI (match_operand:QI 1 register_operand z)) (match_operand:QI 2 )))] icall (%1) [(set_attr cc none)] ) (define_expand call_value [(set (match_operand 0 register_operand =r) (call (match_operand:QI 1 memory_operand m) (match_operand:QI 2 general_operand )))] { if (GET_CODE (XEXP(operands[1], 0)) != REG) XEXP(operands[1], 0) = force_reg (QImode, XEXP (operands[1], 0)); } ) This gives: (insn 27 26 29 2 ../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:564 (set (reg/f:QI 114) (symbol_ref:QI (__lshrqi3) [flags 0x41])) 1 {*movqi} (expr_list:REG_EQUIV (symbol_ref:QI (__lshrqi3) [flags 0x41]) (nil))) ... (call_insn/u 30 29 31 2 ../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:564 (set (reg:QI 4 r4) (call (mem:QI (reg/f:QI 114) [0 S1 A16]) (const_int 0 [0x0]))) 37 {*icall_value} (expr_list:REG_DEAD (reg:QI 5 r5) (expr_list:REG_EH_REGION (const_int -1 [0x]) (nil))) (expr_list:REG_DEP_TRUE (use (reg:QI 5 r5)) (expr_list:REG_DEP_TRUE (use (reg:QI 4 r4 [ D.2373 ])) (nil And r114 gets reloaded into r1: Reloads for insn # 30 Reload 0: reload_in (QI) = (symbol_ref:QI (__lshrqi3) [flags 0x41]) EIGHT_REGS, RELOAD_FOR_INPUT (opnum = 1), can't combine reload_in_reg: (reg/f:QI 114) reload_reg_rtx: (reg:QI 1 r1) Which does not satisfy the *icall_value constraints: ../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c: In function ‘__mulhi3’: ../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:570: error: insn does not satisfy its constraints: (call_insn/u 30 195 162 2 ../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:564 (set (reg:QI 4 r4) (call (mem:QI (reg:QI 1 r1) [0 S1 A16]) (const_int 0 [0x0]))) 37 {*icall_value} (expr_list:REG_EH_REGION (const_int -1 [0x]) (nil)) (expr_list:REG_DEP_TRUE (use (reg:QI 5 r5)) (expr_list:REG_DEP_TRUE (use (reg:QI 4 r4 [ D.2373 ])) (nil It seems that this reload doesn't pass through LEGITIMIZE_ADDRESS or LEGITIMIZE_RELOAD_ADDRESS... How can I specify here to choose an EVEN_REGS in place of the EIGHT_REGS (in fact it should choose one register in the intersection of EIGHT and EVEN_REGS) ? Thanks, -- Stelian Pop [EMAIL PROTECTED]
Re: Problem with reloading in a new backend...
Le jeudi 10 avril 2008 à 15:30 -0400, DJ Delorie a écrit : (call (mem:QI (match_operand:QI 1 register_operand z)) Are you sure your z constraint only matches even numbered hard registers? Well, I think so: enum reg_class { NO_REGS, BP_REGS, STACK_REGS, EIGHT_REGS, EVEN_REGS, GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES }; #define N_REG_CLASSES ((int) LIM_REG_CLASSES) #define REG_CLASS_CONTENTS \ { \ { 0x }, \ { 0x0001 }, \ { 0x8000 }, \ { 0x00FF }, \ { 0x }, \ { 0x7FFE }, \ { (1LL FIRST_PSEUDO_REGISTER) - 1 }\ } ... (define_register_constraint z EVEN_REGS Even registers (r0,r2,r4, @dots{} r30)) -- Stelian Pop [EMAIL PROTECTED]
Re: Problem with reloading in a new backend...
Le jeudi 10 avril 2008 à 15:56 -0400, [EMAIL PROTECTED] a écrit : I noticed Stack register is missing from ALL_REGS. No, it is not. It is missing from GENERAL_REGS but not from ALL_REGS. Are registers 16bit? Yes. Is just one required for pointer? For now, yes, I chose to support only 2^16 RAM addresses. In fact, this microcontroller is able to address 2^24, and two registers are used for indirect accesses (Rx and Rx+1, where x is even), this is the reason why only even registers are allowed in indirect addressing... -- Stelian Pop [EMAIL PROTECTED]
Re: Problem with reloading in a new backend...
[Putting the gcc-list back in CC:, ] Le mardi 08 avril 2008 à 18:24 -0400, DJ Delorie a écrit : Do you have one insn for each pair of src/dest that movqi supports? If so, this isn't the best way to do it - you should have one insn with multiple constraint alternativess, not multiple insns. [...] reload deals with selecting among constraint options, it doesn't usually have the choice about which pattern to choose - the first that matches is used. If you have a list of patterns that all match, only the first is available to reload. Plus, reload gets confused when the predicates are used to choose among otherwise identical patterns. So, it's best to have a more general predicate (like general_operand) and use the constraints to tell reload how to implement that insn in hardware. Thanks to your suggestion, I changed my movqi pattern to look like: (define_insn *movqi [(set (match_operand:QI 0 nonimmediate_operand =r,y,y,m,r) (match_operand:QI 1 general_operand r,n,s,r,m))] { switch (which_alternative) { case 0: /* register to register */ return tfr %0,%1; case 1: /* immediate to register */ output_asm_insn (ldih %0, hi(%1), operands); output_asm_insn (ldil %0, lo(%1), operands); return ; case 2: /* immediate symbol to register */ output_asm_insn (ldih %0, hi(%c1), operands); output_asm_insn (ldil %0, lo(%c1), operands); return ; case 3: /* register to memory */ if (GET_CODE (XEXP(operands[0], 0)) == REG) { operands[0] = XEXP(operands[0], 0); return st %1,(%0); } fatal_insn (Incorrect operand:, operands[0]); case 4: /* memory to register */ if (GET_CODE (XEXP(operands[1], 0)) == REG) { operands[1] = XEXP(operands[1], 0); return ld %0,(%1); } fatal_insn (Incorrect operand:, operands[1]); } return ; } [(set_attr cc none)] ) Does this look ok ? The 'fatal_insn' should not happen, because if I see such a pattern in the define_expand movqi I force the use of a register: (define_expand movqi [(set (match_operand:QI 0 nonimmediate_operand ) (match_operand:QI 1 general_operand ))] { if (!reload_in_progress !reload_completed) { if (GET_CODE (operands[0]) == MEM (GET_CODE (operands[1]) != REG)) { operands[1] = force_reg (QImode, operands[1]); } else if (GET_CODE(operands[1]) == MEM GET_CODE(XEXP(operands[1], 0)) == PLUS GET_CODE(XEXP(XEXP(operands[1], 0), 0)) == REG GET_CODE(XEXP(XEXP(operands[1], 0), 1)) == CONST_INT) { /* indirect load */ XEXP(operands[1], 0) = force_reg (QImode, XEXP (operands[1], 0)); } else if (GET_CODE(operands[0]) == MEM GET_CODE(XEXP(operands[0], 0)) == PLUS GET_CODE(XEXP(XEXP(operands[0], 0), 0)) == REG GET_CODE(XEXP(XEXP(operands[0], 0), 1)) == CONST_INT) { /* indirect store */ XEXP(operands[0], 0) = force_reg (QImode, XEXP (operands[0], 0)); } } } ) This seems to work ok, but I still have issues at reload time, because of the base register addressing mode: in the reload pass gcc generates moves from/to the stack: Reloads for insn # 3 Reload 0: reload_in (QI) = (reg/f:QI 31 r31) EVEN_REGS, RELOAD_FOR_OPERAND_ADDRESS (opnum = 0) reload_in_reg: (reg/f:QI 31 r31) reload_reg_rtx: (reg:QI 0 r0) Reload 1: reload_out (QI) = (mem/c:QI (plus:QI (reg/f:QI 31 r31) (const_int -3 [0xfffd])) [10 S1 A16]) EVEN_REGS, RELOAD_FOR_OUTPUT (opnum = 0), optional reload_out_reg: (reg:QI 109 [ u ]) But those moves are illegal because there is no offset allowed in the base register addressing mode (see the definition of my GO_IF_LEGITIMATE_ADDRESS() ), so gcc crashes with 'unrecognizable insn'. So what's the proper way to tell that indirect addressing is allowed, but not with an offset ? Should I define an extra define_expand to deal with those insns ? Thanks again, Stelian. -- Stelian Pop [EMAIL PROTECTED]
Re: Problem with reloading in a new backend...
Le mercredi 09 avril 2008 à 12:41 -0400, DJ Delorie a écrit : switch (which_alternative) { case 0: /* register to register */ Better to just use the @ syntax that gcc offers, to provide multiple patterns: @ tfr %0,%1 ldih %0, hi(%1); ldil %0, lo(%1) ldih %0, hi(%1); ldil %0, lo(%1) st %1,(%0) ld %0,(%1) Everything else should have been sorted out by the constraints. Right. This seems to work ok, but I still have issues at reload time, because of the base register addressing mode: in the reload pass gcc generates moves from/to the stack: You might need to define LEGITIMIZE_RELOAD_ADDRESS, or at least LEGITIMIZE_ADDRESS. I don't know if reload has assumptions about such offsets, but the m32c port has a limit on the offset range so it might help you figure out your port. Ah, this looks exactly like what I needed, thanks! I'll try this and come back afterwards. -- Stelian Pop [EMAIL PROTECTED]
Re: Problem with reloading in a new backend...
Le mercredi 09 avril 2008 à 21:19 +0200, Stelian Pop a écrit : You might need to define LEGITIMIZE_RELOAD_ADDRESS, or at least LEGITIMIZE_ADDRESS. I don't know if reload has assumptions about such offsets, but the m32c port has a limit on the offset range so it might help you figure out your port. Ah, this looks exactly like what I needed, thanks! I'll try this and come back afterwards. Ok, I tried. Since displacements are not allowed in my addressing mode, I need to replace: (mem (plus (reg X) (const_int Y))) into (set (reg Z) (const_int Y)) (set (reg Z) (plus (reg Z) (reg X))) (mem (reg Z) This means I need to create a new pseodo register. This is allowed in LEGITIMIZE_ADDRESS but not in LEGITIMIZE_RELOAD_ADDRESS... Is there a way to do this ? Maybe I should reserve a special register for this usage (say r0). But maybe there is a better solution... Thanks, -- Stelian Pop [EMAIL PROTECTED]
Problem with reloading in a new backend...
EVEN_REGS:0 ALL_REGS:0 MEM:4175 Register 466 costs: EIGHT_REGS:600 EVEN_REGS:600 ALL_REGS:600 MEM:5200 ... Register 453 pref EVEN_REGS Register 466 pref EVEN_REGS ... (insn 16 15 21 2 ../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1090 (set (reg:QI 453 [ uu+1 ]) (reg:QI 466 [ v ])) 0 {*movqi_reg} (nil)) In libgcc2.c.176.greg I see: Reloads for insn # 16 Reload 0: reload_in (QI) = (plus:QI (reg/f:QI 30 r30) (const_int 24 [0x18])) EVEN_REGS, RELOAD_FOR_OUTPUT_ADDRESS (opnum = 0), can't combine reload_in_reg: (plus:QI (reg/f:QI 30 r30) (const_int 24 [0x18])) reload_reg_rtx: (reg:QI 10 r10) Reload 1: reload_out (QI) = (mem/c:QI (plus:QI (reg/f:QI 30 r30) (const_int 24 [0x18])) [31 S1 A16]) EVEN_REGS, RELOAD_FOR_OUTPUT (opnum = 0) reload_out_reg: (reg:QI 453 [ uu+1 ]) reload_reg_rtx: (reg:QI 14 r14) ... (insn 16 1115 1117 2 ../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1090 (set (reg:QI 14 r14) (reg:QI 2 r2 [orig:466 v ] [466])) 0 {*movqi_reg} (nil)) (insn 1117 16 1118 2 ../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1090 (set (reg:QI 10 r10) (const_int 24 [0x18])) 1 {*movqi_imm} (nil)) (insn 1118 1117 1119 2 ../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1090 (set (reg:QI 10 r10) (plus:QI (reg:QI 10 r10) (reg/f:QI 30 r30))) 13 {addqi3} (expr_list:REG_EQUIV (plus:QI (reg/f:QI 30 r30) (const_int 24 [0x18])) (nil))) (insn 1119 1118 21 2 ../../../../src/gcc-4.3.0/libgcc/../gcc/libgcc2.c:1090 (set (mem/c:QI (reg:QI 10 r10) [31 S1 A16]) (reg:QI 14 r14)) 8 {*movqi_tomem} (nil)) I tried playing with different definitions for PREFERRED_RELOAD_CLASS, PREFERRED_OUTPUT_RELOAD_CLASS, TARGET_SECONDARY_RELOAD, with no luck. Thanks to anybody who can explain to me what's wrong here, and give a clue on what I must do to fix it. Stelian. -- Stelian Pop [EMAIL PROTECTED]