Skip to content

Commit 40b814a

Browse files
committed
Refactored builtins
1 parent b7030d4 commit 40b814a

File tree

7 files changed

+488
-417
lines changed

7 files changed

+488
-417
lines changed

assembly.d.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,18 @@ declare function popcnt<T = i32 | i64>(value: T): T;
3939
declare function rotl<T = i32 | i64>(value: T, shift: T): T;
4040
/** Performs the sign-agnostic rotate right operation on a 32-bit or 64-bit integer. */
4141
declare function rotr<T = i32 | i64>(value: T, shift: T): T;
42-
/** Computes the absolute value of a 32-bit or 64-bit float. */
43-
declare function abs<T = f32 | f64>(value: T): T;
42+
/** Computes the absolute value of an integer or float. */
43+
declare function abs<T = i32 | i64 | f32 | f64>(value: T): T;
44+
/** Determines the maximum of two integers or floats. If either operand is `NaN`, returns `NaN`. */
45+
declare function max<T = i32 | i64 | f32 | f64>(left: T, right: T): T;
46+
/** Determines the minimum of two integers or floats. If either operand is `NaN`, returns `NaN`. */
47+
declare function min<T = i32 | i64 | f32 | f64>(left: T, right: T): T;
4448
/** Performs the ceiling operation on a 32-bit or 64-bit float. */
4549
declare function ceil<T = f32 | f64>(value: T): T;
4650
/** Composes a 32-bit or 64-bit float from the magnitude of `x` and the sign of `y`. */
4751
declare function copysign<T = f32 | f64>(x: T, y: T): T;
4852
/** Performs the floor operation on a 32-bit or 64-bit float. */
4953
declare function floor<T = f32 | f64>(value: T): T;
50-
/** Determines the maximum of two 32-bit or 64-bit floats. If either operand is `NaN`, returns `NaN`. */
51-
declare function max<T = f32 | f64>(left: T, right: T): T;
52-
/** Determines the minimum of two 32-bit or 64-bit floats. If either operand is `NaN`, returns `NaN`. */
53-
declare function min<T = f32 | f64>(left: T, right: T): T;
5454
/** Rounds to the nearest integer tied to even of a 32-bit or 64-bit float. */
5555
declare function nearest<T = f32 | f64>(value: T): T;
5656
/** Reinterprets the bits of a value of type `T1` as type `T2`. Valid reinterpretations are i32 to/from f32 and i64 to/from f64. */

src/builtins.ts

Lines changed: 431 additions & 0 deletions
Large diffs are not rendered by default.

src/compiler.ts

Lines changed: 21 additions & 290 deletions
Large diffs are not rendered by default.

src/glue/js.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ declare type bool = boolean;
1414
// Raw memory access (here: Binaryen memory)
1515
declare function store<T = u8>(ptr: usize, val: T): void;
1616
declare function load<T = u8>(ptr: usize): T;
17+
18+
// Other things that might or might not be useful
19+
declare function select<T>(ifTrue: T, ifFalse: T, condition: bool): T;

src/glue/js.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ globalScope["load"] = function load_u8(ptr: number) {
88
return binaryen.HEAPU8[ptr];
99
};
1010

11+
globalScope["select"] = function select<T>(ifTrue: T, ifFalse: T, condition: bool): T {
12+
return condition ? ifTrue : ifFalse;
13+
};
14+
1115
const binaryen = require("binaryen");
1216
for (const key in binaryen)
1317
if (/^_(?:Binaryen|Relooper|malloc$|free$)/.test(key))

src/program.ts

Lines changed: 20 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { initialize as initializeBuiltins } from "./builtins";
12
import { Target } from "./compiler";
23
import { GETTER_PREFIX, SETTER_PREFIX, PATH_DELIMITER } from "./constants";
3-
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter, DiagnosticCategory } from "./diagnostics";
4+
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
45
import { Type, typesToString } from "./types";
56
import { I64 } from "./util";
67
import {
@@ -57,7 +58,7 @@ class QueuedImport {
5758
declaration: ImportDeclaration;
5859
}
5960

60-
const reusableTypesStub: Map<string,Type> = new Map();
61+
const noTypesYet: Map<string,Type> = new Map();
6162

6263
export class Program extends DiagnosticEmitter {
6364

@@ -70,7 +71,7 @@ export class Program extends DiagnosticEmitter {
7071
/** Elements by internal name. */
7172
elements: Map<string,Element> = new Map();
7273
/** Types by internal name. */
73-
types: Map<string,Type> = reusableTypesStub;
74+
types: Map<string,Type> = noTypesYet;
7475
/** Exports of individual files by internal name. Not global exports. */
7576
exports: Map<string,Element> = new Map();
7677

@@ -82,6 +83,22 @@ export class Program extends DiagnosticEmitter {
8283
/** Initializes the program and its elements prior to compilation. */
8384
initialize(target: Target = Target.WASM32): void {
8485
this.target = target;
86+
this.types = new Map([
87+
["i8", Type.i8],
88+
["i16", Type.i16],
89+
["i32", Type.i32],
90+
["i64", Type.i64],
91+
["isize", target == Target.WASM64 ? Type.isize64 : Type.isize32],
92+
["u8", Type.u8],
93+
["u16", Type.u16],
94+
["u32", Type.u32],
95+
["u64", Type.u64],
96+
["usize", target == Target.WASM64 ? Type.usize64 : Type.usize32],
97+
["bool", Type.bool],
98+
["f32", Type.f32],
99+
["f64", Type.f64],
100+
["void", Type.void]
101+
]);
85102

86103
initializeBuiltins(this);
87104

@@ -1110,120 +1127,3 @@ export class Interface extends Class {
11101127
super(template, internalName, typeArguments, base);
11111128
}
11121129
}
1113-
1114-
const builtinIntTypes: Type[] = [ Type.i32, Type.i64 ];
1115-
const builtinFloatTypes: Type[] = [ Type.f32, Type.f64 ];
1116-
1117-
function initializeBuiltins(program: Program): void {
1118-
1119-
// types
1120-
1121-
program.types = new Map([
1122-
["i8", Type.i8],
1123-
["i16", Type.i16],
1124-
["i32", Type.i32],
1125-
["i64", Type.i64],
1126-
["isize", program.target == Target.WASM64 ? Type.isize64 : Type.isize32],
1127-
["u8", Type.u8],
1128-
["u16", Type.u16],
1129-
["u32", Type.u32],
1130-
["u64", Type.u64],
1131-
["usize", program.target == Target.WASM64 ? Type.usize64 : Type.usize32],
1132-
["bool", Type.bool],
1133-
["f32", Type.f32],
1134-
["f64", Type.f64],
1135-
["void", Type.void]
1136-
]);
1137-
1138-
// functions
1139-
1140-
const usize: Type = program.target == Target.WASM64 ? Type.usize64 : Type.usize32;
1141-
1142-
addGenericUnaryBuiltin(program, "clz", builtinIntTypes);
1143-
addGenericUnaryBuiltin(program, "ctz", builtinIntTypes);
1144-
addGenericUnaryBuiltin(program, "popcnt", builtinIntTypes);
1145-
addGenericBinaryBuiltin(program, "rotl", builtinIntTypes);
1146-
addGenericBinaryBuiltin(program, "rotr", builtinIntTypes);
1147-
1148-
addGenericUnaryBuiltin(program, "abs", builtinFloatTypes);
1149-
addGenericUnaryBuiltin(program, "ceil", builtinFloatTypes);
1150-
addGenericBinaryBuiltin(program, "copysign", builtinFloatTypes);
1151-
addGenericUnaryBuiltin(program, "floor", builtinFloatTypes);
1152-
addGenericBinaryBuiltin(program, "max", builtinFloatTypes);
1153-
addGenericBinaryBuiltin(program, "min", builtinFloatTypes);
1154-
addGenericUnaryBuiltin(program, "nearest", builtinFloatTypes);
1155-
addGenericUnaryBuiltin(program, "sqrt", builtinFloatTypes);
1156-
addGenericUnaryBuiltin(program, "trunc", builtinFloatTypes);
1157-
1158-
addSimpleBuiltin(program, "current_memory", [], usize);
1159-
addSimpleBuiltin(program, "grow_memory", [ usize ], usize);
1160-
addSimpleBuiltin(program, "unreachable", [], Type.void);
1161-
1162-
addGenericAnyBuiltin(program, "load");
1163-
addGenericAnyBuiltin(program, "store");
1164-
addGenericAnyBuiltin(program, "reinterpret");
1165-
addGenericAnyBuiltin(program, "select");
1166-
1167-
addGenericAnyBuiltin(program, "sizeof");
1168-
addGenericUnaryTestBuiltin(program, "isNaN", builtinFloatTypes);
1169-
addGenericUnaryTestBuiltin(program, "isFinite", builtinFloatTypes);
1170-
addSimpleBuiltin(program, "assert", [ Type.bool ], Type.void);
1171-
}
1172-
1173-
/** Adds a simple (non-generic) builtin. */
1174-
function addSimpleBuiltin(program: Program, name: string, parameterTypes: Type[], returnType: Type) {
1175-
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
1176-
prototype.isGeneric = false;
1177-
prototype.isBuiltin = true;
1178-
const k: i32 = parameterTypes.length;
1179-
const parameters: Parameter[] = new Array(k);
1180-
for (let i: i32 = 0; i < k; ++i)
1181-
parameters[i] = new Parameter("arg" + i, parameterTypes[i], null);
1182-
prototype.instances.set("", new Function(prototype, name, [], parameters, returnType, null));
1183-
program.elements.set(name, prototype);
1184-
}
1185-
1186-
/** Adds a generic unary builtin that takes and returns a value of its generic type. */
1187-
function addGenericUnaryBuiltin(program: Program, name: string, types: Type[]): void {
1188-
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
1189-
prototype.isGeneric = true;
1190-
prototype.isBuiltin = true;
1191-
for (let i: i32 = 0, k = types.length; i < k; ++i) {
1192-
const typeName: string = types[i].toString();
1193-
prototype.instances.set(typeName, new Function(prototype, name + "<" + typeName + ">", [ types[i] ], [ new Parameter("value", types[i], null) ], types[i], null));
1194-
}
1195-
program.elements.set(name, prototype);
1196-
}
1197-
1198-
/** Adds a generic binary builtin that takes two and returns a value of its generic type. */
1199-
function addGenericBinaryBuiltin(program: Program, name: string, types: Type[]): void {
1200-
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
1201-
prototype.isGeneric = true;
1202-
prototype.isBuiltin = true;
1203-
for (let i: i32 = 0, k = types.length; i < k; ++i) {
1204-
const typeName: string = types[i].toString();
1205-
prototype.instances.set(typeName, new Function(prototype, name + "<" + typeName + ">", [ types[i], types[i] ], [ new Parameter("left", types[i], null), new Parameter("right", types[i], null) ], types[i], null));
1206-
}
1207-
program.elements.set(name, prototype);
1208-
}
1209-
1210-
/** Adds a generic unary builtin that alwways returns `bool`. */
1211-
function addGenericUnaryTestBuiltin(program: Program, name: string, types: Type[]): void {
1212-
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
1213-
prototype.isGeneric = true;
1214-
prototype.isBuiltin = true;
1215-
for (let i: i32 = 0, k = types.length; i < k; ++i) {
1216-
const typeName: string = types[i].toString();
1217-
prototype.instances.set(typeName, new Function(prototype, name + "<" + typeName + ">", [ types[i] ], [ new Parameter("value", types[i], null) ], Type.bool, null));
1218-
}
1219-
program.elements.set(name, prototype);
1220-
}
1221-
1222-
/** Adds a special generic builtin that takes any type argument. */
1223-
function addGenericAnyBuiltin(program: Program, name: string): void {
1224-
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
1225-
prototype.isGeneric = true;
1226-
prototype.isBuiltin = true;
1227-
program.elements.set(name, prototype);
1228-
// instances are hard coded in compiler.ts
1229-
}

tests/compiler.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => {
5050
}
5151
module.optimize();
5252
actualOptimized = module.toText();
53-
} else
53+
} else {
54+
process.exitCode = 1;
5455
console.log(chalk.default.red("validate ERROR"));
56+
}
5557

5658
if (isCreate) {
5759
fs.writeFileSync(__dirname + "/compiler/" + fixture, actual, { encoding: "utf8" });

0 commit comments

Comments
 (0)