[project @ 2004-08-13 13:04:50 by simonmar]
[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 = StgClosure_payload(R1,0);                                            \
64       Sp = Sp - WITHUPD_FRAME_SIZE;                                     \
65       ENTER();                                                          \
66   }
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_FRAMESIZE, RET_BITMAP, RET_SMALL)    \
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 = StgClosure_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 = 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);
156 }
157
158 INFO_TABLE(stg_ap_2_upd,2,0,THUNK_2_0,"stg_ap_2_upd_info","stg_ap_2_upd_info")
159 {
160   TICK_ENT_DYN_THK();
161   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(2));
162   UPD_BH_UPDATABLE();
163   LDV_ENTER(R1);
164   ENTER_CCS_THUNK(R1);
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
170   TICK_UNKNOWN_CALL();
171   TICK_SLOW_CALL_p();
172   jump RET_LBL(stg_ap_p);
173 }
174
175 INFO_TABLE(stg_ap_3_upd,3,0,THUNK,"stg_ap_3_upd_info","stg_ap_3_upd_info")
176 {
177   TICK_ENT_DYN_THK();
178   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(3));
179   UPD_BH_UPDATABLE();
180   LDV_ENTER(R1);
181   ENTER_CCS_THUNK(R1);
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
188   TICK_UNKNOWN_CALL();
189   TICK_SLOW_CALL_pp();
190   jump RET_LBL(stg_ap_pp);
191 }
192
193 INFO_TABLE(stg_ap_4_upd,4,0,THUNK,"stg_ap_4_upd_info","stg_ap_4_upd_info")
194 {
195   TICK_ENT_DYN_THK();
196   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(4));
197   UPD_BH_UPDATABLE();
198   LDV_ENTER(R1);
199   ENTER_CCS_THUNK(R1);
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
207   TICK_UNKNOWN_CALL();
208   TICK_SLOW_CALL_ppp();
209   jump RET_LBL(stg_ap_ppp);
210 }
211
212 INFO_TABLE(stg_ap_5_upd,5,0,THUNK,"stg_ap_5_upd_info","stg_ap_5_upd_info")
213 {
214   TICK_ENT_DYN_THK();
215   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(5));
216   UPD_BH_UPDATABLE();
217   LDV_ENTER(R1);
218   ENTER_CCS_THUNK(R1);
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
227   TICK_UNKNOWN_CALL();
228   TICK_SLOW_CALL_pppp();
229   jump RET_LBL(stg_ap_pppp);
230 }
231
232 INFO_TABLE(stg_ap_6_upd,6,0,THUNK,"stg_ap_6_upd_info","stg_ap_6_upd_info")
233 {
234   TICK_ENT_DYN_THK();
235   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(6));
236   UPD_BH_UPDATABLE();
237   LDV_ENTER(R1);
238   ENTER_CCS_THUNK(R1);
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
248   TICK_UNKNOWN_CALL();
249   TICK_SLOW_CALL_ppppp();
250   jump RET_LBL(stg_ap_ppppp);
251 }
252
253 INFO_TABLE(stg_ap_7_upd,7,0,THUNK,"stg_ap_7_upd_info","stg_ap_7_upd_info")
254 {
255   TICK_ENT_DYN_THK();
256   STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(7));
257   UPD_BH_UPDATABLE();
258   LDV_ENTER(R1);
259   ENTER_CCS_THUNK(R1);
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
270   TICK_UNKNOWN_CALL();
271   TICK_SLOW_CALL_pppppp();
272   jump RET_LBL(stg_ap_pppppp);
273 }