mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-24 14:42:13 +00:00
Add atomic built-ins (#440)
This commit is contained in:
parent
41a89fa773
commit
7ce3296b5e
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ docs/
|
||||
node_modules/
|
||||
out/
|
||||
raw/
|
||||
.history
|
||||
|
506
src/builtins.ts
506
src/builtins.ts
@ -40,7 +40,8 @@ import {
|
||||
getExpressionType,
|
||||
getConstValueI64High,
|
||||
getConstValueI64Low,
|
||||
getConstValueI32
|
||||
getConstValueI32,
|
||||
AtomicRMWOp
|
||||
} from "./module";
|
||||
|
||||
import {
|
||||
@ -51,7 +52,8 @@ import {
|
||||
OperatorKind,
|
||||
FlowFlags,
|
||||
Global,
|
||||
DecoratorFlags
|
||||
DecoratorFlags,
|
||||
Element
|
||||
} from "./program";
|
||||
|
||||
import {
|
||||
@ -1676,6 +1678,416 @@ export function compileCall(
|
||||
compiler.currentType = Type.void;
|
||||
return module.createStore(typeArguments[0].byteSize, arg0, arg1, type.toNativeType(), offset);
|
||||
}
|
||||
case "Atomic.load": { // Atomic.load<T!>(offset: usize, constantOffset?: usize) -> *
|
||||
if (operands.length < 1 || operands.length > 2) {
|
||||
if (!(typeArguments && typeArguments.length == 1)) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
||||
);
|
||||
}
|
||||
if (operands.length < 1) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
||||
reportNode.range, "1", operands.length.toString(10)
|
||||
);
|
||||
} else {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_arguments_but_got_1,
|
||||
reportNode.range, "2", operands.length.toString(10)
|
||||
);
|
||||
}
|
||||
return module.createUnreachable();
|
||||
}
|
||||
if (!(typeArguments && typeArguments.length == 1)) {
|
||||
if (typeArguments && typeArguments.length) compiler.currentType = typeArguments[0];
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
||||
);
|
||||
return module.createUnreachable();
|
||||
}
|
||||
arg0 = compiler.compileExpression(
|
||||
operands[0],
|
||||
compiler.options.usizeType,
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
let offset = operands.length == 2 ? evaluateConstantOffset(compiler, operands[1]) : 0; // reports
|
||||
if (offset < 0) { // reported in evaluateConstantOffset
|
||||
return module.createUnreachable();
|
||||
}
|
||||
compiler.currentType = typeArguments[0];
|
||||
return module.createAtomicLoad(
|
||||
typeArguments[0].byteSize,
|
||||
arg0,
|
||||
typeArguments[0].is(TypeFlags.INTEGER) &&
|
||||
contextualType.is(TypeFlags.INTEGER) &&
|
||||
contextualType.size > typeArguments[0].size
|
||||
? (compiler.currentType = contextualType).toNativeType()
|
||||
: (compiler.currentType = typeArguments[0]).toNativeType(),
|
||||
offset
|
||||
);
|
||||
}
|
||||
case "Atomic.store": { // Atomic.store<T!>(offset: usize, value: *, constantOffset?: usize) -> void
|
||||
compiler.currentType = Type.void;
|
||||
if (operands.length < 2 || operands.length > 3) {
|
||||
if (!(typeArguments && typeArguments.length == 1)) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
||||
);
|
||||
}
|
||||
if (operands.length < 2) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
||||
reportNode.range, "2", operands.length.toString(10)
|
||||
);
|
||||
} else {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_arguments_but_got_1,
|
||||
reportNode.range, "3", operands.length.toString(10)
|
||||
);
|
||||
}
|
||||
return module.createUnreachable();
|
||||
}
|
||||
if (!(typeArguments && typeArguments.length == 1)) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
||||
);
|
||||
return module.createUnreachable();
|
||||
}
|
||||
arg0 = compiler.compileExpression(
|
||||
operands[0],
|
||||
compiler.options.usizeType,
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
arg1 = compiler.compileExpression(
|
||||
operands[1],
|
||||
typeArguments[0],
|
||||
typeArguments[0].is(TypeFlags.INTEGER)
|
||||
? ConversionKind.NONE // no need to convert to small int (but now might result in a float)
|
||||
: ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
let type: Type;
|
||||
if (
|
||||
typeArguments[0].is(TypeFlags.INTEGER) &&
|
||||
(
|
||||
!compiler.currentType.is(TypeFlags.INTEGER) || // float to int
|
||||
compiler.currentType.size < typeArguments[0].size // int to larger int (clear garbage bits)
|
||||
)
|
||||
) {
|
||||
arg1 = compiler.convertExpression(
|
||||
arg1,
|
||||
compiler.currentType, typeArguments[0],
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE, // still clears garbage bits
|
||||
operands[1]
|
||||
);
|
||||
type = typeArguments[0];
|
||||
} else {
|
||||
type = compiler.currentType;
|
||||
}
|
||||
let offset = operands.length == 3 ? evaluateConstantOffset(compiler, operands[2]) : 0; // reports
|
||||
if (offset < 0) { // reported in evaluateConstantOffset
|
||||
return module.createUnreachable();
|
||||
}
|
||||
compiler.currentType = Type.void;
|
||||
return module.createAtomicStore(typeArguments[0].byteSize, arg0, arg1, type.toNativeType(), offset);
|
||||
}
|
||||
case "Atomic.add": // add<T!>(ptr: usize, value: T, constantOffset?: usize): T;
|
||||
case "Atomic.sub": // sub<T!>(ptr: usize, value: T, constantOffset?: usize): T;
|
||||
case "Atomic.and": // and<T!>(ptr: usize, value: T, constantOffset?: usize): T;
|
||||
case "Atomic.or": // or<T!>(ptr: usize, value: T, constantOffset?: usize): T;
|
||||
case "Atomic.xor": // xor<T!>(ptr: usize, value: T, constantOffset?: usize): T;
|
||||
case "Atomic.xchg": // xchg<T!>(ptr: usize, value: T, constantOffset?: usize): T;
|
||||
{
|
||||
if (operands.length < 2 || operands.length > 3) {
|
||||
if (!(typeArguments && typeArguments.length == 1)) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
||||
);
|
||||
}
|
||||
if (operands.length < 2) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
||||
reportNode.range, "2", operands.length.toString(10)
|
||||
);
|
||||
} else {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_arguments_but_got_1,
|
||||
reportNode.range, "3", operands.length.toString(10)
|
||||
);
|
||||
}
|
||||
return module.createUnreachable();
|
||||
}
|
||||
if (!(typeArguments && typeArguments.length == 1)) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
||||
);
|
||||
return module.createUnreachable();
|
||||
}
|
||||
arg0 = compiler.compileExpression(
|
||||
operands[0],
|
||||
compiler.options.usizeType,
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
arg1 = compiler.compileExpression(
|
||||
operands[1],
|
||||
typeArguments[0],
|
||||
typeArguments[0].is(TypeFlags.INTEGER)
|
||||
? ConversionKind.NONE // no need to convert to small int (but now might result in a float)
|
||||
: ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
|
||||
let type: Type;
|
||||
if (
|
||||
typeArguments[0].is(TypeFlags.INTEGER) &&
|
||||
(
|
||||
!compiler.currentType.is(TypeFlags.INTEGER) || // float to int
|
||||
compiler.currentType.size < typeArguments[0].size // int to larger int (clear garbage bits)
|
||||
)
|
||||
) {
|
||||
arg1 = compiler.convertExpression(
|
||||
arg1,
|
||||
compiler.currentType, typeArguments[0],
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE, // still clears garbage bits
|
||||
operands[1]
|
||||
);
|
||||
type = typeArguments[0];
|
||||
} else {
|
||||
type = compiler.currentType;
|
||||
}
|
||||
|
||||
let offset = operands.length == 3 ? evaluateConstantOffset(compiler, operands[2]) : 0; // reports
|
||||
if (offset < 0) { // reported in evaluateConstantOffset
|
||||
return module.createUnreachable();
|
||||
}
|
||||
let RMWOp: AtomicRMWOp | null = null;
|
||||
switch (prototype.internalName) {
|
||||
case "Atomic.add": { RMWOp = AtomicRMWOp.Add; break; }
|
||||
case "Atomic.sub": { RMWOp = AtomicRMWOp.Sub; break; }
|
||||
case "Atomic.and": { RMWOp = AtomicRMWOp.And; break; }
|
||||
case "Atomic.or": { RMWOp = AtomicRMWOp.Or; break; }
|
||||
case "Atomic.xor": { RMWOp = AtomicRMWOp.Xor; break; }
|
||||
case "Atomic.xchg": { RMWOp = AtomicRMWOp.Xchg; break; }
|
||||
}
|
||||
compiler.currentType = typeArguments[0];
|
||||
if (RMWOp !== null) {
|
||||
return module.createAtomicRMW(
|
||||
RMWOp, typeArguments[0].byteSize, offset, arg0, arg1, type.toNativeType()
|
||||
);
|
||||
} else {
|
||||
compiler.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
||||
);
|
||||
return module.createUnreachable();
|
||||
}
|
||||
}
|
||||
case "Atomic.cmpxchg": { // cmpxchg<T!>(ptr: usize, expected:T, replacement: T, constantOffset?: usize): T;
|
||||
if (operands.length < 3 || operands.length > 4) {
|
||||
if (!(typeArguments && typeArguments.length == 1)) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
||||
);
|
||||
}
|
||||
if (operands.length < 3) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
||||
reportNode.range, "2", operands.length.toString(10)
|
||||
);
|
||||
} else {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_arguments_but_got_1,
|
||||
reportNode.range, "3", operands.length.toString(10)
|
||||
);
|
||||
}
|
||||
return module.createUnreachable();
|
||||
}
|
||||
if (!(typeArguments && typeArguments.length == 1)) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
||||
);
|
||||
return module.createUnreachable();
|
||||
}
|
||||
arg0 = compiler.compileExpression(
|
||||
operands[0],
|
||||
compiler.options.usizeType,
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
arg1 = compiler.compileExpression(
|
||||
operands[1],
|
||||
typeArguments[0],
|
||||
typeArguments[0].is(TypeFlags.INTEGER)
|
||||
? ConversionKind.NONE // no need to convert to small int (but now might result in a float)
|
||||
: ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
arg2 = compiler.compileExpression(
|
||||
operands[2],
|
||||
typeArguments[0],
|
||||
typeArguments[0].is(TypeFlags.INTEGER)
|
||||
? ConversionKind.NONE // no need to convert to small int (but now might result in a float)
|
||||
: ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
|
||||
let type: Type;
|
||||
if (
|
||||
typeArguments[0].is(TypeFlags.INTEGER) &&
|
||||
(
|
||||
!compiler.currentType.is(TypeFlags.INTEGER) || // float to int
|
||||
compiler.currentType.size < typeArguments[0].size // int to larger int (clear garbage bits)
|
||||
)
|
||||
) {
|
||||
arg1 = compiler.convertExpression(
|
||||
arg1,
|
||||
compiler.currentType, typeArguments[0],
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE, // still clears garbage bits
|
||||
operands[1]
|
||||
);
|
||||
arg2 = compiler.convertExpression(
|
||||
arg2,
|
||||
compiler.currentType, typeArguments[0],
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE, // still clears garbage bits
|
||||
operands[2]
|
||||
);
|
||||
type = typeArguments[0];
|
||||
} else {
|
||||
type = compiler.currentType;
|
||||
}
|
||||
|
||||
let offset = operands.length == 4 ? evaluateConstantOffset(compiler, operands[3]) : 0; // reports
|
||||
if (offset < 0) { // reported in evaluateConstantOffset
|
||||
return module.createUnreachable();
|
||||
}
|
||||
compiler.currentType = typeArguments[0];
|
||||
return module.createAtomicCmpxchg(
|
||||
typeArguments[0].byteSize, offset, arg0, arg1, arg2, type.toNativeType()
|
||||
);
|
||||
}
|
||||
case "Atomic.wait": { // wait<T!>(ptr: usize, expected:T, timeout: i64): i32;
|
||||
let hasError = typeArguments == null;
|
||||
if (operands.length != 3) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_arguments_but_got_1,
|
||||
reportNode.range, "3", operands.length.toString(10)
|
||||
);
|
||||
hasError = true;
|
||||
}
|
||||
if (!(typeArguments && typeArguments.length == 1)) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
||||
);
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
if (!typeArguments || hasError) {
|
||||
return module.createUnreachable();
|
||||
}
|
||||
|
||||
arg0 = compiler.compileExpression(
|
||||
operands[0],
|
||||
compiler.options.usizeType,
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
arg1 = compiler.compileExpression(
|
||||
operands[1],
|
||||
typeArguments[0],
|
||||
typeArguments[0].is(TypeFlags.INTEGER)
|
||||
? ConversionKind.NONE // no need to convert to small int (but now might result in a float)
|
||||
: ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
arg2 = compiler.compileExpression(
|
||||
operands[2],
|
||||
Type.i64,
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
|
||||
let type: Type = typeArguments[0];
|
||||
if (
|
||||
typeArguments[0].is(TypeFlags.INTEGER) &&
|
||||
(
|
||||
!compiler.currentType.is(TypeFlags.INTEGER) || // float to int
|
||||
compiler.currentType.size < typeArguments[0].size // int to larger int (clear garbage bits)
|
||||
)
|
||||
) {
|
||||
arg1 = compiler.convertExpression(
|
||||
arg1,
|
||||
compiler.currentType, typeArguments[0],
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE, // still clears garbage bits
|
||||
operands[1]
|
||||
);
|
||||
arg2 = compiler.convertExpression(
|
||||
arg2,
|
||||
compiler.currentType, typeArguments[0],
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE, // still clears garbage bits
|
||||
operands[2]
|
||||
);
|
||||
}
|
||||
|
||||
return module.createAtomicWait(
|
||||
arg0, arg1, arg2, type.toNativeType()
|
||||
);
|
||||
}
|
||||
case "Atomic.notify": { // notify<T!>(ptr: usize, count: u32): u32;
|
||||
let hasError = typeArguments == null;
|
||||
if (operands.length != 2) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_arguments_but_got_1,
|
||||
reportNode.range, "2", operands.length.toString(10)
|
||||
);
|
||||
hasError = true;
|
||||
}
|
||||
if (!(typeArguments && typeArguments.length == 1)) {
|
||||
compiler.error(
|
||||
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
||||
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
||||
);
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
if (!typeArguments || hasError) {
|
||||
return module.createUnreachable();
|
||||
}
|
||||
|
||||
arg0 = compiler.compileExpression(
|
||||
operands[0],
|
||||
compiler.options.usizeType,
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
arg1 = compiler.compileExpression(
|
||||
operands[1],
|
||||
Type.i32,
|
||||
ConversionKind.IMPLICIT,
|
||||
WrapMode.NONE
|
||||
);
|
||||
|
||||
return module.createAtomicWake(
|
||||
arg0, arg1
|
||||
);
|
||||
}
|
||||
case "sizeof": { // sizeof<T!>() -> usize
|
||||
compiler.currentType = compiler.options.usizeType;
|
||||
if (operands.length != 0) {
|
||||
@ -2851,6 +3263,83 @@ function deferASMCall(
|
||||
case "i64.store": return deferASM("store", compiler, Type.i64, operands, Type.i64, reportNode);
|
||||
case "f32.store": return deferASM("store", compiler, Type.f32, operands, Type.f32, reportNode);
|
||||
case "f64.store": return deferASM("store", compiler, Type.f64, operands, Type.f64, reportNode);
|
||||
|
||||
case "i32.atomic.load8_u": return deferASM("Atomic.load", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.load16_u": return deferASM("Atomic.load", compiler, Type.u16, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.load": return deferASM("Atomic.load", compiler, Type.i32, operands, Type.i32, reportNode);
|
||||
case "i64.atomic.load8_u": return deferASM("Atomic.load", compiler, Type.u8, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.load16_u": return deferASM("Atomic.load", compiler, Type.u16, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.load32_u": return deferASM("Atomic.load", compiler, Type.u32, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.load": return deferASM("Atomic.load", compiler, Type.i64, operands, Type.i64, reportNode);
|
||||
|
||||
case "i32.atomic.store8": return deferASM("Atomic.store", compiler, Type.i8, operands, Type.i32, reportNode);
|
||||
case "i32.atomic.store16": return deferASM("Atomic.store", compiler, Type.i16, operands, Type.i32, reportNode);
|
||||
case "i32.atomic.store": return deferASM("Atomic.store", compiler, Type.i32, operands, Type.i32, reportNode);
|
||||
case "i64.atomic.store8": return deferASM("Atomic.store", compiler, Type.i8, operands, Type.i64, reportNode);
|
||||
case "i64.atomic.store16": return deferASM("Atomic.store", compiler, Type.i16, operands, Type.i64, reportNode);
|
||||
case "i64.atomic.store32": return deferASM("Atomic.store", compiler, Type.i32, operands, Type.i64, reportNode);
|
||||
case "i64.atomic.store": return deferASM("Atomic.store", compiler, Type.i64, operands, Type.i64, reportNode);
|
||||
|
||||
case "i32.atomic.rmw8_u.add": return deferASM("Atomic.add", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw16_u.add": return deferASM("Atomic.add", compiler, Type.u16, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw.add": return deferASM("Atomic.add", compiler, Type.u32, operands, Type.u32, reportNode);
|
||||
case "i64.atomic.rmw8_u.add": return deferASM("Atomic.add", compiler, Type.u8, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw16_u.add": return deferASM("Atomic.add", compiler, Type.u16, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw32_u.add": return deferASM("Atomic.add", compiler, Type.u32, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw.add": return deferASM("Atomic.add", compiler, Type.u64, operands, Type.u64, reportNode);
|
||||
|
||||
case "i32.atomic.rmw8_u.sub": return deferASM("Atomic.sub", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw16_u.sub": return deferASM("Atomic.sub", compiler, Type.u16, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw.sub": return deferASM("Atomic.sub", compiler, Type.u32, operands, Type.u32, reportNode);
|
||||
case "i64.atomic.rmw8_u.sub": return deferASM("Atomic.sub", compiler, Type.u8, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw16_u.sub": return deferASM("Atomic.sub", compiler, Type.u16, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw32_u.sub": return deferASM("Atomic.sub", compiler, Type.u32, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw.sub": return deferASM("Atomic.sub", compiler, Type.u64, operands, Type.u64, reportNode);
|
||||
|
||||
case "i32.atomic.rmw8_u.and": return deferASM("Atomic.and", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw16_u.and": return deferASM("Atomic.and", compiler, Type.u16, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw.and": return deferASM("Atomic.and", compiler, Type.u32, operands, Type.u32, reportNode);
|
||||
case "i64.atomic.rmw8_u.and": return deferASM("Atomic.and", compiler, Type.u8, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw16_u.and": return deferASM("Atomic.and", compiler, Type.u16, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw32_u.and": return deferASM("Atomic.and", compiler, Type.u32, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw.and": return deferASM("Atomic.and", compiler, Type.u64, operands, Type.u64, reportNode);
|
||||
|
||||
case "i32.atomic.rmw8_u.or": return deferASM("Atomic.or", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw16_u.or": return deferASM("Atomic.or", compiler, Type.u16, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw.or": return deferASM("Atomic.or", compiler, Type.u32, operands, Type.u32, reportNode);
|
||||
case "i64.atomic.rmw8_u.or": return deferASM("Atomic.or", compiler, Type.u8, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw16_u.or": return deferASM("Atomic.or", compiler, Type.u16, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw32_u.or": return deferASM("Atomic.or", compiler, Type.u32, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw.or": return deferASM("Atomic.or", compiler, Type.u64, operands, Type.u64, reportNode);
|
||||
|
||||
case "i32.atomic.rmw8_u.xor": return deferASM("Atomic.xor", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw16_u.xor": return deferASM("Atomic.xor", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw.xor": return deferASM("Atomic.xor", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i64.atomic.rmw8_u.xor": return deferASM("Atomic.xor", compiler, Type.u8, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw16_u.xor": return deferASM("Atomic.xor", compiler, Type.u16, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw32_u.xor": return deferASM("Atomic.xor", compiler, Type.u32, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw.xor": return deferASM("Atomic.xor", compiler, Type.u64, operands, Type.u64, reportNode);
|
||||
|
||||
case "i32.atomic.rmw8_u.xchg": return deferASM("Atomic.xchg", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw16_u.xchg": return deferASM("Atomic.xchg", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw.xchg": return deferASM("Atomic.xchg", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i64.atomic.rmw8_u.xchg": return deferASM("Atomic.xchg", compiler, Type.u8, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw16_u.xchg": return deferASM("Atomic.xchg", compiler, Type.u16, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw32_u.xchg": return deferASM("Atomic.xchg", compiler, Type.u32, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw.xchg": return deferASM("Atomic.xchg", compiler, Type.u64, operands, Type.u64, reportNode);
|
||||
|
||||
case "i32.atomic.rmw8_u.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw16_u.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i32.atomic.rmw.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u8, operands, Type.u32, reportNode);
|
||||
case "i64.atomic.rmw8_u.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u8, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw16_u.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u16, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw32_u.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u32, operands, Type.u64, reportNode);
|
||||
case "i64.atomic.rmw.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u64, operands, Type.u64, reportNode);
|
||||
|
||||
case "i32.wait": return deferASM("Atomic.wait", compiler, Type.i32, operands, Type.u32, reportNode);
|
||||
case "i64.wait": return deferASM("Atomic.wait", compiler, Type.i64, operands, Type.i64, reportNode);
|
||||
case "i32.notify": return deferASM("Atomic.notify", compiler, Type.i32, operands, Type.u32, reportNode);
|
||||
case "i64.notify": return deferASM("Atomic.notify", compiler, Type.i64, operands, Type.i64, reportNode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -2864,7 +3353,18 @@ function deferASM(
|
||||
valueType: Type,
|
||||
reportNode: Node
|
||||
): ExpressionRef {
|
||||
var prototype = assert(compiler.program.elementsLookup.get(name));
|
||||
// Built-in wasm functions can be namespaced like Atomic.{OPERATION}
|
||||
// Split name by '.' to find member function prototype
|
||||
var names = name.split(".");
|
||||
var prototype: Element = assert(compiler.program.elementsLookup.get(names[0]));
|
||||
if (names.length > 1) {
|
||||
for (let i = 1; i < names.length; i++) {
|
||||
const subName = names[i];
|
||||
if (prototype && prototype.members) {
|
||||
prototype = assert(prototype.members.get(subName));
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||
return compileCall(compiler, <FunctionPrototype>prototype, [ typeArgument ], operands, valueType, reportNode);
|
||||
}
|
||||
|
@ -43,6 +43,20 @@
|
||||
@builtin export declare function call_indirect<T>(target: void, ...args: void[]): T;
|
||||
@builtin export declare function instantiate<T>(...args: void[]): T;
|
||||
|
||||
export namespace Atomic {
|
||||
@builtin export declare function load<T>(offset: usize, constantOffset?: usize): T;
|
||||
@builtin export declare function store<T>(offset: usize, value: void, constantOffset?: usize): void;
|
||||
@builtin export declare function add<T>(ptr: usize, value: T, constantOffset?: usize): T;
|
||||
@builtin export declare function sub<T>(ptr: usize, value: T, constantOffset?: usize): T;
|
||||
@builtin export declare function and<T>(ptr: usize, value: T, constantOffset?: usize): T;
|
||||
@builtin export declare function or<T>(ptr: usize, value: T, constantOffset?: usize): T;
|
||||
@builtin export declare function xor<T>(ptr: usize, value: T, constantOffset?: usize): T;
|
||||
@builtin export declare function xchg<T>(ptr: usize, value: T, constantOffset?: usize): T;
|
||||
@builtin export declare function cmpxchg<T>(ptr: usize, expected:T, replacement: T, constantOffset?: usize): T;
|
||||
@builtin export declare function wait<T>(ptr: usize, expected:T, timeout:i64): i32;
|
||||
@builtin export declare function notify<T>(ptr: usize, count: u32): u32;
|
||||
}
|
||||
|
||||
@builtin export declare function i8(value: void): i8;
|
||||
export namespace i8 {
|
||||
export const MIN_VALUE: i8 = -128;
|
||||
@ -73,6 +87,49 @@ export namespace i32 {
|
||||
@builtin export declare function store8(offset: usize, value: i32, constantOffset?: usize): void;
|
||||
@builtin export declare function store16(offset: usize, value: i32, constantOffset?: usize): void;
|
||||
@builtin export declare function store(offset: usize, value: i32, constantOffset?: usize): void;
|
||||
|
||||
namespace atomic {
|
||||
@builtin export declare function load8_s(offset: usize, constantOffset?: usize): i32;
|
||||
@builtin export declare function load8_u(offset: usize, constantOffset?: usize): i32;
|
||||
@builtin export declare function load16_s(offset: usize, constantOffset?: usize): i32;
|
||||
@builtin export declare function load16_u(offset: usize, constantOffset?: usize): i32;
|
||||
@builtin export declare function load(offset: usize, constantOffset?: usize): i32;
|
||||
@builtin export declare function store8(offset: usize, value: i32, constantOffset?: usize): void;
|
||||
@builtin export declare function store16(offset: usize, value: i32, constantOffset?: usize): void;
|
||||
@builtin export declare function store(offset: usize, value: i32, constantOffset?: usize): void;
|
||||
@builtin export declare function wait(ptr: usize, expected:i32, timeout:i64): i32;
|
||||
@builtin export declare function notify(ptr: usize, count:u32): u32;
|
||||
|
||||
namespace rmw8_u {
|
||||
@builtin export declare function add(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function sub(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function and(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function or(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function xor(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function xchg(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function cmpxchg(offset: usize, expected:i32, replacement: i32, constantOffset?: usize): i32;
|
||||
}
|
||||
|
||||
namespace rmw16_u {
|
||||
@builtin export declare function add(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function sub(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function and(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function or(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function xor(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function xchg(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function cmpxchg(offset: usize, expected:i32, replacement: i32, constantOffset?: usize): i32;
|
||||
}
|
||||
|
||||
namespace rmw {
|
||||
@builtin export declare function add(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function sub(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function and(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function or(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function xor(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function xchg(offset: usize, value: i32, constantOffset?: usize): i32
|
||||
@builtin export declare function cmpxchg(offset: usize, expected:i32, replacement: i32, constantOffset?: usize): i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@builtin export declare function i64(value: void): i64;
|
||||
@ -96,6 +153,59 @@ export namespace i64 {
|
||||
@builtin export declare function store16(offset: usize, value: i64, constantOffset?: usize): void;
|
||||
@builtin export declare function store32(offset: usize, value: i64, constantOffset?: usize): void;
|
||||
@builtin export declare function store(offset: usize, value: i64, constantOffset?: usize): void;
|
||||
|
||||
namespace atomic {
|
||||
@builtin export declare function load8_s(offset: usize, constantOffset?: usize): i64;
|
||||
@builtin export declare function load8_u(offset: usize, constantOffset?: usize): i64;
|
||||
@builtin export declare function load16_s(offset: usize, constantOffset?: usize): i64;
|
||||
@builtin export declare function load16_u(offset: usize, constantOffset?: usize): i64;
|
||||
@builtin export declare function load(offset: usize, constantOffset?: usize): i64;
|
||||
@builtin export declare function store8(offset: usize, value: i64, constantOffset?: usize): void;
|
||||
@builtin export declare function store16(offset: usize, value: i64, constantOffset?: usize): void;
|
||||
@builtin export declare function store(offset: usize, value: i64, constantOffset?: usize): void;
|
||||
@builtin export declare function wait(ptr: usize, expected:i64, timeout:i64): i32;
|
||||
@builtin export declare function notify(ptr: usize, count:u32): u32;
|
||||
|
||||
namespace rmw8_u {
|
||||
@builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, constantOffset?: usize): i64;
|
||||
}
|
||||
|
||||
namespace rmw16_u {
|
||||
@builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, constantOffset?: usize): i64;
|
||||
}
|
||||
|
||||
namespace rmw32_u {
|
||||
@builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, constantOffset?: usize): i64;
|
||||
}
|
||||
|
||||
namespace rmw {
|
||||
@builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64
|
||||
@builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, constantOffset?: usize): i64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@builtin export declare function isize(value: void): isize;
|
||||
|
Loading…
x
Reference in New Issue
Block a user