mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-11 05:51:38 +00:00
Add atomic built-ins (#440)
This commit is contained in:
committed by
Daniel Wirtz
parent
41a89fa773
commit
7ce3296b5e
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ docs/
|
|||||||
node_modules/
|
node_modules/
|
||||||
out/
|
out/
|
||||||
raw/
|
raw/
|
||||||
|
.history
|
||||||
|
506
src/builtins.ts
506
src/builtins.ts
@ -40,7 +40,8 @@ import {
|
|||||||
getExpressionType,
|
getExpressionType,
|
||||||
getConstValueI64High,
|
getConstValueI64High,
|
||||||
getConstValueI64Low,
|
getConstValueI64Low,
|
||||||
getConstValueI32
|
getConstValueI32,
|
||||||
|
AtomicRMWOp
|
||||||
} from "./module";
|
} from "./module";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -51,7 +52,8 @@ import {
|
|||||||
OperatorKind,
|
OperatorKind,
|
||||||
FlowFlags,
|
FlowFlags,
|
||||||
Global,
|
Global,
|
||||||
DecoratorFlags
|
DecoratorFlags,
|
||||||
|
Element
|
||||||
} from "./program";
|
} from "./program";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -1676,6 +1678,416 @@ export function compileCall(
|
|||||||
compiler.currentType = Type.void;
|
compiler.currentType = Type.void;
|
||||||
return module.createStore(typeArguments[0].byteSize, arg0, arg1, type.toNativeType(), offset);
|
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
|
case "sizeof": { // sizeof<T!>() -> usize
|
||||||
compiler.currentType = compiler.options.usizeType;
|
compiler.currentType = compiler.options.usizeType;
|
||||||
if (operands.length != 0) {
|
if (operands.length != 0) {
|
||||||
@ -2851,6 +3263,83 @@ function deferASMCall(
|
|||||||
case "i64.store": return deferASM("store", compiler, Type.i64, operands, Type.i64, reportNode);
|
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 "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 "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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2864,7 +3353,18 @@ function deferASM(
|
|||||||
valueType: Type,
|
valueType: Type,
|
||||||
reportNode: Node
|
reportNode: Node
|
||||||
): ExpressionRef {
|
): 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);
|
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||||
return compileCall(compiler, <FunctionPrototype>prototype, [ typeArgument ], operands, valueType, reportNode);
|
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 call_indirect<T>(target: void, ...args: void[]): T;
|
||||||
@builtin export declare function instantiate<T>(...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;
|
@builtin export declare function i8(value: void): i8;
|
||||||
export namespace i8 {
|
export namespace i8 {
|
||||||
export const MIN_VALUE: i8 = -128;
|
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 store8(offset: usize, value: i32, constantOffset?: usize): void;
|
||||||
@builtin export declare function store16(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 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;
|
@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 store16(offset: usize, value: i64, constantOffset?: usize): void;
|
||||||
@builtin export declare function store32(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;
|
@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;
|
@builtin export declare function isize(value: void): isize;
|
||||||
|
Reference in New Issue
Block a user