浏览代码

* Xtensa: several issues with parameter passing of the windowed api fixed

git-svn-id: trunk@46708 -
florian 5 年之前
父节点
当前提交
250c0750a2
共有 4 个文件被更改,包括 73 次插入69 次删除
  1. 17 0
      compiler/psub.pas
  2. 27 54
      compiler/xtensa/cpupara.pas
  3. 24 15
      compiler/xtensa/cpupi.pas
  4. 5 0
      compiler/xtensa/symcpu.pas

+ 17 - 0
compiler/psub.pas

@@ -1165,6 +1165,23 @@ implementation
               end;
           end;
 {$endif defined(x86) or defined(arm)}
+{$if defined(xtensa)}
+        { On xtensa, the stack frame size can be estimated to avoid using an extra frame pointer,
+          in case parameters are passed on the stack.
+
+          However, the draw back is, if the estimation fails, compilation will break later on
+          with an internal error, so this switch is not enabled by default yet. To overcome this,
+          multipass compilation of subroutines must be supported
+        }
+        if (target_info.abi=abi_xtensa_windowed) and (procdef.stack_tainting_parameter(calleeside)) then
+          begin
+            include(flags,pi_estimatestacksize);
+            set_first_temp_offset;
+            procdef.has_paraloc_info:=callnoside;
+            generate_parameter_info;
+            exit;
+          end;
+{$endif defined(xtensa)}
         { set the start offset to the start of the temp area in the stack }
         set_first_temp_offset;
       end;

+ 27 - 54
compiler/xtensa/cpupara.pas

@@ -43,7 +43,7 @@ unit cpupara;
        private
          { the max. register depends on the used call instruction }
          maxintreg : TSuperRegister;
-         procedure init_values(side: tcallercallee; var curintreg: tsuperregister; var cur_stack_offset: aword);
+         procedure init_values(p: tabstractprocdef; side: tcallercallee; var curintreg: tsuperregister; var cur_stack_offset: aword);
          function create_paraloc_info_intern(p : tabstractprocdef; side : tcallercallee;
            paras : tparalist; var curintreg : tsuperregister;
            var cur_stack_offset : aword; varargsparas : boolean) : longint;
@@ -54,7 +54,8 @@ unit cpupara;
     uses
        cpuinfo,globals,
        verbose,systems,
-       defutil,symtable,
+       defutil,
+       symtable,symcpu,
        procinfo,cpupi;
 
 
@@ -95,17 +96,14 @@ unit cpupara;
             classrefdef:
               result:=LOC_REGISTER;
             procvardef:
-              if (p.size = sizeof(pint)) then
-                result:=LOC_REGISTER
-              else
-                result:=LOC_REFERENCE;
+              result:=LOC_REGISTER;
             recorddef:
-              if (p.size > 4) then
+              if p.size>24 then
                 result:=LOC_REFERENCE
               else
                 result:=LOC_REGISTER;
             objectdef:
-              if is_object(p) then
+              if is_object(p) and (p.size>24) then
                 result:=LOC_REFERENCE
               else
                 result:=LOC_REGISTER;
@@ -117,7 +115,7 @@ unit cpupara;
             filedef:
               result:=LOC_REGISTER;
             arraydef:
-              if is_dynamic_array(p) then
+              if is_dynamic_array(p) or (p.size<=24) then
                 getparaloc:=LOC_REGISTER
               else
                 result:=LOC_REFERENCE;
@@ -127,12 +125,12 @@ unit cpupara;
               else
                 result:=LOC_REFERENCE;
             variantdef:
-              result:=LOC_REFERENCE;
+              result:=LOC_REGISTER;
             { avoid problems with errornous definitions }
             errordef:
               result:=LOC_REGISTER;
             else
-              internalerror(2002071001);
+              internalerror(2020082501);
          end;
       end;
 
@@ -150,33 +148,17 @@ unit cpupara;
           variantdef,
           formaldef :
             result:=true;
-          { regular procvars must be passed by value, because you cannot pass
-            the address of a local stack location when calling e.g.
-            pthread_create with the address of a function (first of all it
-            expects the address of the function to execute and not the address
-            of a memory location containing that address, and secondly if you
-            first store the address on the stack and then pass the address of
-            this stack location, then this stack location may no longer be
-            valid when the newly started thread accesses it.
-
-            However, for "procedure of object" we must use the same calling
-            convention as for "8 byte record" due to the need for
-            interchangeability with the TMethod record type.
-          }
-          procvardef :
-            result:=
-              (def.size <> sizeof(pint));
           recorddef :
-            result := (def.size > 8) or (varspez = vs_const);
+            result:=(varspez = vs_const);
           arraydef:
             result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
                              is_open_array(def) or
                              is_array_of_const(def) or
                              is_array_constructor(def);
           objectdef :
-            result:=is_object(def);
+            result:=is_object(def) and (varspez = vs_const);
           setdef :
-            result:=not is_smallset(def);
+            result:=(varspez = vs_const);
           stringdef :
             result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
           else
@@ -185,7 +167,7 @@ unit cpupara;
       end;
 
 
-    procedure tcpuparamanager.init_values(side : tcallercallee; var curintreg: tsuperregister; var cur_stack_offset: aword);
+    procedure tcpuparamanager.init_values(p : tabstractprocdef; side : tcallercallee; var curintreg: tsuperregister; var cur_stack_offset: aword);
       begin
         cur_stack_offset:=0;
         case target_info.abi of
@@ -195,6 +177,8 @@ unit cpupara;
                 begin
                   curintreg:=RS_A2;
                   maxintreg:=RS_A7;
+                  if current_procinfo.framepointer=NR_STACK_POINTER_REG then
+                    cur_stack_offset:=(p as tcpuprocdef).total_stackframe_size;
                 end
               else
                 begin
@@ -287,7 +271,7 @@ unit cpupara;
         cur_stack_offset: aword;
         curintreg: tsuperregister;
       begin
-        init_values(side,curintreg,cur_stack_offset);
+        init_values(p,side,curintreg,cur_stack_offset);
 
         result := create_paraloc_info_intern(p,side,p.paras,curintreg,cur_stack_offset,false);
 
@@ -363,13 +347,19 @@ unit cpupara;
                     end;
                 end;
 
-              loc := getparaloc(paradef);
+              loc:=getparaloc(paradef);
+
+              if (loc=LOC_REGISTER) and ((maxintreg-nextintreg+1)*4<paradef.size) then
+                begin
+                  loc:=LOC_REFERENCE;
+                  nextintreg:=maxintreg+1;
+                end;
 
               hp.paraloc[side].alignment:=std_param_align;
               hp.paraloc[side].size:=paracgsize;
               hp.paraloc[side].intsize:=paralen;
               hp.paraloc[side].def:=paradef;
-              if (is_64bit(paradef)) and
+              if (loc=LOC_REGISTER) and (is_64bit(paradef)) and
                  odd(nextintreg-RS_A2) then
                 inc(nextintreg);
               if (paralen = 0) then
@@ -410,16 +400,6 @@ unit cpupara;
                           paraloc^.size:=paracgsize;
                           paraloc^.def:=locdef;
                         end;
-                      { aix requires that record data stored in parameter
-                        registers is left-aligned }
-                      if (target_info.system in systems_aix) and
-                         (paradef.typ = recorddef) and
-                         (paralen < sizeof(aint)) then
-                        begin
-                          paraloc^.shiftval := (sizeof(aint)-paralen)*(-8);
-                          paraloc^.size := OS_INT;
-                          paraloc^.def := u32inttype;
-                        end;
                       paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
                       inc(nextintreg);
                       dec(paralen,tcgsize2size[paraloc^.size]);
@@ -440,17 +420,10 @@ unit cpupara;
                          else
                            internalerror(2020031405);
                        end;
-                       if (side = callerside) then
+                       if side = callerside then
                          paraloc^.reference.index:=NR_STACK_POINTER_REG
                        else
-                         begin
-                           paraloc^.reference.index:=NR_FRAME_POINTER_REG;
-
-                           { create_paraloc_info_intern might be also called when being outside of
-                             code generation so current_procinfo might be not set }
-                           if assigned(current_procinfo) then
-                             txtensaprocinfo(current_procinfo).needs_frame_pointer := true;
-                         end;
+                         paraloc^.reference.index:=current_procinfo.framepointer;
 
                        paraloc^.reference.offset:=stack_offset;
 
@@ -481,7 +454,7 @@ unit cpupara;
         hp: tparavarsym;
         paraloc: pcgparalocation;
       begin
-        init_values(side,curintreg,cur_stack_offset);
+        init_values(p,side,curintreg,cur_stack_offset);
 
         result:=create_paraloc_info_intern(p,side,p.paras,curintreg,cur_stack_offset, false);
         if (p.proccalloption in cstylearrayofconst) then

+ 24 - 15
compiler/xtensa/cpupi.pas

@@ -35,19 +35,20 @@ unit cpupi;
 
     type
       txtensaprocinfo = class(tcgprocinfo)
-          callins,callxins : TAsmOp;
-          stackframesize,
-          stackpaddingreg: TSuperRegister;
-
-          needs_frame_pointer: boolean;
-          { highest N used in a call instruction }
-          maxcall : Byte;
-          // procedure handle_body_start;override;
-          // procedure after_pass1;override;            
-          constructor create(aparent: tprocinfo); override;
-          procedure set_first_temp_offset;override;
-          function calc_stackframe_size:longint;override;
-          procedure init_framepointer;override;
+        callins,callxins : TAsmOp;
+        stackframesize,
+        stackpaddingreg: TSuperRegister;
+
+        needs_frame_pointer: boolean;
+        { highest N used in a call instruction }
+        maxcall : Byte;
+        // procedure handle_body_start;override;
+        // procedure after_pass1;override;
+        constructor create(aparent: tprocinfo); override;
+        procedure set_first_temp_offset;override;
+        function calc_stackframe_size:longint;override;
+        procedure init_framepointer;override;
+        procedure generate_parameter_info;override;
       end;
 
 
@@ -152,6 +153,13 @@ unit cpupi;
       end;
 
 
+    procedure txtensaprocinfo.generate_parameter_info;
+      begin
+       tcpuprocdef(procdef).total_stackframe_size:=stackframesize;
+       inherited generate_parameter_info;
+      end;
+
+
     procedure txtensaprocinfo.init_framepointer;
       begin
         if target_info.abi=abi_xtensa_call0 then
@@ -161,8 +169,9 @@ unit cpupi;
           end
         else
           begin
-            RS_FRAME_POINTER_REG:=RS_A7;
-            NR_FRAME_POINTER_REG:=NR_A7;
+            { a frame pointer would be only needed if we do an " alloca" }
+            RS_FRAME_POINTER_REG:=RS_A15;
+            NR_FRAME_POINTER_REG:=NR_A15;
           end;
       end;
 

+ 5 - 0
compiler/xtensa/symcpu.pas

@@ -26,6 +26,7 @@ unit symcpu;
 interface
 
 uses
+  globtype,
   symconst,symtype,symdef,symsym;
 
 type
@@ -91,6 +92,10 @@ type
   tcpuprocvardefclass = class of tcpuprocvardef;
 
   tcpuprocdef = class(tprocdef)
+    { the xtensa paramanager might need to know the total size of the stackframe
+      to avoid cyclic unit dependencies or global variables, this information is
+      stored in total_stackframe_size }
+    total_stackframe_size : aint;
   end;
   tcpuprocdefclass = class of tcpuprocdef;