diff options
author | Tristan Gingold <tgingold@free.fr> | 2015-01-22 04:42:30 +0100 |
---|---|---|
committer | Tristan Gingold <tgingold@free.fr> | 2015-01-22 04:42:30 +0100 |
commit | 6caa543e9416d3a8bfc50b6f6da4b502a8069029 (patch) | |
tree | 6a9bde19612fc2b76552735109b156914eb1d902 /src/ortho/mcode | |
parent | bcd53686ad09a434a81fc8ccf092ed16f454cd5c (diff) | |
download | ghdl-6caa543e9416d3a8bfc50b6f6da4b502a8069029.tar.gz ghdl-6caa543e9416d3a8bfc50b6f6da4b502a8069029.tar.bz2 ghdl-6caa543e9416d3a8bfc50b6f6da4b502a8069029.zip |
mcode x86: handle more conversions (i64 <-> u8. b2)
Diffstat (limited to 'src/ortho/mcode')
-rw-r--r-- | src/ortho/mcode/ortho_code-x86-emits.adb | 104 | ||||
-rw-r--r-- | src/ortho/mcode/ortho_code-x86-insns.adb | 35 |
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 27f78ef47..34ff58cd0 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 2a04e93e7..f96887436 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 |