瀏覽代碼

+ support for @page and @pageoffs addressing on AArch64: these are PIC
references that directly take the address of a symbol, rather than
of its GOT entry
o use these addressing modes to access local symbols

git-svn-id: trunk@29932 -

Jonas Maebe 10 年之前
父節點
當前提交
7fc9d775df
共有 5 個文件被更改,包括 115 次插入75 次删除
  1. 5 5
      compiler/aarch64/aasmcpu.pas
  2. 72 63
      compiler/aarch64/agcpugas.pas
  3. 27 7
      compiler/aarch64/cgcpu.pas
  4. 9 0
      compiler/aarch64/racpugas.pas
  5. 2 0
      compiler/cgbase.pas

+ 5 - 5
compiler/aarch64/aasmcpu.pas

@@ -569,7 +569,7 @@ implementation
       begin
       begin
         result:=sr_complex;
         result:=sr_complex;
         if not assigned(ref.symboldata) and
         if not assigned(ref.symboldata) and
-           not(ref.refaddr in [addr_pic,addr_gotpageoffset,addr_gotpage]) then
+           not(ref.refaddr in [addr_gotpageoffset,addr_gotpage,addr_pageoffset,addr_page]) then
           exit;
           exit;
         { can't use pre-/post-indexed mode here (makes no sense either) }
         { can't use pre-/post-indexed mode here (makes no sense either) }
         if ref.addressmode<>AM_OFFSET then
         if ref.addressmode<>AM_OFFSET then
@@ -580,9 +580,9 @@ implementation
             not(oppostfix in [PF_NONE,PF_W,PF_SW]) or
             not(oppostfix in [PF_NONE,PF_W,PF_SW]) or
             not assigned(ref.symbol)) then
             not assigned(ref.symbol)) then
           exit;
           exit;
-        { if this is a got offset load, we must have a base register and a
+        { if this is a (got) page offset load, we must have a base register and a
           symbol }
           symbol }
-        if (ref.refaddr=addr_gotpageoffset) and
+        if (ref.refaddr in [addr_gotpageoffset,addr_pageoffset]) and
            (not assigned(ref.symbol) or
            (not assigned(ref.symbol) or
             (ref.base=NR_NO) or
             (ref.base=NR_NO) or
             (ref.index<>NR_NO) or
             (ref.index<>NR_NO) or
@@ -594,7 +594,7 @@ implementation
         { cannot have base or index register (we generate these kind of
         { cannot have base or index register (we generate these kind of
           references internally, they should never end up here with an
           references internally, they should never end up here with an
           extra base or offset) }
           extra base or offset) }
-        if (ref.refaddr in [addr_gotpage,addr_pic]) and
+        if (ref.refaddr in [addr_gotpage,addr_page]) and
            (ref.base<>NR_NO) or
            (ref.base<>NR_NO) or
            (ref.index<>NR_NO) then
            (ref.index<>NR_NO) then
           begin
           begin
@@ -647,7 +647,7 @@ implementation
           end;
           end;
 
 
         { any other reference cannot be gotpage/gotpageoffset/pic }
         { any other reference cannot be gotpage/gotpageoffset/pic }
-        if ref.refaddr in [addr_gotpage,addr_gotpageoffset,addr_pic] then
+        if ref.refaddr in [addr_gotpage,addr_gotpageoffset,addr_page,addr_pageoffset,addr_pic] then
           exit;
           exit;
 
 
         { base & index:
         { base & index:

+ 72 - 63
compiler/aarch64/agcpugas.pas

@@ -83,76 +83,85 @@ unit agcpugas;
 {****************************************************************************}
 {****************************************************************************}
 
 
     function getreferencestring(var ref : treference) : string;
     function getreferencestring(var ref : treference) : string;
+      const
+        darwin_addrpage2str: array[addr_page..addr_gotpageoffset] of string[11] =
+           ('@PAGE','@PAGEOFF','@GOTPAGE','@GOTPAGEOFF');
       begin
       begin
-        case ref.refaddr of
-          addr_gotpage:
-            begin
-              if not assigned(ref.symbol) or
-                 (ref.base<>NR_NO) or
-                 (ref.index<>NR_NO) or
-                 (ref.shiftmode<>SM_None) or
-                 (ref.offset<>0) then
-                internalerror(2014121501);
-              if target_asm.id=as_darwin then
-                result:=ref.symbol.name+'@GOTPAGE'
-              else
-                { todo }
-                internalerror(2014121502);
-            end
-          else
-            begin
-              if ref.base=NR_NO then
-                internalerror(2014121503);
-              result:='['+gas_regname(ref.base);
-              if ref.addressmode=AM_POSTINDEXED then
-                result:=result+']';
-              if ref.index<>NR_NO then
+        if ref.base=NR_NO then
+          begin
+            case ref.refaddr of
+              addr_gotpage,
+              addr_page,
+              addr_gotpageoffset,
+              addr_pageoffset:
                 begin
                 begin
-                  if (ref.offset<>0) or
-                     assigned(ref.symbol) then
-                    internalerror(2014121504);
-                  result:=result+', '+gas_regname(ref.index);
-                  case ref.shiftmode of
-                    SM_None: ;
-                    SM_LSL,
-                    SM_UXTB, SM_UXTH, SM_UXTW, SM_UXTX,
-                    SM_SXTB, SM_SXTH, SM_SXTW, SM_SXTX:
-                      result:=result+', lsl #'+tostr(ref.shiftimm);
-                    else
-                      internalerror(2014121505);
-                  end;
+                  if not assigned(ref.symbol) or
+                     (ref.base<>NR_NO) or
+                     (ref.index<>NR_NO) or
+                     (ref.shiftmode<>SM_None) or
+                     (ref.offset<>0) then
+                    internalerror(2014121501);
+                  if target_asm.id=as_darwin then
+                    result:=ref.symbol.name+darwin_addrpage2str[ref.refaddr]
+                  else
+                    { todo }
+                    internalerror(2014121502);
                 end
                 end
-              else
-                begin
-                  if assigned(ref.symbol) then
-                    begin
-                      case ref.refaddr of
-                        addr_gotpageoffset:
-                          begin
-                            if target_asm.id=as_darwin then
-                              result:=result+', '+ref.symbol.name+'@GOTPAGEOFF'
-                            else
-                              result:=result+', #:lo12:'+ref.symbol.name;
-                          end
-                        else
-                          { todo: not yet generated/don't know syntax }
-                          internalerror(2014121506);
-                      end;
-                    end
+            end
+          end
+        else
+          begin
+            result:='['+gas_regname(ref.base);
+            if ref.addressmode=AM_POSTINDEXED then
+              result:=result+']';
+            if ref.index<>NR_NO then
+              begin
+                if (ref.offset<>0) or
+                   assigned(ref.symbol) then
+                  internalerror(2014121504);
+                result:=result+', '+gas_regname(ref.index);
+                case ref.shiftmode of
+                  SM_None: ;
+                  SM_LSL,
+                  SM_UXTB, SM_UXTH, SM_UXTW, SM_UXTX,
+                  SM_SXTB, SM_SXTH, SM_SXTW, SM_SXTX:
+                    result:=result+', lsl #'+tostr(ref.shiftimm);
                   else
                   else
-                    begin
-                      if ref.refaddr<>addr_no then
+                    internalerror(2014121505);
+                end;
+              end
+            else
+              begin
+                if assigned(ref.symbol) then
+                  begin
+                    case ref.refaddr of
+                      addr_gotpageoffset,
+                      addr_pageoffset:
+                        begin
+                          if target_asm.id=as_darwin then
+                            result:=result+', '+ref.symbol.name+darwin_addrpage2str[ref.refaddr]
+                          else
+                            { todo }
+                            internalerror(2014122510);
+                        end
+                      else
+                        { todo: not yet generated/don't know syntax }
                         internalerror(2014121506);
                         internalerror(2014121506);
-                      if (ref.offset<>0) then
-                        result:=result+', #'+tostr(ref.offset);
                     end;
                     end;
-                end;
-              case ref.addressmode of
-                AM_OFFSET:
-                  result:=result+']';
-                AM_PREINDEXED:
-                  result:=result+']!';
+                  end
+                else
+                  begin
+                    if ref.refaddr<>addr_no then
+                      internalerror(2014121506);
+                    if (ref.offset<>0) then
+                      result:=result+', #'+tostr(ref.offset);
+                  end;
               end;
               end;
+            case ref.addressmode of
+              AM_OFFSET:
+                result:=result+']';
+              AM_PREINDEXED:
+                result:=result+']!';
             end;
             end;
           end;
           end;
       end;
       end;

+ 27 - 7
compiler/aarch64/cgcpu.pas

@@ -154,7 +154,7 @@ implementation
           begin
           begin
             { internal "load symbol" instructions should already be valid }
             { internal "load symbol" instructions should already be valid }
             if assigned(ref.symboldata) or
             if assigned(ref.symboldata) or
-               (ref.refaddr in [addr_pic,addr_gotpage,addr_gotpageoffset]) then
+               (ref.refaddr in [addr_pic,addr_gotpage,addr_gotpageoffset,addr_page,addr_pageoffset]) then
               internalerror(2014110802);
               internalerror(2014110802);
             { no relative symbol support (needed) yet }
             { no relative symbol support (needed) yet }
             if assigned(ref.relsymbol) then
             if assigned(ref.relsymbol) then
@@ -171,17 +171,37 @@ implementation
                    (ref.base=preferred_newbasereg) or
                    (ref.base=preferred_newbasereg) or
                    (ref.index=preferred_newbasereg) then
                    (ref.index=preferred_newbasereg) then
                   preferred_newbasereg:=getaddressregister(list);
                   preferred_newbasereg:=getaddressregister(list);
-                { load the GOT page }
+                { load the (GOT) page }
                 reference_reset_symbol(href,ref.symbol,0,8);
                 reference_reset_symbol(href,ref.symbol,0,8);
-                href.refaddr:=addr_gotpage;
+                if ((ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) and
+                    (ref.symbol.bind in [AB_LOCAL,AB_GLOBAL])) or
+                   ((ref.symbol.typ=AT_DATA) and
+                    (ref.symbol.bind=AB_LOCAL)) then
+                  href.refaddr:=addr_page
+                else
+                  href.refaddr:=addr_gotpage;
                 list.concat(taicpu.op_reg_ref(A_ADRP,preferred_newbasereg,href));
                 list.concat(taicpu.op_reg_ref(A_ADRP,preferred_newbasereg,href));
                 { load the GOT entry (= address of the variable) }
                 { load the GOT entry (= address of the variable) }
                 reference_reset_base(href,preferred_newbasereg,0,sizeof(pint));
                 reference_reset_base(href,preferred_newbasereg,0,sizeof(pint));
                 href.symbol:=ref.symbol;
                 href.symbol:=ref.symbol;
-                href.refaddr:=addr_gotpageoffset;
-                { use a_load_ref_reg() rather than directly encoding the LDR,
-                  so that we'll check the validity of the reference }
-                a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,preferred_newbasereg);
+                { code symbols defined in the current compilation unit do not
+                  have to be accessed via the GOT }
+                if ((ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) and
+                    (ref.symbol.bind in [AB_LOCAL,AB_GLOBAL])) or
+                   ((ref.symbol.typ=AT_DATA) and
+                    (ref.symbol.bind=AB_LOCAL)) then
+                  begin
+                    href.base:=NR_NO;
+                    href.refaddr:=addr_pageoffset;
+                    list.concat(taicpu.op_reg_reg_ref(A_ADD,preferred_newbasereg,preferred_newbasereg,href));
+                  end
+                else
+                  begin
+                    href.refaddr:=addr_gotpageoffset;
+                    { use a_load_ref_reg() rather than directly encoding the LDR,
+                      so that we'll check the validity of the reference }
+                    a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,preferred_newbasereg);
+                  end;
                 { set as new base register }
                 { set as new base register }
                 if ref.base=NR_NO then
                 if ref.base=NR_NO then
                   ref.base:=preferred_newbasereg
                   ref.base:=preferred_newbasereg

+ 9 - 0
compiler/aarch64/racpugas.pas

@@ -308,6 +308,11 @@ Unit racpugas;
                         consume(actasmtoken);
                         consume(actasmtoken);
                         oper.opr.ref.refaddr:=addr_gotpageoffset;
                         oper.opr.ref.refaddr:=addr_gotpageoffset;
                       end
                       end
+                    else if actasmpattern='PAGEOFF' then
+                      begin
+                        consume(actasmtoken);
+                        oper.opr.ref.refaddr:=addr_pageoffset;
+                      end
                     else
                     else
                       begin
                       begin
                         do_error;
                         do_error;
@@ -532,6 +537,10 @@ Unit racpugas;
                   oper.opr.ref.refaddr:=addr_gotpage
                   oper.opr.ref.refaddr:=addr_gotpage
                 else if actasmpattern='GOTPAGEOFF' then
                 else if actasmpattern='GOTPAGEOFF' then
                   oper.opr.ref.refaddr:=addr_gotpageoffset
                   oper.opr.ref.refaddr:=addr_gotpageoffset
+                else if actasmpattern='PAGE' then
+                  oper.opr.ref.refaddr:=addr_page
+                else if actasmpattern='PAGEOFF' then
+                  oper.opr.ref.refaddr:=addr_pageoffset
                 else
                 else
                   Message(asmr_e_expr_illegal);
                   Message(asmr_e_expr_illegal);
                 consume(actasmtoken);
                 consume(actasmtoken);

+ 2 - 0
compiler/cgbase.pas

@@ -102,6 +102,8 @@ interface
          ,addr_seg         // used for getting the segment of an object, e.g. 'mov ax, SEG symbol'
          ,addr_seg         // used for getting the segment of an object, e.g. 'mov ax, SEG symbol'
          {$ENDIF}
          {$ENDIF}
          {$IFDEF AARCH64}
          {$IFDEF AARCH64}
+         ,addr_page
+         ,addr_pageoffset
          ,addr_gotpage
          ,addr_gotpage
          ,addr_gotpageoffset
          ,addr_gotpageoffset
          {$ENDIF AARCH64}
          {$ENDIF AARCH64}