Ver código fonte

* zero/sign extend parameter values and return values < 32 bit to 32 bit on
x86_64 (mantis #19269)
* this is also required for darwin/i386 and was already done there for
parameters, but not yet for return values

git-svn-id: trunk@17388 -

Jonas Maebe 14 anos atrás
pai
commit
a08989a76b
3 arquivos alterados com 37 adições e 5 exclusões
  1. 13 2
      compiler/i386/cpupara.pas
  2. 19 2
      compiler/x86_64/cpupara.pas
  3. 5 1
      tests/test/cg/tcalext5.pp

+ 13 - 2
compiler/i386/cpupara.pas

@@ -350,7 +350,18 @@ unit cpupara;
         else
           begin
             retcgsize:=def_cgsize(def);
-            result.intsize:=def.size;
+            { darwin/x86 requires that results < sizeof(aint) are sign/ }
+            { zero extended to sizeof(aint)                             }
+            if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
+               (side=calleeside) and
+               (result.intsize>0) and
+               (result.intsize<sizeof(aint)) then
+              begin
+                result.intsize:=sizeof(aint);
+                retcgsize:=OS_SINT;
+              end
+            else
+              result.intsize:=def.size;
           end;
         result.size:=retcgsize;
         { Return is passed as var parameter }
@@ -456,7 +467,7 @@ unit cpupara;
                    (paralen < sizeof(aint)) then
                   begin
                     paralen := sizeof(aint);
-                    paracgsize:=OS_INT;
+                    paracgsize:=OS_SINT;
                   end
                 else
                   paracgsize:=def_cgsize(hp.vardef);

+ 19 - 2
compiler/x86_64/cpupara.pas

@@ -827,7 +827,16 @@ unit cpupara;
         else
           begin
             retcgsize:=def_cgsize(def);
-            result.intsize:=def.size;
+            { integer sizes < 32 bit have to be sign/zero extended to 32 bit on
+              the callee side (caller can expect those bits are valid) }
+            if (side=calleeside) and
+               (retcgsize in [OS_8,OS_S8,OS_16,OS_S16]) then
+              begin
+                retcgsize:=OS_S32;
+                result.intsize:=4;
+              end
+            else
+              result.intsize:=def.size;
           end;
         result.size:=retcgsize;
         { Return is passed as var parameter }
@@ -973,13 +982,21 @@ unit cpupara;
                 loc[1]:=X86_64_INTEGER_CLASS;
                 loc[2]:=X86_64_NO_CLASS;
                 paracgsize:=OS_ADDR;
-                paralen:=sizeof(aint);
+                paralen:=sizeof(pint);
               end
             else
               begin
                 getvalueparaloc(hp.varspez,hp.vardef,loc[1],loc[2]);
                 paralen:=push_size(hp.varspez,hp.vardef,p.proccalloption);
                 paracgsize:=def_cgsize(hp.vardef);
+                { integer sizes < 32 bit have to be sign/zero extended to 32 bit
+                  on the caller side }
+                if (side=callerside) and
+                   (paracgsize in [OS_8,OS_S8,OS_16,OS_S16]) then
+                  begin
+                    paracgsize:=OS_S32;
+                    paralen:=4;
+                  end;
               end;
 
             { cheat for now, we should copy the value to an mm reg as well (FK) }

+ 5 - 1
tests/test/cg/tcalext5.pp

@@ -543,6 +543,8 @@ var
   s14 : struct14;
   s15 : struct15;
   s31 : struct31;
+  
+  c: cardinal;
 
 begin
   randseed := 30;
@@ -584,7 +586,9 @@ begin
   fill(sa33, sizeof(sa33));
 
 
-  verify(pass1(s1,1), check1(s1), 1);
+  { check that the upper bits of the parameter are cleared when required }
+  c:=$f070d001;
+  verify(pass1(s1,c), check1(s1), 1);
   verify(pass2(s2,2), check2(s2), 2);
   verify(pass3(s3,3), check3(s3), 3);
   verify(pass4(s4,4), check4(s4), 4);