summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/OptimizeInstructions.cpp2
-rw-r--r--src/passes/Print.cpp5
-rw-r--r--src/wasm-binary.h6
-rw-r--r--src/wasm.h4
-rw-r--r--src/wasm/wasm-binary.cpp11
-rw-r--r--src/wasm/wasm-s-parser.cpp9
-rw-r--r--src/wasm/wasm-validator.cpp13
-rw-r--r--src/wasm/wasm.cpp3
-rw-r--r--test/signext.wast12
-rw-r--r--test/signext.wast.from-wast33
-rw-r--r--test/signext.wast.fromBinary36
-rw-r--r--test/signext.wast.fromBinary.noDebugInfo36
12 files changed, 166 insertions, 4 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index acbf39447..1f2f07110 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -31,6 +31,8 @@
#include <ast/properties.h>
#include <ast/literal-utils.h>
+// TODO: Use the new sign-extension opcodes where appropriate. This needs to be conditionalized on the availability of atomics.
+
namespace wasm {
Name I32_EXPR = "i32.expr",
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 3c538a40e..04b649ff6 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -474,6 +474,11 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
case DemoteFloat64: o << "f32.demote/f64"; break;
case ReinterpretInt32: o << "f32.reinterpret/i32"; break;
case ReinterpretInt64: o << "f64.reinterpret/i64"; break;
+ case ExtendS8Int32: o << "i32.extend8_s"; break;
+ case ExtendS16Int32: o << "i32.extend16_s"; break;
+ case ExtendS8Int64: o << "i64.extend8_s"; break;
+ case ExtendS16Int64: o << "i64.extend16_s"; break;
+ case ExtendS32Int64: o << "i64.extend32_s"; break;
default: abort();
}
incIndent();
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 6df49b162..256cea75c 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -531,6 +531,12 @@ enum ASTNodes {
F32ReinterpretI32 = 0xbe,
F64ReinterpretI64 = 0xbf,
+ I32ExtendS8 = 0xc0,
+ I32ExtendS16 = 0xc1,
+ I64ExtendS8 = 0xc2,
+ I64ExtendS16 = 0xc3,
+ I64ExtendS32 = 0xc4,
+
AtomicPrefix = 0xfe
};
diff --git a/src/wasm.h b/src/wasm.h
index 0cd5b05e8..d2bea45a1 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -98,6 +98,10 @@ enum UnaryOp {
PromoteFloat32, // f32 to f64
DemoteFloat64, // f64 to f32
ReinterpretInt32, ReinterpretInt64, // reinterpret bits to float
+ // The following sign-extention operators go along with wasm atomics support.
+ // Extend signed subword-sized integer. This differs from e.g. ExtendSInt32
+ // because the input integer is in an i64 value insetad of an i32 value.
+ ExtendS8Int32, ExtendS16Int32, ExtendS8Int64, ExtendS16Int64, ExtendS32Int64,
};
enum BinaryOp {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 9c0e5cd37..68fb293e8 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -1048,6 +1048,11 @@ void WasmBinaryWriter::visitUnary(Unary *curr) {
case ReinterpretFloat64: o << int8_t(BinaryConsts::I64ReinterpretF64); break;
case ReinterpretInt32: o << int8_t(BinaryConsts::F32ReinterpretI32); break;
case ReinterpretInt64: o << int8_t(BinaryConsts::F64ReinterpretI64); break;
+ case ExtendS8Int32: o << int8_t(BinaryConsts::I32ExtendS8); break;
+ case ExtendS16Int32: o << int8_t(BinaryConsts::I32ExtendS16); break;
+ case ExtendS8Int64: o << int8_t(BinaryConsts::I64ExtendS8); break;
+ case ExtendS16Int64: o << int8_t(BinaryConsts::I64ExtendS16); break;
+ case ExtendS32Int64: o << int8_t(BinaryConsts::I64ExtendS32); break;
default: abort();
}
if (curr->type == unreachable) {
@@ -2678,6 +2683,12 @@ bool WasmBinaryBuilder::maybeVisitUnary(Expression*& out, uint8_t code) {
case BinaryConsts::F32ReinterpretI32: curr = allocator.alloc<Unary>(); curr->op = ReinterpretInt32; curr->type = f32; break;
case BinaryConsts::F64ReinterpretI64: curr = allocator.alloc<Unary>(); curr->op = ReinterpretInt64; curr->type = f64; break;
+ case BinaryConsts::I32ExtendS8: curr = allocator.alloc<Unary>(); curr->op = ExtendS8Int32; curr->type = i32; break;
+ case BinaryConsts::I32ExtendS16: curr = allocator.alloc<Unary>(); curr->op = ExtendS16Int32; curr->type = i32; break;
+ case BinaryConsts::I64ExtendS8: curr = allocator.alloc<Unary>(); curr->op = ExtendS8Int64; curr->type = i64; break;
+ case BinaryConsts::I64ExtendS16: curr = allocator.alloc<Unary>(); curr->op = ExtendS16Int64; curr->type = i64; break;
+ case BinaryConsts::I64ExtendS32: curr = allocator.alloc<Unary>(); curr->op = ExtendS32Int64; curr->type = i64; break;
+
default: return false;
}
if (debug) std::cerr << "zz node: Unary" << std::endl;
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index fd7c7e7ae..a95b551ea 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -699,7 +699,12 @@ Expression* SExpressionWasmBuilder::makeExpression(Element& s) {
if (op[2] == 0) return makeBinary(s, BINARY_INT_OR_FLOAT(Eq), type);
if (op[2] == 'z') return makeUnary(s, type == i32 ? UnaryOp::EqZInt32 : UnaryOp::EqZInt64, type);
}
- if (op[1] == 'x') return makeUnary(s, op[7] == 'u' ? UnaryOp::ExtendUInt32 : UnaryOp::ExtendSInt32, type);
+ if (op[1] == 'x') {
+ if (op[6] == '8') return makeUnary(s, type == i32 ? UnaryOp::ExtendS8Int32 : UnaryOp::ExtendS8Int64, type);
+ if (op[6] == '1') return makeUnary(s, type == i32 ? UnaryOp::ExtendS16Int32 : UnaryOp::ExtendS16Int64, type);
+ if (op[6] == '3') return makeUnary(s, UnaryOp::ExtendS32Int64, type);
+ return makeUnary(s, op[7] == 'u' ? UnaryOp::ExtendUInt32 : UnaryOp::ExtendSInt32, type);
+ }
abort_on(op);
}
case 'f': {
@@ -920,6 +925,8 @@ Expression* SExpressionWasmBuilder::makeUnary(Element& s, UnaryOp op, WasmType t
break;
}
case ExtendSInt32: case ExtendUInt32:
+ case ExtendS8Int32: case ExtendS16Int32:
+ case ExtendS8Int64: case ExtendS16Int64: case ExtendS32Int64:
case WrapInt64:
case PromoteFloat32:
case DemoteFloat64:
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 8e93b1c38..5534eb7b9 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -430,8 +430,17 @@ void WasmValidator::visitUnary(Unary *curr) {
shouldBeTrue(curr->value->type == i64, curr, "i64.eqz input must be i64");
break;
}
- case ExtendSInt32: shouldBeEqual(curr->value->type, i32, curr, "extend type must be correct"); break;
- case ExtendUInt32: shouldBeEqual(curr->value->type, i32, curr, "extend type must be correct"); break;
+ case ExtendSInt32:
+ case ExtendUInt32:
+ case ExtendS8Int32:
+ case ExtendS16Int32: {
+ shouldBeEqual(curr->value->type, i32, curr, "extend type must be correct"); break;
+ }
+ case ExtendS8Int64:
+ case ExtendS16Int64:
+ case ExtendS32Int64: {
+ shouldBeEqual(curr->value->type, i64, curr, "extend type must be correct"); break;
+ }
case WrapInt64: shouldBeEqual(curr->value->type, i64, curr, "wrap type must be correct"); break;
case TruncSFloat32ToInt32: shouldBeEqual(curr->value->type, f32, curr, "trunc type must be correct"); break;
case TruncSFloat32ToInt64: shouldBeEqual(curr->value->type, f32, curr, "trunc type must be correct"); break;
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index a781e0fa3..6db11cc7d 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -443,7 +443,8 @@ void Unary::finalize() {
case SqrtFloat64: type = value->type; break;
case EqZInt32:
case EqZInt64: type = i32; break;
- case ExtendSInt32: case ExtendUInt32: type = i64; break;
+ case ExtendS8Int32: case ExtendS16Int32: type = i32; break;
+ case ExtendSInt32: case ExtendUInt32: case ExtendS8Int64: case ExtendS16Int64: case ExtendS32Int64: type = i64; break;
case WrapInt64: type = i32; break;
case PromoteFloat32: type = f64; break;
case DemoteFloat64: type = f32; break;
diff --git a/test/signext.wast b/test/signext.wast
new file mode 100644
index 000000000..3370e9b16
--- /dev/null
+++ b/test/signext.wast
@@ -0,0 +1,12 @@
+(module
+ (type $0 (func))
+ (func $signext (type $0)
+ (local $0 i32)
+ (local $1 i64)
+ (drop (i32.extend8_s (get_local $0)))
+ (drop (i32.extend16_s (get_local $0)))
+ (drop (i64.extend8_s (get_local $1)))
+ (drop (i64.extend16_s (get_local $1)))
+ (drop (i64.extend32_s (get_local $1)))
+ )
+)
diff --git a/test/signext.wast.from-wast b/test/signext.wast.from-wast
new file mode 100644
index 000000000..6828723b5
--- /dev/null
+++ b/test/signext.wast.from-wast
@@ -0,0 +1,33 @@
+(module
+ (type $0 (func))
+ (memory $0 0)
+ (func $signext (type $0)
+ (local $0 i32)
+ (local $1 i64)
+ (drop
+ (i32.extend8_s
+ (get_local $0)
+ )
+ )
+ (drop
+ (i32.extend16_s
+ (get_local $0)
+ )
+ )
+ (drop
+ (i64.extend8_s
+ (get_local $1)
+ )
+ )
+ (drop
+ (i64.extend16_s
+ (get_local $1)
+ )
+ )
+ (drop
+ (i64.extend32_s
+ (get_local $1)
+ )
+ )
+ )
+)
diff --git a/test/signext.wast.fromBinary b/test/signext.wast.fromBinary
new file mode 100644
index 000000000..ec9b50aa2
--- /dev/null
+++ b/test/signext.wast.fromBinary
@@ -0,0 +1,36 @@
+(module
+ (type $0 (func))
+ (memory $0 0)
+ (func $signext (type $0)
+ (local $var$0 i32)
+ (local $var$1 i64)
+ (block $label$0
+ (drop
+ (i32.extend8_s
+ (get_local $var$0)
+ )
+ )
+ (drop
+ (i32.extend16_s
+ (get_local $var$0)
+ )
+ )
+ (drop
+ (i64.extend8_s
+ (get_local $var$1)
+ )
+ )
+ (drop
+ (i64.extend16_s
+ (get_local $var$1)
+ )
+ )
+ (drop
+ (i64.extend32_s
+ (get_local $var$1)
+ )
+ )
+ )
+ )
+)
+
diff --git a/test/signext.wast.fromBinary.noDebugInfo b/test/signext.wast.fromBinary.noDebugInfo
new file mode 100644
index 000000000..04ada421c
--- /dev/null
+++ b/test/signext.wast.fromBinary.noDebugInfo
@@ -0,0 +1,36 @@
+(module
+ (type $0 (func))
+ (memory $0 0)
+ (func $0 (type $0)
+ (local $var$0 i32)
+ (local $var$1 i64)
+ (block $label$0
+ (drop
+ (i32.extend8_s
+ (get_local $var$0)
+ )
+ )
+ (drop
+ (i32.extend16_s
+ (get_local $var$0)
+ )
+ )
+ (drop
+ (i64.extend8_s
+ (get_local $var$1)
+ )
+ )
+ (drop
+ (i64.extend16_s
+ (get_local $var$1)
+ )
+ )
+ (drop
+ (i64.extend32_s
+ (get_local $var$1)
+ )
+ )
+ )
+ )
+)
+