Skip to content

Commit 1d9d50f

Browse files
committed
Merge pull request #2361 from pguyot/w29/harden-xtensa-codegen
Harden xtensa call_primitive_last and align encode_rrr with the ISA These changes are made under both the "Apache 2.0" and the "GNU Lesser General Public License 2.1 or later" license terms (dual license). SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
2 parents 88a0472 + 40ce601 commit 1d9d50f

3 files changed

Lines changed: 32 additions & 15 deletions

File tree

libs/jit/src/jit_xtensa.erl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ call_primitive_last(
613613
stream = Stream0
614614
} = State0,
615615
Primitive,
616-
Args
616+
[_, jit_state | _] = Args
617617
) ->
618618
%% Xtensa windowed ABI: CALLX8 to the primitive, move its return value
619619
%% from a10 (our view of callee's a2) into our a2, then RETW to C.
@@ -652,7 +652,12 @@ call_primitive_last(
652652
jit_regs:unreachable(State2#state.regs), ?AVAILABLE_REGS_MASK, 0
653653
)
654654
}
655-
end.
655+
end;
656+
%% The windowed-ABI tail-call sequence rewrites the second argument
657+
%% (jit_state -> jit_state_tail_call), so reject every other shape in the
658+
%% function head before allocating registers or appending to the stream.
659+
call_primitive_last(_State, _Primitive, Args) ->
660+
error({unsupported_call_primitive_last_args, Args}).
656661

657662
%%-----------------------------------------------------------------------------
658663
%% @doc Emit a return of a value if it's not equal to ctx.

libs/jit/src/jit_xtensa_asm.erl

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,12 @@ reg_to_num(a15) -> 15.
144144
%% 24-bit Instruction Format Encoders
145145
%%=============================================================================
146146

147-
%% RRR format: op1[23:20] | op2[19:16] | r[15:12] | s[11:8] | t[7:4] | op0[3:0]
147+
%% RRR format: op2[23:20] | op1[19:16] | r[15:12] | s[11:8] | t[7:4] | op0[3:0]
148+
%% Op2/Op1 are ordered high-to-low to match the ISA field layout above; the
149+
%% emitted bytes are unchanged from before this parameter rename.
148150
-spec encode_rrr(integer(), integer(), integer(), integer(), integer(), integer()) -> binary().
149-
encode_rrr(Op0, T, S, R, Op1, Op2) ->
150-
Instr = (Op1 bsl 20) bor (Op2 bsl 16) bor (R bsl 12) bor (S bsl 8) bor (T bsl 4) bor Op0,
151+
encode_rrr(Op0, T, S, R, Op2, Op1) ->
152+
Instr = (Op2 bsl 20) bor (Op1 bsl 16) bor (R bsl 12) bor (S bsl 8) bor (T bsl 4) bor Op0,
151153
<<Instr:24/little>>.
152154

153155
%% RRI8 format: imm8[23:16] | r[15:12] | s[11:8] | t[7:4] | op0[3:0]
@@ -196,31 +198,31 @@ encode_rrrn(Op0, T, S, R) ->
196198
%%=============================================================================
197199

198200
%% ADD: AR[r] = AR[s] + AR[t]
199-
%% op0=0, op1=8, op2=0
201+
%% op0=0, op1=0, op2=8
200202
-spec add(xtensa_register(), xtensa_register(), xtensa_register()) -> binary().
201203
add(Ar, As, At) ->
202204
encode_rrr(0, reg_to_num(At), reg_to_num(As), reg_to_num(Ar), 16#8, 0).
203205

204206
%% SUB: AR[r] = AR[s] - AR[t]
205-
%% op0=0, op1=12, op2=0
207+
%% op0=0, op1=0, op2=12
206208
-spec sub(xtensa_register(), xtensa_register(), xtensa_register()) -> binary().
207209
sub(Ar, As, At) ->
208210
encode_rrr(0, reg_to_num(At), reg_to_num(As), reg_to_num(Ar), 16#C, 0).
209211

210212
%% AND: AR[r] = AR[s] & AR[t]
211-
%% op0=0, op1=1, op2=0
213+
%% op0=0, op1=0, op2=1
212214
-spec and_(xtensa_register(), xtensa_register(), xtensa_register()) -> binary().
213215
and_(Ar, As, At) ->
214216
encode_rrr(0, reg_to_num(At), reg_to_num(As), reg_to_num(Ar), 16#1, 0).
215217

216218
%% OR: AR[r] = AR[s] | AR[t]
217-
%% op0=0, op1=2, op2=0
219+
%% op0=0, op1=0, op2=2
218220
-spec or_(xtensa_register(), xtensa_register(), xtensa_register()) -> binary().
219221
or_(Ar, As, At) ->
220222
encode_rrr(0, reg_to_num(At), reg_to_num(As), reg_to_num(Ar), 16#2, 0).
221223

222224
%% XOR: AR[r] = AR[s] ^ AR[t]
223-
%% op0=0, op1=3, op2=0
225+
%% op0=0, op1=0, op2=3
224226
-spec xor_(xtensa_register(), xtensa_register(), xtensa_register()) -> binary().
225227
xor_(Ar, As, At) ->
226228
encode_rrr(0, reg_to_num(At), reg_to_num(As), reg_to_num(Ar), 16#3, 0).
@@ -243,14 +245,14 @@ srl(Ar, _As, At) ->
243245
encode_rrr(0, reg_to_num(At), 0, reg_to_num(Ar), 16#9, 16#1).
244246

245247
%% SSR: Set SAR for right shift. SAR = AR[s][4:0]
246-
%% op0=0, op1=4, op2=0, r=0, t=0
248+
%% op0=0, op1=0, op2=4, r=0, t=0
247249
-spec ssr(xtensa_register()) -> binary().
248250
ssr(As) ->
249251
encode_rrr(0, 0, reg_to_num(As), 0, 16#4, 0).
250252

251253
%% SLLI: AR[r] = AR[s] << sa (1..31)
252254
%% op0=0, RRR format with shift amount encoded as (32 - sa).
253-
%% The encoded value split: sa_enc[4] at bits[23:20], op=1 at bits[19:16],
255+
%% The encoded value split: sa_enc[4] at bits[23:20], op1=1 at bits[19:16],
254256
%% r at bits[15:12], s at bits[11:8], sa_enc[3:0] at bits[7:4].
255257
-spec slli(xtensa_register(), xtensa_register(), 1..31) -> binary().
256258
slli(Ar, As, Sa) when Sa >= 1, Sa =< 31 ->
@@ -284,19 +286,19 @@ srai(Ar, At, Sa) when Sa >= 0, Sa =< 31 ->
284286
%%=============================================================================
285287

286288
%% MULL: AR[r] = AR[s] * AR[t] (low 32 bits)
287-
%% op0=0, op1=8, op2=2
289+
%% op0=0, op1=2, op2=8
288290
-spec mull(xtensa_register(), xtensa_register(), xtensa_register()) -> binary().
289291
mull(Ar, As, At) ->
290292
encode_rrr(0, reg_to_num(At), reg_to_num(As), reg_to_num(Ar), 16#8, 16#2).
291293

292294
%% QUOS: AR[r] = AR[s] / AR[t] (signed)
293-
%% op0=0, op1=13, op2=2
295+
%% op0=0, op1=2, op2=13
294296
-spec quos(xtensa_register(), xtensa_register(), xtensa_register()) -> binary().
295297
quos(Ar, As, At) ->
296298
encode_rrr(0, reg_to_num(At), reg_to_num(As), reg_to_num(Ar), 16#D, 16#2).
297299

298300
%% REMS: AR[r] = AR[s] % AR[t] (signed)
299-
%% op0=0, op1=15, op2=2
301+
%% op0=0, op1=2, op2=15
300302
-spec rems(xtensa_register(), xtensa_register(), xtensa_register()) -> binary().
301303
rems(Ar, As, At) ->
302304
encode_rrr(0, reg_to_num(At), reg_to_num(As), reg_to_num(Ar), 16#F, 16#2).

tests/libs/jit/jit_xtensa_tests.erl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,16 @@ call_primitive_last_test() ->
290290
>>,
291291
?assertStream(xtensa, Dump, Stream).
292292

293+
% An argument list that exhausts the scratch registers must still be rejected
294+
% with a descriptive error, not an opaque first_avail/1 function_clause.
295+
call_primitive_last_unsupported_args_test() ->
296+
State = ?BACKEND:new(?JIT_VARIANT_PIC, jit_stream_binary, jit_stream_binary:new(0)),
297+
Args = [ctx, a9, a7, a6, a5, 0],
298+
?assertError(
299+
{unsupported_call_primitive_last_args, Args},
300+
?BACKEND:call_primitive_last(State, 0, Args)
301+
).
302+
293303
shift_right_test() ->
294304
State0 = ?BACKEND:new(?JIT_VARIANT_PIC, jit_stream_binary, jit_stream_binary:new(0)),
295305
{State1, RegA} = ?BACKEND:move_to_native_register(State0, {x_reg, 0}),

0 commit comments

Comments
 (0)