From: Jeremy.Allison@corp.SUn.COM (Jeremy Allison)
Subject: (none)
Organization: GNUs Not Usenet
Distribution: gnu
Date: Tue, 13 Oct 1992 16:51:42 GMT

Dear GCC maintainers,

	Firstly, thanks for such a great product. I really appreciate being
able to use ansi C and c++ on my obsolete machine (a Sun386i).

I believe I have found a bug in code generation using gcc2.2.2 with 
-fpic under a sun386i, but I believe this bug would also hit other 
architectures.I am generating pic code using the patch I submitted
earlier to change the format of the assembler generated output for
the sun386i - I don't think this is having an effect on the rtl
generated though. Please contact me if you wish a copy of this
patch.

Consider the following program, testcase.c

-------cut here---------------------
#ifdef WORKS
const double val = 0.3;
#else
#define val 0.3
#endif

int main()
{
        float newval = 5.0;
        float testval = newval/val;

        printf("should be 16.66666 etc. but is %f\n", testval);
}
-------------end testcase-----------

Compile using pic code :-

% gcc -fpic testcase.c

Then run

% a.out
should be 16.66666 etc. but is Inf

But compile with the -DWORKS flag set,

% gcc -fpic -DWORKS testcase.c

Then run

% a.out
should be 16.66666 etc. but is 16.666666


All is well. 


I have examined the code generated and have discovered 
the following.

---------Assembler generated with -fpic -DWORKS (correct code) -----------
        .file   "testcase.c"
        .version        "GNU C 2.2.2"
gcc2_compiled.:
.globl val
.text
        .align 4
val:
        .double 2.9999999999999998889777e-01
.LC0:
        .byte 0x73,0x68,0x6f,0x75,0x6c,0x64,0x20,0x62,0x65,0x20
        .byte 0x31,0x36,0x2e,0x36,0x36,0x36,0x36,0x36,0x20,0x65
        .byte 0x74,0x63,0x2e,0x20,0x62,0x75,0x74,0x20,0x69,0x73
        .byte 0x20,0x25,0x66,0xa,0x0
        .align 4
.globl main
main:
        pushl %ebp
        movl %esp,%ebp
        subl $8,%esp
        pushl %ebx
        call .L2
.L2:
        popl %ebx
        addl $_globtb_offset,%ebx
        call __main, %eax
        movl $1084227584,-4(%ebp)
        flds -4(%ebp)
        movl val(%ebx),%eax
        fdivl (%eax)
        fstps -8(%ebp)
        flds -8(%ebp)
        subl $8,%esp
        fstpl (%esp)
        movl .LC0(%ebx),%edx
        movl %edx,%eax
        pushl %eax
        call printf, %eax
        addl $12,%esp
.L1:
        movl -12(%ebp),%ebx
        leave
        ret

-----------RTL GENERATED FOR ABOVE ASSEMBLER -----
-----(using gcc -fpic -c -dr -DWORKS testcase.c)--

;; Function main

(note 2 0 3 "" NOTE_INSN_DELETED)

(note 3 2 4 "" NOTE_INSN_FUNCTION_BEG)

(note 4 3 6 "" NOTE_INSN_DELETED)

(call_insn 6 4 8 (parallel[ 
           (call (mem:QI (symbol_ref:SI ("__main")))
               (const_int 0))
           (set (reg:SI 7)
               (plus:SI (reg:SI 7)
                   (const_int 0)))
       ] ) -1 (nil)
   (nil))

(note 8 6 9 "" NOTE_INSN_BLOCK_BEG)

(insn 9 8 11 (set (mem:SF (plus:SI (reg:SI 18)
               (const_int -4)))
       (const_double:SF (const_int 0) 0 1075052544)) -1 (nil)
   (nil))

(insn 11 9 13 (set (reg:DF 21)
       (float_extend:DF (mem:SF (plus:SI (reg:SI 18)
                   (const_int -4))))) -1 (nil)
   (nil))

(insn 13 11 14 (set (reg:SI 22)
       (mem:SI (plus:SI (reg:SI 3)
               (symbol_ref:SI ("val"))))) -1 (nil)
   (nil))

(insn 14 13 15 (set (reg:DF 23)
       (div:DF (reg:DF 21)
           (mem/u:DF (reg:SI 22)))) -1 (nil)
   (nil))

(insn 15 14 17 (set (mem:SF (plus:SI (reg:SI 18)
               (const_int -8)))
       (float_truncate:SF (reg:DF 23))) -1 (nil)
   (nil))

(insn 17 15 18 (set (reg:DF 24)
       (float_extend:DF (mem:SF (plus:SI (reg:SI 18)
                   (const_int -8))))) -1 (nil)
   (nil))

(insn 18 17 20 (set (mem:DF (pre_dec:SI (reg:SI 7)))
       (reg:DF 24)) -1 (nil)
   (nil))

(insn 20 18 21 (set (reg:SI 27)
       (mem:SI (plus:SI (reg:SI 3)
               (symbol_ref/v:SI ("*.LC0"))))) -1 (nil)
   (nil))

(insn 21 20 22 (set (reg:SI 26)
       (reg:SI 27)) -1 (nil)
   (expr_list:REG_EQUAL (symbol_ref/v:SI ("*.LC0"))
       (nil)))

(insn 22 21 24 (set (mem:SI (pre_dec:SI (reg:SI 7)))
       (reg:SI 26)) -1 (nil)
   (nil))

(call_insn 24 22 25 (set (reg:SI 0)
       (call (mem:QI (symbol_ref:SI ("printf")))
           (const_int 12))) -1 (nil)
   (nil))

(insn 25 24 27 (set (reg:SI 7)
       (plus:SI (reg:SI 7)
           (const_int 12))) -1 (nil)
   (nil))

(note 27 25 28 "" NOTE_INSN_BLOCK_END)

(note 28 27 30 "" NOTE_INSN_FUNCTION_END)

(code_label 30 28 0 1 "")

-------------------end code-------------------------------

-------Assembler generated with -fpic (incorrect code)----
        .file   "testcase.c"
        .version        "GNU C 2.2.2"
gcc2_compiled.:
.text
.LC0:
        .byte 0x73,0x68,0x6f,0x75,0x6c,0x64,0x20,0x62,0x65,0x20
        .byte 0x31,0x36,0x2e,0x36,0x36,0x36,0x36,0x36,0x20,0x65
        .byte 0x74,0x63,0x2e,0x20,0x62,0x75,0x74,0x20,0x69,0x73
        .byte 0x20,0x25,0x66,0xa,0x0
        .align 4
.LC1:
        .double 2.9999999999999998889777e-01
        .align 4
.globl main
main:
        pushl %ebp
        movl %esp,%ebp
        subl $8,%esp
        pushl %ebx
        call .L2
.L2:
        popl %ebx
        addl $_globtb_offset,%ebx
        call __main, %eax
        movl $1084227584,-4(%ebp)
        flds -4(%ebp) 
        fldl .LC1(%ebx)          <======= NOTE INCORRECT PIC REFERENCE
        fdivrp %st,%st(1)        Should be : movl .LC1(%ebx),%eax
        fstps -8(%ebp)			     fdivl (%eax)
        flds -8(%ebp)
        subl $8,%esp
        fstpl (%esp)
        movl .LC0(%ebx),%edx
        movl %edx,%eax
        pushl %eax
        call printf, %eax
        addl $12,%esp
.L1:
        movl -12(%ebp),%ebx
        leave
        ret

-------RTL GENERATED FOR ABOVE ASSEMBLER ---
-----(using gcc -c -fpic -dr testcase.c)----

;; Function main

(note 2 0 3 "" NOTE_INSN_DELETED)

(note 3 2 4 "" NOTE_INSN_FUNCTION_BEG)

(note 4 3 6 "" NOTE_INSN_DELETED)

(call_insn 6 4 8 (parallel[ 
           (call (mem:QI (symbol_ref:SI ("__main")))
               (const_int 0))
           (set (reg:SI 7)
               (plus:SI (reg:SI 7)
                   (const_int 0)))
       ] ) -1 (nil)
   (nil))

(note 8 6 9 "" NOTE_INSN_BLOCK_BEG)

(insn 9 8 11 (set (mem:SF (plus:SI (reg:SI 18)
               (const_int -4)))
       (const_double:SF (const_int 0) 0 1075052544)) -1 (nil)
   (nil))

(insn 11 9 12 (set (reg:DF 21)
       (float_extend:DF (mem:SF (plus:SI (reg:SI 18)
                   (const_int -4))))) -1 (nil)
   (nil))

(insn 12 11 13 (set (reg:DF 23)
       (const_double:DF (const_int 0) 858993459 1070805811)) -1 (nil)
   (nil))

(insn 13 12 14 (set (reg:DF 22)
       (div:DF (reg:DF 21)
           (reg:DF 23))) -1 (nil)
   (nil))

(insn 14 13 16 (set (mem:SF (plus:SI (reg:SI 18)
               (const_int -8)))
       (float_truncate:SF (reg:DF 22))) -1 (nil)
   (nil))

(insn 16 14 17 (set (reg:DF 24)
       (float_extend:DF (mem:SF (plus:SI (reg:SI 18)
                   (const_int -8))))) -1 (nil)
   (nil))

(insn 17 16 19 (set (mem:DF (pre_dec:SI (reg:SI 7)))
       (reg:DF 24)) -1 (nil)
   (nil))

(insn 19 17 20 (set (reg:SI 27)
       (mem:SI (plus:SI (reg:SI 3)
               (symbol_ref/v:SI ("*.LC0"))))) -1 (nil)
   (nil))

(insn 20 19 21 (set (reg:SI 26)
       (reg:SI 27)) -1 (nil)
   (expr_list:REG_EQUAL (symbol_ref/v:SI ("*.LC0"))
       (nil)))

(insn 21 20 23 (set (mem:SI (pre_dec:SI (reg:SI 7)))
       (reg:SI 26)) -1 (nil)
   (nil))

(call_insn 23 21 24 (set (reg:SI 0)
       (call (mem:QI (symbol_ref:SI ("printf")))
           (const_int 12))) -1 (nil)
   (nil))

(insn 24 23 26 (set (reg:SI 7)
       (plus:SI (reg:SI 7)
           (const_int 12))) -1 (nil)
   (nil))

(note 26 24 27 "" NOTE_INSN_BLOCK_END)

(note 27 26 29 "" NOTE_INSN_FUNCTION_END)

(code_label 29 27 0 1 "")

---------------end code-----------------------------

I have examined the GCC 2.2.2 code and believe I know what
is going wrong, but not yet how to fix it ! 
All numeric constants in a program are put onto a linked list
within each function and then just before the function is
generated are allocated real addresses and output. This is done
in the immed_double_const routines in varasm.c. The problem seems
to be that when pic references are made to these constants *and the
constant is too big to fix into a register* (ie. double float) then
an incorrect pic reference is generated. When the constant is turned
into an symbolic constant (-DWORKS) then a symbol is generated for 
this value and correct pic is generated. The outputting of the pool
constants doesn't seem to be going through the "legitimize_pic_address"
function, which I would have thought should fix the problem.
I have been investigating adding code to generate more rtx expressions
into the immed_double_const routine to return an rtx expression containing
the correct pic code. Please let me know if you think this is the correct
solution (as I haven't been able to get it to work yet, and also would like
to fix this one !).

	Regards,


		Jeremy Allison.

Newsgroups: gnu.gcc.bug