@@ -232,6 +232,20 @@ class ExpressionParser {
232232 parseConstInst (OpBuilder &builder,
233233 std::enable_if_t <std::is_arithmetic_v<valueT>> * = nullptr );
234234
235+ // / Construct an operation with \p numOperands operands and a single result.
236+ // / Each operand must have the same type. Suitable for e.g. binops, unary
237+ // / ops, etc.
238+ // /
239+ // / \p opcode - The WASM opcode to build.
240+ // / \p valueType - The operand and result type for the built instruction.
241+ // / \p numOperands - The number of operands for the built operation.
242+ // /
243+ // / \returns The parsed instruction result, or failure.
244+ template <typename opcode, typename valueType, unsigned int numOperands>
245+ inline parsed_inst_t
246+ buildNumericOp (OpBuilder &builder,
247+ std::enable_if_t <std::is_arithmetic_v<valueType>> * = nullptr );
248+
235249 // / This function generates a dispatch tree to associate an opcode with a
236250 // / parser. Parsers are registered by specialising the
237251 // / `parseSpecificInstruction` function for the op code to handle.
@@ -863,6 +877,95 @@ inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
863877 return parseConstInst<double >(builder);
864878}
865879
880+ template <typename opcode, typename valueType, unsigned int numOperands>
881+ inline parsed_inst_t ExpressionParser::buildNumericOp (
882+ OpBuilder &builder, std::enable_if_t <std::is_arithmetic_v<valueType>> *) {
883+ auto ty = buildLiteralType<valueType>(builder);
884+ LLVM_DEBUG (llvm::dbgs () << " *** buildNumericOp: numOperands = " << numOperands
885+ << " , type = " << ty << " ***\n " );
886+ auto tysToPop = llvm::SmallVector<Type, numOperands>();
887+ tysToPop.resize (numOperands);
888+ std::fill (tysToPop.begin (), tysToPop.end (), ty);
889+ auto operands = popOperands (tysToPop);
890+ if (failed (operands))
891+ return failure ();
892+ auto op = builder.create <opcode>(*currentOpLoc, *operands).getResult ();
893+ LLVM_DEBUG (llvm::dbgs () << " Built: " );
894+ LLVM_DEBUG (op.dump ());
895+ return {{op}};
896+ }
897+
898+ // Convenience macro for generating numerical operations.
899+ #define BUILD_NUMERIC_OP (OP_NAME, N_ARGS, PREFIX, SUFFIX, TYPE ) \
900+ template <> \
901+ inline parsed_inst_t ExpressionParser::parseSpecificInstruction< \
902+ WasmBinaryEncoding::OpCode::PREFIX##SUFFIX>(OpBuilder & builder) { \
903+ return buildNumericOp<OP_NAME, TYPE, N_ARGS>(builder); \
904+ }
905+
906+ // Macro to define binops that only support integer types.
907+ #define BUILD_NUMERIC_BINOP_INT (OP_NAME, PREFIX ) \
908+ BUILD_NUMERIC_OP (OP_NAME, 2 , PREFIX, I32, int32_t ) \
909+ BUILD_NUMERIC_OP (OP_NAME, 2 , PREFIX, I64, int64_t )
910+
911+ // Macro to define binops that only support floating point types.
912+ #define BUILD_NUMERIC_BINOP_FP (OP_NAME, PREFIX ) \
913+ BUILD_NUMERIC_OP (OP_NAME, 2 , PREFIX, F32, float ) \
914+ BUILD_NUMERIC_OP (OP_NAME, 2 , PREFIX, F64, double )
915+
916+ // Macro to define binops that support both floating point and integer types.
917+ #define BUILD_NUMERIC_BINOP_INTFP (OP_NAME, PREFIX ) \
918+ BUILD_NUMERIC_BINOP_INT (OP_NAME, PREFIX) \
919+ BUILD_NUMERIC_BINOP_FP (OP_NAME, PREFIX)
920+
921+ // Macro to implement unary ops that only support integers.
922+ #define BUILD_NUMERIC_UNARY_OP_INT (OP_NAME, PREFIX ) \
923+ BUILD_NUMERIC_OP (OP_NAME, 1 , PREFIX, I32, int32_t ) \
924+ BUILD_NUMERIC_OP (OP_NAME, 1 , PREFIX, I64, int64_t )
925+
926+ // Macro to implement unary ops that support integer and floating point types.
927+ #define BUILD_NUMERIC_UNARY_OP_FP (OP_NAME, PREFIX ) \
928+ BUILD_NUMERIC_OP (OP_NAME, 1 , PREFIX, F32, float ) \
929+ BUILD_NUMERIC_OP (OP_NAME, 1 , PREFIX, F64, double )
930+
931+ BUILD_NUMERIC_BINOP_FP (CopySignOp, copysign)
932+ BUILD_NUMERIC_BINOP_FP (DivOp, div)
933+ BUILD_NUMERIC_BINOP_FP (MaxOp, max)
934+ BUILD_NUMERIC_BINOP_FP (MinOp, min)
935+ BUILD_NUMERIC_BINOP_INT (AndOp, and )
936+ BUILD_NUMERIC_BINOP_INT (DivSIOp, divS)
937+ BUILD_NUMERIC_BINOP_INT (DivUIOp, divU)
938+ BUILD_NUMERIC_BINOP_INT (OrOp, or )
939+ BUILD_NUMERIC_BINOP_INT (RemSIOp, remS)
940+ BUILD_NUMERIC_BINOP_INT (RemUIOp, remU)
941+ BUILD_NUMERIC_BINOP_INT (RotlOp, rotl)
942+ BUILD_NUMERIC_BINOP_INT (RotrOp, rotr)
943+ BUILD_NUMERIC_BINOP_INT (ShLOp, shl)
944+ BUILD_NUMERIC_BINOP_INT (ShRSOp, shrS)
945+ BUILD_NUMERIC_BINOP_INT (ShRUOp, shrU)
946+ BUILD_NUMERIC_BINOP_INT (XOrOp, xor )
947+ BUILD_NUMERIC_BINOP_INTFP (AddOp, add)
948+ BUILD_NUMERIC_BINOP_INTFP (MulOp, mul)
949+ BUILD_NUMERIC_BINOP_INTFP (SubOp, sub)
950+ BUILD_NUMERIC_UNARY_OP_FP (AbsOp, abs)
951+ BUILD_NUMERIC_UNARY_OP_FP (CeilOp, ceil)
952+ BUILD_NUMERIC_UNARY_OP_FP (FloorOp, floor)
953+ BUILD_NUMERIC_UNARY_OP_FP (NegOp, neg)
954+ BUILD_NUMERIC_UNARY_OP_FP (SqrtOp, sqrt)
955+ BUILD_NUMERIC_UNARY_OP_FP (TruncOp, trunc)
956+ BUILD_NUMERIC_UNARY_OP_INT (ClzOp, clz)
957+ BUILD_NUMERIC_UNARY_OP_INT (CtzOp, ctz)
958+ BUILD_NUMERIC_UNARY_OP_INT (PopCntOp, popcnt)
959+
960+ // Don't need these anymore so let's undef them.
961+ #undef BUILD_NUMERIC_BINOP_FP
962+ #undef BUILD_NUMERIC_BINOP_INT
963+ #undef BUILD_NUMERIC_BINOP_INTFP
964+ #undef BUILD_NUMERIC_UNARY_OP_FP
965+ #undef BUILD_NUMERIC_UNARY_OP_INT
966+ #undef BUILD_NUMERIC_OP
967+ #undef BUILD_NUMERIC_CAST_OP
968+
866969class WasmBinaryParser {
867970private:
868971 struct SectionRegistry {
0 commit comments