summaryrefslogtreecommitdiff
path: root/src/ortho
diff options
context:
space:
mode:
Diffstat (limited to 'src/ortho')
-rw-r--r--src/ortho/mcode/ortho_code-x86-emits.adb104
-rw-r--r--src/ortho/mcode/ortho_code-x86-insns.adb35
2 files changed, 92 insertions, 47 deletions
diff --git a/src/ortho/mcode/ortho_code-x86-emits.adb b/src/ortho/mcode/ortho_code-x86-emits.adb
index 27f78ef..34ff58c 100644
--- a/src/ortho/mcode/ortho_code-x86-emits.adb
+++ b/src/ortho/mcode/ortho_code-x86-emits.adb
@@ -1123,34 +1123,26 @@ package body Ortho_Code.X86.Emits is
-- Convert U32 to xx.
procedure Gen_Conv_U32 (Stmt : O_Enode)
is
- Op : O_Enode;
- Reg_Op : O_Reg;
- Reg_Res : O_Reg;
+ 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
- Op := Get_Expr_Operand (Stmt);
- Reg_Op := Get_Expr_Reg (Op);
- Reg_Res := Get_Expr_Reg (Stmt);
case Get_Expr_Mode (Stmt) is
when Mode_I32 =>
- if Reg_Res not in Regs_R32 then
- raise Program_Error;
- end if;
+ pragma Assert (Reg_Res in Regs_R32);
if Reg_Op /= Reg_Res then
Emit_Load (Reg_Res, Op, Sz_32l);
end if;
Emit_Tst (Reg_Res, Sz_32l);
Gen_Ov_Check (R_Sge);
when Mode_I64 =>
- if Reg_Res /= R_Edx_Eax or Reg_Op /= R_Ax then
- raise Program_Error;
- end if;
+ pragma Assert (Reg_Res = R_Edx_Eax);
+ pragma Assert (Reg_Op = R_Ax);
-- Clear edx.
Gen_Clear_Edx;
when Mode_U8
| Mode_B2 =>
- if Reg_Res not in Regs_R32 then
- raise Program_Error;
- end if;
+ pragma Assert (Reg_Res in Regs_R32);
if Reg_Op /= Reg_Res then
Emit_Load (Reg_Res, Op, Sz_32l);
end if;
@@ -1169,23 +1161,17 @@ package body Ortho_Code.X86.Emits is
-- Convert I32 to xxx
procedure Gen_Conv_I32 (Stmt : O_Enode)
is
- Op : O_Enode;
- Reg_Op : O_Reg;
- Reg_Res : O_Reg;
+ 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
- Op := Get_Expr_Operand (Stmt);
- Reg_Op := Get_Expr_Reg (Op);
- Reg_Res := Get_Expr_Reg (Stmt);
case Get_Expr_Mode (Stmt) is
when Mode_I64 =>
- if Reg_Res /= R_Edx_Eax or Reg_Op /= R_Ax then
- raise Program_Error;
- end if;
+ pragma Assert (Reg_Res = R_Edx_Eax);
+ pragma Assert (Reg_Op = R_Ax);
Gen_Cdq;
when Mode_U32 =>
- if Reg_Res not in Regs_R32 then
- raise Program_Error;
- end if;
+ pragma Assert (Reg_Res in Regs_R32);
if Reg_Op /= Reg_Res then
Emit_Load (Reg_Res, Op, Sz_32l);
end if;
@@ -1225,20 +1211,24 @@ package body Ortho_Code.X86.Emits is
-- Convert U8 to xxx
procedure Gen_Conv_U8 (Stmt : O_Enode)
is
- Op : O_Enode;
- Reg_Res : O_Reg;
+ 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
- Op := Get_Expr_Operand (Stmt);
- Reg_Res := Get_Expr_Reg (Stmt);
case Get_Expr_Mode (Stmt) is
when Mode_U32
| Mode_I32
| Mode_U16
| Mode_I16 =>
- if Reg_Res not in Regs_R32 then
- raise Program_Error;
- end if;
+ pragma Assert (Reg_Res in Regs_R32);
Gen_Movzx (Reg_Res, Op, Sz_8);
+ 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;
when others =>
Error_Emit ("gen_conv_U8", Stmt);
end case;
@@ -1247,17 +1237,23 @@ package body Ortho_Code.X86.Emits is
-- Convert B2 to xxx
procedure Gen_Conv_B2 (Stmt : O_Enode)
is
- Op : O_Enode;
- Reg_Res : O_Reg;
+ 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
- Op := Get_Expr_Operand (Stmt);
- Reg_Res := Get_Expr_Reg (Stmt);
case Get_Expr_Mode (Stmt) is
when Mode_U32
| Mode_I32
| Mode_U16
| Mode_I16 =>
+ pragma Assert (Reg_Res in Regs_R32);
Gen_Movzx (Reg_Res, Op, Sz_8);
+ 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;
when others =>
Error_Emit ("gen_conv_B2", Stmt);
end case;
@@ -1266,23 +1262,50 @@ package body Ortho_Code.X86.Emits is
-- Convert I64 to xxx
procedure Gen_Conv_I64 (Stmt : O_Enode)
is
- Op : O_Enode;
+ 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
- Op := Get_Expr_Operand (Stmt);
case Get_Expr_Mode (Stmt) 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 (2#1000_1001#);
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 (2#0011_1001#);
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);
+ 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);
+ 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);
+ Gen_Ov_Check (R_Ule);
when Mode_F64 =>
Emit_Push_32 (Op, Sz_32h);
Emit_Push_32 (Op, Sz_32l);
@@ -1775,6 +1798,7 @@ package body Ortho_Code.X86.Emits is
end case;
when OE_Conv =>
+ -- Call Gen_Conv_FROM
case Get_Expr_Mode (Get_Expr_Operand (Stmt)) is
when Mode_U32 =>
Gen_Conv_U32 (Stmt);
diff --git a/src/ortho/mcode/ortho_code-x86-insns.adb b/src/ortho/mcode/ortho_code-x86-insns.adb
index 2a04e93..f968874 100644
--- a/src/ortho/mcode/ortho_code-x86-insns.adb
+++ b/src/ortho/mcode/ortho_code-x86-insns.adb
@@ -1719,40 +1719,56 @@ package body Ortho_Code.X86.Insns is
Link_Stmt (Stmt);
return Stmt;
when OE_Conv =>
+ Left := Get_Expr_Operand (Stmt);
declare
- O_Mode : Mode_Type; -- Operand mode
- R_Mode : Mode_Type; -- Result mode
+ -- Operand mode
+ O_Mode : constant Mode_Type := Get_Expr_Mode (Left);
+
+ -- Result mode
+ R_Mode : constant Mode_Type := Get_Expr_Mode (Stmt);
+
+ Reg_Op : O_Reg;
begin
- Left := Get_Expr_Operand (Stmt);
- O_Mode := Get_Expr_Mode (Left);
- R_Mode := Get_Expr_Mode (Stmt);
-- Simple case: no conversion.
-- FIXME: should be handled by EXPR and convert to NOP.
if Get_Expr_Mode (Left) = Get_Expr_Mode (Stmt) then
-- A no-op.
return Gen_Insn (Left, Reg, Pnum);
end if;
+
+ -- By default, can work on reg or memory.
+ Reg_Op := R_Rm;
+
case R_Mode is
when Mode_B2 =>
+ -- To B2
case O_Mode is
when Mode_U32
| Mode_I32 =>
-- Detect for bound.
null;
+ when Mode_I64 =>
+ -- Work on registers.
+ Reg_Op := R_Any64;
when others =>
Error_Gen_Insn (Stmt, O_Mode);
end case;
when Mode_U8 =>
+ -- To U8
case O_Mode is
when Mode_U16
| Mode_U32
| Mode_I32 =>
-- Detect for bound.
null;
+ when Mode_I64 =>
+ -- Work on registers.
+ Reg_Op := R_Any64;
when others =>
Error_Gen_Insn (Stmt, O_Mode);
end case;
when Mode_U32 =>
+ -- To U32
case O_Mode is
when Mode_I32 =>
-- Detect for bound.
@@ -1766,6 +1782,7 @@ package body Ortho_Code.X86.Insns is
Error_Gen_Insn (Stmt, O_Mode);
end case;
when Mode_I32 =>
+ -- To I32
case O_Mode is
when Mode_U8
| Mode_I8
@@ -1802,9 +1819,12 @@ package body Ortho_Code.X86.Insns is
Error_Gen_Insn (Stmt, O_Mode);
end case;
when Mode_I64 =>
+ -- To I64
case O_Mode is
when Mode_I32
- | Mode_U32 =>
+ | Mode_U32
+ | Mode_U8
+ | Mode_B2 =>
-- Zero or Sign extend.
Num := Get_Insn_Num;
Left := Gen_Insn (Left, R_Ax, Num);
@@ -1830,6 +1850,7 @@ package body Ortho_Code.X86.Insns is
Error_Gen_Insn (Stmt, O_Mode);
end case;
when Mode_F64 =>
+ -- To F64
case O_Mode is
when Mode_I32
| Mode_I64 =>
@@ -1840,7 +1861,7 @@ package body Ortho_Code.X86.Insns is
when others =>
Error_Gen_Insn (Stmt, O_Mode);
end case;
- Left := Gen_Insn (Left, R_Rm, Pnum);
+ Left := Gen_Insn (Left, Reg_Op, Pnum);
Set_Expr_Operand (Stmt, Left);
case Reg is
when R_Irm