+/* -----------------------------------------------------------------------------
+ *
+ * (c) The University of Glasgow, 1998-2004
+ *
+ * Canned "Standard Form" Thunks
+ *
+ * This file is written in a subset of C--, extended with various
+ * features specific to GHC. It is compiled by GHC directly. For the
+ * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "Cmm.h"
+
+/* -----------------------------------------------------------------------------
+ The code for a thunk that simply extracts a field from a
+ single-constructor datatype depends only on the offset of the field
+ to be selected.
+
+ Here we define some canned "selector" thunks that do just that; any
+ selector thunk appearing in a program will refer to one of these
+ instead of being compiled independently.
+
+ The garbage collector spots selector thunks and reduces them if
+ possible, in order to avoid space leaks resulting from lazy pattern
+ matching.
+ -------------------------------------------------------------------------- */
+
+#define WITHUPD_FRAME_SIZE (SIZEOF_StgUpdateFrame + SIZEOF_StgHeader)
+#define NOUPD_FRAME_SIZE (SIZEOF_StgHeader)
+
+#ifdef PROFILING
+#define SAVE_CCCS(fs) StgHeader_ccs(Sp-fs) = W_[CCCS]
+#define GET_SAVED_CCCS W_[CCCS] = StgHeader_ccs(Sp)
+#define RET_BITMAP 3
+#define RET_FRAMESIZE 2
+#else
+#define SAVE_CCCS(fs) /* empty */
+#define GET_SAVED_CCCS /* empty */
+#define RET_BITMAP 0
+#define RET_FRAMESIZE 0
+#endif
+
+#define SELECTOR_CODE_UPD(offset) \
+ INFO_TABLE_RET(stg_sel_ret_##offset##_upd, RET_FRAMESIZE, RET_BITMAP, RET_SMALL) \
+ { \
+ R1 = StgClosure_payload(R1,offset); \
+ GET_SAVED_CCCS; \
+ Sp = Sp + SIZEOF_StgHeader; \
+ ENTER(); \
+ } \
+ \
+ INFO_TABLE_SELECTOR(stg_sel_##offset##_upd, offset, THUNK_SELECTOR, "stg_sel_upd", "stg_sel_upd") \
+ { \
+ TICK_ENT_DYN_THK(); \
+ STK_CHK_NP(WITHUPD_FRAME_SIZE); \
+ UPD_BH_UPDATABLE(); \
+ LDV_ENTER(R1); \
+ PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1); \
+ ENTER_CCS_THUNK(R1); \
+ SAVE_CCCS(WITHUPD_FRAME_SIZE); \
+ W_[Sp-WITHUPD_FRAME_SIZE] = stg_sel_ret_##offset##_upd_info; \
+ R1 = StgThunk_payload(R1,0); \
+ Sp = Sp - WITHUPD_FRAME_SIZE; \
+ jump %GET_ENTRY(R1); \
+ }
+ /* NOTE: no need to ENTER() here, we know the closure cannot evaluate to a function,
+ because we're going to do a field selection on the result. */
+
+SELECTOR_CODE_UPD(0)
+SELECTOR_CODE_UPD(1)
+SELECTOR_CODE_UPD(2)
+SELECTOR_CODE_UPD(3)
+SELECTOR_CODE_UPD(4)
+SELECTOR_CODE_UPD(5)
+SELECTOR_CODE_UPD(6)
+SELECTOR_CODE_UPD(7)
+SELECTOR_CODE_UPD(8)
+SELECTOR_CODE_UPD(9)
+SELECTOR_CODE_UPD(10)
+SELECTOR_CODE_UPD(11)
+SELECTOR_CODE_UPD(12)
+SELECTOR_CODE_UPD(13)
+SELECTOR_CODE_UPD(14)
+SELECTOR_CODE_UPD(15)
+
+#define SELECTOR_CODE_NOUPD(offset) \
+ INFO_TABLE_RET(stg_sel_ret_##offset##_noupd, RET_FRAMESIZE, RET_BITMAP, RET_SMALL) \
+ { \
+ R1 = StgClosure_payload(R1,offset); \
+ GET_SAVED_CCCS; \
+ Sp = Sp + SIZEOF_StgHeader; \
+ jump %GET_ENTRY(R1); \
+ } \
+ \
+ INFO_TABLE_SELECTOR(stg_sel_##offset##_noupd, offset, THUNK_SELECTOR, "stg_sel_noupd", "stg_sel_noupd")\
+ { \
+ TICK_ENT_DYN_THK(); \
+ STK_CHK_NP(NOUPD_FRAME_SIZE); \
+ UPD_BH_SINGLE_ENTRY(); \
+ LDV_ENTER(R1); \
+ TICK_UPDF_OMITTED(); \
+ ENTER_CCS_THUNK(R1); \
+ SAVE_CCCS(NOUPD_FRAME_SIZE); \
+ W_[Sp-NOUPD_FRAME_SIZE] = stg_sel_ret_##offset##_noupd_info; \
+ R1 = StgThunk_payload(R1,0); \
+ Sp = Sp - NOUPD_FRAME_SIZE; \
+ jump %GET_ENTRY(R1); \
+ }
+
+SELECTOR_CODE_NOUPD(0)
+SELECTOR_CODE_NOUPD(1)
+SELECTOR_CODE_NOUPD(2)
+SELECTOR_CODE_NOUPD(3)
+SELECTOR_CODE_NOUPD(4)
+SELECTOR_CODE_NOUPD(5)
+SELECTOR_CODE_NOUPD(6)
+SELECTOR_CODE_NOUPD(7)
+SELECTOR_CODE_NOUPD(8)
+SELECTOR_CODE_NOUPD(9)
+SELECTOR_CODE_NOUPD(10)
+SELECTOR_CODE_NOUPD(11)
+SELECTOR_CODE_NOUPD(12)
+SELECTOR_CODE_NOUPD(13)
+SELECTOR_CODE_NOUPD(14)
+SELECTOR_CODE_NOUPD(15)
+
+/* -----------------------------------------------------------------------------
+ Apply thunks
+
+ An apply thunk is a thunk of the form
+
+ let z = [x1...xn] \u x1...xn
+ in ...
+
+ We pre-compile some of these because the code is always the same.
+
+ These have to be independent of the update frame size, so the code
+ works when profiling etc.
+ -------------------------------------------------------------------------- */
+
+/* stg_ap_1_upd_info is a bit redundant, but there appears to be a bug
+ * in the compiler that means stg_ap_1 is generated occasionally (ToDo)
+ */
+
+INFO_TABLE(stg_ap_1_upd,1,1,THUNK_1_0,"stg_ap_1_upd_info","stg_ap_1_upd_info")
+{
+ TICK_ENT_DYN_THK();
+ STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(1));
+ UPD_BH_UPDATABLE();
+ LDV_ENTER(R1);
+ ENTER_CCS_THUNK(R1);
+ PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+ R1 = StgThunk_payload(R1,0);
+ Sp = Sp - SIZEOF_StgUpdateFrame;
+ jump stg_ap_0_fast;
+}
+
+INFO_TABLE(stg_ap_2_upd,2,0,THUNK_2_0,"stg_ap_2_upd_info","stg_ap_2_upd_info")
+{
+ TICK_ENT_DYN_THK();
+ STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(2));
+ UPD_BH_UPDATABLE();
+ LDV_ENTER(R1);
+ ENTER_CCS_THUNK(R1);
+ PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,1);
+ R1 = StgThunk_payload(R1,0);
+ Sp = Sp - SIZEOF_StgUpdateFrame - WDS(1);
+ Sp_adj(-1); // for stg_ap_*_ret
+ TICK_UNKNOWN_CALL();
+ TICK_SLOW_CALL_p();
+ jump RET_LBL(stg_ap_p);
+}
+
+INFO_TABLE(stg_ap_3_upd,3,0,THUNK,"stg_ap_3_upd_info","stg_ap_3_upd_info")
+{
+ TICK_ENT_DYN_THK();
+ STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(3));
+ UPD_BH_UPDATABLE();
+ LDV_ENTER(R1);
+ ENTER_CCS_THUNK(R1);
+ PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,2);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,1);
+ R1 = StgThunk_payload(R1,0);
+ Sp = Sp - SIZEOF_StgUpdateFrame - WDS(2);
+ Sp_adj(-1); // for stg_ap_*_ret
+ TICK_UNKNOWN_CALL();
+ TICK_SLOW_CALL_pp();
+ jump RET_LBL(stg_ap_pp);
+}
+
+INFO_TABLE(stg_ap_4_upd,4,0,THUNK,"stg_ap_4_upd_info","stg_ap_4_upd_info")
+{
+ TICK_ENT_DYN_THK();
+ STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(4));
+ UPD_BH_UPDATABLE();
+ LDV_ENTER(R1);
+ ENTER_CCS_THUNK(R1);
+ PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,3);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,2);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,1);
+ R1 = StgThunk_payload(R1,0);
+ Sp = Sp - SIZEOF_StgUpdateFrame - WDS(3);
+ Sp_adj(-1); // for stg_ap_*_ret
+ TICK_UNKNOWN_CALL();
+ TICK_SLOW_CALL_ppp();
+ jump RET_LBL(stg_ap_ppp);
+}
+
+INFO_TABLE(stg_ap_5_upd,5,0,THUNK,"stg_ap_5_upd_info","stg_ap_5_upd_info")
+{
+ TICK_ENT_DYN_THK();
+ STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(5));
+ UPD_BH_UPDATABLE();
+ LDV_ENTER(R1);
+ ENTER_CCS_THUNK(R1);
+ PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,4);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,3);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,2);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,1);
+ R1 = StgThunk_payload(R1,0);
+ Sp = Sp - SIZEOF_StgUpdateFrame - WDS(4);
+ Sp_adj(-1); // for stg_ap_*_ret
+ TICK_UNKNOWN_CALL();
+ TICK_SLOW_CALL_pppp();
+ jump RET_LBL(stg_ap_pppp);
+}
+
+INFO_TABLE(stg_ap_6_upd,6,0,THUNK,"stg_ap_6_upd_info","stg_ap_6_upd_info")
+{
+ TICK_ENT_DYN_THK();
+ STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(6));
+ UPD_BH_UPDATABLE();
+ LDV_ENTER(R1);
+ ENTER_CCS_THUNK(R1);
+ PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,5);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,4);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,3);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,2);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgThunk_payload(R1,1);
+ R1 = StgThunk_payload(R1,0);
+ Sp = Sp - SIZEOF_StgUpdateFrame - WDS(5);
+ Sp_adj(-1); // for stg_ap_*_ret
+ TICK_UNKNOWN_CALL();
+ TICK_SLOW_CALL_ppppp();
+ jump RET_LBL(stg_ap_ppppp);
+}
+
+INFO_TABLE(stg_ap_7_upd,7,0,THUNK,"stg_ap_7_upd_info","stg_ap_7_upd_info")
+{
+ TICK_ENT_DYN_THK();
+ STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(7));
+ UPD_BH_UPDATABLE();
+ LDV_ENTER(R1);
+ ENTER_CCS_THUNK(R1);
+ PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,6);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,5);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,4);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,3);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgThunk_payload(R1,2);
+ W_[Sp-SIZEOF_StgUpdateFrame-WDS(6)] = StgThunk_payload(R1,1);
+ R1 = StgThunk_payload(R1,0);
+ Sp = Sp - SIZEOF_StgUpdateFrame - WDS(6);
+ Sp_adj(-1); // for stg_ap_*_ret
+ TICK_UNKNOWN_CALL();
+ TICK_SLOW_CALL_pppppp();
+ jump RET_LBL(stg_ap_pppppp);
+}