Skip to content

Commit 67457f3

Browse files
feat: Add rem builtin for i32 and i64 (#1310) (#2306)
1 parent f0a1043 commit 67457f3

File tree

7 files changed

+339
-98
lines changed

7 files changed

+339
-98
lines changed

NOTICE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ under the licensing terms detailed in LICENSE:
4848
* Syed Jafri <syed@metalpay.co>
4949
* Peter Hayman <peteyhayman@gmail.com>
5050
* ApsarasX <apsarax@outlook.com>
51+
* Adrien Zinger <zinger.ad@gmail.com>
5152

5253
Portions of this software are derived from third-party works licensed under
5354
the following terms:

src/builtins.ts

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ export namespace BuiltinNames {
163163
export const trunc = "~lib/builtins/trunc";
164164
export const eq = "~lib/builtins/eq";
165165
export const ne = "~lib/builtins/ne";
166+
export const rem = "~lib/builtins/rem";
166167
export const load = "~lib/builtins/load";
167168
export const store = "~lib/builtins/store";
168169
export const atomic_load = "~lib/builtins/atomic.load";
@@ -269,6 +270,11 @@ export namespace BuiltinNames {
269270
export const f32_ne = "~lib/builtins/f32.ne";
270271
export const f64_ne = "~lib/builtins/f64.ne";
271272

273+
export const i32_rem_s = "~lib/builtins/i32.rem_s";
274+
export const i32_rem_u = "~lib/builtins/i32.rem_u";
275+
export const i64_rem_s = "~lib/builtins/i64.rem_s";
276+
export const i64_rem_u = "~lib/builtins/i64.rem_u";
277+
272278
export const i32_load8_s = "~lib/builtins/i32.load8_s";
273279
export const i32_load8_u = "~lib/builtins/i32.load8_u";
274280
export const i32_load16_s = "~lib/builtins/i32.load16_s";
@@ -815,7 +821,7 @@ function builtin_isString(ctx: BuiltinContext): ExpressionRef {
815821
compiler.currentType = Type.bool;
816822
if (!type) return module.unreachable();
817823
var classReference = type.getClass();
818-
return reifyConstantType(ctx,
824+
return reifyConstantType(ctx,
819825
module.i32(
820826
classReference && classReference.isAssignableTo(compiler.program.stringInstance)
821827
? 1
@@ -2231,6 +2237,60 @@ function builtin_store(ctx: BuiltinContext): ExpressionRef {
22312237
}
22322238
builtins.set(BuiltinNames.store, builtin_store);
22332239

2240+
// rem<T?>(left: T, right: T) -> T
2241+
function builtin_rem(ctx: BuiltinContext): ExpressionRef {
2242+
var compiler = ctx.compiler;
2243+
var module = compiler.module;
2244+
if (checkTypeOptional(ctx, true) | checkArgsRequired(ctx, 2)) {
2245+
return module.unreachable();
2246+
}
2247+
var operands = ctx.operands;
2248+
var typeArguments = ctx.typeArguments;
2249+
var left = operands[0];
2250+
var arg0 = typeArguments
2251+
? compiler.compileExpression(
2252+
left,
2253+
typeArguments[0],
2254+
Constraints.CONV_IMPLICIT
2255+
)
2256+
: compiler.compileExpression(operands[0], Type.auto);
2257+
var type = compiler.currentType;
2258+
if (type.isIntegerValue) {
2259+
let arg1: ExpressionRef;
2260+
if (!typeArguments && left.isNumericLiteral) {
2261+
// prefer right type
2262+
arg1 = compiler.compileExpression(
2263+
operands[1],
2264+
type
2265+
);
2266+
if (compiler.currentType != type) {
2267+
arg0 = compiler.compileExpression(
2268+
left,
2269+
(type = compiler.currentType),
2270+
Constraints.CONV_IMPLICIT
2271+
);
2272+
}
2273+
} else {
2274+
arg1 = compiler.compileExpression(
2275+
operands[1],
2276+
type,
2277+
Constraints.CONV_IMPLICIT
2278+
);
2279+
}
2280+
if (type.isIntegerValue) {
2281+
return compiler.makeRem(arg0, arg1, type, ctx.reportNode);
2282+
}
2283+
}
2284+
compiler.error(
2285+
DiagnosticCode.Operation_0_cannot_be_applied_to_type_1,
2286+
ctx.reportNode.typeArgumentsRange,
2287+
"rem",
2288+
type.toString()
2289+
);
2290+
return module.unreachable();
2291+
}
2292+
builtins.set(BuiltinNames.rem, builtin_rem);
2293+
22342294
// add<T?>(left: T, right: T) -> T
22352295
function builtin_add(ctx: BuiltinContext): ExpressionRef {
22362296
var compiler = ctx.compiler;
@@ -6638,6 +6698,42 @@ function builtin_f64_trunc(ctx: BuiltinContext): ExpressionRef {
66386698
}
66396699
builtins.set(BuiltinNames.f64_trunc, builtin_f64_trunc);
66406700

6701+
// i32.rem_s -> rem<i32>
6702+
function builtin_i32_rem_s(ctx: BuiltinContext): ExpressionRef {
6703+
checkTypeAbsent(ctx);
6704+
ctx.typeArguments = [ Type.i32 ];
6705+
ctx.contextualType = Type.i32;
6706+
return builtin_rem(ctx);
6707+
}
6708+
builtins.set(BuiltinNames.i32_rem_s, builtin_i32_rem_s);
6709+
6710+
// i32.rem_u -> rem<u32>
6711+
function builtin_i32_rem_u(ctx: BuiltinContext): ExpressionRef {
6712+
checkTypeAbsent(ctx);
6713+
ctx.typeArguments = [ Type.u32 ];
6714+
ctx.contextualType = Type.u32;
6715+
return builtin_rem(ctx);
6716+
}
6717+
builtins.set(BuiltinNames.i32_rem_u, builtin_i32_rem_u);
6718+
6719+
// i64.rem_s -> rem<i64>
6720+
function builtin_i64_rem_s(ctx: BuiltinContext): ExpressionRef {
6721+
checkTypeAbsent(ctx);
6722+
ctx.typeArguments = [ Type.i64 ];
6723+
ctx.contextualType = Type.i64;
6724+
return builtin_rem(ctx);
6725+
}
6726+
builtins.set(BuiltinNames.i64_rem_s, builtin_i64_rem_s);
6727+
6728+
// i64.rem_u -> rem<u64>
6729+
function builtin_i64_rem_u(ctx: BuiltinContext): ExpressionRef {
6730+
checkTypeAbsent(ctx);
6731+
ctx.typeArguments = [ Type.u64 ];
6732+
ctx.contextualType = Type.u64;
6733+
return builtin_rem(ctx);
6734+
}
6735+
builtins.set(BuiltinNames.i64_rem_u, builtin_i64_rem_u);
6736+
66416737
// i32.add -> add<i32>
66426738
function builtin_i32_add(ctx: BuiltinContext): ExpressionRef {
66436739
checkTypeAbsent(ctx);

std/assembly/builtins.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ export declare function eq<T>(left: T, right: T): i32;
144144
@builtin
145145
export declare function ne<T>(left: T, right: T): i32;
146146

147+
// @ts-ignore: decorator
148+
@builtin
149+
export declare function rem<T>(left: T, right: T): T;
150+
147151
// @ts-ignore: decorator
148152
@unsafe @builtin
149153
export declare function load<T>(ptr: usize, immOffset?: usize, immAlign?: usize): T;
@@ -350,6 +354,14 @@ export namespace i32 {
350354
@builtin
351355
export declare function ne(left: i32, right:i32): i32;
352356

357+
// @ts-ignore: decorator
358+
@builtin
359+
export declare function rem_s(left: i32, right: i32): i32;
360+
361+
// @ts-ignore: decorator
362+
@builtin
363+
export declare function rem_u(left: u32, right: u32): u32;
364+
353365
// @ts-ignore: decorator
354366
@builtin
355367
export declare function reinterpret_f32(value: f32): i32;
@@ -601,6 +613,14 @@ export namespace i64 {
601613
@builtin
602614
export declare function ne(left: i64, right:i64): i32;
603615

616+
// @ts-ignore: decorator
617+
@builtin
618+
export declare function rem_s(left: i64, right: i64): i64;
619+
620+
// @ts-ignore: decorator
621+
@builtin
622+
export declare function rem_u(left: u64, right: u64): u64;
623+
604624
// @ts-ignore: decorator
605625
@builtin
606626
export declare function reinterpret_f64(value: f64): i64;

std/assembly/index.d.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ declare function div<T extends i32 | i64 | f32 | f64>(left: T, right: T): T;
151151
declare function eq<T extends i32 | i64 | f32 | f64>(left: T, right: T): i32;
152152
/** Return 0 if two numbers are equal to each other, 1 otherwise. */
153153
declare function ne<T extends i32 | i64 | f32 | f64>(left: T, right: T): i32;
154+
/** Computes the remainder of two integers. */
155+
declare function rem<T extends i32 | i64>(left: T, right: T): T;
154156
/** Loads a value of the specified type from memory. Equivalent to dereferncing a pointer in other languages. */
155157
declare function load<T>(ptr: usize, immOffset?: usize, immAlign?: usize): T;
156158
/** Stores a value of the specified type to memory. Equivalent to dereferencing a pointer in other languages when assigning a value. */
@@ -342,10 +344,15 @@ declare namespace i32 {
342344
export function div_s(left: i32, right: i32): i32;
343345
/** Computes the unsigned quotient of two 32-bit integers. */
344346
export function div_u(left: i32, right: i32): i32;
345-
/** Return 1 two 32-bit inegers are equal to each other, 0 otherwise. */
347+
/** Return 1 if two 32-bit integers are equal to each other, 0 otherwise. */
346348
export function eq(left: i32, right: i32): i32;
347-
/** Return 0 two 32-bit inegers are equal to each other, 1 otherwise. */
349+
/** Return 0 if two 32-bit integers are equal to each other, 1 otherwise. */
348350
export function ne(left: i32, right: i32): i32;
351+
/** Computes the signed remainder of two 32-bit integers. */
352+
export function rem_s(left: i32, right: i32): i32;
353+
/** Computes the unsigned remainder of two 32-bit integers. */
354+
export function rem_u(left: u32, right: u32): u32;
355+
349356
/** Atomic 32-bit integer operations. */
350357
export namespace atomic {
351358
/** Atomically loads an 8-bit unsigned integer value from memory and returns it as a 32-bit integer. */
@@ -466,10 +473,15 @@ declare namespace i64 {
466473
export function div_s(left: i64, right: i64): i64;
467474
/** Computes the unsigned quotient of two 64-bit integers. */
468475
export function div_u(left: i64, right: i64): i64;
469-
/** Return 1 two 64-bit inegers are equal to each other, 0 otherwise. */
476+
/** Return 1 if two 64-bit integers are equal to each other, 0 otherwise. */
470477
export function eq(left: i64, right: i64): i32;
471-
/** Return 0 two 64-bit inegers are equal to each other, 1 otherwise. */
478+
/** Return 0 if two 64-bit integers are equal to each other, 1 otherwise. */
472479
export function ne(left: i64, right: i64): i32;
480+
/** Computes the signed remainder of two 64-bit integers. */
481+
export function rem_s(left: i64, right: i64): i64;
482+
/** Computes the unsigned remainder of two 64-bit integers. */
483+
export function rem_u(left: u64, right: u64): u64;
484+
473485
/** Atomic 64-bit integer operations. */
474486
export namespace atomic {
475487
/** Atomically loads an 8-bit unsigned integer value from memory and returns it as a 64-bit integer. */

0 commit comments

Comments
 (0)