Skip to content

Commit 7438ab5

Browse files
committed
jit: admit exact arm64 ADDOV two first side
1 parent 060aac5 commit 7438ab5

7 files changed

Lines changed: 295 additions & 77 deletions

src/lj_asm.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,7 @@ static int arm64_ir_constants(const GCtrace *T, LJArm64IRReject *reject)
654654
/* -- Pure ARM64 first-side admission ------------------------------------- */
655655

656656
enum {
657-
ARM64_SIDE_K_ONE = REF_TRUE-1u,
657+
ARM64_SIDE_K_ADDEND = REF_TRUE-1u,
658658
ARM64_SIDE_R_PARENT = REF_BASE+1u,
659659
ARM64_SIDE_R_CGET = REF_BASE+2u,
660660
ARM64_SIDE_R_ADD = REF_BASE+3u,
@@ -667,9 +667,12 @@ enum {
667667
const LJArm64SideShape *lj_asm_arm64_side_shape(ExitNo exitno)
668668
{
669669
static const LJArm64SideShape shapes[] = {
670-
{ 2u, 8u, 13u, { 13u, 14u, 3u, 17u, 7u }, RID_X28, RID_X27 },
671-
{ 6u, 9u, 10u, { 10u, 11u, 3u, 17u, 7u }, RID_X27, RID_X28 },
672-
{ 7u, 11u, 13u, { 13u, 14u, 3u, 17u, 7u }, RID_X28, RID_X27 }
670+
{ 2u, 8u, 13u, { 13u, 14u, 3u, 17u, 7u },
671+
RID_X28, RID_X27, { 1, 1 } },
672+
{ 6u, 9u, 10u, { 10u, 11u, 3u, 17u, 7u },
673+
RID_X27, RID_X28, { 1, 2 } },
674+
{ 7u, 11u, 13u, { 13u, 14u, 3u, 17u, 7u },
675+
RID_X28, RID_X27, { 1, 1 } }
673676
};
674677
MSize i;
675678
for (i = 0; i < sizeof(shapes)/sizeof(shapes[0]); i++)
@@ -739,7 +742,7 @@ int lj_asm_arm64_side_ir_admit(const LJArm64SideIRView *view,
739742
(uintptr_t)view->proto_sizebc >
740743
(UINTPTR_MAX-proto)/sizeof(BCIns) ||
741744
view->nins != ARM64_SIDE_SEMANTIC_NINS ||
742-
view->nk != ARM64_SIDE_K_ONE || view->nsnap != 5u ||
745+
view->nk != ARM64_SIDE_K_ADDEND || view->nsnap != 5u ||
743746
view->nsnapmap != 17u || view->baseslot != 1u+LJ_FR2 ||
744747
view->root_topslot != 5u || view->traceno == 0 ||
745748
view->traceno > UINT16_MAX || view->parent == 0 ||
@@ -752,10 +755,11 @@ int lj_asm_arm64_side_ir_admit(const LJArm64SideIRView *view,
752755
return arm64_ir_reject(reject, LJ_ARM64_IR_REJECT_TRACE,
753756
REF_BASE, IR_BASE, (uint16_t)view->exitno);
754757

755-
ins = ir_load_acq(&ir[ARM64_SIDE_K_ONE]);
756-
if (ins.o != IR_KINT || ins.t.irt != IRT_INT || ins.i != 1)
758+
ins = ir_load_acq(&ir[ARM64_SIDE_K_ADDEND]);
759+
if (ins.o != IR_KINT || ins.t.irt != IRT_INT ||
760+
(ins.i != shape->addends[0] && ins.i != shape->addends[1]))
757761
return arm64_ir_reject(reject, LJ_ARM64_IR_REJECT_CONSTANT,
758-
ARM64_SIDE_K_ONE, (IROp)ins.o, ins.t.irt);
762+
ARM64_SIDE_K_ADDEND, (IROp)ins.o, ins.t.irt);
759763
for (snapno = REF_TRUE; snapno <= REF_NIL; snapno++) {
760764
IRType expected = (IRType)(REF_NIL-snapno);
761765
ins = ir_load_acq(&ir[snapno]);
@@ -780,7 +784,7 @@ int lj_asm_arm64_side_ir_admit(const LJArm64SideIRView *view,
780784
IRSLOAD_PARENT|IRSLOAD_INHERIT);
781785
ARM64_SIDE_REQUIRE(ARM64_SIDE_R_CGET, IR_NOP, IRT_NIL, 0, 0);
782786
ARM64_SIDE_REQUIRE(ARM64_SIDE_R_ADD, IR_ADDOV, IRT_INT|IRT_GUARD,
783-
ARM64_SIDE_R_PARENT, ARM64_SIDE_K_ONE);
787+
ARM64_SIDE_R_PARENT, ARM64_SIDE_K_ADDEND);
784788
ARM64_SIDE_REQUIRE(ARM64_SIDE_R_LIMIT, IR_SLOAD, IRT_INT|IRT_GUARD, 2,
785789
IRSLOAD_TYPECHECK);
786790
ARM64_SIDE_REQUIRE(ARM64_SIDE_R_GT, IR_GT, IRT_INT|IRT_GUARD,
@@ -876,7 +880,7 @@ int lj_asm_arm64_side_prehead_admit(const LJArm64SidePostRAView *view,
876880
ins = ir_load_acq(&ir[ARM64_SIDE_R_XPOLL]);
877881
if (ins.r != RID_INIT || ins.s != SPS_NONE)
878882
return 0;
879-
for (ref = ARM64_SIDE_K_ONE; ref <= REF_NIL; ref++) {
883+
for (ref = ARM64_SIDE_K_ADDEND; ref <= REF_NIL; ref++) {
880884
ins = ir_load_acq(&ir[ref]);
881885
if (ins.r != RID_INIT || ins.s != SPS_NONE)
882886
return 0;

src/lj_asm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ typedef struct LJArm64SideShape {
9595
MSize child_pcpos[LJ_ARM64_SIDE_CHILD_NSNAP];
9696
uint32_t inherited_reg;
9797
uint32_t sload_reg;
98+
int32_t addends[2]; /* Repeat addends[0] for a singleton exact set. */
9899
} LJArm64SideShape;
99100

100101
/* Exact immutable view of the repeatedly observed first-side ARM64 allocator

tests/t-arm64-jit-first-side-production.c

Lines changed: 92 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
**
44
** This fixture is intentionally built without either ARM64 side test seam.
55
** The no-helper build is an embedded-Lua smoke test. The helper build adds
6-
** white-box checks for three independently recorded prototype/root/child pairs,
6+
** white-box checks for four independently recorded prototype/root/child pairs,
77
** native entry, authenticated exit-table representation, and retirement.
88
*/
99

@@ -101,17 +101,25 @@ static void define_probes(lua_State *L)
101101
"end "
102102
"return i "
103103
"end "
104-
"local function unsupported(n, bias) "
104+
"local function fourth(n, bias) "
105105
"local i=0 "
106106
"while i<n do "
107107
"i=(i~=0 and i or i)+2 "
108108
"end "
109109
"return i "
110110
"end "
111+
"local function unsupported(n, bias) "
112+
"local i=0 "
113+
"while i<n do "
114+
"i=(i~=0 and i or i)+3 "
115+
"end "
116+
"return i "
117+
"end "
111118
"__arm64_first_side_production_decoy=decoy; "
112119
"__arm64_first_side_production_first=first; "
113120
"__arm64_first_side_production_second=second; "
114121
"__arm64_first_side_production_third=third; "
122+
"__arm64_first_side_production_fourth=fourth; "
115123
"__arm64_first_side_production_unsupported=unsupported");
116124
}
117125

@@ -127,6 +135,19 @@ static int smoke_main(void)
127135
luaL_openlibs(L);
128136
define_probes(L);
129137

138+
/* Run the two same-bytecode exit-6 variants before unrelated hot-count
139+
** slots can collide. The +2 root is recorded with n=3 and its admitted
140+
** root-linked child with n=5; repeated +3 calls retain only the root. */
141+
assert(call_named(L, "__arm64_first_side_production_fourth", 3, 0) == 4);
142+
assert(call_named(L, "__arm64_first_side_production_fourth", 3, 0) == 4);
143+
assert(call_named(L, "__arm64_first_side_production_fourth", 5, 0) == 6);
144+
assert(call_named(L, "__arm64_first_side_production_fourth", 5, 0) == 6);
145+
assert(call_named(L, "__arm64_first_side_production_fourth", 5, 0) == 6);
146+
assert(call_named(L, "__arm64_first_side_production_fourth", 5, 0) == 6);
147+
for (attempt = 0; attempt < PRODUCTION_ROOT_ATTEMPTS; attempt++)
148+
assert(call_named(L, "__arm64_first_side_production_unsupported",
149+
4, 0) == 6);
150+
130151
assert(call_named(L, "__arm64_first_side_production_decoy", 3, 0) == 3);
131152
assert(call_named(L, "__arm64_first_side_production_first", 3, 0) == 3);
132153
assert(call_named(L, "__arm64_first_side_production_first", 3, 1) == 4);
@@ -138,20 +159,16 @@ static int smoke_main(void)
138159
assert(call_named(L, "__arm64_first_side_production_third", 4, 0) == 4);
139160
assert(call_named(L, "__arm64_first_side_production_third", 4, 0) == 4);
140161
assert(call_named(L, "__arm64_first_side_production_third", 3, 0) == 3);
141-
for (attempt = 0; attempt < PRODUCTION_ROOT_ATTEMPTS; attempt++)
142-
assert(call_named(L, "__arm64_first_side_production_unsupported",
143-
3, 0) == 4);
144-
145162
run_lua(L,
146163
"local util=require('jit.util'); local live, roots, sides=0,0,0; "
147164
"for tr=1,32 do local i=util.traceinfo(tr); if i then "
148165
"live=live+1; "
149166
"if i.linktype=='loop' then roots=roots+1 "
150167
"elseif i.linktype=='root' then sides=sides+1 end "
151168
"end end; "
152-
"assert(live==8, 'expected eight production traces, got '..live); "
153-
"assert(roots==5, 'expected five roots, got '..roots); "
154-
"assert(sides==3, 'expected three first sides, got '..sides)");
169+
"assert(live==10, 'expected ten production traces, got '..live); "
170+
"assert(roots==6, 'expected six roots, got '..roots); "
171+
"assert(sides==4, 'expected four first sides, got '..sides)");
155172

156173
lua_close(L);
157174
puts("t-arm64-jit-first-side-production smoke OK");
@@ -174,12 +191,12 @@ static int smoke_main(void)
174191
#include "lj_trace.h"
175192

176193
enum {
177-
PRODUCTION_PAIR_COUNT = 3,
194+
PRODUCTION_PAIR_COUNT = 4,
178195
PRODUCTION_CHILD_EXIT = 3,
179196
PRODUCTION_TOPSLOT = 5,
180197
PRODUCTION_CHILD_NSNAP = 5,
181198
PRODUCTION_CHILD_NSNAPMAP = 17,
182-
PRODUCTION_CHILD_K_ONE = REF_TRUE-1u,
199+
PRODUCTION_CHILD_K_ADDEND = REF_TRUE-1u,
183200
PRODUCTION_CHILD_R_PARENT = REF_BASE+1u,
184201
PRODUCTION_CHILD_R_CGET = REF_BASE+2u,
185202
PRODUCTION_CHILD_R_ADD = REF_BASE+3u,
@@ -206,6 +223,7 @@ typedef struct ProductionPair {
206223
MSize child_pcpos[PRODUCTION_CHILD_NSNAP];
207224
Reg inherited_reg;
208225
Reg sload_reg;
226+
int32_t addend;
209227
GCproto *pt;
210228
TraceNo rootno;
211229
TraceNo childno;
@@ -501,7 +519,7 @@ static void expect_child_shape(jit_State *J, global_State *g,
501519
assert(trace_exittab_nslots_acq(pair->child) ==
502520
PRODUCTION_CHILD_NSNAP+1u);
503521
assert(ir != NULL && snap != NULL && snapmap != NULL && exittab != NULL);
504-
assert(trace_nk_acq(pair->child) == PRODUCTION_CHILD_K_ONE);
522+
assert(trace_nk_acq(pair->child) == PRODUCTION_CHILD_K_ADDEND);
505523
assert(trace_nins_acq(pair->child) ==
506524
PRODUCTION_CHILD_SEMANTIC_NINS+1u);
507525
assert(la_load8_acq(&pair->child->unused1) ==
@@ -521,7 +539,7 @@ static void expect_child_shape(jit_State *J, global_State *g,
521539
IRSLOAD_PARENT|IRSLOAD_INHERIT);
522540
EXPECT_CHILD_IR(PRODUCTION_CHILD_R_CGET, IR_NOP, IRT_NIL, 0, 0);
523541
EXPECT_CHILD_IR(PRODUCTION_CHILD_R_ADD, IR_ADDOV, IRT_INT|IRT_GUARD,
524-
PRODUCTION_CHILD_R_PARENT, PRODUCTION_CHILD_K_ONE);
542+
PRODUCTION_CHILD_R_PARENT, PRODUCTION_CHILD_K_ADDEND);
525543
EXPECT_CHILD_IR(PRODUCTION_CHILD_R_LIMIT, IR_SLOAD, IRT_INT|IRT_GUARD, 2,
526544
IRSLOAD_TYPECHECK);
527545
EXPECT_CHILD_IR(PRODUCTION_CHILD_R_GT, IR_GT, IRT_INT|IRT_GUARD,
@@ -530,8 +548,9 @@ static void expect_child_shape(jit_State *J, global_State *g,
530548
1, 0);
531549
EXPECT_CHILD_IR(PRODUCTION_CHILD_SEMANTIC_NINS, IR_NOP, IRT_NIL, 0, 0);
532550
#undef EXPECT_CHILD_IR
533-
ins = ir_load_acq(&ir[PRODUCTION_CHILD_K_ONE]);
534-
assert(ins.o == IR_KINT && ins.t.irt == IRT_INT && ins.i == 1);
551+
ins = ir_load_acq(&ir[PRODUCTION_CHILD_K_ADDEND]);
552+
assert(ins.o == IR_KINT && ins.t.irt == IRT_INT &&
553+
ins.i == pair->addend);
535554
ins = ir_load_acq(&ir[REF_BASE]);
536555
assert(ins.r == RID_BASE && ins.s == SPS_NONE);
537556
ins = ir_load_acq(&ir[PRODUCTION_CHILD_R_PARENT]);
@@ -619,6 +638,18 @@ static void expect_native_child(lua_State *L, jit_State *J,
619638
lj_trace_test_reset_exit_stats();
620639
assert(call_named(L, pair->name, pair->native_n, pair->native_bias) ==
621640
pair->native_result);
641+
if (lj_trace_test_exit_calls() != 1 ||
642+
lj_trace_test_first_exit_parent() != pair->childno ||
643+
lj_trace_test_first_exitno() != PRODUCTION_CHILD_EXIT ||
644+
lj_trace_test_last_exit_parent() != pair->childno ||
645+
lj_trace_test_last_exitno() != PRODUCTION_CHILD_EXIT)
646+
fprintf(stderr,
647+
"native child %s: calls=%u first=%u/%u last=%u/%u child=%u\n",
648+
pair->name, (unsigned)lj_trace_test_exit_calls(),
649+
(unsigned)lj_trace_test_first_exit_parent(),
650+
(unsigned)lj_trace_test_first_exitno(),
651+
(unsigned)lj_trace_test_last_exit_parent(),
652+
(unsigned)lj_trace_test_last_exitno(), (unsigned)pair->childno);
622653
assert(lj_trace_test_exit_calls() == 1);
623654
assert(lj_trace_test_first_exit_parent() == pair->childno);
624655
assert(lj_trace_test_first_exitno() == PRODUCTION_CHILD_EXIT);
@@ -652,6 +683,28 @@ static void expect_unsupported_first_side_closed(lua_State *L, jit_State *J,
652683
expect_edge(g, pair, pair->root_fallback);
653684
}
654685

686+
static void expect_return_linked_variant_closed(lua_State *L, jit_State *J,
687+
global_State *g, ProductionPair *pair)
688+
{
689+
uint32_t before = live_trace_count(J);
690+
MSize count_before = snap_count_acq(&pair->root_snap[pair->exitno]);
691+
MSize count_after;
692+
assert(pair->exitno == 6 && pair->addend == 2);
693+
assert(count_before < SNAPCOUNT_DONE-2u);
694+
lj_trace_test_reset_exittab_stats();
695+
assert(call_named(L, pair->name, 3, 0) == 4);
696+
assert(call_named(L, pair->name, 3, 0) == 4);
697+
count_after = snap_count_acq(&pair->root_snap[pair->exitno]);
698+
assert(lj_trace_test_abort_count() == 2);
699+
assert(lj_trace_test_last_abort_error() == LJ_TRERR_NYIIR);
700+
assert(count_after == count_before+2u && count_after < SNAPCOUNT_DONE);
701+
assert(live_trace_count(J) == before);
702+
assert(trace_runnable_acq(pair->root, pair->rootno));
703+
assert(trace_nchild_acq(pair->root) == 0);
704+
assert(trace_nextside_acq(pair->root) == 0);
705+
expect_edge(g, pair, pair->root_fallback);
706+
}
707+
655708
static void expect_quiescent(lua_State *L, jit_State *J, global_State *g,
656709
TGState *tg, void *saved_cframe, int32_t saved_vmstate)
657710
{
@@ -735,7 +788,7 @@ static void expect_full_flush(lua_State *L, jit_State *J, global_State *g,
735788
unsigned i;
736789
lj_trace_test_reset_retire_publish_calls();
737790
assert(lj_trace_flushall_gc(L) == 0);
738-
assert(lj_trace_test_retire_publish_calls() == 8u);
791+
assert(lj_trace_test_retire_publish_calls() == 10u);
739792
assert(trace_traceno_acq(decoy) == 0);
740793
assert(proto_trace_acq(decoy_pt) == 0);
741794
for (i = 0; i < PRODUCTION_PAIR_COUNT; i++) {
@@ -778,7 +831,7 @@ static int detailed_main(int argc, char **argv)
778831
.native_n = 3, .native_bias = 1, .native_result = 4,
779832
.exitno = 2, .root_nsnap = 8, .continuation_pos = 13,
780833
.child_pcpos = { 13, 14, 3, 17, 7 },
781-
.inherited_reg = RID_X28, .sload_reg = RID_X27
834+
.inherited_reg = RID_X28, .sload_reg = RID_X27, .addend = 1
782835
},
783836
{
784837
.name = "__arm64_first_side_production_second",
@@ -787,7 +840,7 @@ static int detailed_main(int argc, char **argv)
787840
.native_n = 2, .native_bias = 0, .native_result = 2,
788841
.exitno = 6, .root_nsnap = 9, .continuation_pos = 10,
789842
.child_pcpos = { 10, 11, 3, 17, 7 },
790-
.inherited_reg = RID_X27, .sload_reg = RID_X28
843+
.inherited_reg = RID_X27, .sload_reg = RID_X28, .addend = 1
791844
},
792845
{
793846
.name = "__arm64_first_side_production_third",
@@ -796,16 +849,25 @@ static int detailed_main(int argc, char **argv)
796849
.native_n = 3, .native_bias = 0, .native_result = 3,
797850
.exitno = 7, .root_nsnap = 11, .continuation_pos = 13,
798851
.child_pcpos = { 13, 14, 3, 17, 7 },
799-
.inherited_reg = RID_X28, .sload_reg = RID_X27
852+
.inherited_reg = RID_X28, .sload_reg = RID_X27, .addend = 1
853+
},
854+
{
855+
.name = "__arm64_first_side_production_fourth",
856+
.root_n = 3, .root_bias = 0, .root_result = 4,
857+
.side_n = 5, .side_bias = 0, .side_result = 6,
858+
.native_n = 3, .native_bias = 0, .native_result = 4,
859+
.exitno = 6, .root_nsnap = 9, .continuation_pos = 10,
860+
.child_pcpos = { 10, 11, 3, 17, 7 },
861+
.inherited_reg = RID_X27, .sload_reg = RID_X28, .addend = 2
800862
}
801863
};
802864
ProductionPair unsupported = {
803865
.name = "__arm64_first_side_production_unsupported",
804-
.root_n = 3, .root_bias = 0, .root_result = 4,
805-
.side_n = 3, .side_bias = 0, .side_result = 4,
866+
.root_n = 4, .root_bias = 0, .root_result = 6,
867+
.side_n = 7, .side_bias = 0, .side_result = 9,
806868
.exitno = 6, .root_nsnap = 9, .continuation_pos = 10,
807869
.child_pcpos = { 10, 11, 3, 17, 7 },
808-
.inherited_reg = RID_X27, .sload_reg = RID_X28
870+
.inherited_reg = RID_X27, .sload_reg = RID_X28, .addend = 3
809871
};
810872
void *saved_cframe;
811873
int32_t saved_vmstate;
@@ -834,26 +896,31 @@ static int detailed_main(int argc, char **argv)
834896
record_root(L, J, &pairs[i]);
835897
expect_root_shape(J, g, &pairs[i]);
836898
assert(pairs[i].rootno > (i == 0 ? decoy_no : pairs[i-1u].childno));
899+
if (pairs[i].addend == 2)
900+
expect_return_linked_variant_closed(L, J, g, &pairs[i]);
837901
expect_post_token_request_cleanup(L, J, g, tg, &pairs[i]);
838902
record_child(L, J, &pairs[i]);
839903
expect_child_shape(J, g, &pairs[i]);
840904
for (j = 0; j < i; j++) {
841905
assert(pairs[i].rootno != pairs[j].rootno);
842906
assert(pairs[i].rootno != pairs[j].childno);
843907
assert(pairs[i].childno != pairs[j].childno);
844-
assert(pairs[i].exitno != pairs[j].exitno);
908+
assert(pairs[i].exitno != pairs[j].exitno ||
909+
pairs[i].addend != pairs[j].addend);
845910
}
846911
}
912+
assert(pairs[1].exitno == 6 && pairs[1].addend == 1);
913+
assert(pairs[3].exitno == 6 && pairs[3].addend == 2);
847914
assert(pairs[0].rootno != 1 && pairs[0].childno != 2);
848915
expect_unsupported_first_side_closed(L, J, g, &unsupported);
849916
assert(unsupported.rootno > pairs[PRODUCTION_PAIR_COUNT-1u].childno);
850-
assert(live_trace_count(J) == 8u);
917+
assert(live_trace_count(J) == 10u);
851918

852919
expect_quiescent(L, J, g, tg, saved_cframe, saved_vmstate);
853920
for (j = 0; j < 2; j++)
854921
for (i = 0; i < PRODUCTION_PAIR_COUNT; i++)
855922
expect_native_child(L, J, &pairs[i]);
856-
assert(live_trace_count(J) == 8u);
923+
assert(live_trace_count(J) == 10u);
857924
for (i = 0; i < PRODUCTION_PAIR_COUNT; i++)
858925
expect_edge(g, &pairs[i], pairs[i].child_mcode);
859926
expect_quiescent(L, J, g, tg, saved_cframe, saved_vmstate);

0 commit comments

Comments
 (0)