4da42489baacb5451fc28f33e90efda0836b0dae
[ghc-hetmet.git] / ghc / 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_BITMAP    3
36 #define RET_FRAMESIZE 2
37 #else
38 #define SAVE_CCCS(fs)   /* empty */
39 #define GET_SAVED_CCCS  /* empty */
40 #define RET_BITMAP    0
41 #define RET_FRAMESIZE 0
42 #endif
43
44 #define SELECTOR_CODE_UPD(offset) \
45   INFO_TABLE_RET(stg_sel_ret_##offset##_upd, RET_FRAMESIZE, RET_BITMAP, RET_SMALL)      \
46   {                                                                     \
47       R1 = StgClosure_payload(R1,offset);                               \
48       GET_SAVED_CCCS;                                                   \
49       Sp = Sp + SIZEOF_StgHeader;                                       \
50       ENTER();                                                          \
51   }                                                                     \
52                                                                         \
53   INFO_TABLE_SELECTOR(stg_sel_##offset##_upd, offset, THUNK_SELECTOR, "stg_sel_upd", "stg_sel_upd") \
54   {                                                                     \
55       TICK_ENT_DYN_THK();                                               \
56       STK_CHK_NP(WITHUPD_FRAME_SIZE);                                   \
57       UPD_BH_UPDATABLE();                                               \
58       LDV_ENTER(R1);                                                    \
59       PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1);                   \
60       ENTER_CCS_THUNK(R1);                                              \
61       SAVE_CCCS(WITHUPD_FRAME_SIZE);                                    \
62       W_[Sp-WITHUPD_FRAME_SIZE] = stg_sel_ret_##offset##_upd_info;      \
63       R1 = StgThunk_payload(R1,0);                                      \
64       Sp = Sp - WITHUPD_FRAME_SIZE;                                     \
65       jump %GET_ENTRY(R1);                                              \
66   }
67   /* NOTE: no need to ENTER() here, we know the closure cannot evaluate to a function,
68      because we're going to do a field selection on the result. */
69
70 SELECTOR_CODE_UPD(0)
71 SELECTOR_CODE_UPD(1)
72 SELECTOR_CODE_UPD(2)
73 SELECTOR_CODE_UPD(3)
74 SELECTOR_CODE_UPD(4)
75 SELECTOR_CODE_UPD(5)
76 SELECTOR_CODE_UPD(6)
77 SELECTOR_CODE_UPD(7)
78 SELECTOR_CODE_UPD(8)
79 SELECTOR_CODE_UPD(9)
80 SELECTOR_CODE_UPD(10)
81 SELECTOR_CODE_UPD(11)
82 SELECTOR_CODE_UPD(12)
83 SELECTOR_CODE_UPD(13)
84 SELECTOR_CODE_UPD(14)
85 SELECTOR_CODE_UPD(15)
86
87 #define SELECTOR_CODE_NOUPD(offset) \
88   INFO_TABLE_RET(stg_sel_ret_##offset##_noupd, RET_FRAMESIZE, RET_BITMAP, RET_SMALL)    \
89   {                                                                     \
90       R1 = StgClosure_payload(R1,offset);                               \
91       GET_SAVED_CCCS;                                                   \
92       Sp = Sp + SIZEOF_StgHeader;                                       \
93       jump %GET_ENTRY(R1);                                              \
94   }                                                                     \
95                                                                         \
96   INFO_TABLE_SELECTOR(stg_sel_##offset##_noupd, offset, THUNK_SELECTOR, "stg_sel_noupd", "stg_sel_noupd")\
97   {                                                                     \
98       TICK_ENT_DYN_THK();                                               \
99       STK_CHK_NP(NOUPD_FRAME_SIZE);                                     \
100       UPD_BH_SINGLE_ENTRY();                                            \
101       LDV_ENTER(R1);                                                    \
102       TICK_UPDF_OMITTED();                                              \
103       ENTER_CCS_THUNK(R1);                                              \
104       SAVE_CCCS(NOUPD_FRAME_SIZE);                                      \
105       W_[Sp-NOUPD_FRAME_SIZE] = stg_sel_ret_##offset##_noupd_info;      \
106       R1 = StgThunk_payload(R1,0);                                      \
107       Sp = Sp - NOUPD_FRAME_SIZE;                                       \
108       jump %GET_ENTRY(R1);                                              \
109   }
110
111 SELECTOR_CODE_NOUPD(0)
112 SELECTOR_CODE_NOUPD(1)
113 SELECTOR_CODE_NOUPD(2)
114 SELECTOR_CODE_NOUPD(3)
115 SELECTOR_CODE_NOUPD(4)
116 SELECTOR_CODE_NOUPD(5)
117 SELECTOR_CODE_NOUPD(6)
118 SELECTOR_CODE_NOUPD(7)
119 SELECTOR_CODE_NOUPD(8)
120 SELECTOR_CODE_NOUPD(9)
121 SELECTOR_CODE_NOUPD(10)
122 SELECTOR_CODE_NOUPD(11)
123 SELECTOR_CODE_NOUPD(12)
124 SELECTOR_CODE_NOUPD(13)
125 SELECTOR_CODE_NOUPD(14)
126 SELECTOR_CODE_NOUPD(15)
127
128 /* -----------------------------------------------------------------------------
129    Apply thunks
130
131    An apply thunk is a thunk of the form
132         
133                 let z = [x1...xn] \u x1...xn
134                 in ...
135
136    We pre-compile some of these because the code is always the same.
137
138    These have to be independent of the update frame size, so the code
139    works when profiling etc.
140    -------------------------------------------------------------------------- */
141
142 /* stg_ap_1_upd_info is a bit redundant, but there appears to be a bug
143  * in the compiler that means stg_ap_1 is generated occasionally (ToDo)
144  */
145
146 INFO_TABLE(stg_ap_1_upd,1,1,THUNK_1_0,"stg_ap_1_upd_info","stg_ap_1_upd_info")
147 {
148   TICK_ENT_DYN_THK();
149   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(1));
150   UPD_BH_UPDATABLE();
151   LDV_ENTER(R1);
152   ENTER_CCS_THUNK(R1);
153   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
154   R1 = StgThunk_payload(R1,0);
155   Sp = Sp - SIZEOF_StgUpdateFrame;
156   Sp_adj(-1); // for stg_ap_0_ret
157   jump RET_LBL(stg_ap_0);
158 }
159
160 INFO_TABLE(stg_ap_2_upd,2,0,THUNK_2_0,"stg_ap_2_upd_info","stg_ap_2_upd_info")
161 {
162   TICK_ENT_DYN_THK();
163   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(2));
164   UPD_BH_UPDATABLE();
165   LDV_ENTER(R1);
166   ENTER_CCS_THUNK(R1);
167   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
168   W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,1);
169   R1 = StgThunk_payload(R1,0);
170   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(1);
171   Sp_adj(-1); // for stg_ap_0_ret
172   TICK_UNKNOWN_CALL();
173   TICK_SLOW_CALL_p();
174   jump RET_LBL(stg_ap_p);
175 }
176
177 INFO_TABLE(stg_ap_3_upd,3,0,THUNK,"stg_ap_3_upd_info","stg_ap_3_upd_info")
178 {
179   TICK_ENT_DYN_THK();
180   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(3));
181   UPD_BH_UPDATABLE();
182   LDV_ENTER(R1);
183   ENTER_CCS_THUNK(R1);
184   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
185   W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,2);
186   W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,1);
187   R1 = StgThunk_payload(R1,0);
188   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(2);
189   Sp_adj(-1); // for stg_ap_0_ret
190   TICK_UNKNOWN_CALL();
191   TICK_SLOW_CALL_pp();
192   jump RET_LBL(stg_ap_pp);
193 }
194
195 INFO_TABLE(stg_ap_4_upd,4,0,THUNK,"stg_ap_4_upd_info","stg_ap_4_upd_info")
196 {
197   TICK_ENT_DYN_THK();
198   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(4));
199   UPD_BH_UPDATABLE();
200   LDV_ENTER(R1);
201   ENTER_CCS_THUNK(R1);
202   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
203   W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,3);
204   W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,2);
205   W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,1);
206   R1 = StgThunk_payload(R1,0);
207   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(3);
208   Sp_adj(-1); // for stg_ap_0_ret
209   TICK_UNKNOWN_CALL();
210   TICK_SLOW_CALL_ppp();
211   jump RET_LBL(stg_ap_ppp);
212 }
213
214 INFO_TABLE(stg_ap_5_upd,5,0,THUNK,"stg_ap_5_upd_info","stg_ap_5_upd_info")
215 {
216   TICK_ENT_DYN_THK();
217   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(5));
218   UPD_BH_UPDATABLE();
219   LDV_ENTER(R1);
220   ENTER_CCS_THUNK(R1);
221   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
222   W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,4);
223   W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,3);
224   W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,2);
225   W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,1);
226   R1 = StgThunk_payload(R1,0);
227   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(4);
228   Sp_adj(-1); // for stg_ap_0_ret
229   TICK_UNKNOWN_CALL();
230   TICK_SLOW_CALL_pppp();
231   jump RET_LBL(stg_ap_pppp);
232 }
233
234 INFO_TABLE(stg_ap_6_upd,6,0,THUNK,"stg_ap_6_upd_info","stg_ap_6_upd_info")
235 {
236   TICK_ENT_DYN_THK();
237   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(6));
238   UPD_BH_UPDATABLE();
239   LDV_ENTER(R1);
240   ENTER_CCS_THUNK(R1);
241   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
242   W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,5);
243   W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,4);
244   W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,3);
245   W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,2);
246   W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgThunk_payload(R1,1);
247   R1 = StgThunk_payload(R1,0);
248   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(5);
249   Sp_adj(-1); // for stg_ap_0_ret
250   TICK_UNKNOWN_CALL();
251   TICK_SLOW_CALL_ppppp();
252   jump RET_LBL(stg_ap_ppppp);
253 }
254
255 INFO_TABLE(stg_ap_7_upd,7,0,THUNK,"stg_ap_7_upd_info","stg_ap_7_upd_info")
256 {
257   TICK_ENT_DYN_THK();
258   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(7));
259   UPD_BH_UPDATABLE();
260   LDV_ENTER(R1);
261   ENTER_CCS_THUNK(R1);
262   PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
263   W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,6);
264   W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,5);
265   W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,4);
266   W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,3);
267   W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgThunk_payload(R1,2);
268   W_[Sp-SIZEOF_StgUpdateFrame-WDS(6)] = StgThunk_payload(R1,1);
269   R1 = StgThunk_payload(R1,0);
270   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(6);
271   Sp_adj(-1); // for stg_ap_0_ret
272   TICK_UNKNOWN_CALL();
273   TICK_SLOW_CALL_pppppp();
274   jump RET_LBL(stg_ap_pppppp);
275 }