Browse Source

* more x86_64 assembler support, rtl compilation works, executables don't work yet

git-svn-id: trunk@3038 -
florian 19 years ago
parent
commit
4c9a08b12b
2 changed files with 135 additions and 63 deletions
  1. 67 3
      compiler/x86/aasmcpu.pas
  2. 68 60
      compiler/x86/rax86.pas

+ 67 - 3
compiler/x86/aasmcpu.pas

@@ -1491,27 +1491,43 @@ implementation
 
            { base }
            case br of
+             NR_R8,
              NR_RAX : base:=0;
+             NR_R9,
              NR_RCX : base:=1;
+             NR_R10,
              NR_RDX : base:=2;
+             NR_R11,
              NR_RBX : base:=3;
+             NR_R12,
              NR_RSP : base:=4;
+             NR_R13,
              NR_NO,
              NR_RBP : base:=5;
+             NR_R14,
              NR_RSI : base:=6;
+             NR_R15,
              NR_RDI : base:=7;
            else
              exit;
            end;
            { index }
            case ir of
+             NR_R8,
              NR_RAX : index:=0;
+             NR_R9,
              NR_RCX : index:=1;
+             NR_R10,
              NR_RDX : index:=2;
+             NR_R11,
              NR_RBX : index:=3;
+             NR_R12,
              NR_NO  : index:=4;
+             NR_R13,
              NR_RBP : index:=5;
+             NR_R14,
              NR_RSI : index:=6;
+             NR_R15,
              NR_RDI : index:=7;
            else
              exit;
@@ -1709,6 +1725,9 @@ implementation
       begin
         len:=0;
         codes:=@p^.code;
+{$ifdef x86_64}
+        rex:=0;
+{$endif x86_64}
         repeat
           c:=ord(codes^);
           inc(codes);
@@ -1727,7 +1746,11 @@ implementation
                   (getsupreg(oper[c-8]^.reg)>=RS_R8)) or
                   ((getregtype(oper[c-8]^.reg)=R_MMREGISTER) and
                   (getsupreg(oper[c-8]^.reg)>=RS_XMM8)) then
-                  rex:=rex or $41;
+                  begin
+                    if rex=0 then
+                      inc(len);
+                    rex:=rex or $41;
+                  end;
 {$endif x86_64}
                 inc(codes);
                 inc(len);
@@ -1776,8 +1799,9 @@ implementation
 {$ifdef x86_64}
                   OT_BITS64:
                     begin
+                      if rex=0 then
+                        inc(len);
                       rex:=rex or $48;
-                      inc(len);
                     end;
 {$endif x86_64}
                 end;
@@ -1808,6 +1832,22 @@ implementation
             64..191 :
               begin
 {$ifdef x86_64}
+                 if (c<127) then
+                  begin
+                    if (oper[c and 7]^.typ=top_reg) then
+                      begin
+                        if ((getregtype(oper[c and 7]^.reg)=R_INTREGISTER) and
+                          (getsupreg(oper[c and 7]^.reg)>=RS_R8)) or
+                          ((getregtype(oper[c and 7]^.reg)=R_MMREGISTER) and
+                          (getsupreg(oper[c and 7]^.reg)>=RS_XMM8)) then
+                          begin
+                            if rex=0 then
+                              inc(len);
+                            rex:=rex or $44;
+                          end;
+                      end;
+                  end;
+
                 ea_data.rex:=0;
                 ea_data.rex_present:=false;
 {$endif x86_64}
@@ -1924,7 +1964,7 @@ implementation
 {$endif extdebug}
         { safety check }
         if objdata.currobjsec.size<>insoffset then
-          internalerror(200130121);
+           internalerror(200130121);
         { load data to write }
         codes:=insentry^.code;
         { Force word push/pop for registers }
@@ -1942,6 +1982,16 @@ implementation
               break;
             1,2,3 :
               begin
+{$ifdef x86_64}
+                if rex<>0 then
+                  begin
+                    bytes[0]:=rex;
+{$ifdef extdebug}
+                    rexwritten:=true;
+{$endif extdebug}
+                    objdata.writebytes(bytes,1);
+                  end;
+{$endif x86_64}
                 objdata.writebytes(codes^,c);
                 inc(codes,c);
               end;
@@ -1981,11 +2031,23 @@ implementation
             8,9,10 :
               begin
                 { rex should be written at this point }
+{
 {$ifdef x86_64}
 {$ifdef extdebug}
                 if (rex<>0) and not(rexwritten) then
                   internalerror(200603192);
 {$endif extdebug}
+{$endif x86_64}
+}
+{$ifdef x86_64}
+                if rex<>0 then
+                  begin
+                    bytes[0]:=rex;
+{$ifdef extdebug}
+                    rexwritten:=true;
+{$endif extdebug}
+                    objdata.writebytes(bytes,1);
+                  end;
 {$endif x86_64}
                 bytes[0]:=ord(codes^)+regval(oper[c-8]^.reg);
                 inc(codes);
@@ -2120,6 +2182,7 @@ implementation
                       Message(asmw_e_64bit_not_supported);
 {$endif x86_64}
                 end;
+{
 {$ifdef x86_64}
                 if rex<>0 then
                   begin
@@ -2130,6 +2193,7 @@ implementation
                     objdata.writebytes(bytes,1);
                   end;
 {$endif x86_64}
+}
               end;
             212 :
               begin

+ 68 - 60
compiler/x86/rax86.pas

@@ -242,65 +242,72 @@ begin
       operands[i].SetCorrectSize(opcode);
       if tx86operand(operands[i]).opsize=S_NO then
         begin
-          case operands[i].Opr.Typ of
-            OPR_LOCAL,
-            OPR_REFERENCE :
-              begin
-                if i=2 then
-                 operand2:=1
-                else
-                 operand2:=2;
-                if operand2<ops then
-                 begin
-                   { Only allow register as operand to take the size from }
-                   if operands[operand2].opr.typ=OPR_REGISTER then
-                     begin
-                       if ((opcode<>A_MOVD) and
-                           (opcode<>A_CVTSI2SS)) then
-                         tx86operand(operands[i]).opsize:=tx86operand(operands[operand2]).opsize;
-                     end
-                   else
-                    begin
-                      { if no register then take the opsize (which is available with ATT),
-                        if not availble then give an error }
-                      if opsize<>S_NO then
-                        tx86operand(operands[i]).opsize:=opsize
-                      else
-                       begin
-                         if (m_delphi in aktmodeswitches) then
-                           Message(asmr_w_unable_to_determine_reference_size_using_dword)
-                         else
-                           Message(asmr_e_unable_to_determine_reference_size);
-                         { recovery }
-                         tx86operand(operands[i]).opsize:=S_L;
-                       end;
-                    end;
-                 end
-                else
-                 begin
-                   if opsize<>S_NO then
-                     tx86operand(operands[i]).opsize:=opsize
-                 end;
-              end;
-            OPR_SYMBOL :
-              begin
-                { Fix lea which need a reference }
-                if opcode=A_LEA then
-                 begin
-                   s:=operands[i].opr.symbol;
-                   so:=operands[i].opr.symofs;
-                   operands[i].opr.typ:=OPR_REFERENCE;
-                   Fillchar(operands[i].opr.ref,sizeof(treference),0);
-                   operands[i].opr.ref.symbol:=s;
-                   operands[i].opr.ref.offset:=so;
-                 end;
 {$ifdef x86_64}
-                tx86operand(operands[i]).opsize:=S_Q;
-{$else x86_64}
-                tx86operand(operands[i]).opsize:=S_L;
+          if (opcode=A_MOVQ) and
+             (ops=2) and
+             (operands[1].opr.typ=OPR_CONSTANT) then
+             opsize:=S_Q
+          else
 {$endif x86_64}
-              end;
-          end;
+            case operands[i].Opr.Typ of
+              OPR_LOCAL,
+              OPR_REFERENCE :
+                begin
+                  if i=2 then
+                   operand2:=1
+                  else
+                   operand2:=2;
+                  if operand2<ops then
+                   begin
+                     { Only allow register as operand to take the size from }
+                     if operands[operand2].opr.typ=OPR_REGISTER then
+                       begin
+                         if ((opcode<>A_MOVD) and
+                             (opcode<>A_CVTSI2SS)) then
+                           tx86operand(operands[i]).opsize:=tx86operand(operands[operand2]).opsize;
+                       end
+                     else
+                      begin
+                        { if no register then take the opsize (which is available with ATT),
+                          if not availble then give an error }
+                        if opsize<>S_NO then
+                          tx86operand(operands[i]).opsize:=opsize
+                        else
+                         begin
+                           if (m_delphi in aktmodeswitches) then
+                             Message(asmr_w_unable_to_determine_reference_size_using_dword)
+                           else
+                             Message(asmr_e_unable_to_determine_reference_size);
+                           { recovery }
+                           tx86operand(operands[i]).opsize:=S_L;
+                         end;
+                      end;
+                   end
+                  else
+                   begin
+                     if opsize<>S_NO then
+                       tx86operand(operands[i]).opsize:=opsize
+                   end;
+                end;
+              OPR_SYMBOL :
+                begin
+                  { Fix lea which need a reference }
+                  if opcode=A_LEA then
+                   begin
+                     s:=operands[i].opr.symbol;
+                     so:=operands[i].opr.symofs;
+                     operands[i].opr.typ:=OPR_REFERENCE;
+                     Fillchar(operands[i].opr.ref,sizeof(treference),0);
+                     operands[i].opr.ref.symbol:=s;
+                     operands[i].opr.ref.offset:=so;
+                   end;
+  {$ifdef x86_64}
+                  tx86operand(operands[i]).opsize:=S_Q;
+  {$else x86_64}
+                  tx86operand(operands[i]).opsize:=S_L;
+  {$endif x86_64}
+                end;
+            end;
         end;
     end;
 end;
@@ -555,14 +562,15 @@ begin
     end;
 
 {$ifdef x86_64}
-  { Convert movq with at least one general registers to mov instruction }
+  { Convert movq with at least one general registers or constant to a mov instruction }
   if (opcode=A_MOVQ) and
      (ops=2) and
      (
       (operands[1].opr.typ=OPR_REGISTER) or
-      (operands[2].opr.typ=OPR_REGISTER)
+      (operands[2].opr.typ=OPR_REGISTER) or
+      (operands[1].opr.typ=OPR_CONSTANT)
      ) then
-    opcode:=A_MOV;
+     opcode:=A_MOV;
 {$endif x86_64}
 
    { GNU AS interprets FDIV without operand differently