Fix the +RTS -V0 option introduced recently; it didn't work at all, now it does.
[ghc.git] / rts / StgStdThunks.cmm
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The University of Glasgow, 1998-2004
4  *
5  * Canned "Standard Form" Thunks
6  *
7  * This file is written in a subset of C--, extended with various
8  * features specific to GHC.  It is compiled by GHC directly.  For the
9  * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
10  *
11  * ---------------------------------------------------------------------------*/
12
13 #include "Cmm.h"
14
15 /* -----------------------------------------------------------------------------
16    The code for a thunk that simply extracts a field from a
17    single-constructor datatype depends only on the offset of the field
18    to be selected.
19
20    Here we define some canned "selector" thunks that do just that; any
21    selector thunk appearing in a program will refer to one of these
22    instead of being compiled independently.
23
24    The garbage collector spots selector thunks and reduces them if
25    possible, in order to avoid space leaks resulting from lazy pattern
26    matching.
27    -------------------------------------------------------------------------- */
28
29 #define WITHUPD_FRAME_SIZE  (SIZEOF_StgUpdateFrame + SIZEOF_StgHeader)
30 #define NOUPD_FRAME_SIZE    (SIZEOF_StgHeader)
31
32 #ifdef PROFILING
33 #define SAVE_CCCS(fs)   StgHeader_ccs(Sp-fs) = W_[CCCS]
34 #define GET_SAVED_CCCS  W_[CCCS] = StgHeader_ccs(Sp)
35 #define RET_PARAMS      W_ unused1, W_ unused2
36 #else
37 #define SAVE_CCCS(fs)   /* empty */
38 #define GET_SAVED_CCCS  /* empty */
39 #define RET_PARAMS
40 #endif
41
42 #define SELECTOR_CODE_UPD(offset) \
43   INFO_TABLE_RET(stg_sel_ret_##offset##_upd, RET_SMALL, RET_PARAMS)     \
44   {                                                                     \
45       R1 = StgClosure_payload(R1,offset);                               \
46       GET_SAVED_CCCS;                                                   \
47       Sp = Sp + SIZEOF_StgHeader;                                       \
48       ENTER();                                                          \
49   }                                                                     \
50                                                                         \
51   INFO_TABLE_SELECTOR(stg_sel_##offset##_upd, offset, THUNK_SELECTOR, "stg_sel_upd", "stg_sel_upd") \
52   {                                                                     \
53       TICK_ENT_DYN_THK();                                               \
54       STK_CHK_NP(WITHUPD_FRAME_SIZE);                                   \
55       UPD_BH_UPDATABLE();                                               \
56       LDV_ENTER(R1);                                                    \
57       PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1);                   \
58       ENTER_CCS_THUNK(R1);                                              \
59       SAVE_CCCS(WITHUPD_FRAME_SIZE);                                    \
60       W_[Sp-WITHUPD_FRAME_SIZE] = stg_sel_ret_##offset##_upd_info;      \
61       R1 = StgThunk_payload(R1,0);                                      \
62       Sp = Sp - WITHUPD_FRAME_SIZE;                                     \
63       jump %GET_ENTRY(R1);                                              \
64   }
65   /* NOTE: no need to ENTER() here, we know the closure cannot evaluate to a function,
66      because we're going to do a field selection on the result. */
67
68 SELECTOR_CODE_UPD(0)
69 SELECTOR_CODE_UPD(1)
70 SELECTOR_CODE_UPD(2)
71 SELECTOR_CODE_UPD(3)
72 SELECTOR_CODE_UPD(4)
73 SELECTOR_CODE_UPD(5)
74 SELECTOR_CODE_UPD(6)
75 SELECTOR_CODE_UPD(7)
76 SELECTOR_CODE_UPD(8)
77 SELECTOR_CODE_UPD(9)
78 SELECTOR_CODE_UPD(10)
79 SELECTOR_CODE_UPD(11)
80 SELECTOR_CODE_UPD(12)
81 SELECTOR_CODE_UPD(13)
82 SELECTOR_CODE_UPD(14)
83 SELECTOR_CODE_UPD(15)
84
85 #define SELECTOR_CODE_NOUPD(offset) \
86   INFO_TABLE_RET(stg_sel_ret_##offset##_noupd, RET_SMALL, RET_PARAMS)   \
87   {                                                                     \
88       R1 = StgClosure_payload(R1,offset);                               \
89       GET_SAVED_CCCS;                                                   \
90       Sp = Sp + SIZEOF_StgHeader;                                       \
91       jump %GET_ENTRY(R1);                                              \
92   }                                                                     \
93                                                                         \
94   INFO_TABLE_SELECTOR(stg_sel_##offset##_noupd, offset, THUNK_SELECTOR, "stg_sel_noupd", "stg_sel_noupd")\
95   {                                                                     \
96       TICK_ENT_DYN_THK();                                               \
97       STK_CHK_NP(NOUPD_FRAME_SIZE);                                     \
98       UPD_BH_SINGLE_ENTRY();                                            \
99       LDV_ENTER(R1);                                                    \
100       TICK_UPDF_OMITTED();                                              \
101       ENTER_CCS_THUNK(R1);                                              \
102       SAVE_CCCS(NOUPD_FRAME_SIZE);                                      \
103       W_[Sp-NOUPD_FRAME_SIZE] = stg_sel_ret_##offset##_noupd_info;      \
104       R1 = StgThunk_payload(R1,0);                                      \
105       Sp = Sp - NOUPD_FRAME_SIZE;                                       \
106       jump %GET_ENTRY(R1);                                              \
107   }
108
109 SELECTOR_CODE_NOUPD(0)
110 SELECTOR_CODE_NOUPD(1)
111 SELECTOR_CODE_NOUPD(2)
112 SELECTOR_CODE_NOUPD(3)
113 SELECTOR_CODE_NOUPD(4)
114 SELECTOR_CODE_NOUPD(5)
115 SELECTOR_CODE_NOUPD(6)
116 SELECTOR_CODE_NOUPD(7)
117 SELECTOR_CODE_NOUPD(8)
118 SELECTOR_CODE_NOUPD(9)
119 SELECTOR_CODE_NOUPD(10)
120 SELECTOR_CODE_NOUPD(11)
121 SELECTOR_CODE_NOUPD(12)
122 SELECTOR_CODE_NOUPD(13)
123 SELECTOR_CODE_NOUPD(14)
124 SELECTOR_CODE_NOUPD(15)
125
126 /* -----------------------------------------------------------------------------
127    Apply thunks
128
129    An apply thunk is a thunk of the form
130         
131                 let z = [x1...xn] \u x1...xn
132                 in ...
133
134    We pre-compile some of these because the code is always the same.
135
136    These have to be independent of the update frame size, so the code
137    works when profiling etc.
138    -------------------------------------------------------------------------- */
139
140 /* stg_ap_1_upd_info is a bit redundant, but there appears to be a bug
141  * in the compiler that means stg_ap_1 is generated occasionally (ToDo)
142  */
143
144 INFO_TABLE(stg_ap_1_upd,1,1,THUNK_1_0,"stg_ap_1_upd_info","stg_ap_1_upd_info")
145 {
146   TICK_ENT_DYN_THK();
147   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(1));
148   UPD_BH_UPDATABLE();
149   LDV_ENTER(R1);
150   ENTER_CCS_THUNK(R1);
151   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
152   R1 = StgThunk_payload(R1,0);
153   Sp = Sp - SIZEOF_StgUpdateFrame;
154   jump stg_ap_0_fast;
155 }
156
157 INFO_TABLE(stg_ap_2_upd,2,0,THUNK_2_0,"stg_ap_2_upd_info","stg_ap_2_upd_info")
158 {
159   TICK_ENT_DYN_THK();
160   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(2));
161   UPD_BH_UPDATABLE();
162   LDV_ENTER(R1);
163   ENTER_CCS_THUNK(R1);
164   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
165   W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,1);
166   R1 = StgThunk_payload(R1,0);
167   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(1);
168   Sp_adj(-1); // for stg_ap_*_ret
169   TICK_UNKNOWN_CALL();
170   TICK_SLOW_CALL_p();
171   jump RET_LBL(stg_ap_p);
172 }
173
174 INFO_TABLE(stg_ap_3_upd,3,0,THUNK,"stg_ap_3_upd_info","stg_ap_3_upd_info")
175 {
176   TICK_ENT_DYN_THK();
177   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(3));
178   UPD_BH_UPDATABLE();
179   LDV_ENTER(R1);
180   ENTER_CCS_THUNK(R1);
181   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
182   W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,2);
183   W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,1);
184   R1 = StgThunk_payload(R1,0);
185   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(2);
186   Sp_adj(-1); // for stg_ap_*_ret
187   TICK_UNKNOWN_CALL();
188   TICK_SLOW_CALL_pp();
189   jump RET_LBL(stg_ap_pp);
190 }
191
192 INFO_TABLE(stg_ap_4_upd,4,0,THUNK,"stg_ap_4_upd_info","stg_ap_4_upd_info")
193 {
194   TICK_ENT_DYN_THK();
195   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(4));
196   UPD_BH_UPDATABLE();
197   LDV_ENTER(R1);
198   ENTER_CCS_THUNK(R1);
199   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
200   W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,3);
201   W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,2);
202   W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,1);
203   R1 = StgThunk_payload(R1,0);
204   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(3);
205   Sp_adj(-1); // for stg_ap_*_ret
206   TICK_UNKNOWN_CALL();
207   TICK_SLOW_CALL_ppp();
208   jump RET_LBL(stg_ap_ppp);
209 }
210
211 INFO_TABLE(stg_ap_5_upd,5,0,THUNK,"stg_ap_5_upd_info","stg_ap_5_upd_info")
212 {
213   TICK_ENT_DYN_THK();
214   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(5));
215   UPD_BH_UPDATABLE();
216   LDV_ENTER(R1);
217   ENTER_CCS_THUNK(R1);
218   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
219   W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,4);
220   W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,3);
221   W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,2);
222   W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,1);
223   R1 = StgThunk_payload(R1,0);
224   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(4);
225   Sp_adj(-1); // for stg_ap_*_ret
226   TICK_UNKNOWN_CALL();
227   TICK_SLOW_CALL_pppp();
228   jump RET_LBL(stg_ap_pppp);
229 }
230
231 INFO_TABLE(stg_ap_6_upd,6,0,THUNK,"stg_ap_6_upd_info","stg_ap_6_upd_info")
232 {
233   TICK_ENT_DYN_THK();
234   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(6));
235   UPD_BH_UPDATABLE();
236   LDV_ENTER(R1);
237   ENTER_CCS_THUNK(R1);
238   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
239   W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,5);
240   W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,4);
241   W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,3);
242   W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,2);
243   W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgThunk_payload(R1,1);
244   R1 = StgThunk_payload(R1,0);
245   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(5);
246   Sp_adj(-1); // for stg_ap_*_ret
247   TICK_UNKNOWN_CALL();
248   TICK_SLOW_CALL_ppppp();
249   jump RET_LBL(stg_ap_ppppp);
250 }
251
252 INFO_TABLE(stg_ap_7_upd,7,0,THUNK,"stg_ap_7_upd_info","stg_ap_7_upd_info")
253 {
254   TICK_ENT_DYN_THK();
255   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(7));
256   UPD_BH_UPDATABLE();
257   LDV_ENTER(R1);
258   ENTER_CCS_THUNK(R1);
259   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
260   W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,6);
261   W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,5);
262   W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,4);
263   W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,3);
264   W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgThunk_payload(R1,2);
265   W_[Sp-SIZEOF_StgUpdateFrame-WDS(6)] = StgThunk_payload(R1,1);
266   R1 = StgThunk_payload(R1,0);
267   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(6);
268   Sp_adj(-1); // for stg_ap_*_ret
269   TICK_UNKNOWN_CALL();
270   TICK_SLOW_CALL_pppppp();
271   jump RET_LBL(stg_ap_pppppp);
272 }