aboutsummaryrefslogtreecommitdiffstats
path: root/src/ortho/mcode/ortho_code-x86-emits.adb
diff options
context:
space:
mode:
authorTristan Gingold <gingold@adacore.com>2016-01-05 06:44:53 +0100
committerTristan Gingold <gingold@adacore.com>2016-01-06 18:38:37 +0100
commitb5797a5cef6d25817da7998f6263afa53e196d25 (patch)
treead3b67a93d16e8a06fab2d7a8c4d8993ff101b8a /src/ortho/mcode/ortho_code-x86-emits.adb
parent955e964b024de556c4c0db8fd745c6abdb8052fe (diff)
downloadghdl-b5797a5cef6d25817da7998f6263afa53e196d25.tar.gz
ghdl-b5797a5cef6d25817da7998f6263afa53e196d25.tar.bz2
ghdl-b5797a5cef6d25817da7998f6263afa53e196d25.zip
mcode: add support for x86-64
Diffstat (limited to 'src/ortho/mcode/ortho_code-x86-emits.adb')
-rw-r--r--src/ortho/mcode/ortho_code-x86-emits.adb2059
1 files changed, 1293 insertions, 766 deletions
diff --git a/src/ortho/mcode/ortho_code-x86-emits.adb b/src/ortho/mcode/ortho_code-x86-emits.adb
index c4cfee930..ed17d0bc6 100644
--- a/src/ortho/mcode/ortho_code-x86-emits.adb
+++ b/src/ortho/mcode/ortho_code-x86-emits.adb
@@ -30,7 +30,23 @@ with Ada.Text_IO;
with Interfaces; use Interfaces;
package body Ortho_Code.X86.Emits is
- type Insn_Size is (Sz_8, Sz_16, Sz_32l, Sz_32h);
+ type Insn_Size is (Sz_8, Sz_16, Sz_32, Sz_32l, Sz_32h, Sz_64);
+
+ -- Sz_64 if M64 or Sz_32
+ Sz_Ptr : constant Insn_Size := Insn_Size'Val
+ (Boolean'Pos (Flags.M64) * Insn_Size'Pos (Sz_64)
+ + Boolean'Pos (not Flags.M64) * Insn_Size'Pos (Sz_32));
+
+ -- For FP, size doesn't matter in modrm and SIB. But don't emit the REX.W
+ -- prefix, that's useless.
+ Sz_Fp : constant Insn_Size := Sz_32;
+
+ type Int_Mode_To_Size_Array is array (Mode_U8 .. Mode_I64) of Insn_Size;
+ Int_Mode_To_Size : constant Int_Mode_To_Size_Array :=
+ (Mode_U8 | Mode_I8 => Sz_8,
+ Mode_U16 | Mode_I16 => Sz_16,
+ Mode_U32 | Mode_I32 => Sz_32,
+ Mode_U64 | Mode_I64 => Sz_64);
-- Well known sections.
Sect_Text : Binary_File.Section_Acc;
@@ -46,6 +62,11 @@ package body Ortho_Code.X86.Emits is
-- x86 opcodes.
Opc_Data16 : constant := 16#66#;
+-- Opc_Rex : constant := 16#40#;
+ Opc_Rex_W : constant := 16#48#;
+ Opc_Rex_R : constant := 16#44#;
+ Opc_Rex_X : constant := 16#42#;
+ Opc_Rex_B : constant := 16#41#;
Opc_Into : constant := 16#ce#;
Opc_Cdq : constant := 16#99#;
Opc_Int : constant := 16#cd#;
@@ -56,6 +77,7 @@ package body Ortho_Code.X86.Emits is
Opc_Leal_Reg_Rm : constant := 16#8d#;
Opc_Movb_Imm_Reg : constant := 16#b0#;
Opc_Movl_Imm_Reg : constant := 16#b8#;
+ Opc_Movsxd_Reg_Rm : constant := 16#63#;
Opc_Imul_Reg_Rm_Imm32 : constant := 16#69#;
Opc_Imul_Reg_Rm_Imm8 : constant := 16#6b#;
Opc_Mov_Rm_Imm : constant := 16#c6#; -- Eb,Ib or Ev,Iz (grp11, opc2=0)
@@ -104,6 +126,10 @@ package body Ortho_Code.X86.Emits is
Opc_Jmp_Short : constant := 16#eb#;
Opc_Ret : constant := 16#c3#;
Opc_Leave : constant := 16#c9#;
+ Opc_Movsd_Xmm_M64 : constant := 16#10#; -- Load xmm <- M64
+ Opc_Movsd_M64_Xmm : constant := 16#11#; -- Store M64 <- xmm
+ Opc_Cvtsi2sd_Xmm_Rm : constant := 16#2a#; -- Xmm <- cvt (rm)
+ Opc_Cvtsd2si_Reg_Xm : constant := 16#2d#; -- Reg <- cvt (xmm/m64)
procedure Error_Emit (Msg : String; Insn : O_Enode)
is
@@ -120,6 +146,31 @@ package body Ortho_Code.X86.Emits is
raise Program_Error;
end Error_Emit;
+ procedure Gen_Rex (B : Byte) is
+ begin
+ if Flags.M64 then
+ Gen_8 (B);
+ end if;
+ end Gen_Rex;
+
+ procedure Gen_Rex_B (R : O_Reg; Sz : Insn_Size)
+ is
+ B : Byte;
+ begin
+ if Flags.M64 then
+ B := 0;
+ if R in Regs_R8_R15 or R in Regs_Xmm8_Xmm15 then
+ B := B or Opc_Rex_B;
+ end if;
+ if Sz = Sz_64 then
+ B := B or Opc_Rex_W;
+ end if;
+ if B /= 0 then
+ Gen_8 (B);
+ end if;
+ end if;
+ end Gen_Rex_B;
+
-- For many opcodes, the size of the operand is coded in bit 0, and the
-- prefix data16 can be used for 16-bit operation.
-- Deal with size.
@@ -127,13 +178,15 @@ package body Ortho_Code.X86.Emits is
begin
case Sz is
when Sz_8 =>
- Gen_B8 (B);
+ Gen_8 (B);
when Sz_16 =>
- Gen_B8 (Opc_Data16);
- Gen_B8 (B + 1);
- when Sz_32l
- | Sz_32h =>
- Gen_B8 (B + 1);
+ Gen_8 (Opc_Data16);
+ Gen_8 (B + 1);
+ when Sz_32
+ | Sz_32l
+ | Sz_32h
+ | Sz_64 =>
+ Gen_8 (B + 1);
end case;
end Gen_Insn_Sz;
@@ -141,13 +194,15 @@ package body Ortho_Code.X86.Emits is
begin
case Sz is
when Sz_8 =>
- Gen_B8 (B);
+ Gen_8 (B);
when Sz_16 =>
- Gen_B8 (Opc_Data16);
- Gen_B8 (B + 3);
- when Sz_32l
- | Sz_32h =>
- Gen_B8 (B + 3);
+ Gen_8 (Opc_Data16);
+ Gen_8 (B + 3);
+ when Sz_32
+ | Sz_32l
+ | Sz_32h
+ | Sz_64 =>
+ Gen_8 (B + 3);
end case;
end Gen_Insn_Sz_S8;
@@ -156,10 +211,13 @@ package body Ortho_Code.X86.Emits is
case Sz is
when Sz_8
| Sz_16
+ | Sz_32
| Sz_32l =>
return Get_Expr_Low (C);
when Sz_32h =>
return Get_Expr_High (C);
+ when Sz_64 =>
+ return Get_Expr_Low (C);
end case;
end Get_Const_Val;
@@ -173,7 +231,7 @@ package body Ortho_Code.X86.Emits is
procedure Gen_Imm8 (N : O_Enode; Sz : Insn_Size) is
begin
- Gen_B8 (Byte (Get_Const_Val (N, Sz)));
+ Gen_8 (Byte (Get_Const_Val (N, Sz)));
end Gen_Imm8;
-- procedure Gen_Imm32 (N : O_Enode; Sz : Insn_Size)
@@ -182,7 +240,7 @@ package body Ortho_Code.X86.Emits is
-- begin
-- case Get_Expr_Kind (N) is
-- when OE_Const =>
--- Gen_Le32 (Unsigned_32 (Get_Const_Val (N, Sz)));
+-- Gen_32 (Unsigned_32 (Get_Const_Val (N, Sz)));
-- when OE_Addrg =>
-- Gen_X86_32 (Get_Decl_Symbol (Get_Addr_Object (N)), 0);
-- when others =>
@@ -191,59 +249,148 @@ package body Ortho_Code.X86.Emits is
-- end Gen_Imm32;
-- Generate an immediat constant.
+ procedure Gen_Imm_Addr (N : O_Enode)
+ is
+ Sym : Symbol;
+ P : O_Enode;
+ L, R : O_Enode;
+ S, C : O_Enode;
+ Off : Int32;
+ begin
+ Off := 0;
+ P := N;
+ while Get_Expr_Kind (P) = OE_Add loop
+ L := Get_Expr_Left (P);
+ R := Get_Expr_Right (P);
+
+ -- Extract the const node.
+ if Get_Expr_Kind (R) = OE_Const then
+ S := L;
+ C := R;
+ elsif Get_Expr_Kind (L) = OE_Const then
+ S := R;
+ C := L;
+ else
+ raise Program_Error;
+ end if;
+ pragma Assert (Get_Expr_Mode (C) = Mode_U32);
+ Off := Off + To_Int32 (Get_Expr_Low (C));
+ P := S;
+ end loop;
+ pragma Assert (Get_Expr_Kind (P) = OE_Addrg);
+ Sym := Get_Decl_Symbol (Get_Addr_Object (P));
+ Gen_Abs (Sym, Integer_32 (Off));
+ end Gen_Imm_Addr;
+
+ -- Generate an immediat constant.
procedure Gen_Imm (N : O_Enode; Sz : Insn_Size) is
begin
case Get_Expr_Kind (N) is
when OE_Const =>
case Sz is
when Sz_8 =>
- Gen_B8 (Byte (Get_Expr_Low (N) and 16#FF#));
+ Gen_8 (Byte (Get_Expr_Low (N) and 16#FF#));
when Sz_16 =>
- Gen_Le16 (Unsigned_32 (Get_Expr_Low (N) and 16#FF_FF#));
- when Sz_32l =>
- Gen_Le32 (Unsigned_32 (Get_Expr_Low (N)));
+ Gen_16 (Unsigned_32 (Get_Expr_Low (N) and 16#FF_FF#));
+ when Sz_32
+ | Sz_32l =>
+ Gen_32 (Unsigned_32 (Get_Expr_Low (N)));
when Sz_32h =>
- Gen_Le32 (Unsigned_32 (Get_Expr_High (N)));
+ Gen_32 (Unsigned_32 (Get_Expr_High (N)));
+ when Sz_64 =>
+ -- Immediates are sign extended.
+ pragma Assert (Is_Expr_S32 (N));
+ Gen_32 (Unsigned_32 (Get_Expr_Low (N)));
end case;
when OE_Add
| OE_Addrg =>
-- Only for 32-bit immediat.
- pragma Assert (Sz = Sz_32l);
- declare
- P : O_Enode;
- L, R : O_Enode;
- S, C : O_Enode;
- Off : Int32;
- begin
- Off := 0;
- P := N;
- while Get_Expr_Kind (P) = OE_Add loop
- L := Get_Expr_Left (P);
- R := Get_Expr_Right (P);
-
- -- Extract the const node.
- if Get_Expr_Kind (R) = OE_Const then
- S := L;
- C := R;
- elsif Get_Expr_Kind (L) = OE_Const then
- S := R;
- C := L;
- else
- raise Program_Error;
- end if;
- pragma Assert (Get_Expr_Mode (C) = Mode_U32);
- Off := Off + To_Int32 (Get_Expr_Low (C));
- P := S;
- end loop;
- pragma Assert (Get_Expr_Kind (P) = OE_Addrg);
- Gen_X86_32 (Get_Decl_Symbol (Get_Addr_Object (P)),
- Integer_32 (Off));
- end;
+ pragma Assert (Sz = Sz_32);
+ Gen_Imm_Addr (N);
when others =>
raise Program_Error;
end case;
end Gen_Imm;
+ function To_Reg32 (R : O_Reg) return Byte is
+ begin
+ pragma Assert (R in Regs_R32);
+ return O_Reg'Pos (R) - O_Reg'Pos (R_Ax);
+ end To_Reg32;
+ pragma Inline (To_Reg32);
+
+ function To_Reg64 (R : O_Reg) return Byte is
+ begin
+ pragma Assert (R in Regs_R64);
+ return Byte (O_Reg'Pos (R) - O_Reg'Pos (R_Ax)) and 7;
+ end To_Reg64;
+ pragma Inline (To_Reg64);
+
+ function To_Reg_Xmm (R : O_Reg) return Byte is
+ begin
+ return O_Reg'Pos (R) - O_Reg'Pos (R_Xmm0);
+ end To_Reg_Xmm;
+ pragma Inline (To_Reg_Xmm);
+
+ function To_Reg32 (R : O_Reg; Sz : Insn_Size) return Byte is
+ begin
+ case Sz is
+ when Sz_8 =>
+ pragma Assert ((not Flags.M64 and R in Regs_R8)
+ or (Flags.M64 and R in Regs_R64));
+ return To_Reg64 (R);
+ when Sz_16 =>
+ pragma Assert (R in Regs_R32);
+ return To_Reg64 (R);
+ when Sz_32 =>
+ pragma Assert ((not Flags.M64 and R in Regs_R32)
+ or (Flags.M64 and R in Regs_R64));
+ return To_Reg64 (R);
+ when Sz_32l =>
+ pragma Assert (not Flags.M64);
+ case R is
+ when R_Edx_Eax =>
+ return 2#000#;
+ when R_Ebx_Ecx =>
+ return 2#001#;
+ when R_Esi_Edi =>
+ return 2#111#;
+ when others =>
+ raise Program_Error;
+ end case;
+ when Sz_32h =>
+ pragma Assert (not Flags.M64);
+ case R is
+ when R_Edx_Eax =>
+ return 2#010#;
+ when R_Ebx_Ecx =>
+ return 2#011#;
+ when R_Esi_Edi =>
+ return 2#110#;
+ when others =>
+ raise Program_Error;
+ end case;
+ when Sz_64 =>
+ pragma Assert (R in Regs_R64);
+ return Byte (O_Reg'Pos (R) - O_Reg'Pos (R_Ax)) and 7;
+ end case;
+ end To_Reg32;
+
+ function To_Cond (R : O_Reg) return Byte is
+ begin
+ return O_Reg'Pos (R) - O_Reg'Pos (R_Ov);
+ end To_Cond;
+ pragma Inline (To_Cond);
+
+ function To_Reg (R : O_Reg; Sz : Insn_Size) return Byte is
+ begin
+ if R in Regs_Xmm then
+ return To_Reg_Xmm (R);
+ else
+ return To_Reg32 (R, Sz);
+ end if;
+ end To_Reg;
+
-- SIB + disp values.
SIB_Scale : Byte;
SIB_Index : O_Reg;
@@ -251,18 +398,52 @@ package body Ortho_Code.X86.Emits is
Rm_Offset : Int32;
Rm_Sym : Symbol;
+ -- If not R_Nil, the reg/opc field (bit 3-5) of the ModR/M byte is a
+ -- register.
+ Rm_Opc_Reg : O_Reg;
+ Rm_Opc_Sz : Insn_Size;
+
-- If not R_Nil, encode mod=11 (no memory access). All above variables
-- must be 0/R_Nil.
Rm_Reg : O_Reg;
Rm_Sz : Insn_Size;
+ procedure Gen_Rex_Mod_Rm
+ is
+ B : Byte;
+ begin
+ if Flags.M64 then
+ B := 0;
+ if Rm_Sz = Sz_64 then
+ B := B or Opc_Rex_W;
+ end if;
+ if Rm_Opc_Reg in Regs_R8_R15
+ or Rm_Opc_Reg in Regs_Xmm8_Xmm15
+ then
+ B := B or Opc_Rex_R;
+ end if;
+ if Rm_Reg in Regs_R8_R15
+ or Rm_Reg in Regs_Xmm8_Xmm15
+ or Rm_Base in Regs_R8_R15
+ then
+ B := B or Opc_Rex_B;
+ end if;
+ if SIB_Index in Regs_R8_R15 then
+ B := B or Opc_Rex_X;
+ end if;
+ if B /= 0 then
+ Gen_8 (B);
+ end if;
+ end if;
+ end Gen_Rex_Mod_Rm;
+
procedure Fill_Sib (N : O_Enode)
is
use Ortho_Code.Decls;
Reg : constant O_Reg := Get_Expr_Reg (N);
begin
-- A simple register.
- if Reg in Regs_R32 then
+ if Reg in Regs_R64 then
if Rm_Base = R_Nil then
Rm_Base := Reg;
elsif SIB_Index = R_Nil then
@@ -309,77 +490,27 @@ package body Ortho_Code.X86.Emits is
end case;
end Fill_Sib;
- function To_Reg32 (R : O_Reg) return Byte is
- begin
- pragma Assert (R in Regs_R32);
- return O_Reg'Pos (R) - O_Reg'Pos (R_Ax);
- end To_Reg32;
- pragma Inline (To_Reg32);
-
- function To_Reg_Xmm (R : O_Reg) return Byte is
- begin
- return O_Reg'Pos (R) - O_Reg'Pos (R_Xmm0);
- end To_Reg_Xmm;
- pragma Inline (To_Reg_Xmm);
-
- function To_Reg32 (R : O_Reg; Sz : Insn_Size) return Byte is
- begin
- case Sz is
- when Sz_8 =>
- pragma Assert (R in Regs_R8);
- return O_Reg'Pos (R) - O_Reg'Pos (R_Ax);
- when Sz_16 =>
- pragma Assert (R in Regs_R32);
- return O_Reg'Pos (R) - O_Reg'Pos (R_Ax);
- when Sz_32l =>
- case R is
- when Regs_R32 =>
- return O_Reg'Pos (R) - O_Reg'Pos (R_Ax);
- when R_Edx_Eax =>
- return 2#000#;
- when R_Ebx_Ecx =>
- return 2#001#;
- when R_Esi_Edi =>
- return 2#111#;
- when others =>
- raise Program_Error;
- end case;
- when Sz_32h =>
- case R is
- when R_Edx_Eax =>
- return 2#010#;
- when R_Ebx_Ecx =>
- return 2#011#;
- when R_Esi_Edi =>
- return 2#110#;
- when others =>
- raise Program_Error;
- end case;
- end case;
- end To_Reg32;
-
- function To_Cond (R : O_Reg) return Byte is
- begin
- return O_Reg'Pos (R) - O_Reg'Pos (R_Ov);
- end To_Cond;
- pragma Inline (To_Cond);
-
-- Write the SIB byte.
procedure Gen_Sib
is
Base : Byte;
begin
if Rm_Base = R_Nil then
- Base := 2#101#;
+ Base := 2#101#; -- BP
else
- Base := To_Reg32 (Rm_Base);
+ pragma Assert (not (SIB_Index = R_Sp
+ and (Rm_Base = R_Bp or Rm_Base = R_R13)));
+ Base := To_Reg64 (Rm_Base);
end if;
- Gen_B8 (SIB_Scale * 2#1_000_000#
- + To_Reg32 (SIB_Index) * 2#1_000#
- + Base);
+ Gen_8
+ (SIB_Scale * 2#1_000_000# + To_Reg64 (SIB_Index) * 2#1_000# + Base);
end Gen_Sib;
- procedure Init_Modrm_Reg (Reg : O_Reg; Sz : Insn_Size) is
+ -- ModRM is a register.
+ procedure Init_Modrm_Reg (Reg : O_Reg;
+ Sz : Insn_Size;
+ Opc : O_Reg := R_Nil;
+ Opc_Sz : Insn_Size := Sz_32) is
begin
Rm_Base := R_Nil;
SIB_Index := R_Nil;
@@ -387,12 +518,17 @@ package body Ortho_Code.X86.Emits is
Rm_Sym := Null_Symbol;
Rm_Offset := 0;
+ Rm_Opc_Reg := Opc;
+ Rm_Opc_Sz := Opc_Sz;
+
Rm_Reg := Reg;
Rm_Sz := Sz;
+
+ Gen_Rex_Mod_Rm;
end Init_Modrm_Reg;
-- Note: SZ is not relevant.
- procedure Init_Modrm_Sym (Sym : Symbol; Sz : Insn_Size) is
+ procedure Init_Modrm_Sym (Sym : Symbol; Sz : Insn_Size; Opc_Reg : O_Reg) is
begin
Rm_Base := R_Nil;
SIB_Index := R_Nil;
@@ -400,11 +536,17 @@ package body Ortho_Code.X86.Emits is
Rm_Sym := Sym;
Rm_Offset := 0;
+ Rm_Opc_Reg := Opc_Reg;
+ Rm_Opc_Sz := Sz;
+
Rm_Reg := R_Nil;
Rm_Sz := Sz;
+
+ Gen_Rex_Mod_Rm;
end Init_Modrm_Sym;
- procedure Init_Modrm_Mem (N : O_Enode; Sz : Insn_Size)
+ -- ModRM is a memory reference.
+ procedure Init_Modrm_Mem (N : O_Enode; Sz : Insn_Size; Opc : O_Reg := R_Nil)
is
Reg : constant O_Reg := Get_Expr_Reg (N);
begin
@@ -413,6 +555,9 @@ package body Ortho_Code.X86.Emits is
Rm_Reg := R_Nil;
Rm_Sz := Sz;
+ Rm_Opc_Reg := Opc;
+ Rm_Opc_Sz := Sz;
+
if Sz = Sz_32h then
Rm_Offset := 4;
else
@@ -429,7 +574,7 @@ package body Ortho_Code.X86.Emits is
| R_I_Off
| R_Sib =>
Fill_Sib (N);
- when Regs_R32 =>
+ when Regs_R64 =>
Rm_Base := Reg;
when R_Spill =>
Rm_Base := R_Bp;
@@ -437,25 +582,29 @@ package body Ortho_Code.X86.Emits is
when others =>
Error_Emit ("init_modrm_mem: unhandled reg", N);
end case;
+
+ Gen_Rex_Mod_Rm;
end Init_Modrm_Mem;
- procedure Init_Rm_Expr (N : O_Enode; Sz : Insn_Size)
+ procedure Init_Modrm_Expr
+ (N : O_Enode; Sz : Insn_Size; Opc : O_Reg := R_Nil)
is
Reg : constant O_Reg := Get_Expr_Reg (N);
begin
case Reg is
- when Regs_R32
- | Regs_R64
+ when Regs_R64
+ | Regs_Pair
| Regs_Xmm =>
-- Destination is a register.
- Init_Modrm_Reg (Reg, Sz);
+ Init_Modrm_Reg (Reg, Sz, Opc, Sz);
when others =>
-- Destination is an effective address.
- Init_Modrm_Mem (N, Sz);
+ Init_Modrm_Mem (N, Sz, Opc);
end case;
- end Init_Rm_Expr;
+ end Init_Modrm_Expr;
- procedure Init_Modrm_Offset (Base : O_Reg; Off : Int32; Sz : Insn_Size) is
+ procedure Init_Modrm_Offset
+ (Base : O_Reg; Off : Int32; Sz : Insn_Size; Opc : O_Reg := R_Nil) is
begin
SIB_Index := R_Nil;
SIB_Scale := 0;
@@ -465,108 +614,135 @@ package body Ortho_Code.X86.Emits is
Rm_Base := Base;
+ Rm_Opc_Reg := Opc;
+ Rm_Opc_Sz := Sz;
+
if Sz = Sz_32h then
Rm_Offset := Off + 4;
else
Rm_Offset := Off;
end if;
+
+ Gen_Rex_Mod_Rm;
end Init_Modrm_Offset;
-- Generate an R/M (+ SIB) byte.
-- R is added to the R/M byte.
- procedure Gen_Mod_Rm (R : Byte) is
+ procedure Gen_Mod_Rm_B (R : Byte) is
begin
- -- Emit bytes.
- if SIB_Index /= R_Nil then
- pragma Assert (Rm_Reg = R_Nil);
- -- SIB.
+ if Rm_Reg /= R_Nil then
+ -- Register: mod = 11, no memory access.
+ pragma Assert (Rm_Base = R_Nil);
+ pragma Assert (Rm_Sym = Null_Symbol);
+ pragma Assert (Rm_Offset = 0);
+ pragma Assert (SIB_Index = R_Nil);
+ Gen_8 (2#11_000_000# + R + To_Reg (Rm_Reg, Rm_Sz));
+ return;
+ end if;
+
+ if SIB_Index /= R_Nil or (Flags.M64 and Rm_Base = R_R12) then
+ -- With SIB.
+ if SIB_Index = R_Nil then
+ SIB_Index := R_Sp;
+ end if;
if Rm_Base = R_Nil then
-- No base (but index). Use the special encoding with base=BP.
- Gen_B8 (2#00_000_100# + R);
+ Gen_8 (2#00_000_100# + R); -- mod=00, rm=SP -> disp32.
Rm_Base := R_Bp;
Gen_Sib;
- Gen_X86_32 (Rm_Sym, Integer_32 (Rm_Offset));
- elsif Rm_Sym = Null_Symbol and Rm_Offset = 0 and Rm_Base /= R_Bp then
+ if Rm_Sym = Null_Symbol then
+ Gen_32 (Unsigned_32 (To_Uns32 (Rm_Offset)));
+ else
+ pragma Assert (not Flags.M64);
+ Gen_X86_32 (Rm_Sym, Integer_32 (Rm_Offset));
+ end if;
+ elsif Rm_Sym = Null_Symbol and Rm_Offset = 0
+ and Rm_Base /= R_Bp and Rm_Base /= R_R13
+ then
-- No offset (only allowed if base is not BP).
- Gen_B8 (2#00_000_100# + R);
+ Gen_8 (2#00_000_100# + R);
Gen_Sib;
- elsif Rm_Sym = Null_Symbol and Rm_Offset <= 127 and Rm_Offset >= -128
- then
+ elsif Rm_Sym = Null_Symbol and Rm_Offset in -128 .. 127 then
-- Disp8
- Gen_B8 (2#01_000_100# + R);
+ Gen_8 (2#01_000_100# + R);
Gen_Sib;
- Gen_B8 (Byte (To_Uns32 (Rm_Offset) and 16#Ff#));
+ Gen_8 (Byte (To_Uns32 (Rm_Offset) and 16#Ff#));
else
-- Disp32
- Gen_B8 (2#10_000_100# + R);
+ Gen_8 (2#10_000_100# + R);
Gen_Sib;
- Gen_X86_32 (Rm_Sym, Integer_32 (Rm_Offset));
- end if;
- return;
- end if;
-
- -- No SIB.
- if Rm_Reg /= R_Nil then
- -- Mod is register, no memory access.
- pragma Assert (Rm_Base = R_Nil);
- pragma Assert (Rm_Sym = Null_Symbol);
- pragma Assert (Rm_Offset = 0);
- if Rm_Reg in Regs_Xmm then
- Gen_B8 (2#11_000_000# + R + To_Reg_Xmm (Rm_Reg));
- else
- Gen_B8 (2#11_000_000# + R + To_Reg32 (Rm_Reg, Rm_Sz));
- end if;
- return;
- end if;
-
- case Rm_Base is
- when R_Sp =>
- -- It isn't possible to use SP as a base register without using
- -- an SIB encoding.
- raise Program_Error;
- when R_Nil =>
- -- Encode for disp32 (Mod=00, R/M=101).
- Gen_B8 (2#00_000_101# + R);
- Gen_X86_32 (Rm_Sym, Integer_32 (Rm_Offset));
- when R_Ax
- | R_Bx
- | R_Cx
- | R_Dx
- | R_Bp
- | R_Si
- | R_Di =>
- if Rm_Offset = 0 and Rm_Sym = Null_Symbol and Rm_Base /= R_Bp then
- -- No disp: use Mod=00 (not supported if base is BP).
- Gen_B8 (2#00_000_000# + R + To_Reg32 (Rm_Base));
- elsif Rm_Sym = Null_Symbol
- and Rm_Offset <= 127 and Rm_Offset >= -128
- then
- -- Disp8 (Mod=01)
- Gen_B8 (2#01_000_000# + R + To_Reg32 (Rm_Base));
- Gen_B8 (Byte (To_Uns32 (Rm_Offset) and 16#Ff#));
+ if Rm_Sym = Null_Symbol then
+ Gen_32 (Unsigned_32 (To_Uns32 (Rm_Offset)));
else
- -- Disp32 (Mod=10)
- Gen_B8 (2#10_000_000# + R + To_Reg32 (Rm_Base));
+ pragma Assert (not Flags.M64);
Gen_X86_32 (Rm_Sym, Integer_32 (Rm_Offset));
end if;
- when others =>
- raise Program_Error;
- end case;
- end Gen_Mod_Rm;
-
- procedure Gen_Rm (R : Byte; N : O_Enode; Sz : Insn_Size)
- is
- Reg : constant O_Reg := Get_Expr_Reg (N);
- begin
- if Reg in Regs_R32 or Reg in Regs_R64 then
- -- Destination is a register.
- Gen_B8 (2#11_000_000# + R + To_Reg32 (Reg, Sz));
+ end if;
else
- -- Destination is an effective address.
- Init_Modrm_Mem (N, Sz);
- Gen_Mod_Rm (R);
+ case Rm_Base is
+ when R_Sp =>
+ -- It isn't possible to use SP as a base register without using
+ -- an SIB encoding.
+ raise Program_Error;
+ when R_Nil =>
+ -- There should be no case where the offset is negative.
+ pragma Assert (Rm_Offset >= 0);
+ -- Encode for disp32 (Mod=00, R/M=101) or RIP relative
+ Gen_8 (2#00_000_101# + R);
+ if Flags.M64 then
+ -- RIP relative
+ Gen_X86_Pc32 (Rm_Sym, Unsigned_32 (Rm_Offset));
+ else
+ -- Disp32.
+ Gen_X86_32 (Rm_Sym, Integer_32 (Rm_Offset));
+ end if;
+ when R_Ax
+ | R_Bx
+ | R_Cx
+ | R_Dx
+ | R_Bp
+ | R_Si
+ | R_Di
+ | R_R8 .. R_R11
+ | R_R13 .. R_R15 =>
+ if Rm_Offset = 0 and Rm_Sym = Null_Symbol
+ and Rm_Base /= R_Bp and Rm_Base /= R_R13
+ then
+ -- No disp: use Mod=00 (not supported if base is BP or R13).
+ Gen_8 (2#00_000_000# + R + To_Reg64 (Rm_Base));
+ elsif Rm_Sym = Null_Symbol
+ and Rm_Offset <= 127 and Rm_Offset >= -128
+ then
+ -- Disp8 (Mod=01)
+ Gen_8 (2#01_000_000# + R + To_Reg64 (Rm_Base));
+ Gen_8 (Byte (To_Uns32 (Rm_Offset) and 16#Ff#));
+ else
+ -- Disp32 (Mod=10)
+ Gen_8 (2#10_000_000# + R + To_Reg64 (Rm_Base));
+ if Rm_Sym = Null_Symbol then
+ Gen_32 (Unsigned_32 (To_Uns32 (Rm_Offset)));
+ else
+ pragma Assert (not Flags.M64);
+ Gen_X86_32 (Rm_Sym, Integer_32 (Rm_Offset));
+ end if;
+ end if;
+ when others =>
+ raise Program_Error;
+ end case;
end if;
- end Gen_Rm;
+ end Gen_Mod_Rm_B;
+
+ procedure Gen_Mod_Rm_Opc (R : Byte) is
+ begin
+ pragma Assert (Rm_Opc_Reg = R_Nil);
+ Gen_Mod_Rm_B (R);
+ end Gen_Mod_Rm_Opc;
+
+ procedure Gen_Mod_Rm_Reg is
+ begin
+ pragma Assert (Rm_Opc_Reg /= R_Nil);
+ Gen_Mod_Rm_B (To_Reg (Rm_Opc_Reg, Rm_Opc_Sz) * 8);
+ end Gen_Mod_Rm_Reg;
procedure Gen_Grp1_Insn (Op : Byte; Stmt : O_Enode; Sz : Insn_Size)
is
@@ -578,24 +754,31 @@ package body Ortho_Code.X86.Emits is
Start_Insn;
case Rr is
when R_Imm =>
- if Is_Imm8 (R, Sz) then
- Gen_Insn_Sz_S8 (16#80#, Sz);
- Gen_Rm (Op, L, Sz);
- Gen_Imm8 (R, Sz);
- elsif Lr = R_Ax then
+ if Lr = R_Ax then
+ -- Use compact encoding.
+ if Sz = Sz_64 then
+ Gen_8 (Opc_Rex_W);
+ end if;
Gen_Insn_Sz (2#000_000_100# + Op, Sz);
Gen_Imm (R, Sz);
+ elsif Is_Imm8 (R, Sz) then
+ Init_Modrm_Expr (L, Sz);
+ Gen_Insn_Sz_S8 (16#80#, Sz);
+ Gen_Mod_Rm_Opc (Op);
+ Gen_Imm8 (R, Sz);
else
+ Init_Modrm_Expr (L, Sz);
Gen_Insn_Sz (16#80#, Sz);
- Gen_Rm (Op, L, Sz);
+ Gen_Mod_Rm_Opc (Op);
Gen_Imm (R, Sz);
end if;
when R_Mem
| R_Spill
- | Regs_R32
- | Regs_R64 =>
+ | Regs_R64
+ | Regs_Pair =>
+ Init_Modrm_Expr (R, Sz, Lr);
Gen_Insn_Sz (2#00_000_010# + Op, Sz);
- Gen_Rm (To_Reg32 (Lr, Sz) * 8, R, Sz);
+ Gen_Mod_Rm_Reg;
when others =>
Error_Emit ("emit_op", Stmt);
end case;
@@ -606,7 +789,7 @@ package body Ortho_Code.X86.Emits is
procedure Gen_1 (B : Byte) is
begin
Start_Insn;
- Gen_B8 (B);
+ Gen_8 (B);
End_Insn;
end Gen_1;
@@ -614,55 +797,57 @@ package body Ortho_Code.X86.Emits is
procedure Gen_2 (B1, B2 : Byte) is
begin
Start_Insn;
- Gen_B8 (B1);
- Gen_B8 (B2);
+ Gen_8 (B1);
+ Gen_8 (B2);
End_Insn;
end Gen_2;
-- Grp1 instructions have a mod/rm and an immediate value VAL.
-- Mod/Rm must be initialized.
- procedure Gen_Insn_Grp1 (Opc2 : Byte; Sz : Insn_Size; Val : Int32) is
+ procedure Gen_Insn_Grp1 (Opc2 : Byte; Val : Int32) is
begin
- Start_Insn;
if Val in -128 .. 127 then
- case Sz is
+ case Rm_Sz is
when Sz_8 =>
- Gen_B8 (Opc_Grp1b_Rm_Imm8);
+ Gen_8 (Opc_Grp1b_Rm_Imm8);
when Sz_16 =>
- Gen_B8 (Opc_Data16);
- Gen_B8 (Opc_Grp1v_Rm_Imm8);
- when Sz_32l
- | Sz_32h =>
- Gen_B8 (Opc_Grp1v_Rm_Imm8);
+ Gen_8 (Opc_Data16);
+ Gen_8 (Opc_Grp1v_Rm_Imm8);
+ when Sz_32
+ | Sz_32l
+ | Sz_32h
+ | Sz_64 =>
+ Gen_8 (Opc_Grp1v_Rm_Imm8);
end case;
- Gen_Mod_Rm (Opc2);
- Gen_B8 (Byte (To_Uns32 (Val) and 16#Ff#));
+ Gen_Mod_Rm_Opc (Opc2);
+ Gen_8 (Byte (To_Uns32 (Val) and 16#Ff#));
else
- case Sz is
+ case Rm_Sz is
when Sz_8 =>
pragma Assert (False);
null;
when Sz_16 =>
- Gen_B8 (Opc_Data16);
- Gen_B8 (Opc_Grp1v_Rm_Imm32);
- when Sz_32l
- | Sz_32h =>
- Gen_B8 (Opc_Grp1v_Rm_Imm32);
+ Gen_8 (Opc_Data16);
+ Gen_8 (Opc_Grp1v_Rm_Imm32);
+ when Sz_32
+ | Sz_32l
+ | Sz_32h
+ | Sz_64 =>
+ Gen_8 (Opc_Grp1v_Rm_Imm32);
end case;
- Gen_Mod_Rm (Opc2);
- Gen_Le32 (Unsigned_32 (To_Uns32 (Val)));
+ Gen_Mod_Rm_Opc (Opc2);
+ Gen_32 (Unsigned_32 (To_Uns32 (Val)));
end if;
- End_Insn;
end Gen_Insn_Grp1;
- procedure Gen_Into is
- begin
- Gen_1 (Opc_Into);
- end Gen_Into;
-
- procedure Gen_Cdq is
+ procedure Gen_Cdq (Sz : Insn_Size) is
begin
- Gen_1 (Opc_Cdq);
+ Start_Insn;
+ if Sz = Sz_64 then
+ Gen_8 (Opc_Rex_W);
+ end if;
+ Gen_8 (Opc_Cdq);
+ End_Insn;
end Gen_Cdq;
procedure Gen_Clear_Edx is
@@ -675,8 +860,9 @@ package body Ortho_Code.X86.Emits is
begin
Start_Insn;
-- Unary Group 3 (test, not, neg...)
+ Init_Modrm_Expr (Val, Sz);
Gen_Insn_Sz (Opc_Grp3_Width, Sz);
- Gen_Rm (Op, Val, Sz);
+ Gen_Mod_Rm_Opc (Op);
End_Insn;
end Gen_Grp3_Insn;
@@ -695,15 +881,37 @@ package body Ortho_Code.X86.Emits is
-- Mov immediate.
case Sz is
when Sz_8 =>
- Gen_B8 (Opc_Movb_Imm_Reg + To_Reg32 (Tr, Sz));
+ Gen_Rex_B (Tr, Sz);
+ Gen_8 (Opc_Movb_Imm_Reg + To_Reg32 (Tr, Sz));
+ Gen_Imm (Stmt, Sz);
when Sz_16 =>
- Gen_B8 (Opc_Data16);
- Gen_B8 (Opc_Movl_Imm_Reg + To_Reg32 (Tr, Sz));
- when Sz_32l
+ Gen_8 (Opc_Data16);
+ Gen_8 (Opc_Movl_Imm_Reg + To_Reg32 (Tr, Sz));
+ Gen_Imm (Stmt, Sz);
+ when Sz_32
+ | Sz_32l
| Sz_32h =>
- Gen_B8 (Opc_Movl_Imm_Reg + To_Reg32 (Tr, Sz));
+ Gen_Rex_B (Tr, Sz);
+ Gen_8 (Opc_Movl_Imm_Reg + To_Reg32 (Tr, Sz));
+ Gen_Imm (Stmt, Sz);
+ when Sz_64 =>
+ if Get_Expr_Kind (Stmt) = OE_Const then
+ if Get_Expr_High (Stmt) = 0 then
+ Gen_Rex_B (Tr, Sz_32);
+ Gen_8 (Opc_Movl_Imm_Reg + To_Reg32 (Tr, Sz));
+ Gen_32 (Unsigned_32 (Get_Expr_Low (Stmt)));
+ else
+ Gen_Rex_B (Tr, Sz_64);
+ Gen_8 (Opc_Movl_Imm_Reg + To_Reg32 (Tr, Sz));
+ Gen_32 (Unsigned_32 (Get_Expr_Low (Stmt)));
+ Gen_32 (Unsigned_32 (Get_Expr_High (Stmt)));
+ end if;
+ else
+ Gen_Rex_B (Tr, Sz_64);
+ Gen_8 (Opc_Movl_Imm_Reg + To_Reg32 (Tr, Sz));
+ Gen_Imm_Addr (Stmt);
+ end if;
end case;
- Gen_Imm (Stmt, Sz);
End_Insn;
end Emit_Load_Imm;
@@ -737,7 +945,7 @@ package body Ortho_Code.X86.Emits is
Sym : Symbol;
begin
Sym := Gen_Constant_Start (2);
- Gen_Le32 (Val);
+ Gen_32 (Val);
Set_Current_Section (Sect_Text);
return Sym;
end Gen_Constant_32;
@@ -747,8 +955,8 @@ package body Ortho_Code.X86.Emits is
Sym : Symbol;
begin
Sym := Gen_Constant_Start (3);
- Gen_Le32 (Lo);
- Gen_Le32 (Hi);
+ Gen_32 (Lo);
+ Gen_32 (Hi);
Set_Current_Section (Sect_Text);
return Sym;
end Gen_Constant_64;
@@ -758,10 +966,10 @@ package body Ortho_Code.X86.Emits is
Sym : Symbol;
begin
Sym := Gen_Constant_Start (4);
- Gen_Le32 (Lo);
- Gen_Le32 (Hi);
- Gen_Le32 (Lo);
- Gen_Le32 (Hi);
+ Gen_32 (Lo);
+ Gen_32 (Hi);
+ Gen_32 (Lo);
+ Gen_32 (Hi);
Set_Current_Section (Sect_Text);
return Sym;
end Gen_Constant_128;
@@ -808,17 +1016,20 @@ package body Ortho_Code.X86.Emits is
end case;
end Get_Xmm_Mask_Constant;
- procedure Gen_SSE_Rep_Opc (Mode : Mode_Fp; Opc : Byte) is
+ procedure Gen_SSE_Prefix (Mode : Mode_Fp) is
begin
case Mode is
when Mode_F32 =>
- Gen_B8 (16#f3#);
+ Gen_8 (16#f3#);
when Mode_F64 =>
- Gen_B8 (16#f2#);
+ Gen_8 (16#f2#);
end case;
- Gen_B8 (16#0f#);
- Gen_B8 (Opc);
- end Gen_SSE_Rep_Opc;
+ end Gen_SSE_Prefix;
+
+ procedure Gen_SSE_Opc (Op : Byte) is
+ begin
+ Gen_8 (16#0f#, Op);
+ end Gen_SSE_Opc;
procedure Gen_SSE_D16_Opc (Mode : Mode_Fp; Opc : Byte) is
begin
@@ -826,10 +1037,10 @@ package body Ortho_Code.X86.Emits is
when Mode_F32 =>
null;
when Mode_F64 =>
- Gen_B8 (Opc_Data16);
+ Gen_8 (Opc_Data16);
end case;
- Gen_B8 (16#0f#);
- Gen_B8 (Opc);
+ Gen_8 (16#0f#);
+ Gen_8 (Opc);
end Gen_SSE_D16_Opc;
procedure Emit_Load_Fp (Stmt : O_Enode; Mode : Mode_Fp)
@@ -850,46 +1061,44 @@ package body Ortho_Code.X86.Emits is
case R is
when R_St0 =>
Start_Insn;
- Gen_B8 (2#11011_001# + Mode_Fp_To_Mf (Mode));
- Gen_B8 (2#00_000_101#);
+ Gen_8 (2#11011_001# + Mode_Fp_To_Mf (Mode));
+ Gen_8 (2#00_000_101#);
Gen_X86_32 (Sym, 0);
End_Insn;
when Regs_Xmm =>
Start_Insn;
- Gen_SSE_Rep_Opc (Mode, 16#10#);
- Gen_B8 (2#00_000_101# + To_Reg_Xmm (R) * 2#1_000#);
- Gen_X86_32 (Sym, 0);
+ Gen_SSE_Prefix (Mode);
+ Gen_SSE_Opc (Opc_Movsd_Xmm_M64);
+ Gen_8 (2#00_000_101# + To_Reg_Xmm (R) * 2#1_000#);
+ if Flags.M64 then
+ -- RIP relative
+ Gen_X86_Pc32 (Sym, 0);
+ else
+ -- Disp32.
+ Gen_X86_32 (Sym, 0);
+ end if;
End_Insn;
when others =>
raise Program_Error;
end case;
end Emit_Load_Fp;
- function Xmm_To_Modrm_Reg (R : O_Reg) return Byte is
- begin
- return To_Reg_Xmm (R) * 8;
- end Xmm_To_Modrm_Reg;
-
- procedure Gen_Xmm_Modrm (Mode : Mode_Fp; Opc : Byte; Dest : O_Reg) is
- begin
- Start_Insn;
- Gen_SSE_Rep_Opc (Mode, Opc);
- Gen_Mod_Rm (Xmm_To_Modrm_Reg (Dest));
- End_Insn;
- end Gen_Xmm_Modrm;
-
procedure Emit_Load_Fp_Mem (Stmt : O_Enode; Mode : Mode_Fp)
is
Dest : constant O_Reg := Get_Expr_Reg (Stmt);
begin
- Init_Modrm_Mem (Get_Expr_Operand (Stmt), Sz_32l);
if Dest in Regs_Xmm then
- Gen_Xmm_Modrm (Mode, 16#10#, Dest);
+ Start_Insn;
+ Gen_SSE_Prefix (Mode);
+ Init_Modrm_Mem (Get_Expr_Operand (Stmt), Sz_Fp, Dest);
+ Gen_SSE_Opc (Opc_Movsd_Xmm_M64);
+ Gen_Mod_Rm_Reg;
+ End_Insn;
else
Start_Insn;
- Gen_B8 (2#11011_001# + Mode_Fp_To_Mf (Mode));
- Init_Modrm_Mem (Get_Expr_Operand (Stmt), Sz_32l);
- Gen_Mod_Rm (2#000_000#);
+ Init_Modrm_Mem (Get_Expr_Operand (Stmt), Sz_Fp);
+ Gen_8 (2#11011_001# + Mode_Fp_To_Mf (Mode));
+ Gen_Mod_Rm_Opc (2#000_000#);
End_Insn;
end if;
end Emit_Load_Fp_Mem;
@@ -900,24 +1109,25 @@ package body Ortho_Code.X86.Emits is
Val : constant O_Enode := Get_Expr_Operand (Stmt);
begin
case Tr is
- when Regs_R32
- | Regs_R64 =>
+ when Regs_R64
+ | Regs_Pair =>
-- mov REG, OP
- Init_Modrm_Mem (Val, Sz);
Start_Insn;
+ Init_Modrm_Mem (Val, Sz, Tr);
Gen_Insn_Sz (Opc_Mov_Reg_Rm, Sz);
- Gen_Mod_Rm (To_Reg32 (Tr, Sz) * 8);
+ Gen_Mod_Rm_Reg;
End_Insn;
when R_Eq =>
-- Cmp OP, 1
+ Start_Insn;
Init_Modrm_Mem (Val, Sz);
- Gen_Insn_Grp1 (Opc2_Grp1_Cmp, Sz, 1);
+ Gen_Insn_Grp1 (Opc2_Grp1_Cmp, 1);
+ End_Insn;
when others =>
Error_Emit ("emit_load_mem", Stmt);
end case;
end Emit_Load_Mem;
-
procedure Emit_Store (Stmt : O_Enode; Sz : Insn_Size)
is
T : constant O_Enode := Get_Assign_Target (Stmt);
@@ -929,29 +1139,31 @@ package body Ortho_Code.X86.Emits is
Start_Insn;
case Rr is
when R_Imm =>
- if False and (Tr in Regs_R32 or Tr in Regs_R64) then
+ if False and (Tr in Regs_R64 or Tr in Regs_Pair) then
B := 2#1011_1_000#;
case Sz is
when Sz_8 =>
B := B and not 2#0000_1_000#;
when Sz_16 =>
- Gen_B8 (16#66#);
- when Sz_32l
- | Sz_32h =>
+ Gen_8 (16#66#);
+ when Sz_32
+ | Sz_32l
+ | Sz_32h
+ | Sz_64 =>
null;
end case;
- Gen_B8 (B + To_Reg32 (Tr, Sz));
+ Gen_8 (B + To_Reg32 (Tr, Sz));
else
Init_Modrm_Mem (T, Sz);
Gen_Insn_Sz (Opc_Mov_Rm_Imm, Sz);
- Gen_Mod_Rm (16#00#);
+ Gen_Mod_Rm_Opc (16#00#);
end if;
Gen_Imm (R, Sz);
- when Regs_R32
- | Regs_R64 =>
+ when Regs_R64
+ | Regs_Pair =>
+ Init_Modrm_Mem (T, Sz, Rr);
Gen_Insn_Sz (Opc_Mov_Rm_Reg, Sz);
- Init_Modrm_Mem (T, Sz);
- Gen_Mod_Rm (To_Reg32 (Rr, Sz) * 8);
+ Gen_Mod_Rm_Reg;
when others =>
Error_Emit ("emit_store", Stmt);
end case;
@@ -962,61 +1174,79 @@ package body Ortho_Code.X86.Emits is
begin
-- fstp
Start_Insn;
- Gen_B8 (2#11011_00_1# + Mode_Fp_To_Mf (Mode));
- Init_Modrm_Mem (Get_Assign_Target (Stmt), Sz_32l);
- Gen_Mod_Rm (2#011_000#);
+ Init_Modrm_Mem (Get_Assign_Target (Stmt), Sz_Ptr);
+ Gen_8 (2#11011_00_1# + Mode_Fp_To_Mf (Mode));
+ Gen_Mod_Rm_Opc (2#011_000#);
End_Insn;
end Emit_Store_Fp;
procedure Emit_Store_Xmm (Stmt : O_Enode; Mode : Mode_Fp) is
begin
-- movsd
- Init_Modrm_Mem (Get_Assign_Target (Stmt), Sz_32l);
Start_Insn;
- Gen_SSE_Rep_Opc (Mode, 16#11#);
- Gen_Mod_Rm (To_Reg_Xmm (Get_Expr_Reg (Get_Expr_Operand (Stmt))) * 8);
+ Gen_SSE_Prefix (Mode);
+ Init_Modrm_Mem (Get_Assign_Target (Stmt), Sz_Fp,
+ Get_Expr_Reg (Get_Expr_Operand (Stmt)));
+ Gen_SSE_Opc (Opc_Movsd_M64_Xmm);
+ Gen_Mod_Rm_Reg;
End_Insn;
end Emit_Store_Xmm;
- procedure Emit_Push_32 (Val : O_Enode; Sz : Insn_Size)
+ procedure Gen_Push_Pop_Reg (Opc : Byte; Reg : O_Reg; Sz : Insn_Size) is
+ begin
+ Start_Insn;
+ if Reg in Regs_R8_R15 then
+ Gen_8 (Opc_Rex_B);
+ end if;
+ Gen_8 (Opc + To_Reg32 (Reg, Sz));
+ End_Insn;
+ end Gen_Push_Pop_Reg;
+
+ procedure Emit_Push (Val : O_Enode; Sz : Insn_Size)
is
R : constant O_Reg := Get_Expr_Reg (Val);
begin
- Start_Insn;
case R is
when R_Imm =>
+ Start_Insn;
if Is_Imm8 (Val, Sz) then
- Gen_B8 (Opc_Push_Imm8);
+ Gen_8 (Opc_Push_Imm8);
Gen_Imm8 (Val, Sz);
else
- Gen_B8 (Opc_Push_Imm);
+ Gen_8 (Opc_Push_Imm);
Gen_Imm (Val, Sz);
end if;
- when Regs_R32
- | Regs_R64 =>
- Gen_B8 (Opc_Push_Reg + To_Reg32 (R, Sz));
+ End_Insn;
+ when Regs_R64
+ | Regs_Pair =>
+ Gen_Push_Pop_Reg (Opc_Push_Reg, R, Sz);
when others =>
- Gen_B8 (Opc_Grp5);
- Gen_Rm (Opc2_Grp5_Push_Rm, Val, Sz);
+ Start_Insn;
+ Init_Modrm_Expr (Val, Sz);
+ Gen_8 (Opc_Grp5);
+ Gen_Mod_Rm_Opc (Opc2_Grp5_Push_Rm);
+ End_Insn;
end case;
- End_Insn;
- end Emit_Push_32;
+ end Emit_Push;
procedure Emit_Subl_Sp_Imm (Len : Byte) is
begin
Start_Insn;
- Gen_B8 (Opc_Grp1v_Rm_Imm8);
- Gen_B8 (Opc2_Grp1_Sub + 2#11_000_100#);
- Gen_B8 (Len);
+ Gen_Rex (Opc_Rex_W);
+ Gen_8 (Opc_Grp1v_Rm_Imm8);
+ Gen_8 (Opc2_Grp1_Sub + 2#11_000_100#);
+ Gen_8 (Len);
End_Insn;
end Emit_Subl_Sp_Imm;
- procedure Emit_Addl_Sp_Imm (Len : Byte) is
+ procedure Emit_Addl_Sp_Imm (Len : Byte)
+ is
+ pragma Assert (not Flags.M64);
begin
Start_Insn;
- Gen_B8 (Opc_Grp1v_Rm_Imm8);
- Gen_B8 (Opc2_Grp1_Add + 2#11_000_100#);
- Gen_B8 (Len);
+ Gen_8 (Opc_Grp1v_Rm_Imm8);
+ Gen_8 (Opc2_Grp1_Add + 2#11_000_100#);
+ Gen_8 (Len);
End_Insn;
end Emit_Addl_Sp_Imm;
@@ -1037,16 +1267,17 @@ package body Ortho_Code.X86.Emits is
if Reg = R_St0 then
-- fstp st, (esp)
Start_Insn;
- Gen_B8 (2#11011_001# + Mode_Fp_To_Mf (Mode));
- Gen_B8 (2#00_011_100#); -- Modrm: SIB, no disp
- Gen_B8 (2#00_100_100#); -- SIB: SS=0, no index, base=esp
+ Gen_8 (2#11011_001# + Mode_Fp_To_Mf (Mode));
+ Gen_8 (2#00_011_100#); -- Modrm: SIB, no disp
+ Gen_8 (2#00_100_100#); -- SIB: SS=0, no index, base=esp
End_Insn;
else
pragma Assert (Reg in Regs_Xmm);
Start_Insn;
- Gen_SSE_Rep_Opc (Mode, 16#11#);
- Gen_B8 (To_Reg_Xmm (Reg) * 8 + 2#00_000_100#); -- Modrm: [--]
- Gen_B8 (2#00_100_100#); -- SIB: SS=0, no index, base=esp
+ Gen_SSE_Prefix (Mode);
+ Gen_SSE_Opc (Opc_Movsd_M64_Xmm);
+ Gen_8 (To_Reg_Xmm (Reg) * 8 + 2#00_000_100#); -- Modrm: [--]
+ Gen_8 (2#00_100_100#); -- SIB: SS=0, no index, base=esp
End_Insn;
end if;
end Emit_Push_Fp;
@@ -1075,19 +1306,19 @@ package body Ortho_Code.X86.Emits is
Opc := To_Cond (Reg);
if Val = 0 then
-- Assume long jmp.
- Gen_B8 (Opc_0f);
- Gen_B8 (Opc2_0f_Jcc + Opc);
- Gen_X86_Pc32 (Sym);
+ Gen_8 (Opc_0f);
+ Gen_8 (Opc2_0f_Jcc + Opc);
+ Gen_X86_Pc32 (Sym, 0);
else
if Val + 128 < Get_Current_Pc + 4 then
-- Long jmp.
- Gen_B8 (Opc_0f);
- Gen_B8 (Opc2_0f_Jcc + Opc);
- Gen_Le32 (Unsigned_32 (Val - (Get_Current_Pc + 4)));
+ Gen_8 (Opc_0f);
+ Gen_8 (Opc2_0f_Jcc + Opc);
+ Gen_32 (To_Unsigned_32 (Val - (Get_Current_Pc + 4)));
else
-- short jmp.
- Gen_B8 (Opc_Jcc + Opc);
- Gen_B8 (Byte (Val - (Get_Current_Pc + 1)));
+ Gen_8 (Opc_Jcc + Opc);
+ Gen_8 (Byte (Val - (Get_Current_Pc + 1)));
end if;
end if;
End_Insn;
@@ -1103,17 +1334,17 @@ package body Ortho_Code.X86.Emits is
Start_Insn;
if Val = 0 then
-- Assume long jmp.
- Gen_B8 (Opc_Jmp_Long);
- Gen_X86_Pc32 (Sym);
+ Gen_8 (Opc_Jmp_Long);
+ Gen_X86_Pc32 (Sym, 0);
else
if Val + 128 < Get_Current_Pc + 4 then
-- Long jmp.
- Gen_B8 (Opc_Jmp_Long);
- Gen_Le32 (Unsigned_32 (Val - (Get_Current_Pc + 4)));
+ Gen_8 (Opc_Jmp_Long);
+ Gen_32 (To_Unsigned_32 (Val - (Get_Current_Pc + 4)));
else
-- short jmp.
- Gen_B8 (Opc_Jmp_Short);
- Gen_B8 (Byte ((Val - (Get_Current_Pc + 1)) and 16#Ff#));
+ Gen_8 (Opc_Jmp_Short);
+ Gen_8 (Byte ((Val - (Get_Current_Pc + 1)) and 16#Ff#));
end if;
end if;
End_Insn;
@@ -1130,8 +1361,8 @@ package body Ortho_Code.X86.Emits is
procedure Gen_Call (Sym : Symbol) is
begin
Start_Insn;
- Gen_B8 (Opc_Call);
- Gen_X86_Pc32 (Sym);
+ Gen_8 (Opc_Call);
+ Gen_X86_Pc32 (Sym, 0);
End_Insn;
end Gen_Call;
@@ -1143,8 +1374,10 @@ package body Ortho_Code.X86.Emits is
-- subl esp, val
Emit_Subl_Sp_Imm (Byte (Val));
elsif Val < 0 then
- Init_Modrm_Reg (R_Sp, Sz_32l);
- Gen_Insn_Grp1 (Opc2_Grp1_Add, Sz_32l, -Val);
+ Start_Insn;
+ Init_Modrm_Reg (R_Sp, Sz_Ptr);
+ Gen_Insn_Grp1 (Opc2_Grp1_Add, -Val);
+ End_Insn;
end if;
end Emit_Stack_Adjust;
@@ -1157,20 +1390,25 @@ package body Ortho_Code.X86.Emits is
begin
Gen_Call (Sym);
- if Abi.Flag_Sse2 and then Mode in Mode_Fp then
- -- Move from St0 to Xmm0.
- -- fstp slot(%ebp)
- Init_Modrm_Offset
- (R_Bp, -Int32 (Cur_Subprg.Target.Fp_Slot), Sz_32l);
- Start_Insn;
- Gen_B8 (2#11011_001# + Mode_Fp_To_Mf (Mode));
- Gen_Mod_Rm (2#00_011_000#);
- End_Insn;
- -- movsd slot(%ebp), %xmm0
- Start_Insn;
- Gen_SSE_Rep_Opc (Mode, 16#10#);
- Gen_Mod_Rm (2#00_000_000#);
- End_Insn;
+ if Abi.Flag_Sse2 and then not Flags.M64 and then Mode in Mode_Fp then
+ declare
+ Sslot : constant Int32 := -Int32 (Cur_Subprg.Target.Fp_Slot);
+ begin
+ -- Move from St0 to Xmm0.
+ -- fstp slot(%ebp)
+ Start_Insn;
+ Init_Modrm_Offset (R_Bp, Sslot, Sz_Fp);
+ Gen_8 (2#11011_001# + Mode_Fp_To_Mf (Mode));
+ Gen_Mod_Rm_Opc (2#00_011_000#);
+ End_Insn;
+ -- movsd slot(%ebp), %xmm0
+ Start_Insn;
+ Gen_SSE_Prefix (Mode);
+ Init_Modrm_Offset (R_Bp, Sslot, Sz_Fp);
+ Gen_SSE_Opc (Opc_Movsd_Xmm_M64);
+ Gen_Mod_Rm_Opc (2#00_000_000#);
+ End_Insn;
+ end;
end if;
end Emit_Call;
@@ -1189,9 +1427,10 @@ package body Ortho_Code.X86.Emits is
begin
pragma Assert (Cond in Regs_Cc);
Start_Insn;
- Gen_B8 (Opc_0f);
- Gen_B8 (Opc2_0f_Setcc + To_Cond (Cond));
- Gen_Rm (2#000_000#, Dest, Sz_8);
+ Init_Modrm_Expr (Dest, Sz_8);
+ Gen_8 (Opc_0f);
+ Gen_8 (Opc2_0f_Setcc + To_Cond (Cond));
+ Gen_Mod_Rm_Opc (2#000_000#);
End_Insn;
end Emit_Setcc;
@@ -1199,24 +1438,27 @@ package body Ortho_Code.X86.Emits is
begin
pragma Assert (Cond in Regs_Cc);
Start_Insn;
- Gen_B8 (Opc_0f);
- Gen_B8 (Opc2_0f_Setcc + To_Cond (Cond));
- Gen_B8 (2#11_000_000# + To_Reg32 (Reg, Sz_8));
+ Gen_8 (Opc_0f);
+ Gen_8 (Opc2_0f_Setcc + To_Cond (Cond));
+ Gen_8 (2#11_000_000# + To_Reg32 (Reg, Sz_8));
End_Insn;
end Emit_Setcc_Reg;
procedure Emit_Tst (Reg : O_Reg; Sz : Insn_Size) is
begin
Start_Insn;
+ Init_Modrm_Reg (Reg, Sz, Reg, Sz);
Gen_Insn_Sz (Opc_Test_Rm_Reg, Sz);
- Gen_B8 (2#11_000_000# + To_Reg32 (Reg, Sz) * 9);
+ Gen_Mod_Rm_Reg;
End_Insn;
end Emit_Tst;
procedure Gen_Cmp_Imm (Reg : O_Reg; Val : Int32; Sz : Insn_Size) is
begin
+ Start_Insn;
Init_Modrm_Reg (Reg, Sz);
- Gen_Insn_Grp1 (Opc2_Grp1_Cmp, Sz, Val);
+ Gen_Insn_Grp1 (Opc2_Grp1_Cmp, Val);
+ End_Insn;
end Gen_Cmp_Imm;
procedure Emit_Spill (Stmt : O_Enode; Sz : Insn_Size)
@@ -1226,10 +1468,10 @@ package body Ortho_Code.X86.Emits is
begin
-- A reload is missing.
pragma Assert (Reg /= R_Spill);
- Init_Modrm_Mem (Stmt, Sz);
Start_Insn;
+ Init_Modrm_Mem (Stmt, Sz, Reg);
Gen_Insn_Sz (Opc_Mov_Rm_Reg, Sz);
- Gen_Mod_Rm (To_Reg32 (Reg, Sz) * 8);
+ Gen_Mod_Rm_Reg;
End_Insn;
end Emit_Spill;
@@ -1241,10 +1483,11 @@ package body Ortho_Code.X86.Emits is
-- A reload is missing.
pragma Assert (Reg in Regs_Xmm);
-- movsd
- Init_Modrm_Mem (Stmt, Sz_32l);
Start_Insn;
- Gen_SSE_Rep_Opc (Mode, 16#11#);
- Gen_Mod_Rm (To_Reg_Xmm (Reg) * 8);
+ Gen_SSE_Prefix (Mode);
+ Init_Modrm_Mem (Stmt, Sz_Fp, Reg);
+ Gen_SSE_Opc (Opc_Movsd_M64_Xmm);
+ Gen_Mod_Rm_Reg;
End_Insn;
end Emit_Spill_Xmm;
@@ -1252,8 +1495,9 @@ package body Ortho_Code.X86.Emits is
is
begin
Start_Insn;
+ Init_Modrm_Expr (Val, Sz, Reg);
Gen_Insn_Sz (Opc_Mov_Reg_Rm, Sz);
- Gen_Rm (To_Reg32 (Reg, Sz) * 8, Val, Sz);
+ Gen_Mod_Rm_Reg;
End_Insn;
end Emit_Load;
@@ -1264,10 +1508,10 @@ package body Ortho_Code.X86.Emits is
-- Hack: change the register to use the real address instead of it.
Set_Expr_Reg (Stmt, R_Mem);
- Init_Modrm_Mem (Stmt, Sz_32l);
Start_Insn;
- Gen_B8 (Opc_Leal_Reg_Rm);
- Gen_Mod_Rm (To_Reg32 (Reg) * 8);
+ Init_Modrm_Mem (Stmt, Sz_Ptr, Reg);
+ Gen_8 (Opc_Leal_Reg_Rm);
+ Gen_Mod_Rm_Reg;
End_Insn;
-- Restore.
@@ -1279,8 +1523,9 @@ package body Ortho_Code.X86.Emits is
begin
pragma Assert (Get_Expr_Reg (Get_Expr_Left (Stmt)) = R_Ax);
Start_Insn;
+ Init_Modrm_Expr (Get_Expr_Right (Stmt), Sz);
Gen_Insn_Sz (Opc_Grp3_Width, Sz);
- Gen_Rm (Opc2_Grp3_Mul, Get_Expr_Right (Stmt), Sz);
+ Gen_Mod_Rm_Opc (Opc2_Grp3_Mul);
End_Insn;
end Gen_Umul;
@@ -1291,30 +1536,32 @@ package body Ortho_Code.X86.Emits is
Reg_R : O_Reg;
begin
pragma Assert (Get_Expr_Reg (Get_Expr_Left (Stmt)) = Reg);
- pragma Assert (Sz = Sz_32l);
Start_Insn;
if Reg = R_Ax then
+ Init_Modrm_Expr (Right, Sz);
Gen_Insn_Sz (Opc_Grp3_Width, Sz);
- Gen_Rm (Opc2_Grp3_Mul, Right, Sz);
+ Gen_Mod_Rm_Opc (Opc2_Grp3_Mul);
else
Reg_R := Get_Expr_Reg (Right);
case Reg_R is
when R_Imm =>
+ Init_Modrm_Reg (Reg, Sz, Reg, Sz);
if Is_Imm8 (Right, Sz) then
- Gen_B8 (Opc_Imul_Reg_Rm_Imm8);
- Gen_B8 (To_Reg32 (Reg, Sz) * 9 or 2#11_000_000#);
+ Gen_8 (Opc_Imul_Reg_Rm_Imm8);
+ Gen_Mod_Rm_Reg;
Gen_Imm8 (Right, Sz);
else
- Gen_B8 (Opc_Imul_Reg_Rm_Imm32);
- Gen_B8 (To_Reg32 (Reg, Sz) * 9 or 2#11_000_000#);
+ Gen_8 (Opc_Imul_Reg_Rm_Imm32);
+ Gen_Mod_Rm_Reg;
Gen_Imm (Right, Sz);
end if;
when R_Mem
| R_Spill
- | Regs_R32 =>
- Gen_B8 (Opc_0f);
- Gen_B8 (Opc2_0f_Imul);
- Gen_Rm (To_Reg32 (Reg, Sz) * 8, Right, Sz);
+ | Regs_R64 =>
+ Init_Modrm_Expr (Right, Sz, Reg);
+ Gen_8 (Opc_0f);
+ Gen_8 (Opc2_0f_Imul);
+ Gen_Mod_Rm_Reg;
when others =>
Error_Emit ("gen_mul", Stmt);
end case;
@@ -1331,90 +1578,142 @@ package body Ortho_Code.X86.Emits is
Gen_2 (Opc_Int, 16#04#);
end Gen_Ov_Check;
+ procedure Gen_Into is
+ begin
+ if Flags.M64 then
+ Gen_Ov_Check (R_No);
+ else
+ Gen_1 (Opc_Into);
+ end if;
+ end Gen_Into;
+
procedure Emit_Abs (Val : O_Enode; Mode : Mode_Type)
is
- Szh : Insn_Size;
+ Szl, Szh : Insn_Size;
Pc_Jmp : Pc_Type;
begin
case Mode is
when Mode_I32 =>
- Szh := Sz_32l;
+ Szh := Sz_32;
+ Szl := Sz_32;
when Mode_I64 =>
- Szh := Sz_32h;
+ if Flags.M64 then
+ Szh := Sz_64;
+ Szl := Sz_64;
+ else
+ Szh := Sz_32h;
+ Szl := Sz_32l;
+ end if;
when others =>
raise Program_Error;
end case;
Emit_Tst (Get_Expr_Reg (Val), Szh);
- -- JXX +
- Start_Insn;
- Gen_B8 (Opc_Jcc + To_Cond (R_Sge));
- Gen_B8 (0);
- End_Insn;
+ -- JGE xxx (skip if positive).
+ Gen_2 (Opc_Jcc + To_Cond (R_Sge), 0);
Pc_Jmp := Get_Current_Pc;
-- NEG
- Gen_Grp3_Insn (Opc2_Grp3_Neg, Val, Sz_32l);
- if Mode = Mode_I64 then
+ Gen_Grp3_Insn (Opc2_Grp3_Neg, Val, Szl);
+ if (not Flags.M64) and Mode = Mode_I64 then
-- Propagate carry.
-- Adc reg,0
-- neg reg
- Init_Rm_Expr (Val, Sz_32h);
- Gen_Insn_Grp1 (Opc2_Grp1_Adc, Sz_32h, 0);
+ Start_Insn;
+ Init_Modrm_Expr (Val, Sz_32h);
+ Gen_Insn_Grp1 (Opc2_Grp1_Adc, 0);
+ End_Insn;
Gen_Grp3_Insn (Opc2_Grp3_Neg, Val, Sz_32h);
end if;
Gen_Into;
- Patch_B8 (Pc_Jmp - 1, Unsigned_8 (Get_Current_Pc - Pc_Jmp));
+ Patch_8 (Pc_Jmp - 1, Unsigned_8 (Get_Current_Pc - Pc_Jmp));
end Emit_Abs;
procedure Gen_Alloca (Stmt : O_Enode)
is
Reg : constant O_Reg := Get_Expr_Reg (Get_Expr_Operand (Stmt));
begin
- pragma Assert (Reg in Regs_R32);
+ pragma Assert (Reg in Regs_R64);
pragma Assert (Reg = Get_Expr_Reg (Stmt));
-- Align stack on word.
-- Add reg, (stack_boundary - 1)
Start_Insn;
- Gen_B8 (Opc_Grp1v_Rm_Imm8);
- Gen_B8 (Opc2_Grp1_Add or 2#11_000_000# or To_Reg32 (Reg));
- Gen_B8 (Byte (X86.Flags.Stack_Boundary - 1));
+ Gen_Rex_B (Reg, Sz_Ptr);
+ Gen_8 (Opc_Grp1v_Rm_Imm8);
+ Gen_8 (Opc2_Grp1_Add or 2#11_000_000# or To_Reg32 (Reg));
+ Gen_8 (Byte (X86.Flags.Stack_Boundary - 1));
End_Insn;
-- and reg, ~(stack_boundary - 1)
Start_Insn;
- Gen_B8 (Opc_Grp1v_Rm_Imm32);
- Gen_B8 (Opc2_Grp1_And or 2#11_000_000# or To_Reg32 (Reg));
- Gen_Le32 (not (X86.Flags.Stack_Boundary - 1));
+ Gen_Rex_B (Reg, Sz_Ptr);
+ Gen_8 (Opc_Grp1v_Rm_Imm32);
+ Gen_8 (Opc2_Grp1_And or 2#11_000_000# or To_Reg32 (Reg));
+ Gen_32 (not (X86.Flags.Stack_Boundary - 1));
End_Insn;
if X86.Flags.Flag_Alloca_Call then
Gen_Call (Chkstk_Symbol);
else
-- subl esp, reg
- Gen_2 (Opc_Subl_Reg_Rm, 2#11_100_000# + To_Reg32 (Reg));
+ Start_Insn;
+ Gen_Rex_B (Reg, Sz_Ptr);
+ Gen_8 (Opc_Subl_Reg_Rm);
+ Gen_8 (2#11_100_000# + To_Reg32 (Reg));
+ End_Insn;
end if;
-- movl reg, esp
- Gen_2 (Opc_Mov_Rm_Reg + 1, 2#11_100_000# + To_Reg32 (Reg));
+ Start_Insn;
+ Gen_Rex_B (Reg, Sz_Ptr);
+ Gen_8 (Opc_Mov_Rm_Reg + 1);
+ Gen_8 (2#11_100_000# + To_Reg32 (Reg));
+ End_Insn;
end Gen_Alloca;
-- Byte/word to long.
- procedure Gen_Movzx (Reg : Regs_R32; Op : O_Enode; Sz : Insn_Size)
- is
- B : Byte;
+ procedure Gen_Movzx (Reg : Regs_R64; Op : O_Enode; Dst_Sz : Insn_Size) is
begin
Start_Insn;
- Gen_B8 (Opc_0f);
- case Sz is
- when Sz_8 =>
- B := 0;
- when Sz_16 =>
- B := 1;
- when Sz_32l
- | Sz_32h =>
+ Init_Modrm_Expr (Op, Dst_Sz, Reg);
+ Gen_8 (Opc_0f);
+ case Get_Expr_Mode (Op) is
+ when Mode_I8 | Mode_U8 | Mode_B2 =>
+ Gen_8 (Opc2_0f_Movzx);
+ when Mode_I16 | Mode_U16 =>
+ Gen_8 (Opc2_0f_Movzx + 1);
+ when others =>
raise Program_Error;
end case;
- Gen_B8 (Opc2_0f_Movzx + B);
- Gen_Rm (To_Reg32 (Reg) * 8, Op, Sz_8);
+ Gen_Mod_Rm_Reg;
End_Insn;
end Gen_Movzx;
+ procedure Gen_Movsxd (Src : O_Reg; Dst : O_Reg) is
+ begin
+ Start_Insn;
+ Init_Modrm_Reg (Src, Sz_64, Dst, Sz_64);
+ Gen_8 (Opc_Movsxd_Reg_Rm);
+ Gen_Mod_Rm_Reg;
+ End_Insn;
+ end Gen_Movsxd;
+
+ procedure Emit_Move (Operand : O_Enode; Sz : Insn_Size; Reg : O_Reg) is
+ begin
+ -- mov REG, OP
+ Start_Insn;
+ Init_Modrm_Expr (Operand, Sz, Reg);
+ Gen_Insn_Sz (Opc_Mov_Reg_Rm, Sz);
+ Gen_Mod_Rm_Reg;
+ End_Insn;
+ end Emit_Move;
+
+ procedure Emit_Move_Xmm (Operand : O_Enode; Mode : Mode_Fp; Reg : O_Reg) is
+ begin
+ -- movsd REG, OP
+ Start_Insn;
+ Gen_SSE_Prefix (Mode);
+ Init_Modrm_Expr (Operand, Sz_Fp, Reg);
+ Gen_SSE_Opc (Opc_Movsd_Xmm_M64);
+ Gen_Mod_Rm_Reg;
+ End_Insn;
+ end Emit_Move_Xmm;
+
-- Convert U32 to xx.
procedure Gen_Conv_U32 (Stmt : O_Enode)
is
@@ -1426,26 +1725,31 @@ package body Ortho_Code.X86.Emits is
when Mode_I32 =>
pragma Assert (Reg_Res in Regs_R32);
if Reg_Op /= Reg_Res then
- Emit_Load (Reg_Res, Op, Sz_32l);
+ Emit_Load (Reg_Res, Op, Sz_32);
end if;
- Emit_Tst (Reg_Res, Sz_32l);
+ Emit_Tst (Reg_Res, Sz_32);
Gen_Ov_Check (R_Sge);
when Mode_I64 =>
- pragma Assert (Reg_Res = R_Edx_Eax);
- pragma Assert (Reg_Op = R_Ax);
- -- Clear edx.
- Gen_Clear_Edx;
+ if Flags.M64 then
+ Emit_Move (Op, Sz_32, Reg_Res);
+ else
+ pragma Assert (Reg_Res = R_Edx_Eax);
+ pragma Assert (Reg_Op = R_Ax);
+ -- Clear edx.
+ Gen_Clear_Edx;
+ end if;
when Mode_U8
| Mode_B2 =>
pragma Assert (Reg_Res in Regs_R32);
if Reg_Op /= Reg_Res then
- Emit_Load (Reg_Res, Op, Sz_32l);
+ Emit_Load (Reg_Res, Op, Sz_32);
end if;
-- cmpl VAL, 0xff
Start_Insn;
- Gen_B8 (Opc_Grp1v_Rm_Imm32);
- Gen_Rm (Opc2_Grp1_Cmp, Op, Sz_32l);
- Gen_Le32 (16#00_00_00_Ff#);
+ Init_Modrm_Expr (Op, Sz_32);
+ Gen_8 (Opc_Grp1v_Rm_Imm32);
+ Gen_Mod_Rm_Opc (Opc2_Grp1_Cmp);
+ Gen_32 (16#00_00_00_Ff#);
End_Insn;
Gen_Ov_Check (R_Ule);
when others =>
@@ -1462,42 +1766,47 @@ package body Ortho_Code.X86.Emits is
begin
case Get_Expr_Mode (Stmt) is
when Mode_I64 =>
- pragma Assert (Reg_Res = R_Edx_Eax);
- pragma Assert (Reg_Op = R_Ax);
- Gen_Cdq;
+ if Flags.M64 then
+ Gen_Movsxd (Reg_Op, Reg_Res);
+ else
+ pragma Assert (Reg_Res = R_Edx_Eax);
+ pragma Assert (Reg_Op = R_Ax);
+ Gen_Cdq (Sz_32);
+ end if;
when Mode_U32 =>
pragma Assert (Reg_Res in Regs_R32);
if Reg_Op /= Reg_Res then
- Emit_Load (Reg_Res, Op, Sz_32l);
+ Emit_Load (Reg_Res, Op, Sz_32);
end if;
- Emit_Tst (Reg_Res, Sz_32l);
+ Emit_Tst (Reg_Res, Sz_32);
Gen_Ov_Check (R_Sge);
when Mode_B2 =>
if Reg_Op /= Reg_Res then
- Emit_Load (Reg_Res, Op, Sz_32l);
+ Emit_Load (Reg_Res, Op, Sz_32);
end if;
- Gen_Cmp_Imm (Reg_Res, 1, Sz_32l);
+ Gen_Cmp_Imm (Reg_Res, 1, Sz_32);
Gen_Ov_Check (R_Ule);
when Mode_U8 =>
if Reg_Op /= Reg_Res then
- Emit_Load (Reg_Res, Op, Sz_32l);
+ Emit_Load (Reg_Res, Op, Sz_32);
end if;
- Gen_Cmp_Imm (Reg_Res, 16#Ff#, Sz_32l);
+ Gen_Cmp_Imm (Reg_Res, 16#Ff#, Sz_32);
Gen_Ov_Check (R_Ule);
when Mode_F64 =>
if Reg_Res in Regs_Xmm then
-- cvtsi2sd
- Init_Rm_Expr (Op, Sz_32l);
- Gen_SSE_Rep_Opc (Mode_F64, 16#2a#);
- Gen_Mod_Rm (To_Reg_Xmm (Reg_Res) * 8);
+ Gen_SSE_Prefix (Mode_F64);
+ Init_Modrm_Expr (Op, Sz_32, Reg_Res);
+ Gen_SSE_Opc (Opc_Cvtsi2sd_Xmm_Rm);
+ Gen_Mod_Rm_Reg;
End_Insn;
else
- Emit_Push_32 (Op, Sz_32l);
+ Emit_Push (Op, Sz_32);
-- fild (%esp)
Start_Insn;
- Gen_B8 (2#11011_011#);
- Gen_B8 (2#00_000_100#);
- Gen_B8 (2#00_100_100#);
+ Gen_8 (2#11011_011#);
+ Gen_8 (2#00_000_100#);
+ Gen_8 (2#00_100_100#);
End_Insn;
-- addl %esp, 4
Emit_Addl_Sp_Imm (4);
@@ -1510,24 +1819,29 @@ package body Ortho_Code.X86.Emits is
-- Convert U8 to xxx
procedure Gen_Conv_U8 (Stmt : O_Enode)
is
+ Mode : constant Mode_Type := Get_Expr_Mode (Stmt);
Op : constant O_Enode := Get_Expr_Operand (Stmt);
Reg_Res : constant O_Reg := Get_Expr_Reg (Stmt);
Reg_Op : constant O_Reg := Get_Expr_Reg (Op);
begin
- case Get_Expr_Mode (Stmt) is
+ case Mode is
when Mode_U32
| Mode_I32
| Mode_U16
| Mode_I16 =>
- pragma Assert (Reg_Res in Regs_R32);
- Gen_Movzx (Reg_Res, Op, Sz_8);
+ pragma Assert (Reg_Res in Regs_R64);
+ Gen_Movzx (Reg_Res, Op, Int_Mode_To_Size (Mode));
when Mode_I64
| Mode_U64 =>
- pragma Assert (Reg_Res = R_Edx_Eax);
- pragma Assert (Reg_Op = R_Ax);
- Gen_Movzx (R_Ax, Op, Sz_8);
- -- Sign-extend, but we know the sign is positive.
- Gen_Cdq;
+ if Flags.M64 then
+ Gen_Movzx (Reg_Res, Op, Sz_64);
+ else
+ pragma Assert (Reg_Res = R_Edx_Eax);
+ pragma Assert (Reg_Op = R_Ax);
+ Gen_Movzx (R_Ax, Op, Sz_32);
+ -- Sign-extend, but we know the sign is positive.
+ Gen_Cdq (Sz_32);
+ end if;
when others =>
Error_Emit ("gen_conv_U8", Stmt);
end case;
@@ -1536,23 +1850,28 @@ package body Ortho_Code.X86.Emits is
-- Convert B2 to xxx
procedure Gen_Conv_B2 (Stmt : O_Enode)
is
+ Mode : constant Mode_Type := Get_Expr_Mode (Stmt);
Op : constant O_Enode := Get_Expr_Operand (Stmt);
Reg_Op : constant O_Reg := Get_Expr_Reg (Op);
Reg_Res : constant O_Reg := Get_Expr_Reg (Stmt);
begin
- case Get_Expr_Mode (Stmt) is
+ case Mode is
when Mode_U32
| Mode_I32
| Mode_U16
| Mode_I16 =>
- pragma Assert (Reg_Res in Regs_R32);
- Gen_Movzx (Reg_Res, Op, Sz_8);
+ pragma Assert (Reg_Res in Regs_R64);
+ Gen_Movzx (Reg_Res, Op, Int_Mode_To_Size (Mode));
when Mode_I64 =>
- pragma Assert (Reg_Res = R_Edx_Eax);
- pragma Assert (Reg_Op = R_Ax);
- Gen_Movzx (R_Ax, Op, Sz_8);
- -- Sign-extend, but we know the sign is positive.
- Gen_Cdq;
+ if Flags.M64 then
+ Gen_Movzx (Reg_Res, Op, Sz_64);
+ else
+ pragma Assert (Reg_Res = R_Edx_Eax);
+ pragma Assert (Reg_Op = R_Ax);
+ Gen_Movzx (R_Ax, Op, Sz_32);
+ -- Sign-extend, but we know the sign is positive.
+ Gen_Cdq (Sz_32);
+ end if;
when others =>
Error_Emit ("gen_conv_B2", Stmt);
end case;
@@ -1561,75 +1880,111 @@ package body Ortho_Code.X86.Emits is
-- Convert I64 to xxx
procedure Gen_Conv_I64 (Stmt : O_Enode)
is
+ Mode : constant Mode_Type := Get_Expr_Mode (Stmt);
Op : constant O_Enode := Get_Expr_Operand (Stmt);
Reg_Op : constant O_Reg := Get_Expr_Reg (Op);
Reg_Res : constant O_Reg := Get_Expr_Reg (Stmt);
begin
- case Get_Expr_Mode (Stmt) is
+ case Mode is
when Mode_I32 =>
- pragma Assert (Reg_Op = R_Edx_Eax);
- pragma Assert (Reg_Res = R_Ax);
- -- move dx to reg_helper
- Start_Insn;
- Gen_B8 (Opc_Mov_Rm_Reg + 1);
- Gen_B8 (2#11_010_000# + To_Reg32 (Reg_Helper));
- End_Insn;
- -- Sign extend eax.
- Gen_Cdq;
- -- cmp reg_helper, dx
- Start_Insn;
- Gen_B8 (Opc_Cmpl_Rm_Reg);
- Gen_B8 (2#11_010_000# + To_Reg32 (Reg_Helper));
- End_Insn;
- -- Overflow if extended value is different from initial value.
- Gen_Ov_Check (R_Eq);
- when Mode_U8 =>
- pragma Assert (Reg_Op in Regs_R64);
- -- Check MSB = 0
- Emit_Tst (Reg_Op, Sz_32h);
- Gen_Ov_Check (R_Eq);
- -- Check LSB <= 255
- if Reg_Op /= Reg_Res then
- Emit_Load (Reg_Res, Op, Sz_32l);
+ if Flags.M64 then
+ -- movsxd src, dst
+ Gen_Movsxd (Reg_Op, Reg_Res);
+ -- cmp src,dst
+ Start_Insn;
+ Init_Modrm_Reg (Reg_Op, Sz_64, Reg_Res, Sz_64);
+ Gen_8 (Opc_Cmpl_Rm_Reg);
+ Gen_Mod_Rm_Reg;
+ End_Insn;
+ else
+ pragma Assert (Reg_Op = R_Edx_Eax);
+ pragma Assert (Reg_Res = R_Ax);
+ -- move dx to reg_helper
+ Start_Insn;
+ Gen_8 (Opc_Mov_Rm_Reg + 1);
+ Gen_8 (2#11_010_000# + To_Reg32 (Reg_Helper));
+ End_Insn;
+ -- Sign extend eax.
+ Gen_Cdq (Sz_32);
+ -- cmp reg_helper, dx
+ Start_Insn;
+ Gen_8 (Opc_Cmpl_Rm_Reg);
+ Gen_8 (2#11_010_000# + To_Reg32 (Reg_Helper));
+ End_Insn;
end if;
- Gen_Cmp_Imm (Reg_Res, 16#Ff#, Sz_32l);
- Gen_Ov_Check (R_Ule);
- when Mode_B2 =>
- pragma Assert (Reg_Op in Regs_R64);
- -- Check MSB = 0
- Emit_Tst (Reg_Op, Sz_32h);
+ -- Overflow if extended value is different from initial value.
Gen_Ov_Check (R_Eq);
- -- Check LSB <= 1
- if Reg_Op /= Reg_Res then
- Emit_Load (Reg_Res, Op, Sz_32l);
- end if;
- Gen_Cmp_Imm (Reg_Res, 16#1#, Sz_32l);
+ when Mode_U8
+ | Mode_B2 =>
+ declare
+ Ubound : Int32;
+ begin
+ if Mode = Mode_B2 then
+ Ubound := 1;
+ else
+ Ubound := 16#ff#;
+ end if;
+
+ if Flags.M64 then
+ Emit_Load (Reg_Res, Op, Sz_64);
+ Start_Insn;
+ Init_Modrm_Reg (Reg_Res, Sz_64);
+ Gen_Insn_Grp1 (Opc2_Grp1_Cmp, Ubound);
+ End_Insn;
+ else
+ pragma Assert (Reg_Op in Regs_Pair);
+ -- Check MSB = 0
+ Emit_Tst (Reg_Op, Sz_32h);
+ Gen_Ov_Check (R_Eq);
+ -- Check LSB <= 255 (U8) or LSB <= 1 (B2)
+ if Reg_Op /= Reg_Res then
+ -- Move reg_op -> reg_res
+ -- FIXME: factorize with OE_Mov.
+ Start_Insn;
+ Init_Modrm_Reg (Reg_Op, Sz_32l, Reg_Res);
+ Gen_Insn_Sz (Opc_Mov_Reg_Rm, Sz_32);
+ Gen_Mod_Rm_Reg;
+ End_Insn;
+ end if;
+ Gen_Cmp_Imm (Reg_Res, Ubound, Sz_32);
+ end if;
+ end;
Gen_Ov_Check (R_Ule);
when Mode_F64 =>
- Emit_Push_32 (Op, Sz_32h);
- Emit_Push_32 (Op, Sz_32l);
- -- fild (%esp)
- Start_Insn;
- Gen_B8 (2#11011_111#);
- Gen_B8 (2#00_101_100#);
- Gen_B8 (2#00_100_100#);
- End_Insn;
- if Reg_Res in Regs_Xmm then
- -- fstp (%esp)
- Start_Insn;
- Gen_B8 (2#11011_00_1# + Mode_Fp_To_Mf (Mode_F64));
- Gen_B8 (2#00_011_100#);
- Gen_B8 (2#00_100_100#);
+ if Flags.M64 then
+ -- cvtsi2sd
+ Gen_SSE_Prefix (Mode_F64);
+ Init_Modrm_Expr (Op, Sz_64, Reg_Res);
+ Gen_SSE_Opc (Opc_Cvtsi2sd_Xmm_Rm);
+ Gen_Mod_Rm_Reg;
End_Insn;
- -- movsd (%esp), %xmm
+ else
+ Emit_Push (Op, Sz_32h);
+ Emit_Push (Op, Sz_32l);
+ -- fild (%esp)
Start_Insn;
- Gen_SSE_Rep_Opc (Mode_F64, 16#10#);
- Gen_B8 (To_Reg_Xmm (Reg_Res) * 8 + 2#00_000_100#);
- Gen_B8 (2#00_100_100#);
+ Gen_8 (2#11011_111#);
+ Gen_8 (2#00_101_100#);
+ Gen_8 (2#00_100_100#);
End_Insn;
+ if Reg_Res in Regs_Xmm then
+ -- fstp (%esp)
+ Start_Insn;
+ Gen_8 (2#11011_00_1# + Mode_Fp_To_Mf (Mode_F64));
+ Gen_8 (2#00_011_100#);
+ Gen_8 (2#00_100_100#);
+ End_Insn;
+ -- movsd (%esp), %xmm
+ Start_Insn;
+ Gen_SSE_Prefix (Mode_F64);
+ Gen_SSE_Opc (Opc_Movsd_Xmm_M64);
+ Gen_8 (To_Reg_Xmm (Reg_Res) * 8 + 2#00_000_100#);
+ Gen_8 (2#00_100_100#);
+ End_Insn;
+ end if;
+ -- addl %esp, 8
+ Emit_Addl_Sp_Imm (8);
end if;
- -- addl %esp, 8
- Emit_Addl_Sp_Imm (8);
when others =>
Error_Emit ("gen_conv_I64", Stmt);
end case;
@@ -1641,29 +1996,33 @@ package body Ortho_Code.X86.Emits is
Mode : constant Mode_Type := Get_Expr_Mode (Stmt);
Reg : constant O_Reg := Get_Expr_Reg (Stmt);
Reg_Op : constant O_Reg := Get_Expr_Reg (Get_Expr_Operand (Stmt));
+ Sslot : constant Int32 := -Int32 (Cur_Subprg.Target.Fp_Slot);
begin
- if Mode = Mode_I32 and then Reg_Op in Regs_Xmm then
+ if Abi.Flag_Sse2 and then
+ (Mode = Mode_I32 or (Flags.M64 and Mode = Mode_I64))
+ then
-- cvtsd2si
- Init_Modrm_Reg (Reg_Op, Sz_32l);
- Gen_SSE_Rep_Opc (Mode_F64, 16#2d#);
- Gen_Mod_Rm (To_Reg32 (Reg) * 8);
+ Gen_SSE_Prefix (Mode_F64);
+ Init_Modrm_Reg (Reg_Op, Int_Mode_To_Size (Mode), Reg);
+ Gen_SSE_Opc (Opc_Cvtsd2si_Reg_Xm);
+ Gen_Mod_Rm_Reg;
End_Insn;
return;
end if;
- Init_Modrm_Offset
- (R_Bp, -Int32 (Cur_Subprg.Target.Fp_Slot), Sz_32l);
-
if Reg_Op in Regs_Xmm then
-- movsd %xmm, (%ebp),
Start_Insn;
- Gen_SSE_Rep_Opc (Mode_F64, 16#11#);
- Gen_Mod_Rm (To_Reg_Xmm (Reg_Op) * 8);
+ Gen_SSE_Prefix (Mode_F64);
+ Init_Modrm_Offset (R_Bp, Sslot, Sz_Ptr, Reg_Op);
+ Gen_SSE_Opc (Opc_Movsd_M64_Xmm);
+ Gen_Mod_Rm_Reg;
End_Insn;
-- fldl slot(%ebp)
Start_Insn;
- Gen_B8 (2#11011_00_1# + Mode_Fp_To_Mf (Mode_F64));
- Gen_Mod_Rm (2#00_000_000#);
+ Init_Modrm_Offset (R_Bp, Sslot, Sz_Ptr);
+ Gen_8 (2#11011_00_1# + Mode_Fp_To_Mf (Mode_F64));
+ Gen_Mod_Rm_Opc (2#00_000_000#);
End_Insn;
end if;
@@ -1671,32 +2030,31 @@ package body Ortho_Code.X86.Emits is
when Mode_I32 =>
-- fistpl slot(%ebp)
Start_Insn;
- Gen_B8 (2#11011_011#);
- Gen_Mod_Rm (2#00_011_000#);
+ Init_Modrm_Offset (R_Bp, Sslot, Sz_32);
+ Gen_8 (2#11011_011#);
+ Gen_Mod_Rm_Opc (2#00_011_000#);
End_Insn;
-- movl slot(%ebp), reg
- -- Keep same modrm parameters.
Start_Insn;
- Gen_B8 (Opc_Movl_Reg_Rm);
- Gen_Mod_Rm (To_Reg32 (Reg, Sz_32l) * 8);
+ Init_Modrm_Offset (R_Bp, Sslot, Sz_32, Reg);
+ Gen_8 (Opc_Movl_Reg_Rm);
+ Gen_Mod_Rm_Reg;
End_Insn;
when Mode_I64 =>
-- fistpq slot(%ebp)
Start_Insn;
- Gen_B8 (2#11011_111#);
- Gen_Mod_Rm (2#00_111_000#);
+ Init_Modrm_Offset (R_Bp, Sslot, Sz_32);
+ Gen_8 (2#11011_111#);
+ Gen_Mod_Rm_Opc (2#00_111_000#);
End_Insn;
-- movl slot(%ebp), reg
- -- Keep same modrm parameters.
- Start_Insn;
- Gen_B8 (Opc_Movl_Reg_Rm);
- Gen_Mod_Rm (To_Reg32 (Reg, Sz_32l) * 8);
- End_Insn;
- Rm_Offset := Rm_Offset + 4;
- Start_Insn;
- Gen_B8 (Opc_Movl_Reg_Rm);
- Gen_Mod_Rm (To_Reg32 (Reg, Sz_32h) * 8);
- End_Insn;
+ for Sz in Sz_32l .. Sz_32h loop
+ Start_Insn;
+ Init_Modrm_Offset (R_Bp, Sslot, Sz, Reg);
+ Gen_8 (Opc_Movl_Reg_Rm);
+ Gen_Mod_Rm_Reg;
+ End_Insn;
+ end loop;
when others =>
Error_Emit ("gen_conv_fp", Stmt);
end case;
@@ -1708,11 +2066,15 @@ package body Ortho_Code.X86.Emits is
when Mode_U32
| Mode_I32
| Mode_P32 =>
- Gen_Grp1_Insn (Cl, Stmt, Sz_32l);
+ Gen_Grp1_Insn (Cl, Stmt, Sz_32);
when Mode_I64
| Mode_U64 =>
- Gen_Grp1_Insn (Cl, Stmt, Sz_32l);
- Gen_Grp1_Insn (Ch, Stmt, Sz_32h);
+ if Flags.M64 then
+ Gen_Grp1_Insn (Cl, Stmt, Sz_64);
+ else
+ Gen_Grp1_Insn (Cl, Stmt, Sz_32l);
+ Gen_Grp1_Insn (Ch, Stmt, Sz_32h);
+ end if;
when Mode_B2
| Mode_I8
| Mode_U8 =>
@@ -1743,17 +2105,15 @@ package body Ortho_Code.X86.Emits is
procedure Gen_Emit_Fp_Op (Stmt : O_Enode; Fp_Op : Byte)
is
- Right : O_Enode;
- Reg : O_Reg;
+ Right : constant O_Enode := Get_Expr_Right (Stmt);
+ Reg : constant O_Reg := Get_Expr_Reg (Right);
B_Size : Byte;
begin
- Right := Get_Expr_Right (Stmt);
- Reg := Get_Expr_Reg (Right);
Start_Insn;
case Reg is
when R_St0 =>
- Gen_B8 (2#11011_110#);
- Gen_B8 (2#11_000_001# or Fp_Op);
+ Gen_8 (2#11011_110#);
+ Gen_8 (2#11_000_001# or Fp_Op);
when R_Mem =>
case Get_Expr_Mode (Stmt) is
when Mode_F32 =>
@@ -1763,9 +2123,9 @@ package body Ortho_Code.X86.Emits is
when others =>
raise Program_Error;
end case;
- Gen_B8 (2#11011_000# or B_Size);
- Init_Modrm_Mem (Right, Sz_32l);
- Gen_Mod_Rm (Fp_Op);
+ Init_Modrm_Mem (Right, Sz_Ptr);
+ Gen_8 (2#11011_000# or B_Size);
+ Gen_Mod_Rm_Opc (Fp_Op);
when others =>
raise Program_Error;
end case;
@@ -1782,15 +2142,19 @@ package body Ortho_Code.X86.Emits is
Mode : constant Mode_Type := Get_Expr_Mode (Stmt);
Right : constant O_Enode := Get_Expr_Right (Stmt);
begin
- Init_Rm_Expr (Right, Sz_32l);
- Gen_Xmm_Modrm (Mode, Xmm_Op, Reg);
+ Start_Insn;
+ Gen_SSE_Prefix (Mode);
+ Init_Modrm_Expr (Right, Sz_32, Reg);
+ Gen_SSE_Opc (Xmm_Op);
+ Gen_Mod_Rm_Reg;
+ End_Insn;
end;
else
Gen_Emit_Fp_Op (Stmt, Fp_Op);
end if;
end Gen_Emit_Fp_Or_Xmm_Op;
- procedure Emit_Mod (Stmt : O_Enode)
+ procedure Emit_Mod (Stmt : O_Enode; Sz : Insn_Size)
is
Right : O_Enode;
Pc1, Pc2, Pc3: Pc_Type;
@@ -1812,36 +2176,42 @@ package body Ortho_Code.X86.Emits is
-- end if
Right := Get_Expr_Right (Stmt);
-- %edx <- right
- Emit_Load (R_Dx, Right, Sz_32l);
+ Emit_Load (R_Dx, Right, Sz);
-- xorl %eax -> %edx
Start_Insn;
- Gen_B8 (Opc_Xorl_Rm_Reg);
- Gen_B8 (2#11_000_010#);
+ Gen_Rex_B (R_None, Sz);
+ Gen_8 (Opc_Xorl_Rm_Reg);
+ Gen_8 (2#11_000_010#);
End_Insn;
- Gen_Cdq;
+ Gen_Cdq (Sz);
-- js
Gen_2 (Opc_Jcc + 2#1000#, 0);
Pc1 := Get_Current_Pc;
-- idiv
- Gen_Grp3_Insn (Opc2_Grp3_Idiv, Right, Sz_32l);
+ Gen_Grp3_Insn (Opc2_Grp3_Idiv, Right, Sz);
-- jmp
Gen_2 (Opc_Jmp_Short, 0);
Pc2 := Get_Current_Pc;
- Patch_B8 (Pc1 - 1, Unsigned_8 (Get_Current_Pc - Pc1));
+ Patch_8 (Pc1 - 1, Unsigned_8 (Get_Current_Pc - Pc1));
-- idiv
- Gen_Grp3_Insn (Opc2_Grp3_Idiv, Right, Sz_32l);
+ Gen_Grp3_Insn (Opc2_Grp3_Idiv, Right, Sz);
-- tstl %edx,%edx
- Gen_2 (Opc_Test_Rm_Reg + 1, 2#11_010_010#);
+ Start_Insn;
+ Gen_Rex_B (R_None, Sz);
+ Gen_8 (Opc_Test_Rm_Reg + 1);
+ Gen_8 (2#11_010_010#);
+ End_Insn;
-- jz
Gen_2 (Opc_Jcc + 2#0100#, 0);
Pc3 := Get_Current_Pc;
-- addl b, %edx
Start_Insn;
- Gen_B8 (Opc_Addl_Reg_Rm);
- Gen_Rm (2#010_000#, Right, Sz_32l);
+ Init_Modrm_Expr (Right, Sz, R_Dx);
+ Gen_8 (Opc_Addl_Reg_Rm);
+ Gen_Mod_Rm_Reg;
End_Insn;
- Patch_B8 (Pc2 - 1, Unsigned_8 (Get_Current_Pc - Pc2));
- Patch_B8 (Pc3 - 1, Unsigned_8 (Get_Current_Pc - Pc3));
+ Patch_8 (Pc2 - 1, Unsigned_8 (Get_Current_Pc - Pc2));
+ Patch_8 (Pc3 - 1, Unsigned_8 (Get_Current_Pc - Pc3));
end Emit_Mod;
procedure Emit_Insn (Stmt : O_Enode)
@@ -1894,10 +2264,14 @@ package body Ortho_Code.X86.Emits is
when Mode_U16 =>
Gen_Umul (Stmt, Sz_16);
when Mode_U32 =>
- Gen_Mul (Stmt, Sz_32l);
+ Gen_Mul (Stmt, Sz_32);
when Mode_I32 =>
- Gen_Grp3_Insn (Opc2_Grp3_Imul,
- Get_Expr_Right (Stmt), Sz_32l);
+ Gen_Grp3_Insn (Opc2_Grp3_Imul, Get_Expr_Right (Stmt), Sz_32);
+ when Mode_I64 =>
+ Gen_Grp3_Insn (Opc2_Grp3_Imul, Get_Expr_Right (Stmt), Sz_64);
+ when Mode_U64 =>
+ pragma Assert (Flags.M64);
+ Gen_Mul (Stmt, Sz_64);
when Mode_F32
| Mode_F64 =>
Gen_Emit_Fp_Or_Xmm_Op (Stmt, 2#001_000#, 16#59#);
@@ -1912,7 +2286,7 @@ package body Ortho_Code.X86.Emits is
begin
case Mode is
when Mode_U32 =>
- Sz := Sz_32l;
+ Sz := Sz_32;
when others =>
Error_Emit ("emit_insn: shl", Stmt);
end case;
@@ -1920,20 +2294,22 @@ package body Ortho_Code.X86.Emits is
if Get_Expr_Kind (Right) = OE_Const then
Val := Get_Expr_Low (Right);
Start_Insn;
+ Init_Modrm_Expr (Get_Expr_Left (Stmt), Sz);
if Val = 1 then
Gen_Insn_Sz (2#1101000_0#, Sz);
- Gen_Rm (2#100_000#, Get_Expr_Left (Stmt), Sz);
+ Gen_Mod_Rm_Opc (2#100_000#);
else
Gen_Insn_Sz (2#1100000_0#, Sz);
- Gen_Rm (2#100_000#, Get_Expr_Left (Stmt), Sz);
- Gen_B8 (Byte (Val and 31));
+ Gen_Mod_Rm_Opc (2#100_000#);
+ Gen_8 (Byte (Val and 31));
end if;
End_Insn;
else
pragma Assert (Get_Expr_Reg (Right) = R_Cx);
Start_Insn;
+ Init_Modrm_Expr (Get_Expr_Left (Stmt), Sz);
Gen_Insn_Sz (2#1101001_0#, Sz);
- Gen_Rm (2#100_000#, Get_Expr_Left (Stmt), Sz);
+ Gen_Mod_Rm_Opc (2#100_000#);
End_Insn;
end if;
end;
@@ -1941,17 +2317,24 @@ package body Ortho_Code.X86.Emits is
| OE_Rem
| OE_Div_Ov =>
case Mode is
- when Mode_U32 =>
+ when Mode_U32
+ | Mode_U64 =>
Gen_Clear_Edx;
- Gen_Grp3_Insn (Opc2_Grp3_Div, Get_Expr_Right (Stmt), Sz_32l);
- when Mode_I32 =>
- if Kind = OE_Mod then
- Emit_Mod (Stmt);
- else
- Gen_Cdq;
- Gen_Grp3_Insn
- (Opc2_Grp3_Idiv, Get_Expr_Right (Stmt), Sz_32l);
- end if;
+ Gen_Grp3_Insn (Opc2_Grp3_Div, Get_Expr_Right (Stmt),
+ Int_Mode_To_Size (Mode));
+ when Mode_I32
+ | Mode_I64 =>
+ declare
+ Sz : constant Insn_Size := Int_Mode_To_Size (Mode);
+ begin
+ if Kind = OE_Mod then
+ Emit_Mod (Stmt, Sz);
+ else
+ Gen_Cdq (Sz);
+ Gen_Grp3_Insn
+ (Opc2_Grp3_Idiv, Get_Expr_Right (Stmt), Sz);
+ end if;
+ end;
when Mode_F32
| Mode_F64 =>
-- No Mod or Rem for fp types.
@@ -1966,19 +2349,24 @@ package body Ortho_Code.X86.Emits is
when Mode_B2 =>
-- Xor VAL, $1
Start_Insn;
- Gen_B8 (Opc_Grp1v_Rm_Imm8);
- Gen_Rm (Opc2_Grp1_Xor, Stmt, Sz_8);
- Gen_B8 (16#01#);
+ Init_Modrm_Expr (Stmt, Sz_8);
+ Gen_8 (Opc_Grp1v_Rm_Imm8);
+ Gen_Mod_Rm_Opc (Opc2_Grp1_Xor);
+ Gen_8 (16#01#);
End_Insn;
when Mode_U8 =>
Gen_Grp3_Insn_Stmt (Opc2_Grp3_Not, Stmt, Sz_8);
when Mode_U16 =>
Gen_Grp3_Insn_Stmt (Opc2_Grp3_Not, Stmt, Sz_16);
when Mode_U32 =>
- Gen_Grp3_Insn_Stmt (Opc2_Grp3_Not, Stmt, Sz_32l);
+ Gen_Grp3_Insn_Stmt (Opc2_Grp3_Not, Stmt, Sz_32);
when Mode_U64 =>
- Gen_Grp3_Insn_Stmt (Opc2_Grp3_Not, Stmt, Sz_32l);
- Gen_Grp3_Insn_Stmt (Opc2_Grp3_Not, Stmt, Sz_32h);
+ if Flags.M64 then
+ Gen_Grp3_Insn_Stmt (Opc2_Grp3_Not, Stmt, Sz_64);
+ else
+ Gen_Grp3_Insn_Stmt (Opc2_Grp3_Not, Stmt, Sz_32l);
+ Gen_Grp3_Insn_Stmt (Opc2_Grp3_Not, Stmt, Sz_32h);
+ end if;
when others =>
Error_Emit ("emit_insn: not", Stmt);
end case;
@@ -1992,27 +2380,32 @@ package body Ortho_Code.X86.Emits is
Gen_Grp3_Insn_Stmt (Opc2_Grp3_Neg, Stmt, Sz_16);
--Gen_Into;
when Mode_I32 =>
- Gen_Grp3_Insn_Stmt (Opc2_Grp3_Neg, Stmt, Sz_32l);
+ Gen_Grp3_Insn_Stmt (Opc2_Grp3_Neg, Stmt, Sz_32);
--Gen_Into;
when Mode_I64 =>
- Gen_Grp3_Insn_Stmt (Opc2_Grp3_Neg, Stmt, Sz_32l);
- -- adcl 0, high
- Start_Insn;
- Gen_B8 (Opc_Grp1v_Rm_Imm8);
- Gen_Rm (Opc2_Grp1_Adc, Get_Expr_Operand (Stmt), Sz_32h);
- Gen_B8 (0);
- End_Insn;
- Gen_Grp3_Insn_Stmt (Opc2_Grp3_Neg, Stmt, Sz_32h);
- --Gen_Into;
+ if Flags.M64 then
+ Gen_Grp3_Insn_Stmt (Opc2_Grp3_Neg, Stmt, Sz_64);
+ else
+ Gen_Grp3_Insn_Stmt (Opc2_Grp3_Neg, Stmt, Sz_32l);
+ -- adcl 0, high
+ Start_Insn;
+ Init_Modrm_Expr (Get_Expr_Operand (Stmt), Sz_32h);
+ Gen_8 (Opc_Grp1v_Rm_Imm8);
+ Gen_Mod_Rm_Opc (Opc2_Grp1_Adc);
+ Gen_8 (0);
+ End_Insn;
+ Gen_Grp3_Insn_Stmt (Opc2_Grp3_Neg, Stmt, Sz_32h);
+ --Gen_Into;
+ end if;
when Mode_F32
| Mode_F64 =>
Reg := Get_Expr_Reg (Stmt);
if Reg in Regs_Xmm then
-- Xorp{sd} reg, cst
- Init_Modrm_Sym (Get_Xmm_Sign_Constant (Mode), Sz_32l);
Start_Insn;
+ Init_Modrm_Sym (Get_Xmm_Sign_Constant (Mode), Sz_32, Reg);
Gen_SSE_D16_Opc (Mode, Opc2_0f_Xorp);
- Gen_Mod_Rm (Xmm_To_Modrm_Reg (Reg));
+ Gen_Mod_Rm_Reg;
End_Insn;
else
-- fchs
@@ -2032,10 +2425,10 @@ package body Ortho_Code.X86.Emits is
Reg := Get_Expr_Reg (Stmt);
if Reg in Regs_Xmm then
-- Andp{sd} reg, cst
- Init_Modrm_Sym (Get_Xmm_Mask_Constant (Mode), Sz_32l);
Start_Insn;
+ Init_Modrm_Sym (Get_Xmm_Mask_Constant (Mode), Sz_32, Reg);
Gen_SSE_D16_Opc (Mode, Opc2_0f_Andp);
- Gen_Mod_Rm (Xmm_To_Modrm_Reg (Reg));
+ Gen_Mod_Rm_Reg;
End_Insn;
else
-- fabs
@@ -2054,65 +2447,70 @@ package body Ortho_Code.X86.Emits is
when Mode_U32
| Mode_I32
| Mode_P32 =>
- Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_32l);
+ Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_32);
when Mode_B2
| Mode_I8
| Mode_U8 =>
Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_8);
- when Mode_U64 =>
- declare
- Pc : Pc_Type;
- begin
- Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_32h);
- -- jne
- Start_Insn;
- Gen_B8 (Opc_Jcc + 2#0101#);
- Gen_B8 (0);
- End_Insn;
- Pc := Get_Current_Pc;
- Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_32l);
- Patch_B8 (Pc - 1, Unsigned_8 (Get_Current_Pc - Pc));
- end;
+ when Mode_U64
+ | Mode_P64 =>
+ if Flags.M64 then
+ Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_64);
+ else
+ declare
+ Pc : Pc_Type;
+ begin
+ Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_32h);
+ -- jne
+ Gen_2 (Opc_Jcc + 2#0101#, 0);
+ Pc := Get_Current_Pc;
+ Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_32l);
+ Patch_8 (Pc - 1, Unsigned_8 (Get_Current_Pc - Pc));
+ end;
+ end if;
when Mode_I64 =>
- declare
- Pc : Pc_Type;
- begin
- Reg := Get_Expr_Reg (Stmt);
- Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_32h);
- -- Note: this does not clobber a reg due to care in
- -- insns.
- Emit_Setcc_Reg (Reg, Insns.Ekind_Signed_To_Cc (Kind));
- -- jne
- Start_Insn;
- Gen_B8 (Opc_Jcc + 2#0101#);
- Gen_B8 (0);
- End_Insn;
- Pc := Get_Current_Pc;
- Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_32l);
- Emit_Setcc_Reg
- (Reg, Insns.Ekind_Unsigned_To_Cc (Kind));
- Patch_B8 (Pc - 1, Unsigned_8 (Get_Current_Pc - Pc));
- return;
- end;
+ if Flags.M64 then
+ Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_64);
+ else
+ declare
+ Pc : Pc_Type;
+ begin
+ Reg := Get_Expr_Reg (Stmt);
+ Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_32h);
+ -- Note: this does not clobber a reg due to care in
+ -- insns.
+ Emit_Setcc_Reg
+ (Reg, Insns.Ekind_Signed_To_Cc (Kind));
+ -- jne
+ Gen_2 (Opc_Jcc + 2#0101#, 0);
+ Pc := Get_Current_Pc;
+ Gen_Grp1_Insn (Opc2_Grp1_Cmp, Stmt, Sz_32l);
+ Emit_Setcc_Reg
+ (Reg, Insns.Ekind_Unsigned_To_Cc (Kind));
+ Patch_8 (Pc - 1, Unsigned_8 (Get_Current_Pc - Pc));
+ return;
+ end;
+ end if;
when Mode_F32
| Mode_F64 =>
if Abi.Flag_Sse2 then
-- comisd %xmm, rm
Start_Insn;
+ Init_Modrm_Expr (Get_Expr_Right (Stmt), Sz_32,
+ Get_Expr_Reg (Left));
Gen_SSE_D16_Opc (Op_Mode, 16#2f#);
- Init_Rm_Expr (Get_Expr_Right (Stmt), Sz_32l);
- Gen_Mod_Rm (To_Reg_Xmm (Get_Expr_Reg (Left)) * 8);
+ Gen_Mod_Rm_Reg;
End_Insn;
else
-- fcomip st, st(1)
Start_Insn;
- Gen_B8 (2#11011_111#);
- Gen_B8 (2#1111_0001#);
+ Gen_8 (2#11011_111#);
+ Gen_8 (2#1111_0001#);
End_Insn;
-- fstp st, st (0)
Start_Insn;
- Gen_B8 (2#11011_101#);
- Gen_B8 (2#11_011_000#);
+ Gen_8 (2#11011_101#);
+ Gen_8 (2#11_011_000#);
End_Insn;
end if;
when others =>
@@ -2121,21 +2519,36 @@ package body Ortho_Code.X86.Emits is
-- Result is in eflags.
pragma Assert (Get_Expr_Reg (Stmt) in Regs_Cc);
end;
- when OE_Const
- | OE_Addrg =>
+ when OE_Addrg =>
+ pragma Assert (Mode = Abi.Mode_Ptr);
+ if Flags.M64
+ and then not Insns.Is_External_Object (Get_Addr_Object (Stmt))
+ then
+ -- Use RIP relative to load an address.
+ Emit_Lea (Stmt);
+ else
+ Emit_Load_Imm (Stmt, Sz_Ptr);
+ end if;
+ when OE_Const =>
case Mode is
- when Mode_U32
- | Mode_I32
- | Mode_P32 =>
- Emit_Load_Imm (Stmt, Sz_32l);
when Mode_B2
| Mode_U8
| Mode_I8 =>
Emit_Load_Imm (Stmt, Sz_8);
+ when Mode_U32
+ | Mode_I32
+ | Mode_P32 =>
+ Emit_Load_Imm (Stmt, Sz_32);
when Mode_I64
- | Mode_U64 =>
- Emit_Load_Imm (Stmt, Sz_32l);
- Emit_Load_Imm (Stmt, Sz_32h);
+ | Mode_U64
+ | Mode_P64 =>
+ if Flags.M64 then
+ Emit_Load_Imm (Stmt, Sz_64);
+ else
+ pragma Assert (Mode /= Mode_P64);
+ Emit_Load_Imm (Stmt, Sz_32l);
+ Emit_Load_Imm (Stmt, Sz_32h);
+ end if;
when Mode_Fp =>
Emit_Load_Fp (Stmt, Mode);
when others =>
@@ -2146,15 +2559,21 @@ package body Ortho_Code.X86.Emits is
when Mode_U32
| Mode_I32
| Mode_P32 =>
- Emit_Load_Mem (Stmt, Sz_32l);
+ Emit_Load_Mem (Stmt, Sz_32);
when Mode_B2
| Mode_U8
| Mode_I8 =>
Emit_Load_Mem (Stmt, Sz_8);
when Mode_U64
- | Mode_I64 =>
- Emit_Load_Mem (Stmt, Sz_32l);
- Emit_Load_Mem (Stmt, Sz_32h);
+ | Mode_I64
+ | Mode_P64 =>
+ if Flags.M64 then
+ Emit_Load_Mem (Stmt, Sz_64);
+ else
+ pragma Assert (Mode /= Mode_P64);
+ Emit_Load_Mem (Stmt, Sz_32l);
+ Emit_Load_Mem (Stmt, Sz_32h);
+ end if;
when Mode_Fp =>
Emit_Load_Fp_Mem (Stmt, Mode);
when others =>
@@ -2186,15 +2605,20 @@ package body Ortho_Code.X86.Emits is
when Mode_U32
| Mode_I32
| Mode_P32 =>
- Emit_Store (Stmt, Sz_32l);
+ Emit_Store (Stmt, Sz_32);
when Mode_B2
| Mode_U8
| Mode_I8 =>
Emit_Store (Stmt, Sz_8);
when Mode_U64
- | Mode_I64 =>
- Emit_Store (Stmt, Sz_32l);
- Emit_Store (Stmt, Sz_32h);
+ | Mode_I64
+ | Mode_P64 =>
+ if Flags.M64 then
+ Emit_Store (Stmt, Sz_64);
+ else
+ Emit_Store (Stmt, Sz_32l);
+ Emit_Store (Stmt, Sz_32h);
+ end if;
when Mode_Fp =>
if Abi.Flag_Sse2 then
Emit_Store_Xmm (Stmt, Mode);
@@ -2231,11 +2655,16 @@ package body Ortho_Code.X86.Emits is
when Mode_U32
| Mode_I32
| Mode_P32 =>
- Emit_Push_32 (Get_Expr_Operand (Stmt), Sz_32l);
+ Emit_Push (Get_Expr_Operand (Stmt), Sz_32);
when Mode_U64
- | Mode_I64 =>
- Emit_Push_32 (Get_Expr_Operand (Stmt), Sz_32h);
- Emit_Push_32 (Get_Expr_Operand (Stmt), Sz_32l);
+ | Mode_I64
+ | Mode_P64 =>
+ if Flags.M64 then
+ Emit_Push (Get_Expr_Operand (Stmt), Sz_64);
+ else
+ Emit_Push (Get_Expr_Operand (Stmt), Sz_32h);
+ Emit_Push (Get_Expr_Operand (Stmt), Sz_32l);
+ end if;
when Mode_Fp =>
Emit_Push_Fp (Get_Expr_Operand (Stmt), Mode);
when others =>
@@ -2256,10 +2685,10 @@ package body Ortho_Code.X86.Emits is
Reg := Get_Expr_Reg (Stmt);
case Mode is
when Mode_B2 =>
- if Reg in Regs_R32 and then Op_Reg in Regs_Cc then
+ if Reg in Regs_R64 and then Op_Reg in Regs_Cc then
Emit_Setcc (Stmt, Op_Reg);
elsif (Reg = R_Eq or Reg = R_Ne)
- and then Op_Reg in Regs_R32
+ and then Op_Reg in Regs_R64
then
Emit_Tst (Op_Reg, Sz_8);
else
@@ -2267,22 +2696,26 @@ package body Ortho_Code.X86.Emits is
end if;
when Mode_U32
| Mode_I32 =>
- -- mov REG, OP
- Start_Insn;
- Gen_Insn_Sz (Opc_Mov_Reg_Rm, Sz_32l);
- Gen_Rm (To_Reg32 (Reg, Sz_32l) * 8, Operand, Sz_32l);
- End_Insn;
+ Emit_Move (Operand, Sz_32, Reg);
+ when Mode_U64
+ | Mode_I64
+ | Mode_P64 =>
+ pragma Assert (Flags.M64);
+ Emit_Move (Operand, Sz_64, Reg);
+ when Mode_F64
+ | Mode_F32 =>
+ Emit_Move_Xmm (Operand, Mode, Reg);
when others =>
Error_Emit ("emit_insn: move", Stmt);
end case;
end;
when OE_Alloca =>
- pragma Assert (Mode = Mode_P32);
+ pragma Assert (Mode = Abi.Mode_Ptr);
Gen_Alloca (Stmt);
when OE_Set_Stack =>
- Emit_Load_Mem (Stmt, Sz_32l);
+ Emit_Load_Mem (Stmt, Sz_Ptr);
when OE_Add
| OE_Addrl =>
@@ -2291,6 +2724,11 @@ package body Ortho_Code.X86.Emits is
| Mode_I32
| Mode_P32 =>
Emit_Lea (Stmt);
+ when Mode_U64
+ | Mode_I64
+ | Mode_P64 =>
+ pragma Assert (Flags.M64);
+ Emit_Lea (Stmt);
when others =>
Error_Emit ("emit_insn: oe_add", Stmt);
end case;
@@ -2304,11 +2742,16 @@ package body Ortho_Code.X86.Emits is
when Mode_U32
| Mode_I32
| Mode_P32 =>
- Emit_Spill (Stmt, Sz_32l);
+ Emit_Spill (Stmt, Sz_32);
when Mode_U64
- | Mode_I64 =>
- Emit_Spill (Stmt, Sz_32l);
- Emit_Spill (Stmt, Sz_32h);
+ | Mode_I64
+ | Mode_P64 =>
+ if Flags.M64 then
+ Emit_Spill (Stmt, Sz_64);
+ else
+ Emit_Spill (Stmt, Sz_32l);
+ Emit_Spill (Stmt, Sz_32h);
+ end if;
when Mode_F32
| Mode_F64 =>
Emit_Spill_Xmm (Stmt, Mode);
@@ -2329,19 +2772,25 @@ package body Ortho_Code.X86.Emits is
when Mode_U32
| Mode_I32
| Mode_P32 =>
- Emit_Load (Reg, Expr, Sz_32l);
+ Emit_Load (Reg, Expr, Sz_32);
when Mode_U64
- | Mode_I64 =>
- Emit_Load (Reg, Expr, Sz_32l);
- Emit_Load (Reg, Expr, Sz_32h);
+ | Mode_I64
+ | Mode_P64 =>
+ if Flags.M64 then
+ Emit_Load (Reg, Expr, Sz_64);
+ else
+ Emit_Load (Reg, Expr, Sz_32l);
+ Emit_Load (Reg, Expr, Sz_32h);
+ end if;
when Mode_F32
| Mode_F64 =>
pragma Assert (Reg in Regs_Xmm);
-- movsd
- Init_Modrm_Mem (Expr, Sz_32l);
Start_Insn;
- Gen_SSE_Rep_Opc (Mode_F64, 16#10#);
- Gen_Mod_Rm (To_Reg_Xmm (Reg) * 8);
+ Gen_SSE_Prefix (Mode_F64);
+ Init_Modrm_Mem (Expr, Sz_Fp, Reg);
+ Gen_SSE_Opc (Opc_Movsd_Xmm_M64);
+ Gen_Mod_Rm_Reg;
End_Insn;
when others =>
Error_Emit ("emit_insn: reload", Stmt);
@@ -2365,21 +2814,33 @@ package body Ortho_Code.X86.Emits is
end case;
end Emit_Insn;
- procedure Push_Reg_If_Used (Reg : Regs_R32)
+ function Get_Preserved_Regs return O_Reg_Array is
+ begin
+ if Flags.M64 then
+ return Preserved_Regs_64;
+ else
+ return Preserved_Regs_32;
+ end if;
+ end Get_Preserved_Regs;
+
+ -- List of registers preserved accross calls.
+ Preserved_Regs : constant O_Reg_Array := Get_Preserved_Regs;
+
+ procedure Push_Reg_If_Used (Reg : Regs_R64)
is
use Ortho_Code.X86.Insns;
begin
if Reg_Used (Reg) then
- Gen_1 (Opc_Push_Reg + To_Reg32 (Reg, Sz_32l));
+ Gen_Push_Pop_Reg (Opc_Push_Reg, Reg, Sz_Ptr);
end if;
end Push_Reg_If_Used;
- procedure Pop_Reg_If_Used (Reg : Regs_R32)
+ procedure Pop_Reg_If_Used (Reg : Regs_R64)
is
use Ortho_Code.X86.Insns;
begin
if Reg_Used (Reg) then
- Gen_1 (Opc_Pop_Reg + To_Reg32 (Reg, Sz_32l));
+ Gen_Push_Pop_Reg (Opc_Pop_Reg, Reg, Sz_Ptr);
end if;
end Pop_Reg_If_Used;
@@ -2393,6 +2854,7 @@ package body Ortho_Code.X86.Emits is
Is_Global : Boolean;
Frame_Size : Unsigned_32;
Saved_Regs_Size : Unsigned_32;
+ Has_Fp_Inter : Boolean;
begin
-- Switch to .text section and align the function (to avoid the nested
-- function trick and for performance).
@@ -2412,52 +2874,110 @@ package body Ortho_Code.X86.Emits is
Set_Symbol_Pc (Sym, Is_Global);
Subprg_Pc := Get_Current_Pc;
- Saved_Regs_Size := Boolean'Pos (Reg_Used (R_Di)) * 4
- + Boolean'Pos (Reg_Used (R_Si)) * 4
- + Boolean'Pos (Reg_Used (R_Bx)) * 4;
+ -- Return address and saved frame pointer are preserved.
+ Saved_Regs_Size := 2;
+ for I in Preserved_Regs'Range loop
+ if Reg_Used (Preserved_Regs (I)) then
+ Saved_Regs_Size := Saved_Regs_Size + 1;
+ end if;
+ end loop;
+ if Flags.M64 then
+ Saved_Regs_Size := Saved_Regs_Size * 8;
+ else
+ Saved_Regs_Size := Saved_Regs_Size * 4;
+ end if;
-- Compute frame size.
- -- 8 bytes are used by return address and saved frame pointer.
- Frame_Size := Unsigned_32 (Subprg.Stack_Max) + 8 + Saved_Regs_Size;
+ Frame_Size := Unsigned_32 (Subprg.Stack_Max) + Saved_Regs_Size;
-- Align.
Frame_Size := (Frame_Size + X86.Flags.Stack_Boundary - 1)
and not (X86.Flags.Stack_Boundary - 1);
- -- The 8 bytes are already allocated.
- Frame_Size := Frame_Size - 8 - Saved_Regs_Size;
+ -- The bytes for saved regs are already allocated.
+ Frame_Size := Frame_Size - Saved_Regs_Size;
-- Emit prolog.
- -- push %ebp
- Gen_1 (Opc_Push_Reg + To_Reg32 (R_Bp));
- -- movl %esp, %ebp
+ -- push %ebp / push %rbp
+ Gen_Push_Pop_Reg (Opc_Push_Reg, R_Bp, Sz_Ptr);
+ -- movl %esp, %ebp / movl %rsp, %rbp
Start_Insn;
- Gen_B8 (Opc_Mov_Rm_Reg + 1);
- Gen_B8 (2#11_100_101#);
+ Gen_Rex (16#48#);
+ Gen_8 (Opc_Mov_Rm_Reg + 1);
+ Gen_8 (2#11_100_101#);
End_Insn;
- -- subl XXX, %esp
+
+ -- Save int registers.
+ Has_Fp_Inter := False;
+ if Flags.M64 then
+ declare
+ Inter : O_Dnode;
+ R : O_Reg;
+ begin
+ Inter := Get_Subprg_Interfaces (Subprg.D_Decl);
+ while Inter /= O_Dnode_Null loop
+ R := Get_Decl_Reg (Inter);
+ if R in Regs_R64 then
+ Gen_Push_Pop_Reg (Opc_Push_Reg, R, Sz_Ptr);
+ Frame_Size := Frame_Size - 8;
+ elsif R in Regs_Xmm then
+ Has_Fp_Inter := True;
+ else
+ pragma Assert (R = R_None);
+ null;
+ end if;
+ Inter := Get_Interface_Chain (Inter);
+ end loop;
+ end;
+ end if;
+
+ -- subl XXX, %esp / subl XXX, %rsp
if Frame_Size /= 0 then
if not X86.Flags.Flag_Alloca_Call
or else Frame_Size <= 4096
then
- Init_Modrm_Reg (R_Sp, Sz_32l);
- Gen_Insn_Grp1 (Opc2_Grp1_Sub, Sz_32l, Int32 (Frame_Size));
+ Start_Insn;
+ Init_Modrm_Reg (R_Sp, Sz_Ptr);
+ Gen_Insn_Grp1 (Opc2_Grp1_Sub, Int32 (Frame_Size));
+ End_Insn;
else
+ pragma Assert (not Flags.M64);
-- mov stack_size,%eax
Start_Insn;
- Gen_B8 (Opc_Movl_Imm_Reg + To_Reg32 (R_Ax));
- Gen_Le32 (Frame_Size);
+ Gen_8 (Opc_Movl_Imm_Reg + To_Reg32 (R_Ax));
+ Gen_32 (Frame_Size);
End_Insn;
Gen_Call (Chkstk_Symbol);
end if;
end if;
+ if Flags.M64 and Has_Fp_Inter then
+ declare
+ Inter : O_Dnode;
+ R : O_Reg;
+ begin
+ Inter := Get_Subprg_Interfaces (Subprg.D_Decl);
+ while Inter /= O_Dnode_Null loop
+ R := Get_Decl_Reg (Inter);
+ if R in Regs_Xmm then
+ Start_Insn;
+ Gen_SSE_Prefix (Mode_F64);
+ Init_Modrm_Offset (R_Bp, Get_Local_Offset (Inter), Sz_Fp, R);
+ Gen_SSE_Opc (Opc_Movsd_M64_Xmm);
+ Gen_Mod_Rm_Reg;
+ End_Insn;
+ end if;
+ Inter := Get_Interface_Chain (Inter);
+ end loop;
+ end;
+ end if;
+
if Flag_Profile then
Gen_Call (Mcount_Symbol);
end if;
-- Save registers.
- Push_Reg_If_Used (R_Di);
- Push_Reg_If_Used (R_Si);
- Push_Reg_If_Used (R_Bx);
+ for I in Preserved_Regs'Range loop
+ Push_Reg_If_Used (Preserved_Regs (I));
+ end loop;
end Emit_Prologue;
procedure Emit_Epilogue (Subprg : Subprogram_Data_Acc)
@@ -2469,9 +2989,9 @@ package body Ortho_Code.X86.Emits is
Mode : Mode_Type;
begin
-- Restore registers.
- Pop_Reg_If_Used (R_Bx);
- Pop_Reg_If_Used (R_Si);
- Pop_Reg_If_Used (R_Di);
+ for I in reverse Preserved_Regs'Range loop
+ Pop_Reg_If_Used (Preserved_Regs (I));
+ end loop;
Decl := Subprg.D_Decl;
if Get_Decl_Kind (Decl) = OD_Function then
@@ -2481,30 +3001,32 @@ package body Ortho_Code.X86.Emits is
| Mode_B2 =>
-- movzx %al,%eax
Start_Insn;
- Gen_B8 (Opc_0f);
- Gen_B8 (Opc2_0f_Movzx);
- Gen_B8 (2#11_000_000#);
+ Gen_8 (Opc_0f);
+ Gen_8 (Opc2_0f_Movzx);
+ Gen_8 (2#11_000_000#);
End_Insn;
when Mode_U32
| Mode_I32
| Mode_U64
| Mode_I64
- | Mode_P32 =>
+ | Mode_P32
+ | Mode_P64 =>
null;
when Mode_F32
| Mode_F64 =>
- if Abi.Flag_Sse2 then
+ if Abi.Flag_Sse2 and not Flags.M64 then
-- movsd %xmm0, slot(%ebp)
- Init_Modrm_Offset
- (R_Bp, -Int32 (Cur_Subprg.Target.Fp_Slot), Sz_32l);
Start_Insn;
- Gen_SSE_Rep_Opc (Mode, 16#11#);
- Gen_Mod_Rm (2#00_000_000#);
+ Gen_SSE_Prefix (Mode);
+ Init_Modrm_Offset
+ (R_Bp, -Int32 (Cur_Subprg.Target.Fp_Slot), Sz_32);
+ Gen_SSE_Opc (Opc_Movsd_M64_Xmm);
+ Gen_Mod_Rm_Opc (2#00_000_000#);
End_Insn;
- -- fldl slot(%ebp)
+ -- fldl slot(%ebp) [keep same modrm parameters]
Start_Insn;
- Gen_B8 (2#11011_001# + Mode_Fp_To_Mf (Mode));
- Gen_Mod_Rm (2#00_000_000#);
+ Gen_8 (2#11011_001# + Mode_Fp_To_Mf (Mode));
+ Gen_Mod_Rm_Opc (2#00_000_000#);
End_Insn;
end if;
when others =>
@@ -2556,7 +3078,7 @@ package body Ortho_Code.X86.Emits is
Dtype : O_Tnode;
begin
Set_Current_Section (Sect_Bss);
- Sym := Create_Symbol (Get_Decl_Ident (Decl));
+ Sym := Create_Symbol (Get_Decl_Ident (Decl), False);
Set_Decl_Info (Decl, To_Int32 (Uns32 (Sym)));
Storage := Get_Decl_Storage (Decl);
Dtype := Get_Decl_Type (Decl);
@@ -2581,7 +3103,7 @@ package body Ortho_Code.X86.Emits is
Sym : Symbol;
begin
Set_Current_Section (Sect_Rodata);
- Sym := Create_Symbol (Get_Decl_Ident (Decl));
+ Sym := Create_Symbol (Get_Decl_Ident (Decl), False);
Set_Decl_Info (Decl, To_Int32 (Uns32 (Sym)));
Set_Current_Section (Sect_Text);
end Emit_Const_Decl;
@@ -2603,23 +3125,24 @@ package body Ortho_Code.X86.Emits is
when Mode_U8
| Mode_I8
| Mode_B2 =>
- Gen_B8 (Byte (L));
+ Gen_8 (Byte (L));
when Mode_U32
| Mode_I32
| Mode_F32
| Mode_P32 =>
- Gen_Le32 (Unsigned_32 (L));
+ Gen_32 (Unsigned_32 (L));
when Mode_F64
| Mode_I64
- | Mode_U64 =>
- Gen_Le32 (Unsigned_32 (L));
- Gen_Le32 (Unsigned_32 (H));
+ | Mode_U64
+ | Mode_P64 =>
+ Gen_32 (Unsigned_32 (L));
+ Gen_32 (Unsigned_32 (H));
when others =>
raise Program_Error;
end case;
when OC_Address
| OC_Subprg_Address =>
- Gen_X86_32 (Get_Decl_Symbol (Get_Const_Decl (Val)), 0);
+ Gen_Abs (Get_Decl_Symbol (Get_Const_Decl (Val)), 0);
when OC_Array =>
for I in 0 .. Get_Const_Aggr_Length (Val) - 1 loop
Emit_Const (Get_Const_Aggr_Element (Val, I));
@@ -2645,13 +3168,11 @@ package body Ortho_Code.X86.Emits is
is
use Decls;
use Types;
- Sym : Symbol;
- Dtype : O_Tnode;
+ Sym : constant Symbol := Get_Decl_Symbol (Decl);
+ Dtype : constant O_Tnode := Get_Decl_Type (Decl);
begin
Set_Current_Section (Sect_Rodata);
- Sym := Get_Decl_Symbol (Decl);
- Dtype := Get_Decl_Type (Decl);
Gen_Pow_Align (Get_Type_Align (Dtype));
Set_Symbol_Pc (Sym, Get_Decl_Storage (Decl) = O_Storage_Public);
Prealloc (Pc_Type (Get_Type_Size (Dtype)));
@@ -2665,7 +3186,11 @@ package body Ortho_Code.X86.Emits is
use Ortho_Ident;
use Ortho_Code.Flags;
begin
- Arch := Arch_X86;
+ if Flags.M64 then
+ Arch := Arch_X86_64;
+ else
+ Arch := Arch_X86;
+ end if;
Create_Section (Sect_Text, ".text", Section_Exec + Section_Read);
Create_Section (Sect_Rodata, ".rodata", Section_Read);
@@ -2675,27 +3200,29 @@ package body Ortho_Code.X86.Emits is
Set_Current_Section (Sect_Text);
if Flag_Profile then
- Mcount_Symbol := Create_Symbol (Get_Identifier ("mcount"));
+ Mcount_Symbol := Create_Symbol (Get_Identifier ("mcount"), True);
end if;
if X86.Flags.Flag_Alloca_Call then
- Chkstk_Symbol := Create_Symbol (Get_Identifier ("___chkstk"));
+ Chkstk_Symbol := Create_Symbol (Get_Identifier ("___chkstk"), True);
end if;
- Intrinsics_Symbol (Intrinsic_Mul_Ov_U64) :=
- Create_Symbol (Get_Identifier ("__muldi3"));
- Intrinsics_Symbol (Intrinsic_Div_Ov_U64) :=
- Create_Symbol (Get_Identifier ("__mcode_div_ov_u64"));
- Intrinsics_Symbol (Intrinsic_Mod_Ov_U64) :=
- Create_Symbol (Get_Identifier ("__mcode_mod_ov_u64"));
- Intrinsics_Symbol (Intrinsic_Mul_Ov_I64) :=
- Create_Symbol (Get_Identifier ("__muldi3"));
- Intrinsics_Symbol (Intrinsic_Div_Ov_I64) :=
- Create_Symbol (Get_Identifier ("__divdi3"));
- Intrinsics_Symbol (Intrinsic_Mod_Ov_I64) :=
- Create_Symbol (Get_Identifier ("__mcode_mod_ov_i64"));
- Intrinsics_Symbol (Intrinsic_Rem_Ov_I64) :=
- Create_Symbol (Get_Identifier ("__mcode_rem_ov_i64"));
+ if not Flags.M64 then
+ Intrinsics_Symbol (Intrinsic_Mul_Ov_U64) :=
+ Create_Symbol (Get_Identifier ("__muldi3"), True);
+ Intrinsics_Symbol (Intrinsic_Div_Ov_U64) :=
+ Create_Symbol (Get_Identifier ("__mcode_div_ov_u64"), True);
+ Intrinsics_Symbol (Intrinsic_Mod_Ov_U64) :=
+ Create_Symbol (Get_Identifier ("__mcode_mod_ov_u64"), True);
+ Intrinsics_Symbol (Intrinsic_Mul_Ov_I64) :=
+ Create_Symbol (Get_Identifier ("__muldi3"), True);
+ Intrinsics_Symbol (Intrinsic_Div_Ov_I64) :=
+ Create_Symbol (Get_Identifier ("__divdi3"), True);
+ Intrinsics_Symbol (Intrinsic_Mod_Ov_I64) :=
+ Create_Symbol (Get_Identifier ("__mcode_mod_ov_i64"), True);
+ Intrinsics_Symbol (Intrinsic_Rem_Ov_I64) :=
+ Create_Symbol (Get_Identifier ("__mcode_rem_ov_i64"), True);
+ end if;
if Debug.Flag_Debug_Asm then
Dump_Asm := True;