Richard Biener wrote: > On Fri, Mar 8, 2013 at 5:03 PM, Georg-Johann Lay <a...@gjlay.de> wrote: >> Richard Biener wrote: >>> On Fri, Mar 8, 2013 at 3:19 PM, Richard Biener >>> <richard.guent...@gmail.com> wrote: >>>> On Fri, Mar 8, 2013 at 2:57 PM, Georg-Johann Lay wrote: >>>>> While implementing PR56263 (Strict address-space checking for AVR), I >>>>> encountered the problem that pointer casts with address spaces are always >>>>> expanded as const_int 0. >>>>> >>>>> The problem occurs if the attached patch that implements PR56263 and the >>>>> following code is compiled as >>>>> >>>>> $ avr-gcc -Os flash-cast.c -S -mstrict-addr-space-subsets >>>>> >>>>> >>>>> #define PROGMEM __attribute__((__progmem__)) >>>>> >>>>> #define PSTR(s) \ >>>>> (__extension__ \ >>>>> ({ \ >>>>> static const char __c[] PROGMEM = (s); \ >>>>> &__c[0]; \ >>>>> })) >>>>> >>>>> extern void print (const __memx char*, ...); >>>>> >>>>> const __flash char *p; >>>>> >>>>> void f (const char *c) >>>>> { >>>>> c = (const char*) p; >>>>> >>>>> print ((const __flash char*) PSTR ("Hallo flash")); >>>>> } >>>>> >>>>> >>>>> >>>>> The corresponding .expand dump reads: >>>>> >>>>> >>>>> f (const char * c) >>>>> { >>>>> static const char __c[12] = "Hallo flash"; >>>>> const <address-space-1> char * _2; >>>>> const <address-space-7> char * _3; >>>>> >>>>> ;; basic block 2, loop depth 0 >>>>> ;; pred: ENTRY >>>>> _2 = (const <address-space-1> char *) (&__c[0]); >>>>> _3 = (const <address-space-7> char *) _2; >>>>> print (_3); [tail call] >>>>> return; >>>>> ;; succ: EXIT >>>>> >>>>> } >>>>> >>>>> >>>>> but the expression is always emit as (const_int 0). >>>>> >>>>> >>>>> Trying to track this issue, I ended up in build1_stat which enters the >>>>> default >>>>> case for "code" (ADDR_SPACE_CONVERT_EXPR at that time) and returns the >>>>> following tree: >>>>> >>>>> >>>>> (gdb) p t >>>>> $62 = (tree) 0xb7bb4578 >>>>> (gdb) pt >>>>> <addr_space_convert_expr 0xb7bb4578 >>>>> type <pointer_type 0xb7bc3a80 >>>>> type <integer_type 0xb7bc3a20 char readonly sizes-gimplified >>>>> address-space-1 string-flag QI >>>>> size <integer_cst 0xb7b3a1a4 constant 8> >>>>> unit size <integer_cst 0xb7b3a1b8 constant 1> >>>>> align 8 symtab 0 alias set -1 canonical type 0xb7bc3a20 >>>>> precision 8 >>>>> min <integer_cst 0xb7b3a1e0 -128> max <integer_cst 0xb7b3a208 127> >>>>> pointer_to_this <pointer_type 0xb7bc3a80>> >>>>> unsigned HI >>>>> size <integer_cst 0xb7b3a08c constant 16> >>>>> unit size <integer_cst 0xb7b3a0a0 constant 2> >>>>> align 8 symtab 0 alias set -1 canonical type 0xb7bc3a80> >>>>> readonly constant >>>>> arg 0 <addr_expr 0xb7bb449c >>>>> type <pointer_type 0xb7b4f2a0 type <integer_type 0xb7b4f240 char> >>>>> public unsigned HI size <integer_cst 0xb7b3a08c 16> unit size >>>>> <integer_cst 0xb7b3a0a0 2> >>>>> align 8 symtab 0 alias set -1 canonical type 0xb7b4f2a0 >>>>> pointer_to_this <pointer_type 0xb7b4f840>> >>>>> readonly constant >>>>> arg 0 <array_ref 0xb7b465a0 type <integer_type 0xb7b4f240 char> >>>>> readonly arg 0 <var_decl 0xb7bcd05c __c> >>>>> arg 1 <integer_cst 0xb7b3a460 constant 0> >>>>> flash-cast.c:18:128> >>>>> flash-cast.c:18:124>> >>>>> >>>>> Problem is the arg 1 <integer_cst 0xb7b3a460 constant 0> at the end which >>>>> leads >>>>> to the expansion of 0. >>>>> >>>>> The call chain is: >>>>> >>>>> #0 build1_stat (code=ADDR_SPACE_CONVERT_EXPR, type=0xb7bc3a80, >>>>> node=0xb7bb449c) at ../../../gcc.gnu.org/trunk/gcc/tree.c:3848 >>>>> (gdb) bt >>>>> #0 build1_stat (code=ADDR_SPACE_CONVERT_EXPR, type=0xb7bc3a80, >>>>> node=0xb7bb449c) at ../../../gcc.gnu.org/trunk/gcc/tree.c:3848 >>>>> #1 0x08286be0 in gimple_assign_rhs_to_tree (stmt=0xb7bc2c30) at >>>>> ../../../gcc.gnu.org/trunk/gcc/cfgexpand.c:86 >>>>> #2 0x0837047f in expand_expr_real_1 (exp=0xb7b972f8, target=0x0, >>>>> tmode=VOIDmode, modifier=EXPAND_STACK_PARM, alt_rtl=0x0) at >>>>> ../../../gcc.gnu.org/trunk/gcc/expr.c:9274 >>>>> #3 0x083762f2 in expand_expr_real (exp=0xb7b972f8, target=0x0, >>>>> tmode=VOIDmode, >>>>> modifier=EXPAND_STACK_PARM, alt_rtl=0x0) at >>>>> ../../../gcc.gnu.org/trunk/gcc/expr.c:7863 >>>>> #4 0x08376a7e in expand_expr (exp=0xb7b972f8, target=0x0, mode=VOIDmode, >>>>> modifier=EXPAND_STACK_PARM) at ../../../gcc.gnu.org/trunk/gcc/expr.h:444 >>>>> #5 0x0836ae96 in expand_expr_real_2 (ops=0xbfffca10, target=0x0, >>>>> tmode=VOIDmode, modifier=EXPAND_STACK_PARM) at >>>>> ../../../gcc.gnu.org/trunk/gcc/expr.c:8150 >>>>> #6 0x08376234 in expand_expr_real_1 (exp=0xb7bb4564, target=0x0, >>>>> tmode=VOIDmode, modifier=EXPAND_STACK_PARM, alt_rtl=0x0) at >>>>> ../../../gcc.gnu.org/trunk/gcc/expr.c:10491 >>>>> #7 0x083762f2 in expand_expr_real (exp=0xb7bb4564, target=0x0, >>>>> tmode=VOIDmode, >>>>> modifier=EXPAND_STACK_PARM, alt_rtl=0x0) at >>>>> ../../../gcc.gnu.org/trunk/gcc/expr.c:7863 >>>>> #8 0x083704a6 in expand_expr_real_1 (exp=0xb7b97320, target=0x0, >>>>> tmode=VOIDmode, modifier=EXPAND_STACK_PARM, alt_rtl=0x0) at >>>>> ../../../gcc.gnu.org/trunk/gcc/expr.c:9274 >>>>> #9 0x083762f2 in expand_expr_real (exp=0xb7b97320, target=0x0, >>>>> tmode=VOIDmode, >>>>> modifier=EXPAND_STACK_PARM, alt_rtl=0x0) at >>>>> ../../../gcc.gnu.org/trunk/gcc/expr.c:7863 >>>>> #10 0x0826ae1a in expand_expr (exp=0xb7b97320, target=0x0, mode=VOIDmode, >>>>> modifier=EXPAND_STACK_PARM) at ../../../gcc.gnu.org/trunk/gcc/expr.h:444 >>>>> #11 0x0826c215 in store_one_arg (arg=0xbfffd130, argblock=0x0, flags=0, >>>>> variable_size=0, reg_parm_stack_space=0) at >>>>> ../../../gcc.gnu.org/trunk/gcc/calls.c:4500 >>>>> #12 0x08274d79 in expand_call (exp=0xb7b46640, target=0x0, ignore=1) at >>>>> ../../../gcc.gnu.org/trunk/gcc/calls.c:3040 >>>>> #13 0x08375088 in expand_expr_real_1 (exp=0xb7b46640, target=0x0, >>>>> tmode=VOIDmode, modifier=EXPAND_NORMAL, alt_rtl=0x0) at >>>>> ../../../gcc.gnu.org/trunk/gcc/expr.c:10209 >>>>> #14 0x0828cb86 in expand_call_stmt (stmt=0xb7fde140) at >>>>> ../../../gcc.gnu.org/trunk/gcc/cfgexpand.c:2114 >>>>> >>>>> ... >>>>> >>>>> >>>>> The problem comes apparent in #5 expand_expr_real_2 >>>>> >>>>> if (targetm.addr_space.subset_p (as_to, as_from) >>>>> || targetm.addr_space.subset_p (as_from, as_to)) >>>>> { >>>>> op0 = expand_expr (treeop0, NULL_RTX, VOIDmode, modifier); >>>>> op0 = targetm.addr_space.convert (op0, treeop0_type, type); >>>>> gcc_assert (op0); >>>>> return op0; >>>>> } >>>>> >>>>> where op0 is const0_rtx and targetm.addr_space.convert cannot recover >>>>> from that. >>>>> >>>>> Maybe someone can help me fixing the root cause? >>>> Doesn't make sense - in the above code treeop0 should be the >>>> >>>> arg 0 <addr_expr 0xb7bb449c >>>> >>>> not the zero integer constant. >>> The first conversion expands to >>> >>> (symbol_ref:HI ("__c.1466") [flags 0x202] <var_decl 0x7ffff6dfaa18 __c>) >>> >>> then we try to convert that to another address-space and the target hook >>> returns >>> >>> (insn 6 0 7 (set (reg/f:HI 46) >>> (symbol_ref:HI ("__c.1466") [flags 0x202] <var_decl >>> 0x7ffff6dfaa18 __c>)) t.c:18 -1 >>> (nil)) >>> >>> (insn 7 6 0 (set (reg:PSI 45) >>> (zero_extend:PSI (reg/f:HI 46))) t.c:18 -1 >>> (nil)) >>> >>> (reg:PSI 45) >>> >>> so the issue must be elsewhere (in case the above is correct). >> This looks correct. Without the patch you'll have always >> -mno-strict-addr-space-subsets where the code is good. >> >>> -mstrict-addr-space-subsets >>> >>> doesn't exist for me. >> You must apply the patch "strict-addr-spaces.diff" from the initial mail. >> This >> adds the -mstrict-addr-space-subsets option so the user can pick strictness >> of >> address space checking (PR56263). >> >> For a quick change you can change avr.c from >> >> static bool >> avr_addr_space_subset_p (addr_space_t subset ATTRIBUTE_UNUSED, >> addr_space_t superset ATTRIBUTE_UNUSED) >> { >> return true; >> } >> >> to >> >> static bool >> avr_addr_space_subset_p (addr_space_t subset ATTRIBUTE_UNUSED, >> addr_space_t superset) >> { >> return superset == ADDR_SPACE_MEMX; >> } >> >> >> The C code contains 2 casts: The first casts a pointer to generic space in >> PSTR ("Hallo world") to a 16-bit __flash pointer. The second cast is to a >> 24-bit __memx pointer which is for the print() prototype. >> >> PSTR is a common idiom in avr applications to put a string literal into flash >> (progmem) memory. >> > > Well, then you hit undefined behavior: > > /* Ask target code to handle conversion between pointers > to overlapping address spaces. */ > if (targetm.addr_space.subset_p (as_to, as_from) > || targetm.addr_space.subset_p (as_from, as_to)) > { > op0 = expand_expr (treeop0, NULL_RTX, VOIDmode, modifier); > op0 = targetm.addr_space.convert (op0, treeop0_type, type); > gcc_assert (op0); > return op0; > } > > /* For disjoint address spaces, converting anything but > a null pointer invokes undefined behaviour. We simply > always return a null pointer here. */ > return CONST0_RTX (mode); > > thus your input program is not valid, or your strict addr-space implementation > is bogus. > > Choose ;)
*sigh* The point is that targetm.addr_space.convert is *not* called, at least for the small test case in my initial post. That is, the backend has no means to produce a warning. Moreover, there is no location information to use warning_at... Making addr-spaces disjoint was just a means to trigger the desired diagnose, but one more time the middle end is myopic. Why not let decide the back-end what to return if address spaces are no subsets? Well, how would you implement warnings on address space casts so that: - The diagnose has proper location information - It's purely in the back end by means of some target hooks - No warnings are bypassed - Distinguish between explicit casts by the user or implicit casts, e.g. calling a function with a non-matching address space pointer. A quick try shows that TARGET_CONVERT_TO_TYPE could do the job. locations look reasonable, but I have no idea how to test the last point with implicit or explicit casts. Using some type of promotion and diagnose inside the hook? Johann