Browse Source

+ improved x86-64 assembler

git-svn-id: trunk@2983 -
florian 19 years ago
parent
commit
ec768f88ae
3 changed files with 156 additions and 73 deletions
  1. 154 71
      compiler/x86/aasmcpu.pas
  2. 1 1
      compiler/x86/x86ins.dat
  3. 1 1
      compiler/x86_64/x8664tab.inc

+ 154 - 71
compiler/x86/aasmcpu.pas

@@ -250,10 +250,13 @@ interface
          procedure ppuderefoper(var o:toper);override;
       private
          { next fields are filled in pass1, so pass2 is faster }
-         inssize   : shortint;
+         insentry  : PInsEntry;
          insoffset : longint;
          LastInsOffset : longint; { need to be public to be reset }
-         insentry  : PInsEntry;
+         inssize   : shortint;
+{$ifdef x86_64}
+         rex       : byte;
+{$endif x86_64}
          function  InsEnd:longint;
          procedure create_ot(objdata:TObjData);
          function  Matches(p:PInsEntry):boolean;
@@ -973,12 +976,16 @@ implementation
 *****************************************************************************}
 
     type
-      ea=packed record
+      ea = packed record
         sib_present : boolean;
         bytes : byte;
         size  : byte;
         modrm : byte;
         sib   : byte;
+{$ifdef x86_64}
+        rex_present : boolean;
+        rex   : byte;
+{$endif x86_64}
       end;
 
     procedure taicpu.create_ot(objdata:TObjData);
@@ -1414,7 +1421,19 @@ implementation
             output.bytes:=0;
             output.modrm:=$c0 or (rfield shl 3) or rv;
             output.size:=1;
+
+            if ((getregtype(input.reg)=R_INTREGISTER) and
+              (getsupreg(input.reg)>=RS_R8)) or
+              ((getregtype(input.reg)=R_MMREGISTER) and
+              (getsupreg(input.reg)>=RS_XMM8)) then
+              begin
+                output.rex_present:=true;
+                output.rex:=output.rex or $44;
+                inc(output.size,1);
+              end;
+
             process_ea:=true;
+
             exit;
          end;
         {No register, so memory reference.}
@@ -1444,36 +1463,32 @@ implementation
            { 16 bit address? }
            if ((ir<>NR_NO) and (isub<>R_SUBADDR)) or
               ((br<>NR_NO) and (bsub<>R_SUBADDR)) then
-{$ifdef x86_64}
              message(asmw_e_16bit_32bit_not_supported);
-{$else x86_64}
-             message(asmw_e_16bit_not_supported);
-{$endif x86_64}
-{$ifdef OPTEA}
-           { make single reg base }
-           if (br=NR_NO) and (s=1) then
-            begin
-              br:=ir;
-              ir:=NR_NO;
-            end;
-           { convert [3,5,9]*EAX to EAX+[2,4,8]*EAX }
-           if (br=NR_NO) and
-              (((s=2) and (ir<>NR_ESP)) or
-                (s=3) or (s=5) or (s=9)) then
-            begin
-              br:=ir;
-              dec(s);
-            end;
-           { swap ESP into base if scalefactor is 1 }
-           if (s=1) and (ir=NR_ESP) then
-            begin
-              ir:=br;
-              br:=NR_ESP;
-            end;
-{$endif OPTEA}
            { wrong, for various reasons }
            if (ir=NR_ESP) or ((s<>1) and (s<>2) and (s<>4) and (s<>8) and (ir<>NR_NO)) then
             exit;
+
+           if ((getregtype(br)=R_INTREGISTER) and
+             (getsupreg(br)>=RS_R8)) or
+             ((getregtype(br)=R_MMREGISTER) and
+             (getsupreg(br)>=RS_XMM8)) then
+             begin
+               output.rex_present:=true;
+               output.rex:=output.rex or $41;
+             end;
+
+           if ((getregtype(ir)=R_INTREGISTER) and
+             (getsupreg(ir)>=RS_R8)) or
+             ((getregtype(ir)=R_MMREGISTER) and
+             (getsupreg(ir)>=RS_XMM8)) then
+             begin
+               output.rex_present:=true;
+               output.rex:=output.rex or $42;
+             end;
+
+           process_ea:=true;
+
+
            { base }
            case br of
              NR_RAX : base:=0;
@@ -1490,14 +1505,14 @@ implementation
            end;
            { index }
            case ir of
-             NR_EAX : index:=0;
-             NR_ECX : index:=1;
-             NR_EDX : index:=2;
-             NR_EBX : index:=3;
+             NR_RAX : index:=0;
+             NR_RCX : index:=1;
+             NR_RDX : index:=2;
+             NR_RBX : index:=3;
              NR_NO  : index:=4;
-             NR_EBP : index:=5;
-             NR_ESI : index:=6;
-             NR_EDI : index:=7;
+             NR_RBP : index:=5;
+             NR_RSI : index:=6;
+             NR_RDI : index:=7;
            else
              exit;
            end;
@@ -1535,10 +1550,7 @@ implementation
               output.sib:=(scalefactor shl 6) or (index shl 3) or base;
             end;
          end;
-        if output.sib_present then
-         output.size:=2+output.bytes
-        else
-         output.size:=1+output.bytes;
+        output.size:=1+ord(output.sib_present)+ord(output.rex_present)+output.bytes;
         process_ea:=true;
       end;
 
@@ -1708,7 +1720,19 @@ implementation
                 inc(codes,c);
                 inc(len,c);
               end;
-            8,9,10,11 :
+            8,9,10 :
+              begin
+{$ifdef x86_64}
+                if ((getregtype(oper[c-8]^.reg)=R_INTREGISTER) and
+                  (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;
+{$endif x86_64}
+                inc(codes);
+                inc(len);
+              end;
+            11 :
               begin
                 inc(codes);
                 inc(len);
@@ -1730,7 +1754,13 @@ implementation
             31,
             48,49,50 :
               inc(len,2);
-            28,29,30, { we don't have 16 bit immediates code }
+            28,29,30:
+              begin
+                if opsize=S_Q then
+                  inc(len,8)
+                else
+                  inc(len,4);
+              end;
             32,33,34,
             52,53,54,
             56,57,58 :
@@ -1741,9 +1771,15 @@ implementation
             208,209,210 :
               begin
                 case (oper[c-208]^.ot and OT_SIZE_MASK) of
-                  OT_BITS16,
-                  OT_BITS64 :
+                  OT_BITS16:
                     inc(len);
+{$ifdef x86_64}
+                  OT_BITS64:
+                    begin
+                      rex:=rex or $48;
+                      inc(len);
+                    end;
+{$endif x86_64}
                 end;
               end;
             212,
@@ -1759,10 +1795,21 @@ implementation
               inc(len);
             64..191 :
               begin
+{$ifdef x86_64}
+                ea_data.rex:=0;
+                ea_data.rex_present:=false;
+{$endif x86_64}
                 if not process_ea(oper[(c shr 3) and 7]^, ea_data, 0) then
-                 Message(asmw_e_invalid_effective_address)
+                  Message(asmw_e_invalid_effective_address)
                 else
-                 inc(len,ea_data.size);
+                  inc(len,ea_data.size);
+{$ifdef x86_64}
+                { did we already create include a rex into the length calculation? }
+                if (rex<>0) and (ea_data.rex<>0) then
+                  dec(len);
+                rex:=rex or ea_data.rex;
+{$endif x86_64}
+
               end;
             else
              InternalError(200603141);
@@ -1821,26 +1868,26 @@ implementation
       }
 
       var
-        currval : longint;
+        currval : aint;
         currsym : tobjsymbol;
 
         procedure getvalsym(opidx:longint);
-        begin
-          case oper[opidx]^.typ of
-            top_ref :
-              begin
-                currval:=oper[opidx]^.ref^.offset;
-                currsym:=ObjData.symbolref(oper[opidx]^.ref^.symbol);
-              end;
-            top_const :
-              begin
-                currval:=longint(oper[opidx]^.val);
-                currsym:=nil;
-              end;
-            else
-              Message(asmw_e_immediate_or_reference_expected);
+          begin
+            case oper[opidx]^.typ of
+              top_ref :
+                begin
+                  currval:=oper[opidx]^.ref^.offset;
+                  currsym:=ObjData.symbolref(oper[opidx]^.ref^.symbol);
+                end;
+              top_const :
+                begin
+                  currval:=longint(oper[opidx]^.val);
+                  currsym:=nil;
+                end;
+              else
+                Message(asmw_e_immediate_or_reference_expected);
+            end;
           end;
-        end;
 
       const
         CondVal:array[TAsmCond] of byte=($0,
@@ -1855,7 +1902,13 @@ implementation
         rfield,
         data,s,opidx : longint;
         ea_data : ea;
+{$ifdef extdebug}
+        rexwritten : boolean;
+{$endif extdebug}
       begin
+{$ifdef extdebug}
+        rexwritten:=false;
+{$endif extdebug}
         { safety check }
         if objdata.currobjsec.size<>insoffset then
           internalerror(200130121);
@@ -1914,6 +1967,13 @@ implementation
               end;
             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}
                 bytes[0]:=ord(codes^)+regval(oper[c-8]^.reg);
                 inc(codes);
                 objdata.writebytes(bytes,1);
@@ -1972,10 +2032,20 @@ implementation
             28,29,30 :
               begin
                 getvalsym(c-28);
-                if assigned(currsym) then
-                 objdata.writereloc(currval,4,currsym,RELOC_ABSOLUTE)
+                if opsize=S_Q then
+                  begin
+                    if assigned(currsym) then
+                     objdata.writereloc(currval,8,currsym,RELOC_ABSOLUTE)
+                    else
+                     objdata.writebytes(currval,8);
+                  end
                 else
-                 objdata.writebytes(currval,4);
+                  begin
+                    if assigned(currsym) then
+                     objdata.writereloc(currval,4,currsym,RELOC_ABSOLUTE)
+                    else
+                     objdata.writebytes(currval,4);
+                  end
               end;
             32,33,34 :
               begin
@@ -2032,15 +2102,21 @@ implementation
                       bytes[0]:=$66;
                       objdata.writebytes(bytes,1);
                     end;
-                  OT_BITS64 :
-                    begin
 {$ifndef x86_64}
+                  OT_BITS64 :
                       Message(asmw_e_64bit_not_supported);
 {$endif x86_64}
-                      bytes[0]:=$48;
-                      objdata.writebytes(bytes,1);
-                    end;
                 end;
+{$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}
               end;
             212 :
               begin
@@ -2081,6 +2157,13 @@ implementation
               end
             else
               begin
+                { rex should be written at this point }
+{$ifdef x86_64}
+{$ifdef extdebug}
+                if (rex<>0) and not(rexwritten) then
+                  internalerror(200603191);
+{$endif extdebug}
+{$endif x86_64}
                 if (c>=64) and (c<=191) then
                  begin
                    if (c<127) then
@@ -2094,7 +2177,7 @@ implementation
                     rfield:=c and 7;
                    opidx:=(c shr 3) and 7;
                    if not process_ea(oper[opidx]^,ea_data,rfield) then
-                    Message(asmw_e_invalid_effective_address);
+                     Message(asmw_e_invalid_effective_address);
 
                    pb:=@bytes;
                    pb^:=chr(ea_data.modrm);

+ 1 - 1
compiler/x86/x86ins.dat

@@ -1014,7 +1014,7 @@ mem_offs,reg_ax|32    \300\320\1\xA3\34               8086,SM,NOX86_64
 regmem,reg16|32|64    \320\300\1\x89\101              8086,SM
 reg_ax|32,mem_offs    \325\301\1\xA1\35               8086,SM,NOX86_64
 reg16|32|64,regmem    \320\301\1\x8B\110              8086,SM
-reg32|64,imm          \320\10\xB8\41                  386,SD
+reg32|64,imm          \320\10\xB8\35                  386,SD
 rm32|64,imm           \320\300\1\xC7\200\41           386,SD
 reg16,imm             \324\10\xB8\31                  8086,SW
 rm16,imm              \324\300\1\xC7\200\31           8086,SW

+ 1 - 1
compiler/x86_64/x8664tab.inc

@@ -2937,7 +2937,7 @@
     opcode  : A_MOV;
     ops     : 2;
     optypes : (ot_reg32 or ot_bits64,ot_immediate,ot_none);
-    code    : #208#8#184#33;
+    code    : #208#8#184#29;
     flags   : if_386 or if_sd
   ),
   (