소스 검색

* parameter passing support for AIX:
o the last bytes of records passed by value whose size is not a multiple
of the register size must be passed in the upper (leftmost) bytes of
a register

git-svn-id: trunk@20804 -

Jonas Maebe 13 년 전
부모
커밋
dc70db9402
4개의 변경된 파일60개의 추가작업 그리고 17개의 파일을 삭제
  1. 28 5
      compiler/cgobj.pas
  2. 14 7
      compiler/parabase.pas
  3. 1 0
      compiler/paramgr.pas
  4. 17 5
      compiler/powerpc/cpupara.pas

+ 28 - 5
compiler/cgobj.pas

@@ -899,6 +899,8 @@ implementation
       begin
       begin
          cgpara.check_simple_location;
          cgpara.check_simple_location;
          paramanager.alloccgpara(list,cgpara);
          paramanager.alloccgpara(list,cgpara);
+         if cgpara.location^.shiftval<0 then
+           a_op_const_reg(list,OP_SHL,cgpara.location^.size,-cgpara.location^.shiftval,r);
          case cgpara.location^.loc of
          case cgpara.location^.loc of
             LOC_REGISTER,LOC_CREGISTER:
             LOC_REGISTER,LOC_CREGISTER:
               a_load_reg_reg(list,size,cgpara.location^.size,r,cgpara.location^.register);
               a_load_reg_reg(list,size,cgpara.location^.size,r,cgpara.location^.register);
@@ -974,6 +976,8 @@ implementation
                      begin
                      begin
                        cgpara.check_simple_location;
                        cgpara.check_simple_location;
                        a_load_ref_reg(list,size,location^.size,tmpref,location^.register);
                        a_load_ref_reg(list,size,location^.size,tmpref,location^.register);
+                       if location^.shiftval<0 then
+                         a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
                      end
                      end
                    { there's a lot more data left, and the current paraloc's
                    { there's a lot more data left, and the current paraloc's
                      register is entirely filled with part of that data }
                      register is entirely filled with part of that data }
@@ -987,6 +991,8 @@ implementation
                    else if (sizeleft in [1,2{$ifndef cpu16bitalu},4{$endif}{$ifdef cpu64bitalu},8{$endif}]) then
                    else if (sizeleft in [1,2{$ifndef cpu16bitalu},4{$endif}{$ifdef cpu64bitalu},8{$endif}]) then
                      begin
                      begin
                        a_load_ref_reg(list,int_cgsize(sizeleft),location^.size,tmpref,location^.register);
                        a_load_ref_reg(list,int_cgsize(sizeleft),location^.size,tmpref,location^.register);
+                       if location^.shiftval<0 then
+                         a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
                      end
                      end
                    { we're at the end of the data, and we need multiple loads
                    { we're at the end of the data, and we need multiple loads
                      to get it in the register because it's an irregular size }
                      to get it in the register because it's an irregular size }
@@ -1047,6 +1053,8 @@ implementation
                              a_load_reg_reg(list,location^.size,location^.size,tmpreg,location^.register);
                              a_load_reg_reg(list,location^.size,location^.size,tmpreg,location^.register);
                            inc(tmpref.offset);
                            inc(tmpref.offset);
                          end;
                          end;
+                       if location^.shiftval<0 then
+                         a_op_const_reg(list,OP_SHL,location^.size,-location^.shiftval,location^.register);
                        { the loop will already adjust the offset and sizeleft }
                        { the loop will already adjust the offset and sizeleft }
                        dec(tmpref.offset,orgsizeleft);
                        dec(tmpref.offset,orgsizeleft);
                        sizeleft:=orgsizeleft;
                        sizeleft:=orgsizeleft;
@@ -1128,15 +1136,28 @@ implementation
     procedure tcg.a_load_cgparaloc_ref(list : TAsmList;const paraloc : TCGParaLocation;const ref : treference;sizeleft : tcgint;align : longint);
     procedure tcg.a_load_cgparaloc_ref(list : TAsmList;const paraloc : TCGParaLocation;const ref : treference;sizeleft : tcgint;align : longint);
       var
       var
         href : treference;
         href : treference;
+        hreg : tregister;
+        cgsize: tcgsize;
       begin
       begin
          case paraloc.loc of
          case paraloc.loc of
            LOC_REGISTER :
            LOC_REGISTER :
              begin
              begin
-{$IFDEF POWERPC64}
-               if (paraloc.shiftval <> 0) then
-                 a_op_const_reg_reg(list, OP_SHL, OS_INT, paraloc.shiftval, paraloc.register, paraloc.register);
-{$ENDIF POWERPC64}
-               a_load_reg_ref(list,paraloc.size,paraloc.size,paraloc.register,ref);
+               hreg:=paraloc.register;
+               cgsize:=paraloc.size;
+               if paraloc.shiftval>0 then
+                 a_op_const_reg_reg(list,OP_SHL,OS_INT,paraloc.shiftval,paraloc.register,paraloc.register)
+               else if (paraloc.shiftval<0) and
+                       (sizeleft in [1,2,4]) then
+                 begin
+                   a_op_const_reg_reg(list,OP_SHR,OS_INT,-paraloc.shiftval,paraloc.register,paraloc.register);
+                   { convert to a register of 1/2/4 bytes in size, since the
+                     original register had to be made larger to be able to hold
+                     the shifted value }
+                   cgsize:=int_cgsize(tcgsize2size[OS_INT]-(-paraloc.shiftval div 8));
+                   hreg:=getintregister(list,cgsize);
+                   a_load_reg_reg(list,OS_INT,cgsize,paraloc.register,hreg);
+                 end;
+               a_load_reg_ref(list,paraloc.size,cgsize,hreg,ref);
              end;
              end;
            LOC_MMREGISTER :
            LOC_MMREGISTER :
              begin
              begin
@@ -1175,6 +1196,8 @@ implementation
          case paraloc.loc of
          case paraloc.loc of
            LOC_REGISTER :
            LOC_REGISTER :
              begin
              begin
+               if paraloc.shiftval<0 then
+                 a_op_const_reg_reg(list,OP_SHR,OS_INT,-paraloc.shiftval,paraloc.register,paraloc.register);
                case getregtype(reg) of
                case getregtype(reg) of
                  R_INTREGISTER:
                  R_INTREGISTER:
                    a_load_reg_reg(list,paraloc.size,regsize,paraloc.register,reg);
                    a_load_reg_reg(list,paraloc.size,regsize,paraloc.register,reg);

+ 14 - 7
compiler/parabase.pas

@@ -48,7 +48,11 @@ unit parabase;
            LOC_CMMREGISTER,
            LOC_CMMREGISTER,
            LOC_REGISTER,
            LOC_REGISTER,
            LOC_CREGISTER : (
            LOC_CREGISTER : (
-             { The number of bits the value in the register must be shifted to the left before
+             {
+
+             * If shiftval > 0:
+
+             The number of bits the value in the register must be shifted to the left before
              it can be stored to memory in the function prolog.
              it can be stored to memory in the function prolog.
              This is used for passing OS_NO memory blocks less than register size and of "odd"
              This is used for passing OS_NO memory blocks less than register size and of "odd"
              (3, 5, 6, 7) size on big endian machines, so that small memory blocks passed via
              (3, 5, 6, 7) size on big endian machines, so that small memory blocks passed via
@@ -56,8 +60,15 @@ unit parabase;
 
 
              E.g. the value $5544433 is passed in bits 40-63 of the register (others are zero),
              E.g. the value $5544433 is passed in bits 40-63 of the register (others are zero),
              but they should actually be stored in the first bits of the stack location reserved
              but they should actually be stored in the first bits of the stack location reserved
-             for this value. So they have to be shifted left by this amount of bits before. }
-             {$IFDEF POWERPC64}shiftval : byte;{$ENDIF POWERPC64}
+             for this value. So they have to be shifted left by this amount of bits before.
+
+             * if shiftval < 0:
+
+             Similar as above, but the shifting must always be done and
+               1) for all parameter sizes < regsize
+               2) on the caller side
+             }
+             shiftval : shortint;
              register : tregister);
              register : tregister);
        end;
        end;
 
 
@@ -281,9 +292,7 @@ implementation
               LOC_REGISTER,
               LOC_REGISTER,
               LOC_CREGISTER :
               LOC_CREGISTER :
                 begin
                 begin
-{$ifdef powerpc64}
                   ppufile.putbyte(hparaloc^.shiftval);
                   ppufile.putbyte(hparaloc^.shiftval);
-{$endif}
                   ppufile.putlongint(longint(hparaloc^.register));
                   ppufile.putlongint(longint(hparaloc^.register));
                 end;
                 end;
               { This seems to be required for systems using explicitparaloc (eg. MorphOS)
               { This seems to be required for systems using explicitparaloc (eg. MorphOS)
@@ -331,9 +340,7 @@ implementation
               LOC_REGISTER,
               LOC_REGISTER,
               LOC_CREGISTER :
               LOC_CREGISTER :
                 begin
                 begin
-{$ifdef powerpc64}
                   hparaloc^.shiftval:=ppufile.getbyte;
                   hparaloc^.shiftval:=ppufile.getbyte;
-{$endif}
                   hparaloc^.register:=tregister(ppufile.getlongint);
                   hparaloc^.register:=tregister(ppufile.getlongint);
                 end;
                 end;
               { This seems to be required for systems using explicitparaloc (eg. MorphOS)
               { This seems to be required for systems using explicitparaloc (eg. MorphOS)

+ 1 - 0
compiler/paramgr.pas

@@ -366,6 +366,7 @@ implementation
               len:=tcgsize2size[paraloc^.size];
               len:=tcgsize2size[paraloc^.size];
             newparaloc:=cgpara.add_location;
             newparaloc:=cgpara.add_location;
             newparaloc^.size:=paraloc^.size;
             newparaloc^.size:=paraloc^.size;
+            newparaloc^.shiftval:=paraloc^.shiftval;
             { $warning maybe release this optimization for all targets?  }
             { $warning maybe release this optimization for all targets?  }
             { released for all CPUs:
             { released for all CPUs:
               i386 isn't affected anyways because it uses the stack to push parameters
               i386 isn't affected anyways because it uses the stack to push parameters

+ 17 - 5
compiler/powerpc/cpupara.pas

@@ -137,9 +137,10 @@ unit cpupara;
               else
               else
                 result:=LOC_REFERENCE;
                 result:=LOC_REFERENCE;
             recorddef:
             recorddef:
-              if (target_info.abi<>abi_powerpc_aix) or
-                 ((p.size >= 3) and
-                  ((p.size mod 4) <> 0)) then
+              if not(target_info.system in systems_aix) and
+                 ((target_info.abi<>abi_powerpc_aix) or
+                  ((p.size >= 3) and
+                   ((p.size mod 4) <> 0))) then
                 result:=LOC_REFERENCE
                 result:=LOC_REFERENCE
               else
               else
                 result:=LOC_REGISTER;
                 result:=LOC_REGISTER;
@@ -501,6 +502,15 @@ unit cpupara;
                         paraloc^.size := OS_INT
                         paraloc^.size := OS_INT
                       else
                       else
                         paraloc^.size := paracgsize;
                         paraloc^.size := paracgsize;
+                      { aix requires that record data stored in parameter
+                        registers is left-aligned }
+                      if (target_info.system in systems_aix) and
+                         (paradef.typ = recorddef) and
+                         (tcgsize2size[paraloc^.size] <> sizeof(aint)) then
+                        begin
+                          paraloc^.shiftval := (sizeof(aint)-tcgsize2size[paraloc^.size])*(-8);
+                          paraloc^.size := OS_INT;
+                        end;
                       paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
                       paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
                       inc(nextintreg);
                       inc(nextintreg);
                       dec(paralen,tcgsize2size[paraloc^.size]);
                       dec(paralen,tcgsize2size[paraloc^.size]);
@@ -561,9 +571,11 @@ unit cpupara;
                            tppcprocinfo(current_procinfo).needs_frame_pointer := true;
                            tppcprocinfo(current_procinfo).needs_frame_pointer := true;
                          end;
                          end;
 
 
-                       if (target_info.abi = abi_powerpc_aix) and
+                       if not((target_info.system in systems_aix) and
+                              (paradef.typ=recorddef)) and
+                          (target_info.abi = abi_powerpc_aix) and
                           (hp.paraloc[side].intsize < 3) then
                           (hp.paraloc[side].intsize < 3) then
-                           paraloc^.reference.offset:=stack_offset+(4-paralen)
+                         paraloc^.reference.offset:=stack_offset+(4-paralen)
                        else
                        else
                          paraloc^.reference.offset:=stack_offset;
                          paraloc^.reference.offset:=stack_offset;