Browse Source

* MIPS: fixed a_call_name and a_call_reg methods to workaround a bug in GAS <2.21, see comments in source for details.
+ g_external_wrapper method.

git-svn-id: trunk@23565 -

sergei 12 years ago
parent
commit
a0c1e1b07f
2 changed files with 59 additions and 14 deletions
  1. 57 13
      compiler/mips/cgcpu.pas
  2. 2 1
      compiler/mips/cpugas.pas

+ 57 - 13
compiler/mips/cgcpu.pas

@@ -88,6 +88,7 @@ type
     procedure g_concatcopy_move(list: tasmlist; const Source, dest: treference; len: tcgint);
     procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint); override;
     procedure g_intf_wrapper(list: tasmlist; procdef: tprocdef; const labelname: string; ioffset: longint); override;
+    procedure g_external_wrapper(list : TAsmList; procdef: tprocdef; const externalname: string);override;
     { Transform unsupported methods into Internal errors }
     procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); override;
     procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override;
@@ -678,28 +679,50 @@ begin
       reference_reset(href,sizeof(aint));
       href.symbol:=current_asmdata.RefAsmSymbol(s);
       a_loadaddr_ref_reg(list,href,NR_PIC_FUNC);
-      { Use JAL pseudo-instruction }
+      { JAL handled as macro provides delay slot and correct restoring of GP. }
+      { Doing it ourselves requires a fixup pass, because GP restore location
+        becomes known only in g_proc_entry, when all code is already generated. }
+
+      { GAS <2.21 is buggy, it doesn't add delay slot in noreorder mode. As a result,
+        the code will crash if dealing with stack frame size >32767 or if calling
+        into shared library.
+        This can be remedied by enabling instruction reordering, but then we also
+        have to emit .set macro/.set nomacro pair and exclude JAL from the
+        list of macro instructions (because noreorder is not allowed after nomacro) }
+      list.concat(taicpu.op_none(A_P_SET_MACRO));
+      list.concat(taicpu.op_none(A_P_SET_REORDER));
       list.concat(taicpu.op_reg(A_JAL,NR_PIC_FUNC));
+      list.concat(taicpu.op_none(A_P_SET_NOREORDER));
+      list.concat(taicpu.op_none(A_P_SET_NOMACRO));
     end
-  else  
-    list.concat(taicpu.op_sym(A_JAL,current_asmdata.RefAsmSymbol(s)));
-  { Delay slot }
-  list.concat(taicpu.op_none(A_NOP));
+  else
+    begin
+      list.concat(taicpu.op_sym(A_JAL,current_asmdata.RefAsmSymbol(s)));
+      { Delay slot }
+      list.concat(taicpu.op_none(A_NOP));
+    end;
 end;
 
 
 procedure TCGMIPS.a_call_reg(list: tasmlist; Reg: TRegister);
 begin
-  if (cs_create_pic in current_settings.moduleswitches) and 
-     (Reg <> NR_PIC_FUNC) then
-    list.concat(taicpu.op_reg_reg(A_MOVE, reg, NR_PIC_FUNC));
-
   if (cs_create_pic in current_settings.moduleswitches) then
-    list.concat(taicpu.op_reg(A_JAL, NR_PIC_FUNC))
+    begin
+      if (Reg <> NR_PIC_FUNC) then
+        list.concat(taicpu.op_reg_reg(A_MOVE,NR_PIC_FUNC,reg));
+      { See comments in a_call_name }
+      list.concat(taicpu.op_none(A_P_SET_MACRO));
+      list.concat(taicpu.op_none(A_P_SET_REORDER));
+      list.concat(taicpu.op_reg(A_JAL,NR_PIC_FUNC));
+      list.concat(taicpu.op_none(A_P_SET_NOREORDER));
+      list.concat(taicpu.op_none(A_P_SET_NOMACRO));
+    end
   else
-    list.concat(taicpu.op_reg(A_JALR, reg));
-  { Delay slot }
-  list.concat(taicpu.op_none(A_NOP));
+    begin
+      list.concat(taicpu.op_reg(A_JALR, reg));
+      { Delay slot }
+      list.concat(taicpu.op_none(A_NOP));
+    end;
 end;
 
 
@@ -924,6 +947,8 @@ begin
           ref.base  := tmpreg;
       end;
 end;
+
+
 procedure TCGMIPS.a_loadaddr_ref_reg(list: tasmlist; const ref: TReference; r: tregister);
 var
   tmpref, href: treference;
@@ -2002,6 +2027,25 @@ begin
   List.concat(Tai_symbol_end.Createname(labelname));
 end;
 
+
+procedure TCGMIPS.g_external_wrapper(list: TAsmList; procdef: tprocdef; const externalname: string);
+  var
+    href: treference;
+  begin
+    { Always do indirect jump using $t9, it won't harm in non-PIC mode.
+      .cpload is safe in this respect, too. }
+    list.concat(taicpu.op_none(A_P_SET_NOREORDER));
+    list.concat(taicpu.op_reg(A_P_CPLOAD,NR_PIC_FUNC));
+    reference_reset_symbol(href,current_asmdata.RefAsmSymbol(externalname),0,sizeof(aint));
+    href.refaddr:=addr_pic_call16;
+    list.concat(taicpu.op_reg_ref(A_LW,NR_PIC_FUNC,href));
+    list.concat(taicpu.op_reg(A_J,NR_PIC_FUNC));
+    { Delay slot }
+    list.Concat(taicpu.op_none(A_NOP));
+    list.Concat(taicpu.op_none(A_P_SET_REORDER));
+  end;
+
+
 procedure TCGMIPS.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint);
   begin
     { This method is integrated into g_intf_wrapper and shouldn't be called separately }

+ 2 - 1
compiler/mips/cpugas.pas

@@ -228,7 +228,8 @@ unit cpugas;
         { 'seq', 'sge', 'sgeu', 'sgt', 'sgtu', 'sle', 'sleu', 'sne', }
           (op=A_SEQ) or (op = A_SGE) or (op=A_SGEU) or (op=A_SGT) or
           (op=A_SGTU) or (op=A_SLE) or (op=A_SLEU) or (op=A_SNE)
-          or (op=A_LA) or (op=A_BC) or (op=A_JAL)
+          { JAL is not here! See comments in TCGMIPS.a_call_name. }
+          or (op=A_LA) or (op=A_BC) {or (op=A_JAL)}
           or (op=A_REM) or (op=A_REMU)
           or (op=A_DIV) or (op=A_DIVU) 
           { A_LI is only a macro if the immediate is not in thez 16-bit range }