1 /* -----------------------------------------------------------------------------
3 * (c) The University of Glasgow, 1998-2004
5 * Canned "Standard Form" Thunks
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.
11 * ---------------------------------------------------------------------------*/
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
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.
24 The garbage collector spots selector thunks and reduces them if
25 possible, in order to avoid space leaks resulting from lazy pattern
27 -------------------------------------------------------------------------- */
29 #define WITHUPD_FRAME_SIZE (SIZEOF_StgUpdateFrame + SIZEOF_StgHeader)
30 #define NOUPD_FRAME_SIZE (SIZEOF_StgHeader)
33 #define SAVE_CCCS(fs) StgHeader_ccs(Sp-fs) = W_[CCCS]
34 #define GET_SAVED_CCCS W_[CCCS] = StgHeader_ccs(Sp)
36 #define RET_FRAMESIZE 2
38 #define SAVE_CCCS(fs) /* empty */
39 #define GET_SAVED_CCCS /* empty */
41 #define RET_FRAMESIZE 0
44 #define SELECTOR_CODE_UPD(offset) \
45 INFO_TABLE_RET(stg_sel_ret_##offset##_upd, RET_FRAMESIZE, RET_BITMAP, RET_SMALL) \
47 R1 = StgClosure_payload(R1,offset); \
49 Sp = Sp + SIZEOF_StgHeader; \
53 INFO_TABLE_SELECTOR(stg_sel_##offset##_upd, offset, THUNK_SELECTOR, "stg_sel_upd", "stg_sel_upd") \
56 STK_CHK_NP(WITHUPD_FRAME_SIZE); \
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 = StgClosure_payload(R1,0); \
64 Sp = Sp - WITHUPD_FRAME_SIZE; \
85 #define SELECTOR_CODE_NOUPD(offset) \
86 INFO_TABLE_RET(stg_sel_ret_##offset##_noupd, RET_FRAMESIZE, RET_BITMAP, RET_SMALL) \
88 R1 = StgClosure_payload(R1,offset); \
90 Sp = Sp + SIZEOF_StgHeader; \
91 jump %GET_ENTRY(R1); \
94 INFO_TABLE_SELECTOR(stg_sel_##offset##_noupd, offset, THUNK_SELECTOR, "stg_sel_noupd", "stg_sel_noupd")\
97 STK_CHK_NP(NOUPD_FRAME_SIZE); \
98 UPD_BH_SINGLE_ENTRY(); \
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 = StgClosure_payload(R1,0); \
105 Sp = Sp - NOUPD_FRAME_SIZE; \
106 jump %GET_ENTRY(R1); \
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)
126 /* -----------------------------------------------------------------------------
129 An apply thunk is a thunk of the form
131 let z = [x1...xn] \u x1...xn
134 We pre-compile some of these because the code is always the same.
136 These have to be independent of the update frame size, so the code
137 works when profiling etc.
138 -------------------------------------------------------------------------- */
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)
144 INFO_TABLE(stg_ap_1_upd,1,1,THUNK_1_0,"stg_ap_1_upd_info","stg_ap_1_upd_info")
147 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(1));
151 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
152 R1 = StgClosure_payload(R1,0);
153 Sp = Sp - SIZEOF_StgUpdateFrame;
154 Sp_adj(-1); // for stg_ap_0_ret
155 jump RET_LBL(stg_ap_0);
158 INFO_TABLE(stg_ap_2_upd,2,0,THUNK_2_0,"stg_ap_2_upd_info","stg_ap_2_upd_info")
161 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(2));
165 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
166 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,1);
167 R1 = StgClosure_payload(R1,0);
168 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(1);
169 Sp_adj(-1); // for stg_ap_0_ret
172 jump RET_LBL(stg_ap_p);
175 INFO_TABLE(stg_ap_3_upd,3,0,THUNK,"stg_ap_3_upd_info","stg_ap_3_upd_info")
178 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(3));
182 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
183 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,2);
184 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,1);
185 R1 = StgClosure_payload(R1,0);
186 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(2);
187 Sp_adj(-1); // for stg_ap_0_ret
190 jump RET_LBL(stg_ap_pp);
193 INFO_TABLE(stg_ap_4_upd,4,0,THUNK,"stg_ap_4_upd_info","stg_ap_4_upd_info")
196 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(4));
200 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
201 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,3);
202 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,2);
203 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgClosure_payload(R1,1);
204 R1 = StgClosure_payload(R1,0);
205 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(3);
206 Sp_adj(-1); // for stg_ap_0_ret
208 TICK_SLOW_CALL_ppp();
209 jump RET_LBL(stg_ap_ppp);
212 INFO_TABLE(stg_ap_5_upd,5,0,THUNK,"stg_ap_5_upd_info","stg_ap_5_upd_info")
215 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(5));
219 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
220 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,4);
221 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,3);
222 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgClosure_payload(R1,2);
223 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgClosure_payload(R1,1);
224 R1 = StgClosure_payload(R1,0);
225 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(4);
226 Sp_adj(-1); // for stg_ap_0_ret
228 TICK_SLOW_CALL_pppp();
229 jump RET_LBL(stg_ap_pppp);
232 INFO_TABLE(stg_ap_6_upd,6,0,THUNK,"stg_ap_6_upd_info","stg_ap_6_upd_info")
235 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(6));
239 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
240 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,5);
241 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,4);
242 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgClosure_payload(R1,3);
243 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgClosure_payload(R1,2);
244 W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgClosure_payload(R1,1);
245 R1 = StgClosure_payload(R1,0);
246 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(5);
247 Sp_adj(-1); // for stg_ap_0_ret
249 TICK_SLOW_CALL_ppppp();
250 jump RET_LBL(stg_ap_ppppp);
253 INFO_TABLE(stg_ap_7_upd,7,0,THUNK,"stg_ap_7_upd_info","stg_ap_7_upd_info")
256 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(7));
260 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
261 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,6);
262 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,5);
263 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgClosure_payload(R1,4);
264 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgClosure_payload(R1,3);
265 W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgClosure_payload(R1,2);
266 W_[Sp-SIZEOF_StgUpdateFrame-WDS(6)] = StgClosure_payload(R1,1);
267 R1 = StgClosure_payload(R1,0);
268 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(6);
269 Sp_adj(-1); // for stg_ap_0_ret
271 TICK_SLOW_CALL_pppppp();
272 jump RET_LBL(stg_ap_pppppp);