| /* | |
| * Copyright 2018 WebAssembly Community Group participants | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| // Abstracts out operations from specific opcodes. | |
| #ifndef wasm_ir_abstract_h | |
| #define wasm_ir_abstract_h | |
| #include <wasm.h> | |
| namespace wasm::Abstract { | |
| enum Op { | |
| // Unary | |
| Abs, | |
| Neg, | |
| Popcnt, | |
| // Binary | |
| Add, | |
| Sub, | |
| Mul, | |
| DivU, | |
| DivS, | |
| RemU, | |
| RemS, | |
| Shl, | |
| ShrU, | |
| ShrS, | |
| RotL, | |
| RotR, | |
| And, | |
| Or, | |
| Xor, | |
| CopySign, | |
| // Relational | |
| EqZ, | |
| Eq, | |
| Ne, | |
| LtS, | |
| LtU, | |
| LeS, | |
| LeU, | |
| GtS, | |
| GtU, | |
| GeS, | |
| GeU | |
| }; | |
| inline bool hasAnyRotateShift(BinaryOp op) { | |
| return op == RotLInt32 || op == RotRInt32 || op == RotLInt64 || | |
| op == RotRInt64; | |
| } | |
| inline bool hasAnyShift(BinaryOp op) { | |
| return hasAnyRotateShift(op) || op == ShlInt32 || op == ShrSInt32 || | |
| op == ShrUInt32 || op == ShlInt64 || op == ShrSInt64 || | |
| op == ShrUInt64; | |
| } | |
| inline bool hasAnyReinterpret(UnaryOp op) { | |
| return op == ReinterpretInt32 || op == ReinterpretInt64 || | |
| op == ReinterpretFloat32 || op == ReinterpretFloat64; | |
| } | |
| // Provide a wasm type and an abstract op and get the concrete one. For example, | |
| // you can provide i32 and Add and receive the specific opcode for a 32-bit | |
| // addition, AddInt32. If the op does not exist, it returns Invalid. | |
| inline UnaryOp getUnary(Type type, Op op) { | |
| switch (type.getBasic()) { | |
| case Type::i32: { | |
| switch (op) { | |
| case EqZ: | |
| return EqZInt32; | |
| case Popcnt: | |
| return PopcntInt32; | |
| default: | |
| return InvalidUnary; | |
| } | |
| break; | |
| } | |
| case Type::i64: { | |
| switch (op) { | |
| case EqZ: | |
| return EqZInt64; | |
| case Popcnt: | |
| return PopcntInt64; | |
| default: | |
| return InvalidUnary; | |
| } | |
| break; | |
| } | |
| case Type::f32: { | |
| switch (op) { | |
| case Abs: | |
| return AbsFloat32; | |
| case Neg: | |
| return NegFloat32; | |
| default: | |
| return InvalidUnary; | |
| } | |
| break; | |
| } | |
| case Type::f64: { | |
| switch (op) { | |
| case Abs: | |
| return AbsFloat64; | |
| case Neg: | |
| return NegFloat64; | |
| default: | |
| return InvalidUnary; | |
| } | |
| break; | |
| } | |
| case Type::v128: | |
| case Type::none: | |
| case Type::unreachable: { | |
| return InvalidUnary; | |
| } | |
| } | |
| WASM_UNREACHABLE("invalid type"); | |
| } | |
| inline BinaryOp getBinary(Type type, Op op) { | |
| switch (type.getBasic()) { | |
| case Type::i32: { | |
| switch (op) { | |
| case Add: | |
| return AddInt32; | |
| case Sub: | |
| return SubInt32; | |
| case Mul: | |
| return MulInt32; | |
| case DivU: | |
| return DivUInt32; | |
| case DivS: | |
| return DivSInt32; | |
| case RemU: | |
| return RemUInt32; | |
| case RemS: | |
| return RemSInt32; | |
| case Shl: | |
| return ShlInt32; | |
| case ShrU: | |
| return ShrUInt32; | |
| case ShrS: | |
| return ShrSInt32; | |
| case RotL: | |
| return RotLInt32; | |
| case RotR: | |
| return RotRInt32; | |
| case And: | |
| return AndInt32; | |
| case Or: | |
| return OrInt32; | |
| case Xor: | |
| return XorInt32; | |
| case Eq: | |
| return EqInt32; | |
| case Ne: | |
| return NeInt32; | |
| case LtS: | |
| return LtSInt32; | |
| case LtU: | |
| return LtUInt32; | |
| case LeS: | |
| return LeSInt32; | |
| case LeU: | |
| return LeUInt32; | |
| case GtS: | |
| return GtSInt32; | |
| case GtU: | |
| return GtUInt32; | |
| case GeS: | |
| return GeSInt32; | |
| case GeU: | |
| return GeUInt32; | |
| default: | |
| return InvalidBinary; | |
| } | |
| break; | |
| } | |
| case Type::i64: { | |
| switch (op) { | |
| case Add: | |
| return AddInt64; | |
| case Sub: | |
| return SubInt64; | |
| case Mul: | |
| return MulInt64; | |
| case DivU: | |
| return DivUInt64; | |
| case DivS: | |
| return DivSInt64; | |
| case RemU: | |
| return RemUInt64; | |
| case RemS: | |
| return RemSInt64; | |
| case Shl: | |
| return ShlInt64; | |
| case ShrU: | |
| return ShrUInt64; | |
| case ShrS: | |
| return ShrSInt64; | |
| case RotL: | |
| return RotLInt64; | |
| case RotR: | |
| return RotRInt64; | |
| case And: | |
| return AndInt64; | |
| case Or: | |
| return OrInt64; | |
| case Xor: | |
| return XorInt64; | |
| case Eq: | |
| return EqInt64; | |
| case Ne: | |
| return NeInt64; | |
| case LtS: | |
| return LtSInt64; | |
| case LtU: | |
| return LtUInt64; | |
| case LeS: | |
| return LeSInt64; | |
| case LeU: | |
| return LeUInt64; | |
| case GtS: | |
| return GtSInt64; | |
| case GtU: | |
| return GtUInt64; | |
| case GeS: | |
| return GeSInt64; | |
| case GeU: | |
| return GeUInt64; | |
| default: | |
| return InvalidBinary; | |
| } | |
| break; | |
| } | |
| case Type::f32: { | |
| switch (op) { | |
| case Add: | |
| return AddFloat32; | |
| case Sub: | |
| return SubFloat32; | |
| case Mul: | |
| return MulFloat32; | |
| case DivU: | |
| return DivFloat32; | |
| case DivS: | |
| return DivFloat32; | |
| case CopySign: | |
| return CopySignFloat32; | |
| case Eq: | |
| return EqFloat32; | |
| case Ne: | |
| return NeFloat32; | |
| default: | |
| return InvalidBinary; | |
| } | |
| break; | |
| } | |
| case Type::f64: { | |
| switch (op) { | |
| case Add: | |
| return AddFloat64; | |
| case Sub: | |
| return SubFloat64; | |
| case Mul: | |
| return MulFloat64; | |
| case DivU: | |
| return DivFloat64; | |
| case DivS: | |
| return DivFloat64; | |
| case CopySign: | |
| return CopySignFloat64; | |
| case Eq: | |
| return EqFloat64; | |
| case Ne: | |
| return NeFloat64; | |
| default: | |
| return InvalidBinary; | |
| } | |
| break; | |
| } | |
| case Type::v128: | |
| case Type::none: | |
| case Type::unreachable: { | |
| return InvalidBinary; | |
| } | |
| } | |
| WASM_UNREACHABLE("invalid type"); | |
| } | |
| // Logical negation, e.g. !(x < 10) == x >= 10 | |
| inline Op negateRelational(Op op) { | |
| switch (op) { | |
| case Eq: | |
| return Ne; | |
| case Ne: | |
| return Eq; | |
| case LtS: | |
| return GeS; | |
| case LtU: | |
| return GeU; | |
| case LeS: | |
| return GtS; | |
| case LeU: | |
| return GtU; | |
| case GtS: | |
| return LeS; | |
| case GtU: | |
| return LeU; | |
| case GeS: | |
| return LtS; | |
| case GeU: | |
| return LtU; | |
| default: | |
| WASM_UNREACHABLE("invalid relational"); | |
| } | |
| } | |
| // Side flipping, e.g. x < 10 flips to 10 > x (while still saying the same | |
| // thing, not negated). | |
| inline Op flipRelational(Op op) { | |
| switch (op) { | |
| case Eq: | |
| return Eq; | |
| case Ne: | |
| return Ne; | |
| case LtS: | |
| return GtS; | |
| case LtU: | |
| return GtU; | |
| case LeS: | |
| return GeS; | |
| case LeU: | |
| return GeU; | |
| case GtS: | |
| return LtS; | |
| case GtU: | |
| return LtU; | |
| case GeS: | |
| return LeS; | |
| case GeU: | |
| return LeU; | |
| default: | |
| WASM_UNREACHABLE("invalid relational"); | |
| } | |
| } | |
| inline bool isRelationalSymmetric(Op op) { return op == Eq || op == Ne; } | |
| inline bool isRelationalAntisymmetric(Op op) { | |
| switch (op) { | |
| case LtS: | |
| case LtU: | |
| case LeS: | |
| case LeU: | |
| case GtS: | |
| case GtU: | |
| case GeS: | |
| case GeU: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| std::ostream& operator<<(std::ostream& o, Op op); | |
| } // namespace wasm::Abstract | |
| #endif // wasm_ir_abstract_h |