1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
package com.seaofnodes.simple.codegen;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeFunPtr;
import com.seaofnodes.simple.type.TypeInteger;
abstract public class Machine {
// Human readable machine name. Something like "x86-64" or "arm" or "risc5"
public abstract String name();
// Default opcode size for printing; 4 bytes for most 32-bit risc chips
public int defaultOpSize() { return 4; }
// Human-readable name for a register number, e.g. "RAX" or "R0"
public abstract String[] regs();
// Create a split op; any register to any register, including stack slots.
// The FunNode holds the stack layout after RegAlloc, which in turn
// dictates the stack slot (the frame offset) for stack splits.
public abstract SplitNode split( LRG lrg, String kind, byte round );
// List of caller-save registers, as a 64bit mask
public abstract long callerSave();
public long callerSave(String conv) { return callerSave(); }
// List of never-save registers, e.g. RSP or a ZERO register if you have one
public abstract long neverSave();
// Call Argument Mask. Passed in the function signature and argument
// number (2-based; 0 is for control and 1 for memory). Also passed in a 0
// for the function itself, or for *outgoing* calls, the maximum stack slot
// given to the incoming function arguments (stack slots reserved for
// incoming arguments).
public abstract RegMask callArgMask(TypeFunPtr tfp, int arg, int maxArgSlot);
public RegMask callArgMask(TypeFunPtr tfp, int arg, int maxArgSlot, String conv) { return callArgMask(tfp,arg,maxArgSlot); }
// Return register mask, based on signature (GPR vs FPR)
public abstract RegMask retMask(TypeFunPtr tfp);
// Return PC register
public abstract int rpc();
// Return a MachNode unconditional branch
public abstract CFGNode jump();
// Instruction select from ideal nodes
public abstract Node instSelect( Node n );
/** Stack Slot Numbering
RA gives all registers a number, starting at 0. Stack slots continue this
numbering going up from the last register number. Common register numbers are
0-15 for GPRs, 16-31 for FPRs, 32 for flags, and stack slots starting at
register#33 going up. These numbers are machine-specific, YMMV, etc; e.g. RPC
is only in stack slot 0 on X86; other cpus start with the rpc in a register
which may spill into any generic spill slot.
For ease of reading and printing, stack slots start again at slot#0 - but
during RA they are actually biased by CPU.MAX_REG.
Stack Layout during Reg Alloc:
Slot Value Description
---- ------- -----------
MAXREG+ R+1 argR maxArgSlot(calleR tfp), can be 0
...
MAXREG+ 1 arg0
---- -- Caller ------
MAXREG+ 0 RPC
MAXREG+ R+E+N PAD optional alignment
MAXREG+ + Spills Caller Frame Space; N spills
MAXREG+ R+E+1 Spills
MAXREG+ R+E argE maxArgSlot(calleE tfp), can be 0
...
MAXREG+ R+2 arg0
---- -- Callee -------
...
Slots defined by maxArgSlot do not have to contain the actual passed argument;
they can be "shadow slots". If they exist, they are property of the frame /
FunNode where the TFP comes from.
For a given calleR, there are generally many calleE's and they all share the
low-range stack slots.
Example:, Win64, main(int arg) { calloc(1,size); }
Post-Warp: SP+56 shadow-main-arg
Pre-alloc Post-Alloc SP+48 RPC
--- ------- ---------- -------------
40 spill#3 SP+40 SP+40 spill#3
39 spill#2 SP+32 ""
38 spill#1 SP+24 ""
37 spill#0 SP+16 "" spill#0
36 shadow-calloc#size SP+ 8 SP+ 8 shadow-calloc#size
35 shadow-calloc#1 SP+ 0 SP+ 0 shadow-calloc#1
--- --- FRAME BASE ---------- ---- FRAME BASE -------
34 shadow-main-arg SP+56
33 RPC SP+48
*/
// Maximum stack slot (or 0) for the args in this TFP. This will include
// shadow slots if defined in the ABI, even if all arguments are passed in
// registers.
public abstract short maxArgSlot(TypeFunPtr tfp);
public short maxArgSlot(TypeFunPtr tfp, String conv) { return maxArgSlot(tfp); }
// Calling convention used for external C symbols.
public String cCallingConv(String callingConv) { return callingConv; }
// Only the declared C result width describes the physical return register.
// Simple functions already return canonical full-width integer values.
protected static TypeInteger cReturn(ProjNode prj) {
if( prj._idx==2 && prj.in(0) instanceof CallEndNode cend &&
cend.call().fptr()._type instanceof TypeFunPtr tfp && tfp.isConstant() &&
CodeGen.CODE.externFunc(tfp.fidx())!=null &&
tfp.ret() instanceof TypeInteger ret && ret.log_size()<3 )
return ret;
return null;
}
}
|