Skip to content

Commit ac01b0a

Browse files
authored
feat: Add i32/i64/f32/f64.eq/ne builtins (#2258)
1 parent a835094 commit ac01b0a

File tree

6 files changed

+1002
-92
lines changed

6 files changed

+1002
-92
lines changed

Diff for: src/builtins.ts

+193
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ export namespace BuiltinNames {
161161
export const reinterpret = "~lib/builtins/reinterpret";
162162
export const sqrt = "~lib/builtins/sqrt";
163163
export const trunc = "~lib/builtins/trunc";
164+
export const eq = "~lib/builtins/eq";
165+
export const ne = "~lib/builtins/ne";
164166
export const load = "~lib/builtins/load";
165167
export const store = "~lib/builtins/store";
166168
export const atomic_load = "~lib/builtins/atomic.load";
@@ -258,6 +260,15 @@ export namespace BuiltinNames {
258260
export const f32_div = "~lib/builtins/f32.div";
259261
export const f64_div = "~lib/builtins/f64.div";
260262

263+
export const i32_eq = "~lib/builtins/i32.eq";
264+
export const i64_eq = "~lib/builtins/i64.eq";
265+
export const f32_eq = "~lib/builtins/f32.eq";
266+
export const f64_eq = "~lib/builtins/f64.eq";
267+
export const i32_ne = "~lib/builtins/i32.ne";
268+
export const i64_ne = "~lib/builtins/i64.ne";
269+
export const f32_ne = "~lib/builtins/f32.ne";
270+
export const f64_ne = "~lib/builtins/f64.ne";
271+
261272
export const i32_load8_s = "~lib/builtins/i32.load8_s";
262273
export const i32_load8_u = "~lib/builtins/i32.load8_u";
263274
export const i32_load16_s = "~lib/builtins/i32.load16_s";
@@ -2436,6 +2447,116 @@ function builtin_div(ctx: BuiltinContext): ExpressionRef {
24362447
}
24372448
builtins.set(BuiltinNames.div, builtin_div);
24382449

2450+
// eq<T?>(left: T, right: T) -> i32
2451+
function builtin_eq(ctx: BuiltinContext): ExpressionRef {
2452+
var compiler = ctx.compiler;
2453+
var module = compiler.module;
2454+
if (checkTypeOptional(ctx, true) | checkArgsRequired(ctx, 2)) {
2455+
return module.unreachable();
2456+
}
2457+
var operands = ctx.operands;
2458+
var typeArguments = ctx.typeArguments;
2459+
var left = operands[0];
2460+
var arg0 = typeArguments
2461+
? compiler.compileExpression(
2462+
left,
2463+
typeArguments[0],
2464+
Constraints.CONV_IMPLICIT
2465+
)
2466+
: compiler.compileExpression(operands[0], Type.auto);
2467+
var type = compiler.currentType;
2468+
if (type.isValue) {
2469+
let arg1: ExpressionRef;
2470+
if (!typeArguments && left.isNumericLiteral) {
2471+
// prefer right type
2472+
arg1 = compiler.compileExpression(
2473+
operands[1],
2474+
type
2475+
);
2476+
if (compiler.currentType != type) {
2477+
arg0 = compiler.compileExpression(
2478+
left,
2479+
(type = compiler.currentType),
2480+
Constraints.CONV_IMPLICIT
2481+
);
2482+
}
2483+
} else {
2484+
arg1 = compiler.compileExpression(
2485+
operands[1],
2486+
type,
2487+
Constraints.CONV_IMPLICIT
2488+
);
2489+
}
2490+
if (type.isNumericValue) {
2491+
compiler.currentType = Type.i32;
2492+
return compiler.makeEq(arg0, arg1, type, ctx.reportNode);
2493+
}
2494+
}
2495+
compiler.error(
2496+
DiagnosticCode.Operation_0_cannot_be_applied_to_type_1,
2497+
ctx.reportNode.typeArgumentsRange,
2498+
"eq",
2499+
type.toString()
2500+
);
2501+
return module.unreachable();
2502+
}
2503+
builtins.set(BuiltinNames.eq, builtin_eq);
2504+
2505+
// ne<T?>(left: T, right: T) -> i32
2506+
function builtin_ne(ctx: BuiltinContext): ExpressionRef {
2507+
var compiler = ctx.compiler;
2508+
var module = compiler.module;
2509+
if (checkTypeOptional(ctx, true) | checkArgsRequired(ctx, 2)) {
2510+
return module.unreachable();
2511+
}
2512+
var operands = ctx.operands;
2513+
var typeArguments = ctx.typeArguments;
2514+
var left = operands[0];
2515+
var arg0 = typeArguments
2516+
? compiler.compileExpression(
2517+
left,
2518+
typeArguments[0],
2519+
Constraints.CONV_IMPLICIT
2520+
)
2521+
: compiler.compileExpression(operands[0], Type.auto);
2522+
var type = compiler.currentType;
2523+
if (type.isValue) {
2524+
let arg1: ExpressionRef;
2525+
if (!typeArguments && left.isNumericLiteral) {
2526+
// prefer right type
2527+
arg1 = compiler.compileExpression(
2528+
operands[1],
2529+
type
2530+
);
2531+
if (compiler.currentType != type) {
2532+
arg0 = compiler.compileExpression(
2533+
left,
2534+
(type = compiler.currentType),
2535+
Constraints.CONV_IMPLICIT
2536+
);
2537+
}
2538+
} else {
2539+
arg1 = compiler.compileExpression(
2540+
operands[1],
2541+
type,
2542+
Constraints.CONV_IMPLICIT
2543+
);
2544+
}
2545+
if (type.isNumericValue) {
2546+
compiler.currentType = Type.i32;
2547+
return compiler.makeNe(arg0, arg1, type, ctx.reportNode);
2548+
}
2549+
}
2550+
compiler.error(
2551+
DiagnosticCode.Operation_0_cannot_be_applied_to_type_1,
2552+
ctx.reportNode.typeArgumentsRange,
2553+
"ne",
2554+
type.toString()
2555+
);
2556+
return module.unreachable();
2557+
}
2558+
builtins.set(BuiltinNames.ne, builtin_ne);
2559+
24392560
// === Atomics ================================================================================
24402561

24412562
// atomic.load<T!>(offset: usize, immOffset?: usize) -> T*
@@ -6679,6 +6800,78 @@ function builtin_f64_div(ctx: BuiltinContext): ExpressionRef {
66796800
}
66806801
builtins.set(BuiltinNames.f64_div, builtin_f64_div);
66816802

6803+
// i32.eq -> eq<i32>
6804+
function builtin_i32_eq(ctx: BuiltinContext): ExpressionRef {
6805+
checkTypeAbsent(ctx);
6806+
ctx.typeArguments = [ Type.i32 ];
6807+
ctx.contextualType = Type.i32;
6808+
return builtin_eq(ctx);
6809+
}
6810+
builtins.set(BuiltinNames.i32_eq, builtin_i32_eq);
6811+
6812+
// i64.eq -> eq<i64>
6813+
function builtin_i64_eq(ctx: BuiltinContext): ExpressionRef {
6814+
checkTypeAbsent(ctx);
6815+
ctx.typeArguments = [ Type.i64 ];
6816+
ctx.contextualType = Type.i32;
6817+
return builtin_eq(ctx);
6818+
}
6819+
builtins.set(BuiltinNames.i64_eq, builtin_i64_eq);
6820+
6821+
// f32.eq -> eq<f32>
6822+
function builtin_f32_eq(ctx: BuiltinContext): ExpressionRef {
6823+
checkTypeAbsent(ctx);
6824+
ctx.typeArguments = [ Type.f32 ];
6825+
ctx.contextualType = Type.i32;
6826+
return builtin_eq(ctx);
6827+
}
6828+
builtins.set(BuiltinNames.f32_eq, builtin_f32_eq);
6829+
6830+
// f64.eq -> eq<f64>
6831+
function builtin_f64_eq(ctx: BuiltinContext): ExpressionRef {
6832+
checkTypeAbsent(ctx);
6833+
ctx.typeArguments = [ Type.f64 ];
6834+
ctx.contextualType = Type.i32;
6835+
return builtin_eq(ctx);
6836+
}
6837+
builtins.set(BuiltinNames.f64_eq, builtin_f64_eq);
6838+
6839+
// i32.ne -> ne<i32>
6840+
function builtin_i32_ne(ctx: BuiltinContext): ExpressionRef {
6841+
checkTypeAbsent(ctx);
6842+
ctx.typeArguments = [ Type.i32 ];
6843+
ctx.contextualType = Type.i32;
6844+
return builtin_ne(ctx);
6845+
}
6846+
builtins.set(BuiltinNames.i32_ne, builtin_i32_ne);
6847+
6848+
// i64.ne -> ne<i64>
6849+
function builtin_i64_ne(ctx: BuiltinContext): ExpressionRef {
6850+
checkTypeAbsent(ctx);
6851+
ctx.typeArguments = [ Type.i64 ];
6852+
ctx.contextualType = Type.i32;
6853+
return builtin_ne(ctx);
6854+
}
6855+
builtins.set(BuiltinNames.i64_ne, builtin_i64_ne);
6856+
6857+
// f32.ne -> ne<f32>
6858+
function builtin_f32_ne(ctx: BuiltinContext): ExpressionRef {
6859+
checkTypeAbsent(ctx);
6860+
ctx.typeArguments = [ Type.f32 ];
6861+
ctx.contextualType = Type.i32;
6862+
return builtin_ne(ctx);
6863+
}
6864+
builtins.set(BuiltinNames.f32_ne, builtin_f32_ne);
6865+
6866+
// f64.ne-> ne<f64>
6867+
function builtin_f64_ne(ctx: BuiltinContext): ExpressionRef {
6868+
checkTypeAbsent(ctx);
6869+
ctx.typeArguments = [ Type.f64 ];
6870+
ctx.contextualType = Type.i32;
6871+
return builtin_ne(ctx);
6872+
}
6873+
builtins.set(BuiltinNames.f64_ne, builtin_f64_ne);
6874+
66826875
// i32.load8_s -> <i32>load<i8>
66836876
function builtin_i32_load8_s(ctx: BuiltinContext): ExpressionRef {
66846877
checkTypeAbsent(ctx);

Diff for: std/assembly/builtins.ts

+40
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ export declare function mul<T>(left: T, right: T): T;
136136
@builtin
137137
export declare function div<T>(left: T, right: T): T;
138138

139+
// @ts-ignore: decorator
140+
@builtin
141+
export declare function eq<T>(left: T, right: T): i32;
142+
143+
// @ts-ignore: decorator
144+
@builtin
145+
export declare function ne<T>(left: T, right: T): i32;
146+
139147
// @ts-ignore: decorator
140148
@unsafe @builtin
141149
export declare function load<T>(ptr: usize, immOffset?: usize, immAlign?: usize): T;
@@ -334,6 +342,14 @@ export namespace i32 {
334342
@builtin
335343
export declare function rotr(value: i32, shift: i32): i32;
336344

345+
// @ts-ignore: decorator
346+
@builtin
347+
export declare function eq(left: i32, right:i32): i32;
348+
349+
// @ts-ignore: decorator
350+
@builtin
351+
export declare function ne(left: i32, right:i32): i32;
352+
337353
// @ts-ignore: decorator
338354
@builtin
339355
export declare function reinterpret_f32(value: f32): i32;
@@ -577,6 +593,14 @@ export namespace i64 {
577593
@builtin
578594
export declare function rotr(value: i64, shift: i64): i64;
579595

596+
// @ts-ignore: decorator
597+
@builtin
598+
export declare function eq(left: i64, right:i64): i32;
599+
600+
// @ts-ignore: decorator
601+
@builtin
602+
export declare function ne(left: i64, right:i64): i32;
603+
580604
// @ts-ignore: decorator
581605
@builtin
582606
export declare function reinterpret_f64(value: f64): i64;
@@ -977,6 +1001,14 @@ export namespace f32 {
9771001
// @ts-ignore: decorator
9781002
@builtin
9791003
export declare function div(left: f32, right: f32): f32;
1004+
1005+
// @ts-ignore: decorator
1006+
@builtin
1007+
export declare function eq(left: f32, right: f32): i32;
1008+
1009+
// @ts-ignore: decorator
1010+
@builtin
1011+
export declare function ne(left: f32, right: f32): i32;
9801012
}
9811013

9821014
// @ts-ignore: decorator
@@ -1084,6 +1116,14 @@ export namespace f64 {
10841116
// @ts-ignore: decorator
10851117
@builtin
10861118
export declare function div(left: f64, right: f64): f64;
1119+
1120+
// @ts-ignore: decorator
1121+
@builtin
1122+
export declare function eq(left: f64, right: f64): i32;
1123+
1124+
// @ts-ignore: decorator
1125+
@builtin
1126+
export declare function ne(left: f64, right: f64): i32;
10871127
}
10881128

10891129
// @ts-ignore: decorator

Diff for: std/assembly/index.d.ts

+20
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ declare function sub<T extends i32 | i64 | f32 | f64>(left: T, right: T): T;
147147
declare function mul<T extends i32 | i64 | f32 | f64>(left: T, right: T): T;
148148
/** Computes the quotient of two integers or floats. */
149149
declare function div<T extends i32 | i64 | f32 | f64>(left: T, right: T): T;
150+
/** Return 1 if two numbers are equal to each other, 0 otherwise. */
151+
declare function eq<T extends i32 | i64 | f32 | f64>(left: T, right: T): i32;
152+
/** Return 0 if two numbers are equal to each other, 1 otherwise. */
153+
declare function ne<T extends i32 | i64 | f32 | f64>(left: T, right: T): i32;
150154
/** Loads a value of the specified type from memory. Equivalent to dereferncing a pointer in other languages. */
151155
declare function load<T>(ptr: usize, immOffset?: usize, immAlign?: usize): T;
152156
/** Stores a value of the specified type to memory. Equivalent to dereferencing a pointer in other languages when assigning a value. */
@@ -338,6 +342,10 @@ declare namespace i32 {
338342
export function div_s(left: i32, right: i32): i32;
339343
/** Computes the unsigned quotient of two 32-bit integers. */
340344
export function div_u(left: i32, right: i32): i32;
345+
/** Return 1 two 32-bit inegers are equal to each other, 0 otherwise. */
346+
export function eq(left: i32, right: i32): i32;
347+
/** Return 0 two 32-bit inegers are equal to each other, 1 otherwise. */
348+
export function ne(left: i32, right: i32): i32;
341349
/** Atomic 32-bit integer operations. */
342350
export namespace atomic {
343351
/** Atomically loads an 8-bit unsigned integer value from memory and returns it as a 32-bit integer. */
@@ -458,6 +466,10 @@ declare namespace i64 {
458466
export function div_s(left: i64, right: i64): i64;
459467
/** Computes the unsigned quotient of two 64-bit integers. */
460468
export function div_u(left: i64, right: i64): i64;
469+
/** Return 1 two 64-bit inegers are equal to each other, 0 otherwise. */
470+
export function eq(left: i64, right: i64): i32;
471+
/** Return 0 two 64-bit inegers are equal to each other, 1 otherwise. */
472+
export function ne(left: i64, right: i64): i32;
461473
/** Atomic 64-bit integer operations. */
462474
export namespace atomic {
463475
/** Atomically loads an 8-bit unsigned integer value from memory and returns it as a 64-bit integer. */
@@ -625,6 +637,10 @@ declare namespace f32 {
625637
export function mul(left: f32, right: f32): f32;
626638
/** Computes the quotient of two 32-bit floats. */
627639
export function div(left: f32, right: f32): f32;
640+
/** Return 1 two 32-bit floats are equal to each other, 0 otherwise. */
641+
export function eq(left: f32, right: f32): i32;
642+
/** Return 0 two 32-bit floats are equal to each other, 1 otherwise. */
643+
export function ne(left: f32, right: f32): i32;
628644
/** Computes the absolute value of a 32-bit float. */
629645
export function abs(value: f32): f32;
630646
/** Determines the maximum of two 32-bit floats. If either operand is `NaN`, returns `NaN`. */
@@ -679,6 +695,10 @@ declare namespace f64 {
679695
export function mul(left: f64, right: f64): f64;
680696
/** Computes the quotient of two 64-bit floats. */
681697
export function div(left: f64, right: f64): f64;
698+
/** Return 1 two 64-bit floats are equal to each other, 0 otherwise. */
699+
export function eq(left: f64, right: f64): i32;
700+
/** Return 0 two 32-bit floats are equal to each other, 1 otherwise. */
701+
export function ne(left: f64, right: f64): i32;
682702
/** Computes the absolute value of a 64-bit float. */
683703
export function abs(value: f64): f64;
684704
/** Determines the maximum of two 64-bit floats. If either operand is `NaN`, returns `NaN`. */

0 commit comments

Comments
 (0)