aboutsummaryrefslogtreecommitdiffstats
path: root/ortho/mcode/ortho_code-x86-insns.adb
diff options
context:
space:
mode:
Diffstat (limited to 'ortho/mcode/ortho_code-x86-insns.adb')
-rw-r--r--ortho/mcode/ortho_code-x86-insns.adb65
1 files changed, 55 insertions, 10 deletions
diff --git a/ortho/mcode/ortho_code-x86-insns.adb b/ortho/mcode/ortho_code-x86-insns.adb
index d3ea79233..9ef638505 100644
--- a/ortho/mcode/ortho_code-x86-insns.adb
+++ b/ortho/mcode/ortho_code-x86-insns.adb
@@ -15,6 +15,7 @@
-- along with GCC; see the file COPYING. If not, write to the Free
-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-- 02111-1307, USA.
+with Interfaces;
with Ada.Text_IO;
with Ortho_Code.Abi;
with Ortho_Code.Decls; use Ortho_Code.Decls;
@@ -72,6 +73,10 @@ package body Ortho_Code.X86.Insns is
Stack_Offset : Uns32 := 0;
Stack_Max : Uns32 := 0;
+ -- Count how many bytes have been pushed on the stack, during a call. This
+ -- is used to correctly align the stack for nested calls.
+ Push_Offset : Uns32 := 0;
+
-- STMT is an OE_END statement.
-- Swap Stack_Offset with Max_Stack of STMT.
procedure Swap_Stack_Offset (Blk : O_Dnode)
@@ -1004,15 +1009,30 @@ package body Ortho_Code.X86.Insns is
function Gen_Call (Stmt : O_Enode; Reg : O_Reg; Pnum : O_Inum)
return O_Enode
is
+ use Interfaces;
Left : O_Enode;
Reg_Res : O_Reg;
+ Subprg : O_Dnode;
+ Push_Size : Uns32;
+ Pad : Uns32;
+ Res_Stmt : O_Enode;
begin
- Link_Stmt
- (New_Enode (OE_Setup_Frame, Mode_Nil, O_Tnode_Null,
- O_Enode (Get_Call_Subprg (Stmt)), O_Enode_Null));
+ -- Emit Setup_Frame (to align stack).
+ Subprg := Get_Call_Subprg (Stmt);
+ Push_Size := Uns32 (Get_Subprg_Stack (Subprg));
+ -- Pad the stack if necessary.
+ Pad := (Push_Size + Push_Offset) and Uns32 (Flags.Stack_Boundary - 1);
+ if Pad /= 0 then
+ Pad := Uns32 (Flags.Stack_Boundary) - Pad;
+ Link_Stmt (New_Enode (OE_Stack_Adjust, Mode_Nil, O_Tnode_Null,
+ O_Enode (Pad), O_Enode_Null));
+ end if;
+ -- The stack has been adjusted by Pad bytes.
+ Push_Offset := Push_Offset + Pad;
+
+ -- Generate code for arguments (if any).
Left := Get_Arg_Link (Stmt);
if Left /= O_Enode_Null then
- -- Generate code for arguments.
Left := Gen_Insn (Left, R_None, Pnum);
end if;
@@ -1022,9 +1042,22 @@ package body Ortho_Code.X86.Insns is
Clobber_R32 (R_Cx);
-- FIXME: fp regs.
+ -- Add the call.
Reg_Res := Get_Call_Register (Get_Expr_Mode (Stmt));
Set_Expr_Reg (Stmt, Reg_Res);
Link_Stmt (Stmt);
+ Res_Stmt := Stmt;
+
+ if Push_Size + Pad /= 0 then
+ Res_Stmt :=
+ New_Enode (OE_Stack_Adjust, Get_Expr_Mode (Stmt), O_Tnode_Null,
+ O_Enode (-Int32 (Push_Size + Pad)), O_Enode_Null);
+ Set_Expr_Reg (Res_Stmt, Reg_Res);
+ Link_Stmt (Res_Stmt);
+ end if;
+
+ -- The stack has been restored (just after the call).
+ Push_Offset := Push_Offset - (Push_Size + Pad);
case Reg is
when R_Any32
@@ -1037,18 +1070,18 @@ package body Ortho_Code.X86.Insns is
| R_Ax
| R_St0
| R_Edx_Eax =>
- Reg_Res := Alloc_Reg (Reg_Res, Stmt, Pnum);
- return Stmt;
+ Reg_Res := Alloc_Reg (Reg_Res, Res_Stmt, Pnum);
+ return Res_Stmt;
when R_Any_Cc =>
-- Move to register.
-- (use the 'test' instruction).
- Alloc_Cc (Stmt, Pnum);
- return Insert_Move (Stmt, R_Ne);
+ Alloc_Cc (Res_Stmt, Pnum);
+ return Insert_Move (Res_Stmt, R_Ne);
when R_None =>
if Reg_Res /= R_None then
raise Program_Error;
end if;
- return Stmt;
+ return Res_Stmt;
when others =>
Error_Gen_Insn (Stmt, Reg);
end case;
@@ -1621,6 +1654,7 @@ package body Ortho_Code.X86.Insns is
return Reload (Stmt, Reg, Pnum);
when Mode_U64
| Mode_I64 =>
+ -- FIXME: align stack
Insert_Arg (Gen_Insn (Right, R_Irm, Num));
Insert_Arg (Gen_Insn (Left, R_Irm, Num));
return Insert_Intrinsic (Stmt, R_Edx_Eax, Pnum);
@@ -1821,9 +1855,11 @@ package body Ortho_Code.X86.Insns is
end if;
Left := Get_Arg_Link (Stmt);
if Left /= O_Enode_Null then
- -- Previous argument.
+ -- Recurse on next argument, so the first argument is pushed
+ -- the last one.
Left := Gen_Insn (Left, R_None, Pnum);
end if;
+
Left := Get_Expr_Operand (Stmt);
case Get_Expr_Mode (Left) is
when Mode_F32 .. Mode_F64 =>
@@ -1835,6 +1871,8 @@ package body Ortho_Code.X86.Insns is
end case;
Left := Gen_Insn (Left, Reg_Res, Pnum);
Set_Expr_Operand (Stmt, Left);
+ Push_Offset := Push_Offset +
+ Do_Align (Get_Mode_Size (Get_Expr_Mode (Left)), Mode_U32);
Link_Stmt (Stmt);
Free_Insn_Regs (Left);
return Stmt;
@@ -2010,7 +2048,14 @@ package body Ortho_Code.X86.Insns is
exit when Get_Expr_Kind (Stmt) = OE_Leave;
Stmt := N_Stmt;
end loop;
+
+ -- Keep stack depth for this subprogram.
Subprg.Stack_Max := Stack_Max;
+
+ -- Sanity check: there must be no remaining pushed bytes.
+ if Push_Offset /= 0 then
+ raise Program_Error with "gen_subprg_insn: push_offset not 0";
+ end if;
end Gen_Subprg_Insns;
end Ortho_Code.X86.Insns;