@@ -88,6 +88,51 @@ call_primitive_2_args_test() ->
8888 >>,
8989 ? assertEqual (dump_to_bin (Dump ), Stream ).
9090
91+ call_primitive_5_args_test () ->
92+ State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
93+ State1 = ? BACKEND :call_primitive_last (State0 , ? PRIM_ALLOCATE , [ctx , jit_state , 16 , 32 , 2 ]),
94+ Stream = ? BACKEND :stream (State1 ),
95+ Dump =
96+ <<
97+ " 0: f9401447 ldr x7, [x2, #40]\n "
98+ " 4: d2800202 mov x2, #0x10 // #16\n "
99+ " 8: d2800403 mov x3, #0x20 // #32\n "
100+ " c: d2800044 mov x4, #0x2 // #2\n "
101+ " 10: d61f00e0 br x7"
102+ >>,
103+ ? assertEqual (dump_to_bin (Dump ), Stream ).
104+
105+ call_primitive_6_args_test () ->
106+ State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
107+ % Get bin_ptr from x_reg 0 (similar to get_list_test pattern)
108+ {State1 , RegA } = ? BACKEND :move_to_native_register (State0 , {x_reg , 0 }),
109+ State2 = ? BACKEND :and_ (State1 , RegA , ? TERM_PRIMARY_CLEAR_MASK ),
110+ % Get another register for the last parameter to test {free, Reg} handling
111+ {State3 , OtherReg } = ? BACKEND :move_to_native_register (State2 , {x_reg , 1 }),
112+ % Call PRIM_BITSTRING_EXTRACT_INTEGER with 6 arguments
113+ {State4 , _ResultReg } = ? BACKEND :call_primitive (State3 , ? PRIM_BITSTRING_EXTRACT_INTEGER , [
114+ ctx , jit_state , {free , RegA }, 64 , 8 , {free , OtherReg }
115+ ]),
116+ Stream = ? BACKEND :stream (State4 ),
117+ Dump =
118+ <<
119+ " 0: f9401807 ldr x7, [x0, #48]\n "
120+ " 4: 927ef4e7 and x7, x7, #0xfffffffffffffffc\n "
121+ " 8: f9401c08 ldr x8, [x0, #56]\n "
122+ " c: f940b850 ldr x16, [x2, #368]\n "
123+ " 10: a9bf03fe stp x30, x0, [sp, #-16]!\n "
124+ " 14: a9bf0be1 stp x1, x2, [sp, #-16]!\n "
125+ " 18: aa0703e2 mov x2, x7\n "
126+ " 1c: d2800803 mov x3, #0x40 // #64\n "
127+ " 20: d2800104 mov x4, #0x8 // #8\n "
128+ " 24: aa0803e5 mov x5, x8\n "
129+ " 28: d63f0200 blr x16\n "
130+ " 2c: aa0003e7 mov x7, x0\n "
131+ " 30: a8c10be1 ldp x1, x2, [sp], #16\n "
132+ " 34: a8c103fe ldp x30, x0, [sp], #16"
133+ >>,
134+ ? assertEqual (dump_to_bin (Dump ), Stream ).
135+
91136call_primitive_extended_regs_test () ->
92137 State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
93138 {State1 , RegA } = ? BACKEND :call_primitive (State0 , ? PRIM_EXTENDED_REGISTER_PTR , [ctx , 19 ]),
@@ -146,6 +191,44 @@ call_primitive_extended_regs_test() ->
146191 >>,
147192 ? assertEqual (dump_to_bin (Dump ), Stream ).
148193
194+ call_primitive_few_free_regs_test () ->
195+ State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
196+ {State1 , Reg1 } = ? BACKEND :move_to_native_register (State0 , 1 ),
197+ {State2 , Reg2 } = ? BACKEND :move_to_native_register (State1 , 2 ),
198+ {State3 , Reg3 } = ? BACKEND :move_to_native_register (State2 , 3 ),
199+ {State4 , Reg4 } = ? BACKEND :move_to_native_register (State3 , 4 ),
200+ {State5 , Reg5 } = ? BACKEND :move_to_native_register (State4 , 5 ),
201+ {State6 , ResultReg } = ? BACKEND :call_primitive (State5 , ? PRIM_BITSTRING_INSERT_INTEGER , [
202+ Reg2 , Reg1 , {free , Reg4 }, Reg3 , {free , Reg5 }
203+ ]),
204+ State7 = ? BACKEND :free_native_registers (State6 , [ResultReg , Reg2 , Reg1 , Reg3 ]),
205+ ? BACKEND :assert_all_native_free (State7 ),
206+ Stream = ? BACKEND :stream (State7 ),
207+ Dump = <<
208+ " 0: d2800027 mov x7, #0x1 // #1\n "
209+ " 4: d2800048 mov x8, #0x2 // #2\n "
210+ " 8: d2800069 mov x9, #0x3 // #3\n "
211+ " c: d280008a mov x10, #0x4 // #4\n "
212+ " 10: d28000ab mov x11, #0x5 // #5\n "
213+ " 14: f940e450 ldr x16, [x2, #456]\n "
214+ " 18: a9bf03fe stp x30, x0, [sp, #-16]!\n "
215+ " 1c: a9bf0be1 stp x1, x2, [sp, #-16]!\n "
216+ " 20: a9bf23e9 stp x9, x8, [sp, #-16]!\n "
217+ " 24: f81f0fe7 str x7, [sp, #-16]!\n "
218+ " 28: aa0803e0 mov x0, x8\n "
219+ " 2c: aa0703e1 mov x1, x7\n "
220+ " 30: aa0a03e2 mov x2, x10\n "
221+ " 34: aa0903e3 mov x3, x9\n "
222+ " 38: aa0b03e4 mov x4, x11\n "
223+ " 3c: d63f0200 blr x16\n "
224+ " 40: aa0003ea mov x10, x0\n "
225+ " 44: f84107e7 ldr x7, [sp], #16\n "
226+ " 48: a8c123e9 ldp x9, x8, [sp], #16\n "
227+ " 4c: a8c10be1 ldp x1, x2, [sp], #16\n "
228+ " 50: a8c103fe ldp x30, x0, [sp], #16"
229+ >>,
230+ ? assertEqual (dump_to_bin (Dump ), Stream ).
231+
149232call_ext_only_test () ->
150233 State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
151234 State1 = ? BACKEND :decrement_reductions_and_maybe_schedule_next (State0 ),
@@ -168,6 +251,23 @@ call_ext_only_test() ->
168251 >>,
169252 ? assertEqual (dump_to_bin (Dump ), Stream ).
170253
254+ call_primitive_last_5_args_test () ->
255+ State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
256+ {State1 , RegA } = ? BACKEND :move_to_native_register (State0 , {x_reg , 0 }),
257+ State2 = ? BACKEND :call_primitive_last (State1 , ? PRIM_RAISE_ERROR_TUPLE , [
258+ ctx , jit_state , offset , ? CASE_CLAUSE_ATOM , {free , RegA }
259+ ]),
260+ Stream = ? BACKEND :stream (State2 ),
261+ Dump = <<
262+ " 0: f9401807 ldr x7, [x0, #48]\n "
263+ " 4: f9404c48 ldr x8, [x2, #152]\n "
264+ " 8: d2800102 mov x2, #0x8 // #8\n "
265+ " c: d2805963 mov x3, #0x2cb // #715\n "
266+ " 10: aa0703e4 mov x4, x7\n "
267+ " 14: d61f0100 br x8"
268+ >>,
269+ ? assertEqual (dump_to_bin (Dump ), Stream ).
270+
171271call_ext_last_test () ->
172272 State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
173273 State1 = ? BACKEND :decrement_reductions_and_maybe_schedule_next (State0 ),
@@ -1038,6 +1138,179 @@ is_boolean_test() ->
10381138 >>,
10391139 ? assertEqual (dump_to_bin (Dump ), Stream ).
10401140
1141+ % % Test OP_WAIT_TIMEOUT pattern
1142+ wait_timeout_test () ->
1143+ State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
1144+
1145+ Label = 42 ,
1146+ {State1 , OffsetRef0 } = ? BACKEND :set_continuation_to_offset (State0 ),
1147+ {State2 , TimeoutReg } = ? BACKEND :move_to_native_register (State1 , 5000 ),
1148+ State3 = ? BACKEND :call_primitive_last (State2 , ? PRIM_WAIT_TIMEOUT , [
1149+ ctx , jit_state , {free , TimeoutReg }, Label
1150+ ]),
1151+ State4 = ? BACKEND :add_label (State3 , OffsetRef0 ),
1152+ State5 = ? BACKEND :continuation_entry_point (State4 ),
1153+ {State6 , ResultReg0 } = ? BACKEND :call_primitive (State5 , ? PRIM_PROCESS_SIGNAL_MESSAGES , [
1154+ ctx , jit_state
1155+ ]),
1156+ State7 = ? BACKEND :return_if_not_equal_to_ctx (State6 , {free , ResultReg0 }),
1157+ % ?WAITING_TIMEOUT_EXPIRED
1158+ {State8 , ResultReg1 } = ? BACKEND :call_primitive (State7 , ? PRIM_CONTEXT_GET_FLAGS , [ctx , 2 ]),
1159+ State9 = ? BACKEND :if_block (State8 , {{free , ResultReg1 }, '==' , 0 }, fun (BlockSt ) ->
1160+ ? BACKEND :call_primitive_last (BlockSt , ? PRIM_WAIT_TIMEOUT_TRAP_HANDLER , [
1161+ ctx , jit_state , Label
1162+ ])
1163+ end ),
1164+ State10 = ? BACKEND :update_branches (State9 ),
1165+
1166+ Stream = ? BACKEND :stream (State10 ),
1167+ Dump = <<
1168+ " 0: 100000e7 adr x7, 0x1c\n "
1169+ " 4: f9000427 str x7, [x1, #8]\n "
1170+ " 8: d2827107 mov x7, #0x1388 // #5000\n "
1171+ " c: f9407848 ldr x8, [x2, #240]\n "
1172+ " 10: aa0703e2 mov x2, x7\n "
1173+ " 14: d2800543 mov x3, #0x2a // #42\n "
1174+ " 18: d61f0100 br x8\n "
1175+ " 1c: f9405450 ldr x16, [x2, #168]\n "
1176+ " 20: a9bf03fe stp x30, x0, [sp, #-16]!\n "
1177+ " 24: a9bf0be1 stp x1, x2, [sp, #-16]!\n "
1178+ " 28: d63f0200 blr x16\n "
1179+ " 2c: aa0003e7 mov x7, x0\n "
1180+ " 30: a8c10be1 ldp x1, x2, [sp], #16\n "
1181+ " 34: a8c103fe ldp x30, x0, [sp], #16\n "
1182+ " 38: eb0000ff cmp x7, x0\n "
1183+ " 3c: 54000060 b.eq 0x48 // b.none\n "
1184+ " 40: aa0703e0 mov x0, x7\n "
1185+ " 44: d65f03c0 ret\n "
1186+ " 48: f9408450 ldr x16, [x2, #264]\n "
1187+ " 4c: a9bf03fe stp x30, x0, [sp, #-16]!\n "
1188+ " 50: a9bf0be1 stp x1, x2, [sp, #-16]!\n "
1189+ " 54: d2800041 mov x1, #0x2 // #2\n "
1190+ " 58: d63f0200 blr x16\n "
1191+ " 5c: aa0003e7 mov x7, x0\n "
1192+ " 60: a8c10be1 ldp x1, x2, [sp], #16\n "
1193+ " 64: a8c103fe ldp x30, x0, [sp], #16\n "
1194+ " 68: b5000087 cbnz x7, 0x78\n "
1195+ " 6c: f9407c47 ldr x7, [x2, #248]\n "
1196+ " 70: d2800542 mov x2, #0x2a // #42\n "
1197+ " 74: d61f00e0 br x7"
1198+ >>,
1199+ ? assertEqual (dump_to_bin (Dump ), Stream ).
1200+
1201+ % % Test OP_WAIT pattern that uses set_continuation_to_label
1202+ wait_test () ->
1203+ State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
1204+
1205+ State1 = ? BACKEND :jump_table (State0 , 5 ),
1206+ State2 = ? BACKEND :add_label (State1 , 1 ),
1207+ Label = 2 ,
1208+ State3 = ? BACKEND :set_continuation_to_label (State2 , Label ),
1209+ State4 = ? BACKEND :call_primitive_last (State3 , ? PRIM_SCHEDULE_WAIT_CP , [ctx , jit_state ]),
1210+
1211+ Stream = ? BACKEND :stream (State4 ),
1212+ Dump = <<
1213+ " 0: 14000000 b 0x0\n "
1214+ " 4: 14000000 b 0x4\n "
1215+ " 8: 14000000 b 0x8\n "
1216+ " c: 14000000 b 0xc\n "
1217+ " 10: 14000000 b 0x10\n "
1218+ " 14: 14000000 b 0x14\n "
1219+ " 18: 10000007 adr x7, 0x18\n "
1220+ " 1c: f9000427 str x7, [x1, #8]\n "
1221+ " 20: f9407447 ldr x7, [x2, #232]\n "
1222+ " 24: d61f00e0 br x7"
1223+ >>,
1224+ ? assertEqual (dump_to_bin (Dump ), Stream ).
1225+
1226+ return_labels_and_lines_test () ->
1227+ State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
1228+
1229+ % Test return_labels_and_lines with some sample labels and lines
1230+ State1 = ? BACKEND :add_label (State0 , 2 , 32 ),
1231+ State2 = ? BACKEND :add_label (State1 , 1 , 16 ),
1232+
1233+ % {Line, Offset} pairs
1234+ SortedLines = [{10 , 16 }, {20 , 32 }],
1235+
1236+ State3 = ? BACKEND :return_labels_and_lines (State2 , SortedLines ),
1237+ Stream = ? BACKEND :stream (State3 ),
1238+
1239+ % Should have generated adr + ret + labels table + lines table
1240+ % adr = 4 bytes, ret = 4 bytes, labels table = 6*2 = 12 bytes, lines table = 6*2 = 12 bytes
1241+ % Total minimum: 36 bytes
1242+ ? assert (byte_size (Stream ) >= 36 ),
1243+
1244+ % Expected: adr x0, #8 + ret + labels table + lines table
1245+ % The data tables start at offset 0x8, so we load PC + 8 into x0
1246+ Dump = <<
1247+ " 0: 10000040 adr x0, 0x8\n "
1248+ " 4: d65f03c0 ret\n "
1249+ " 8: 01000200 .word 0x01000200\n "
1250+ " c: 10000000 adr x0, 0xc\n "
1251+ " 10: 00000200 .word 0x00000200\n "
1252+ " 14: 02002000 .word 0x02002000\n "
1253+ " 18: 00000a00 .word 0x00000a00\n "
1254+ " 1c: 14001000 .word 0x14001000\n "
1255+ " 20: 20000000 .word 0x20000000"
1256+ >>,
1257+ ? assertEqual (dump_to_bin (Dump ), Stream ).
1258+
1259+ % % Test call_primitive with {free, {x_reg, X}}
1260+ gc_bif2_test () ->
1261+ State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
1262+ {State1 , FuncPtr } = ? BACKEND :call_primitive (State0 , ? PRIM_GET_IMPORTED_BIF , [jit_state , 42 ]),
1263+ {State2 , _ResultReg } = ? BACKEND :call_func_ptr (State1 , {free , FuncPtr }, [
1264+ ctx , 0 , 3 , {y_reg , 0 }, {free , {x_reg , 0 }}
1265+ ]),
1266+
1267+ Stream = ? BACKEND :stream (State2 ),
1268+ Dump = <<
1269+ " 0: f9402050 ldr x16, [x2, #64]\n "
1270+ " 4: a9bf03fe stp x30, x0, [sp, #-16]!\n "
1271+ " 8: a9bf0be1 stp x1, x2, [sp, #-16]!\n "
1272+ " c: aa0103e0 mov x0, x1\n "
1273+ " 10: d2800541 mov x1, #0x2a // #42\n "
1274+ " 14: d63f0200 blr x16\n "
1275+ " 18: aa0003e7 mov x7, x0\n "
1276+ " 1c: a8c10be1 ldp x1, x2, [sp], #16\n "
1277+ " 20: a8c103fe ldp x30, x0, [sp], #16\n "
1278+ " 24: a9bf03fe stp x30, x0, [sp, #-16]!\n "
1279+ " 28: a9bf0be1 stp x1, x2, [sp, #-16]!\n "
1280+ " 2c: d2800001 mov x1, #0x0 // #0\n "
1281+ " 30: d2800062 mov x2, #0x3 // #3\n "
1282+ " 34: f9401403 ldr x3, [x0, #40]\n "
1283+ " 38: f9400063 ldr x3, [x3]\n "
1284+ " 3c: f9401804 ldr x4, [x0, #48]\n "
1285+ " 40: d63f00e0 blr x7\n "
1286+ " 44: aa0003e7 mov x7, x0\n "
1287+ " 48: a8c10be1 ldp x1, x2, [sp], #16\n "
1288+ " 4c: a8c103fe ldp x30, x0, [sp], #16"
1289+ >>,
1290+ ? assertEqual (dump_to_bin (Dump ), Stream ).
1291+
1292+ % % Test case where parameter value is in r1
1293+ memory_ensure_free_with_roots_test () ->
1294+ State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
1295+ {State1 , _FuncPtr } = ? BACKEND :call_primitive (State0 , ? PRIM_MEMORY_ENSURE_FREE_WITH_ROOTS , [
1296+ ctx , jit_state , {free , r1 }, 4 , 1
1297+ ]),
1298+
1299+ Stream = ? BACKEND :stream (State1 ),
1300+ Dump = <<
1301+ " 0: f940b050 ldr x16, [x2, #352]\n "
1302+ " 4: a9bf03fe stp x30, x0, [sp, #-16]!\n "
1303+ " 8: a9bf0be1 stp x1, x2, [sp, #-16]!\n "
1304+ " c: aa0103e2 mov x2, x1\n "
1305+ " 10: d2800083 mov x3, #0x4 // #4\n "
1306+ " 14: d2800024 mov x4, #0x1 // #1\n "
1307+ " 18: d63f0200 blr x16\n "
1308+ " 1c: aa0003e7 mov x7, x0\n "
1309+ " 20: a8c10be1 ldp x1, x2, [sp], #16\n "
1310+ " 24: a8c103fe ldp x30, x0, [sp], #16"
1311+ >>,
1312+ ? assertEqual (dump_to_bin (Dump ), Stream ).
1313+
10411314call_ext_test () ->
10421315 State0 = ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 )),
10431316 State1 = ? BACKEND :decrement_reductions_and_maybe_schedule_next (State0 ),
@@ -1662,6 +1935,66 @@ move_to_native_register_test_() ->
16621935 ]
16631936 end }.
16641937
1938+ add_test0 (State0 , Reg , Imm , Dump ) ->
1939+ State1 = ? BACKEND :add (State0 , Reg , Imm ),
1940+ Stream = ? BACKEND :stream (State1 ),
1941+ ? assertEqual (dump_to_bin (Dump ), Stream ).
1942+
1943+ add_test_ () ->
1944+ {setup ,
1945+ fun () ->
1946+ ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 ))
1947+ end ,
1948+ fun (State0 ) ->
1949+ [
1950+ ? _test (begin
1951+ add_test0 (State0 , r2 , 2 , <<
1952+ " 0: 91000842 add x2, x2, #0x2"
1953+ >>)
1954+ end ),
1955+ ? _test (begin
1956+ add_test0 (State0 , r2 , 256 , <<
1957+ " 0: 91040042 add x2, x2, #0x100"
1958+ >>)
1959+ end ),
1960+ ? _test (begin
1961+ add_test0 (State0 , r2 , r3 , <<
1962+ " 0: 8b030042 add x2, x2, x3"
1963+ >>)
1964+ end )
1965+ ]
1966+ end }.
1967+
1968+ sub_test0 (State0 , Reg , Imm , Dump ) ->
1969+ State1 = ? BACKEND :sub (State0 , Reg , Imm ),
1970+ Stream = ? BACKEND :stream (State1 ),
1971+ ? assertEqual (dump_to_bin (Dump ), Stream ).
1972+
1973+ sub_test_ () ->
1974+ {setup ,
1975+ fun () ->
1976+ ? BACKEND :new (? JIT_VARIANT_PIC , jit_stream_binary , jit_stream_binary :new (0 ))
1977+ end ,
1978+ fun (State0 ) ->
1979+ [
1980+ ? _test (begin
1981+ sub_test0 (State0 , r2 , 2 , <<
1982+ " 0: d1000842 sub x2, x2, #0x2"
1983+ >>)
1984+ end ),
1985+ ? _test (begin
1986+ sub_test0 (State0 , r2 , 256 , <<
1987+ " 0: d1040042 sub x2, x2, #0x100"
1988+ >>)
1989+ end ),
1990+ ? _test (begin
1991+ sub_test0 (State0 , r2 , r3 , <<
1992+ " 0: cb030042 sub x2, x2, x3"
1993+ >>)
1994+ end )
1995+ ]
1996+ end }.
1997+
16651998mul_test0 (State0 , Reg , Imm , Dump ) ->
16661999 State1 = ? BACKEND :mul (State0 , Reg , Imm ),
16672000 Stream = ? BACKEND :stream (State1 ),
0 commit comments