diff --git a/compiler/x86/aasmcpu.pas b/compiler/x86/aasmcpu.pas index 31b68de834..b63d77bc33 100644 --- a/compiler/x86/aasmcpu.pas +++ b/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); diff --git a/compiler/x86/x86ins.dat b/compiler/x86/x86ins.dat index 446f17234d..865a868997 100644 --- a/compiler/x86/x86ins.dat +++ b/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 diff --git a/compiler/x86_64/x8664tab.inc b/compiler/x86_64/x8664tab.inc index 277ba07f7e..f8045dde89 100644 --- a/compiler/x86_64/x8664tab.inc +++ b/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 ), (