summaryrefslogtreecommitdiff
path: root/rts
diff options
context:
space:
mode:
authorLuite Stegeman <stegeman@gmail.com>2021-03-30 04:06:59 +0200
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-05-29 05:04:39 -0400
commit28e0dca2e93dabee88f28ce38282dbcb8c62ab99 (patch)
tree1bfb0bfd0478315c0366b252d273d25d170f85ff /rts
parent5ae070f168ba7f9679b045ea4b8f30917f47f800 (diff)
downloadhaskell-28e0dca2e93dabee88f28ce38282dbcb8c62ab99.tar.gz
Work around LLVM backend overlapping register limitations
The stg_ctoi_t and stg_ret_t procedures which convert unboxed tuples between the bytecode an native calling convention were causing a panic when using the LLVM backend. Fixes #19591
Diffstat (limited to 'rts')
-rw-r--r--rts/Interpreter.c2
-rw-r--r--rts/StgMiscClosures.cmm100
2 files changed, 18 insertions, 84 deletions
diff --git a/rts/Interpreter.c b/rts/Interpreter.c
index efbfd091d8..b2aa5e1e6c 100644
--- a/rts/Interpreter.c
+++ b/rts/Interpreter.c
@@ -1382,7 +1382,7 @@ run_BCO:
SpW(-2) = tuple_info;
SpW(-3) = BCO_PTR(o_bco);
W_ ctoi_t_offset;
- int tuple_stack_words = tuple_info & 0x3fff;
+ int tuple_stack_words = (tuple_info >> 24) & 0xff;
switch(tuple_stack_words) {
case 0: ctoi_t_offset = (W_)&stg_ctoi_t0_info; break;
case 1: ctoi_t_offset = (W_)&stg_ctoi_t1_info; break;
diff --git a/rts/StgMiscClosures.cmm b/rts/StgMiscClosures.cmm
index b9379ab3e6..244f55d67a 100644
--- a/rts/StgMiscClosures.cmm
+++ b/rts/StgMiscClosures.cmm
@@ -110,9 +110,6 @@ stg_interp_constr7_entry (P_ ret) { return (ret + 7); }
which is just what we want -- the "standard" return layout for the
interpreter. Hurrah!
-
- Don't ask me how unboxed tuple returns are supposed to work. We
- haven't got a good story about that yet.
*/
INFO_TABLE_RET( stg_ctoi_R1p, RET_BCO)
@@ -221,7 +218,7 @@ INFO_TABLE_RET( stg_ctoi_V, RET_BCO )
spilled_1
spilled_2
spilled_3 <- Sp
-
+
When stg_ctoi_t is called, the stack looks like:
...
@@ -340,26 +337,23 @@ MK_STG_CTOI_T(62)
the tuple_info word describes the register and stack usage of the tuple:
- [ rrrr ffff ffdd dddd llss ssss ssss ssss ]
+ [ ssss ssss rrrr rrrr rrrr rrrr rrrr rrrr ]
- - r: number of vanilla registers R1..Rn
- - f: bitmap of float registers F1..F6
- - d: bitmap of double registers D1..D6
- - l: bitmap of long registers L1..Ln
+ - r: bitmap of live registers, corresponding to the list of registers
+ returned by GHC.Cmm.CallConv.tupleRegsCover (the least significant
+ bit corresponds to the first element in the list)
- s: number of words on stack (in addition to registers)
- The order in which the registers are pushed on the stack is determined by
- the Ord instance of GHC.Cmm.Expr.GlobalReg. If you change the Ord instance,
- the order in stg_ctoi_t and stg_ret_t needs to be adjusted accordingly.
-
+ The order of the live registers in the bitmap is the same as the list
+ given by GHC.Cmm.CallConv.tupleRegsCover, with the least significant
+ bit corresponding to the first register in the list.
*/
stg_ctoi_t
/* explicit stack */
{
- W_ tuple_info, tuple_stack, tuple_regs_R,
- tuple_regs_F, tuple_regs_D, tuple_regs_L;
+ W_ tuple_info, tuple_stack;
P_ tuple_BCO;
tuple_info = Sp(2); /* tuple information word */
@@ -370,41 +364,12 @@ stg_ctoi_t
CCCS = Sp(4);
#endif
- tuple_stack = tuple_info & 0x3fff; /* number of words spilled on stack */
- tuple_regs_R = (tuple_info >> 28) & 0xf; /* number of R1..Rn */
- tuple_regs_F = (tuple_info >> 22) & 0x3f; /* 6 bits bitmap */
- tuple_regs_D = (tuple_info >> 16) & 0x3f; /* 6 bits bitmap */
- tuple_regs_L = (tuple_info >> 14) & 0x3; /* 2 bits bitmap */
+ /* number of words spilled on stack */
+ tuple_stack = (tuple_info >> 24) & 0xff;
Sp = Sp - WDS(tuple_stack);
- /* save long registers */
- /* fixme L2 ? */
- if((tuple_regs_L & 1) != 0) { Sp = Sp - 8; L_[Sp] = L1; }
-
- /* save double registers */
- if((tuple_regs_D & 32) != 0) { Sp = Sp - SIZEOF_DOUBLE; D_[Sp] = D6; }
- if((tuple_regs_D & 16) != 0) { Sp = Sp - SIZEOF_DOUBLE; D_[Sp] = D5; }
- if((tuple_regs_D & 8) != 0) { Sp = Sp - SIZEOF_DOUBLE; D_[Sp] = D4; }
- if((tuple_regs_D & 4) != 0) { Sp = Sp - SIZEOF_DOUBLE; D_[Sp] = D3; }
- if((tuple_regs_D & 2) != 0) { Sp = Sp - SIZEOF_DOUBLE; D_[Sp] = D2; }
- if((tuple_regs_D & 1) != 0) { Sp = Sp - SIZEOF_DOUBLE; D_[Sp] = D1; }
-
- /* save float registers */
- if((tuple_regs_F & 32) != 0) { Sp_adj(-1); F_[Sp] = F6; }
- if((tuple_regs_F & 16) != 0) { Sp_adj(-1); F_[Sp] = F5; }
- if((tuple_regs_F & 8) != 0) { Sp_adj(-1); F_[Sp] = F4; }
- if((tuple_regs_F & 4) != 0) { Sp_adj(-1); F_[Sp] = F3; }
- if((tuple_regs_F & 2) != 0) { Sp_adj(-1); F_[Sp] = F2; }
- if((tuple_regs_F & 1) != 0) { Sp_adj(-1); F_[Sp] = F1; }
-
- /* save vanilla registers */
- if(tuple_regs_R >= 6) { Sp_adj(-1); Sp(0) = R6; }
- if(tuple_regs_R >= 5) { Sp_adj(-1); Sp(0) = R5; }
- if(tuple_regs_R >= 4) { Sp_adj(-1); Sp(0) = R4; }
- if(tuple_regs_R >= 3) { Sp_adj(-1); Sp(0) = R3; }
- if(tuple_regs_R >= 2) { Sp_adj(-1); Sp(0) = R2; }
- if(tuple_regs_R >= 1) { Sp_adj(-1); Sp(0) = R1; }
+ PUSH_TUPLE_REGS(tuple_info);
/* jump to the BCO that will finish the return of the tuple */
Sp_adj(-3);
@@ -417,46 +382,15 @@ stg_ctoi_t
INFO_TABLE_RET( stg_ret_t, RET_BCO )
{
- W_ tuple_info, tuple_stack, tuple_regs_R, tuple_regs_F,
- tuple_regs_D, tuple_regs_L;
+ W_ tuple_info, tuple_stack;
tuple_info = Sp(2);
Sp_adj(3);
- tuple_stack = tuple_info & 0x3fff; /* number of words spilled on stack */
- tuple_regs_R = (tuple_info >> 28) & 0xf; /* number of R1..Rn */
- tuple_regs_F = (tuple_info >> 22) & 0x3f; /* 6 bits bitmap */
- tuple_regs_D = (tuple_info >> 16) & 0x3f; /* 6 bits bitmap */
- tuple_regs_L = (tuple_info >> 14) & 0x3; /* 2 bits bitmap */
-
- /* restore everything in the reverse order of stg_ctoi_t */
-
- /* restore vanilla registers */
- if(tuple_regs_R >= 1) { R1 = Sp(0); Sp_adj(1); }
- if(tuple_regs_R >= 2) { R2 = Sp(0); Sp_adj(1); }
- if(tuple_regs_R >= 3) { R3 = Sp(0); Sp_adj(1); }
- if(tuple_regs_R >= 4) { R4 = Sp(0); Sp_adj(1); }
- if(tuple_regs_R >= 5) { R5 = Sp(0); Sp_adj(1); }
- if(tuple_regs_R >= 6) { R6 = Sp(0); Sp_adj(1); }
-
- /* restore float registers */
- if((tuple_regs_F & 1) != 0) { F1 = F_[Sp]; Sp_adj(1); }
- if((tuple_regs_F & 2) != 0) { F2 = F_[Sp]; Sp_adj(1); }
- if((tuple_regs_F & 4) != 0) { F3 = F_[Sp]; Sp_adj(1); }
- if((tuple_regs_F & 8) != 0) { F4 = F_[Sp]; Sp_adj(1); }
- if((tuple_regs_F & 16) != 0) { F5 = F_[Sp]; Sp_adj(1); }
- if((tuple_regs_F & 32) != 0) { F6 = F_[Sp]; Sp_adj(1); }
-
- /* restore double registers */
- if((tuple_regs_D & 1) != 0) { D1 = D_[Sp]; Sp = Sp + SIZEOF_DOUBLE; }
- if((tuple_regs_D & 2) != 0) { D2 = D_[Sp]; Sp = Sp + SIZEOF_DOUBLE; }
- if((tuple_regs_D & 4) != 0) { D3 = D_[Sp]; Sp = Sp + SIZEOF_DOUBLE; }
- if((tuple_regs_D & 8) != 0) { D4 = D_[Sp]; Sp = Sp + SIZEOF_DOUBLE; }
- if((tuple_regs_D & 16) != 0) { D5 = D_[Sp]; Sp = Sp + SIZEOF_DOUBLE; }
- if((tuple_regs_D & 32) != 0) { D6 = D_[Sp]; Sp = Sp + SIZEOF_DOUBLE; }
-
- /* restore long registers */
- if((tuple_regs_L & 1) != 0) { L1 = L_[Sp]; Sp = Sp + 8; }
+ /* number of words spilled on stack */
+ tuple_stack = (tuple_info >> 24) & 0xff;
+
+ POP_TUPLE_REGS(tuple_info);
/* Sp points to the topmost argument now */
jump %ENTRY_CODE(Sp(tuple_stack)) [*]; // NB. all registers live!