Skip to content

Commit a2acee0

Browse files
committed
Add rem builtin (#1310)
1 parent 324d41c commit a2acee0

File tree

7 files changed

+269
-98
lines changed

7 files changed

+269
-98
lines changed

NOTICE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ under the licensing terms detailed in LICENSE:
4747
* Yasushi Ando <[email protected]>
4848
* Syed Jafri <[email protected]>
4949
* Peter Hayman <[email protected]>
50+
* Adrien Zinger <[email protected]>
5051

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

src/builtins.ts

Lines changed: 77 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,9 @@ 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 = "~lib/builtins/i32.rem";
274+
export const i64_rem = "~lib/builtins/i64.rem";
275+
272276
export const i32_load8_s = "~lib/builtins/i32.load8_s";
273277
export const i32_load8_u = "~lib/builtins/i32.load8_u";
274278
export const i32_load16_s = "~lib/builtins/i32.load16_s";
@@ -815,7 +819,7 @@ function builtin_isString(ctx: BuiltinContext): ExpressionRef {
815819
compiler.currentType = Type.bool;
816820
if (!type) return module.unreachable();
817821
var classReference = type.getClass();
818-
return reifyConstantType(ctx,
822+
return reifyConstantType(ctx,
819823
module.i32(
820824
classReference && classReference.isAssignableTo(compiler.program.stringInstance)
821825
? 1
@@ -2231,6 +2235,60 @@ function builtin_store(ctx: BuiltinContext): ExpressionRef {
22312235
}
22322236
builtins.set(BuiltinNames.store, builtin_store);
22332237

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

6699+
// i32.rem -> rem<i32>
6700+
function builtin_i32_rem(ctx: BuiltinContext): ExpressionRef {
6701+
checkTypeAbsent(ctx);
6702+
ctx.typeArguments = [ Type.i32 ];
6703+
ctx.contextualType = Type.i32;
6704+
return builtin_rem(ctx);
6705+
}
6706+
builtins.set(BuiltinNames.i32_rem, builtin_i32_rem);
6707+
6708+
// i64.rem -> rem<i64>
6709+
function builtin_i64_rem(ctx: BuiltinContext): ExpressionRef {
6710+
checkTypeAbsent(ctx);
6711+
ctx.typeArguments = [ Type.i64 ];
6712+
ctx.contextualType = Type.i64;
6713+
return builtin_rem(ctx);
6714+
}
6715+
builtins.set(BuiltinNames.i64_rem, builtin_i64_rem);
6716+
66416717
// i32.add -> add<i32>
66426718
function builtin_i32_add(ctx: BuiltinContext): ExpressionRef {
66436719
checkTypeAbsent(ctx);

std/assembly/builtins.ts

Lines changed: 12 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,10 @@ 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(left: i32, right: i32): i32;
360+
353361
// @ts-ignore: decorator
354362
@builtin
355363
export declare function reinterpret_f32(value: f32): i32;
@@ -601,6 +609,10 @@ export namespace i64 {
601609
@builtin
602610
export declare function ne(left: i64, right:i64): i32;
603611

612+
// @ts-ignore: decorator
613+
@builtin
614+
export declare function rem(left: i64, right: i64): i64;
615+
604616
// @ts-ignore: decorator
605617
@builtin
606618
export declare function reinterpret_f64(value: f64): i64;

std/assembly/index.d.ts

Lines changed: 10 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 rem of two positive 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,12 @@ 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+
/** Compute the remaining between two 32-bit positive integers. */
352+
export function rem(left: i32, right: i32): i32;
349353
/** Atomic 32-bit integer operations. */
350354
export namespace atomic {
351355
/** Atomically loads an 8-bit unsigned integer value from memory and returns it as a 32-bit integer. */
@@ -466,10 +470,12 @@ declare namespace i64 {
466470
export function div_s(left: i64, right: i64): i64;
467471
/** Computes the unsigned quotient of two 64-bit integers. */
468472
export function div_u(left: i64, right: i64): i64;
469-
/** Return 1 two 64-bit inegers are equal to each other, 0 otherwise. */
473+
/** Return 1 if two 64-bit integers are equal to each other, 0 otherwise. */
470474
export function eq(left: i64, right: i64): i32;
471-
/** Return 0 two 64-bit inegers are equal to each other, 1 otherwise. */
475+
/** Return 0 if two 64-bit integers are equal to each other, 1 otherwise. */
472476
export function ne(left: i64, right: i64): i32;
477+
/** Compute the remaining between two 64-bit positive integers. */
478+
export function rem(left: i64, right: i64): i64;
473479
/** Atomic 64-bit integer operations. */
474480
export namespace atomic {
475481
/** Atomically loads an 8-bit unsigned integer value from memory and returns it as a 64-bit integer. */

0 commit comments

Comments
 (0)