Skip to content

Commit 9fd3ece

Browse files
authored
[wasm] Implement more jiterpreter opcodes (#82940)
* Implement a bunch of missing math opcodes like exp, log and pow * Implement STELEM_VT
1 parent 2974f90 commit 9fd3ece

File tree

3 files changed

+145
-105
lines changed

3 files changed

+145
-105
lines changed

src/mono/mono/mini/interp/jiterpreter.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ jiterp_should_abort_trace (InterpInst *ins, gboolean *inside_branch_block)
786786
)
787787
return TRACE_CONTINUE;
788788
else if (
789-
// math intrinsics
789+
// math intrinsics - we implement most but not all of these
790790
(opcode >= MINT_ASIN) &&
791791
(opcode <= MINT_MAXF)
792792
)
@@ -1171,6 +1171,11 @@ mono_jiterp_math_atan2 (double lhs, double rhs) {
11711171
return atan2(lhs, rhs);
11721172
}
11731173

1174+
EMSCRIPTEN_KEEPALIVE double
1175+
mono_jiterp_math_pow (double lhs, double rhs) {
1176+
return pow(lhs, rhs);
1177+
}
1178+
11741179
EMSCRIPTEN_KEEPALIVE double
11751180
mono_jiterp_math_acos (double value)
11761181
{
@@ -1207,6 +1212,36 @@ mono_jiterp_math_tan (double value)
12071212
return tan(value);
12081213
}
12091214

1215+
EMSCRIPTEN_KEEPALIVE double
1216+
mono_jiterp_math_exp (double value)
1217+
{
1218+
return exp(value);
1219+
}
1220+
1221+
EMSCRIPTEN_KEEPALIVE double
1222+
mono_jiterp_math_log (double value)
1223+
{
1224+
return log(value);
1225+
}
1226+
1227+
EMSCRIPTEN_KEEPALIVE double
1228+
mono_jiterp_math_log2 (double value)
1229+
{
1230+
return log2(value);
1231+
}
1232+
1233+
EMSCRIPTEN_KEEPALIVE double
1234+
mono_jiterp_math_log10 (double value)
1235+
{
1236+
return log10(value);
1237+
}
1238+
1239+
EMSCRIPTEN_KEEPALIVE double
1240+
mono_jiterp_math_fma (double x, double y, double z)
1241+
{
1242+
return fma(x, y, z);
1243+
}
1244+
12101245
EMSCRIPTEN_KEEPALIVE int
12111246
mono_jiterp_stelem_ref (
12121247
MonoArray *o, gint32 aindex, MonoObject *ref

src/mono/wasm/runtime/jiterpreter-trace-generator.ts

Lines changed: 94 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,7 @@ export function generate_wasm_body (
972972
append_stloc_tail(builder, getArgU16(ip, 1), isI32 ? WasmOpcode.i32_store : WasmOpcode.i64_store);
973973
break;
974974
}
975+
975976
case MintOpcode.MINT_MONO_CMPXCHG_I4:
976977
builder.local("pLocals");
977978
append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load); // dest
@@ -992,6 +993,33 @@ export function generate_wasm_body (
992993
builder.callImport("cmpxchg_i64");
993994
break;
994995

996+
case MintOpcode.MINT_FMA:
997+
case MintOpcode.MINT_FMAF: {
998+
const isF32 = (opcode === MintOpcode.MINT_FMAF),
999+
loadOp = isF32 ? WasmOpcode.f32_load : WasmOpcode.f64_load,
1000+
storeOp = isF32 ? WasmOpcode.f32_store : WasmOpcode.f64_store;
1001+
1002+
builder.local("pLocals");
1003+
1004+
// LOCAL_VAR (ip [1], double) = fma (LOCAL_VAR (ip [2], double), LOCAL_VAR (ip [3], double), LOCAL_VAR (ip [4], double));
1005+
append_ldloc(builder, getArgU16(ip, 2), loadOp);
1006+
if (isF32)
1007+
builder.appendU8(WasmOpcode.f64_promote_f32);
1008+
append_ldloc(builder, getArgU16(ip, 3), loadOp);
1009+
if (isF32)
1010+
builder.appendU8(WasmOpcode.f64_promote_f32);
1011+
append_ldloc(builder, getArgU16(ip, 4), loadOp);
1012+
if (isF32)
1013+
builder.appendU8(WasmOpcode.f64_promote_f32);
1014+
1015+
builder.callImport("fma");
1016+
1017+
if (isF32)
1018+
builder.appendU8(WasmOpcode.f32_demote_f64);
1019+
append_stloc_tail(builder, getArgU16(ip, 1), storeOp);
1020+
break;
1021+
}
1022+
9951023
default:
9961024
if (
9971025
(
@@ -1064,7 +1092,7 @@ export function generate_wasm_body (
10641092
(opcode >= MintOpcode.MINT_LDELEM_I1) &&
10651093
(opcode <= MintOpcode.MINT_LDLEN)
10661094
) {
1067-
if (!emit_arrayop(builder, ip, opcode))
1095+
if (!emit_arrayop(builder, frame, ip, opcode))
10681096
ip = abort;
10691097
} else if (
10701098
(opcode >= MintOpcode.MINT_BRFALSE_I4_SP) &&
@@ -2478,113 +2506,66 @@ function emit_relop_branch (builder: WasmBuilder, ip: MintOpcodePtr, opcode: Min
24782506
return emit_branch(builder, ip, opcode, displacement);
24792507
}
24802508

2509+
const mathIntrinsicTable : { [opcode: number] : [isUnary: boolean, isF32: boolean, opcodeOrFuncName: WasmOpcode | string] } = {
2510+
[MintOpcode.MINT_SQRT]: [true, false, WasmOpcode.f64_sqrt],
2511+
[MintOpcode.MINT_SQRTF]: [true, true, WasmOpcode.f32_sqrt],
2512+
[MintOpcode.MINT_CEILING]: [true, false, WasmOpcode.f64_ceil],
2513+
[MintOpcode.MINT_CEILINGF]: [true, true, WasmOpcode.f32_ceil],
2514+
[MintOpcode.MINT_FLOOR]: [true, false, WasmOpcode.f64_floor],
2515+
[MintOpcode.MINT_FLOORF]: [true, true, WasmOpcode.f32_floor],
2516+
[MintOpcode.MINT_ABS]: [true, false, WasmOpcode.f64_abs],
2517+
[MintOpcode.MINT_ABSF]: [true, true, WasmOpcode.f32_abs],
2518+
[MintOpcode.MINT_MIN]: [true, false, WasmOpcode.f64_min],
2519+
[MintOpcode.MINT_MINF]: [true, true, WasmOpcode.f32_min],
2520+
[MintOpcode.MINT_MAX]: [true, false, WasmOpcode.f64_max],
2521+
[MintOpcode.MINT_MAXF]: [true, true, WasmOpcode.f32_max],
2522+
2523+
[MintOpcode.MINT_ACOS]: [true, false, "acos"],
2524+
[MintOpcode.MINT_ACOSF]: [true, true, "acos"],
2525+
[MintOpcode.MINT_COS]: [true, false, "cos"],
2526+
[MintOpcode.MINT_COSF]: [true, true, "cos"],
2527+
[MintOpcode.MINT_ASIN]: [true, false, "asin"],
2528+
[MintOpcode.MINT_ASINF]: [true, true, "asin"],
2529+
[MintOpcode.MINT_SIN]: [true, false, "sin"],
2530+
[MintOpcode.MINT_SINF]: [true, true, "sin"],
2531+
[MintOpcode.MINT_ATAN]: [true, false, "atan"],
2532+
[MintOpcode.MINT_ATANF]: [true, true, "atan"],
2533+
[MintOpcode.MINT_TAN]: [true, false, "tan"],
2534+
[MintOpcode.MINT_TANF]: [true, true, "tan"],
2535+
[MintOpcode.MINT_EXP]: [true, false, "exp"],
2536+
[MintOpcode.MINT_EXPF]: [true, true, "exp"],
2537+
[MintOpcode.MINT_LOG]: [true, false, "log"],
2538+
[MintOpcode.MINT_LOGF]: [true, true, "log"],
2539+
[MintOpcode.MINT_LOG2]: [true, false, "log2"],
2540+
[MintOpcode.MINT_LOG2F]: [true, true, "log2"],
2541+
[MintOpcode.MINT_LOG10]: [true, false, "log10"],
2542+
[MintOpcode.MINT_LOG10F]: [true, true, "log10"],
2543+
2544+
[MintOpcode.MINT_ATAN2]: [false, false, "atan2"],
2545+
[MintOpcode.MINT_ATAN2F]: [false, true, "atan2"],
2546+
[MintOpcode.MINT_POW]: [false, false, "pow"],
2547+
[MintOpcode.MINT_POWF]: [false, true, "pow"],
2548+
[MintOpcode.MINT_REM_R4]: [false, true, "rem"],
2549+
[MintOpcode.MINT_REM_R8]: [false, false, "rem"],
2550+
};
2551+
24812552
function emit_math_intrinsic (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode) : boolean {
24822553
let isUnary : boolean, isF32 : boolean, name: string | undefined;
24832554
let wasmOp : WasmOpcode | undefined;
24842555
const destOffset = getArgU16(ip, 1),
24852556
srcOffset = getArgU16(ip, 2),
24862557
rhsOffset = getArgU16(ip, 3);
24872558

2488-
switch (opcode) {
2489-
// oddly the interpreter has no opcodes for abs!
2490-
case MintOpcode.MINT_SQRT:
2491-
case MintOpcode.MINT_SQRTF:
2492-
isUnary = true;
2493-
isF32 = (opcode === MintOpcode.MINT_SQRTF);
2494-
wasmOp = isF32
2495-
? WasmOpcode.f32_sqrt
2496-
: WasmOpcode.f64_sqrt;
2497-
break;
2498-
case MintOpcode.MINT_CEILING:
2499-
case MintOpcode.MINT_CEILINGF:
2500-
isUnary = true;
2501-
isF32 = (opcode === MintOpcode.MINT_CEILINGF);
2502-
wasmOp = isF32
2503-
? WasmOpcode.f32_ceil
2504-
: WasmOpcode.f64_ceil;
2505-
break;
2506-
case MintOpcode.MINT_FLOOR:
2507-
case MintOpcode.MINT_FLOORF:
2508-
isUnary = true;
2509-
isF32 = (opcode === MintOpcode.MINT_FLOORF);
2510-
wasmOp = isF32
2511-
? WasmOpcode.f32_floor
2512-
: WasmOpcode.f64_floor;
2513-
break;
2514-
case MintOpcode.MINT_ABS:
2515-
case MintOpcode.MINT_ABSF:
2516-
isUnary = true;
2517-
isF32 = (opcode === MintOpcode.MINT_ABSF);
2518-
wasmOp = isF32
2519-
? WasmOpcode.f32_abs
2520-
: WasmOpcode.f64_abs;
2521-
break;
2522-
case MintOpcode.MINT_REM_R4:
2523-
case MintOpcode.MINT_REM_R8:
2524-
isUnary = false;
2525-
isF32 = (opcode === MintOpcode.MINT_REM_R4);
2526-
name = "rem";
2527-
break;
2528-
case MintOpcode.MINT_ATAN2:
2529-
case MintOpcode.MINT_ATAN2F:
2530-
isUnary = false;
2531-
isF32 = (opcode === MintOpcode.MINT_ATAN2F);
2532-
name = "atan2";
2533-
break;
2534-
case MintOpcode.MINT_ACOS:
2535-
case MintOpcode.MINT_ACOSF:
2536-
isUnary = true;
2537-
isF32 = (opcode === MintOpcode.MINT_ACOSF);
2538-
name = "acos";
2539-
break;
2540-
case MintOpcode.MINT_COS:
2541-
case MintOpcode.MINT_COSF:
2542-
isUnary = true;
2543-
isF32 = (opcode === MintOpcode.MINT_COSF);
2544-
name = "cos";
2545-
break;
2546-
case MintOpcode.MINT_SIN:
2547-
case MintOpcode.MINT_SINF:
2548-
isUnary = true;
2549-
isF32 = (opcode === MintOpcode.MINT_SINF);
2550-
name = "sin";
2551-
break;
2552-
case MintOpcode.MINT_ASIN:
2553-
case MintOpcode.MINT_ASINF:
2554-
isUnary = true;
2555-
isF32 = (opcode === MintOpcode.MINT_ASINF);
2556-
name = "asin";
2557-
break;
2558-
case MintOpcode.MINT_TAN:
2559-
case MintOpcode.MINT_TANF:
2560-
isUnary = true;
2561-
isF32 = (opcode === MintOpcode.MINT_TANF);
2562-
name = "tan";
2563-
break;
2564-
case MintOpcode.MINT_ATAN:
2565-
case MintOpcode.MINT_ATANF:
2566-
isUnary = true;
2567-
isF32 = (opcode === MintOpcode.MINT_ATANF);
2568-
name = "atan";
2569-
break;
2570-
case MintOpcode.MINT_MIN:
2571-
case MintOpcode.MINT_MINF:
2572-
isUnary = false;
2573-
isF32 = (opcode === MintOpcode.MINT_MINF);
2574-
wasmOp = isF32
2575-
? WasmOpcode.f32_min
2576-
: WasmOpcode.f64_min;
2577-
break;
2578-
case MintOpcode.MINT_MAX:
2579-
case MintOpcode.MINT_MAXF:
2580-
isUnary = false;
2581-
isF32 = (opcode === MintOpcode.MINT_MAXF);
2582-
wasmOp = isF32
2583-
? WasmOpcode.f32_max
2584-
: WasmOpcode.f64_max;
2585-
break;
2586-
default:
2587-
return false;
2559+
const tableEntry = mathIntrinsicTable[opcode];
2560+
if (tableEntry) {
2561+
isUnary = tableEntry[0];
2562+
isF32 = tableEntry[1];
2563+
if (typeof (tableEntry[2]) === "string")
2564+
name = tableEntry[2];
2565+
else
2566+
wasmOp = tableEntry[2];
2567+
} else {
2568+
return false;
25882569
}
25892570

25902571
// Pre-load locals for the stloc at the end
@@ -2859,7 +2840,7 @@ function append_getelema1 (
28592840
// append_getelema1 leaves the address on the stack
28602841
}
28612842

2862-
function emit_arrayop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode) : boolean {
2843+
function emit_arrayop (builder: WasmBuilder, frame: NativePointer, ip: MintOpcodePtr, opcode: MintOpcode) : boolean {
28632844
const isLoad = (
28642845
(opcode <= MintOpcode.MINT_LDELEMA_TC) &&
28652846
(opcode >= MintOpcode.MINT_LDELEM_I1)
@@ -2977,6 +2958,17 @@ function emit_arrayop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpco
29772958
invalidate_local_range(getArgU16(ip, 1), elementSize);
29782959
return true;
29792960
}
2961+
case MintOpcode.MINT_STELEM_VT: {
2962+
const elementSize = getArgU16(ip, 5),
2963+
klass = get_imethod_data(frame, getArgU16(ip, 4));
2964+
// dest
2965+
append_getelema1(builder, ip, objectOffset, indexOffset, elementSize);
2966+
// src
2967+
append_ldloca(builder, valueOffset, 0);
2968+
builder.ptr_const(klass);
2969+
builder.callImport("value_copy");
2970+
return true;
2971+
}
29802972
default:
29812973
return false;
29822974
}

src/mono/wasm/runtime/jiterpreter.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,17 +231,22 @@ export let traceImports : Array<[string, string, Function]> | undefined;
231231
export let _wrap_trace_function: Function;
232232

233233
const mathOps1 = [
234+
"asin",
234235
"acos",
236+
"atan",
235237
"cos",
238+
"exp",
239+
"log",
240+
"log2",
241+
"log10",
236242
"sin",
237-
"asin",
238243
"tan",
239-
"atan"
240244
];
241245

242246
const mathOps2 = [
243247
"rem",
244248
"atan2",
249+
"pow",
245250
];
246251

247252
function getTraceImports () {
@@ -278,6 +283,7 @@ function getTraceImports () {
278283
importDef("cmpxchg_i32", getRawCwrap("mono_jiterp_cas_i32")),
279284
importDef("cmpxchg_i64", getRawCwrap("mono_jiterp_cas_i64")),
280285
importDef("stelem_ref", getRawCwrap("mono_jiterp_stelem_ref")),
286+
importDef("fma", getRawCwrap("mono_jiterp_math_fma")),
281287
];
282288

283289
if (instrumentedMethodNames.length > 0) {
@@ -411,6 +417,13 @@ function initialize_builder (builder: WasmBuilder) {
411417
"rhs": WasmValtype.f64,
412418
}, WasmValtype.f64, true
413419
);
420+
builder.defineType(
421+
"fma", {
422+
"x": WasmValtype.f64,
423+
"y": WasmValtype.f64,
424+
"z": WasmValtype.f64,
425+
}, WasmValtype.f64, true
426+
);
414427
builder.defineType(
415428
"trace_eip", {
416429
"traceId": WasmValtype.i32,

0 commit comments

Comments
 (0)