diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index 727b4688980020..5550d219719519 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -748,6 +748,9 @@ class CodeGen final : public CodeGenInterface #endif void genCodeForTreeNode(GenTree* treeNode); void genCodeForBinary(GenTreeOp* treeNode); +#ifdef TARGET_WASM + void genCodeForShiftOrRotate(GenTreeOp* treeNode); +#endif bool genIsSameLocalVar(GenTree* tree1, GenTree* tree2); #if defined(TARGET_X86) diff --git a/src/coreclr/jit/codegenwasm.cpp b/src/coreclr/jit/codegenwasm.cpp index 1ed20a7634379c..84bfb2eb99199b 100644 --- a/src/coreclr/jit/codegenwasm.cpp +++ b/src/coreclr/jit/codegenwasm.cpp @@ -80,9 +80,26 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) switch (treeNode->OperGet()) { case GT_ADD: + case GT_SUB: + case GT_MUL: + case GT_DIV: + case GT_MOD: + case GT_UDIV: + case GT_UMOD: + case GT_OR: + case GT_XOR: + case GT_AND: genCodeForBinary(treeNode->AsOp()); break; + case GT_LSH: + case GT_RSH: + case GT_RSZ: + case GT_ROL: + case GT_ROR: + genCodeForShiftOrRotate(treeNode->AsOp()); + break; + case GT_LCL_VAR: genCodeForLclVar(treeNode->AsLclVar()); break; @@ -153,9 +170,13 @@ void CodeGen::genCodeForBinary(GenTreeOp* treeNode) switch (PackOperAndType(treeNode)) { case PackOperAndType(GT_ADD, TYP_INT): + if (treeNode->gtOverflow()) + NYI_WASM("Overflow checks"); ins = INS_i32_add; break; case PackOperAndType(GT_ADD, TYP_LONG): + if (treeNode->gtOverflow()) + NYI_WASM("Overflow checks"); ins = INS_i64_add; break; case PackOperAndType(GT_ADD, TYP_FLOAT): @@ -164,6 +185,96 @@ void CodeGen::genCodeForBinary(GenTreeOp* treeNode) case PackOperAndType(GT_ADD, TYP_DOUBLE): ins = INS_f64_add; break; + + case PackOperAndType(GT_SUB, TYP_INT): + if (treeNode->gtOverflow()) + NYI_WASM("Overflow checks"); + ins = INS_i32_sub; + break; + case PackOperAndType(GT_SUB, TYP_LONG): + if (treeNode->gtOverflow()) + NYI_WASM("Overflow checks"); + ins = INS_i64_sub; + break; + case PackOperAndType(GT_SUB, TYP_FLOAT): + ins = INS_f32_sub; + break; + case PackOperAndType(GT_SUB, TYP_DOUBLE): + ins = INS_f64_sub; + break; + + case PackOperAndType(GT_MUL, TYP_INT): + if (treeNode->gtOverflow()) + NYI_WASM("Overflow checks"); + ins = INS_i32_mul; + break; + case PackOperAndType(GT_MUL, TYP_LONG): + if (treeNode->gtOverflow()) + NYI_WASM("Overflow checks"); + ins = INS_i64_mul; + break; + case PackOperAndType(GT_MUL, TYP_FLOAT): + ins = INS_f32_mul; + break; + case PackOperAndType(GT_MUL, TYP_DOUBLE): + ins = INS_f64_mul; + break; + + case PackOperAndType(GT_DIV, TYP_INT): + ins = INS_i32_div_s; + break; + case PackOperAndType(GT_DIV, TYP_LONG): + ins = INS_i64_div_s; + break; + case PackOperAndType(GT_DIV, TYP_FLOAT): + ins = INS_f32_div; + break; + case PackOperAndType(GT_DIV, TYP_DOUBLE): + ins = INS_f64_div; + break; + + case PackOperAndType(GT_UDIV, TYP_INT): + ins = INS_i32_div_u; + break; + case PackOperAndType(GT_UDIV, TYP_LONG): + ins = INS_i64_div_u; + break; + + case PackOperAndType(GT_MOD, TYP_INT): + ins = INS_i32_rem_s; + break; + case PackOperAndType(GT_MOD, TYP_LONG): + ins = INS_i64_rem_s; + break; + + case PackOperAndType(GT_UMOD, TYP_INT): + ins = INS_i32_rem_u; + break; + case PackOperAndType(GT_UMOD, TYP_LONG): + ins = INS_i64_rem_u; + break; + + case PackOperAndType(GT_AND, TYP_INT): + ins = INS_i32_and; + break; + case PackOperAndType(GT_AND, TYP_LONG): + ins = INS_i64_and; + break; + + case PackOperAndType(GT_OR, TYP_INT): + ins = INS_i32_or; + break; + case PackOperAndType(GT_OR, TYP_LONG): + ins = INS_i64_or; + break; + + case PackOperAndType(GT_XOR, TYP_INT): + ins = INS_i32_xor; + break; + case PackOperAndType(GT_XOR, TYP_LONG): + ins = INS_i64_xor; + break; + default: ins = INS_none; NYI_WASM("genCodeForBinary"); @@ -174,6 +285,68 @@ void CodeGen::genCodeForBinary(GenTreeOp* treeNode) genProduceReg(treeNode); } +//------------------------------------------------------------------------ +// genCodeForShiftOrRotate: Generate code for a shift or rotate operator +// +// Arguments: +// treeNode - The shift or rotate operation for which we are generating code. +// +void CodeGen::genCodeForShiftOrRotate(GenTreeOp* treeNode) +{ + genConsumeOperands(treeNode); + + // TODO-WASM: Zero-extend the 2nd operand for shifts and rotates as needed when the 1st and 2nd operand are + // different types. The shift operand width in IR is always TYP_INT; the WASM operations have the same widths + // for both the shift and shiftee. So the shift may need to be extended (zero-extended) for TYP_LONG. + + instruction ins; + switch (PackOperAndType(treeNode)) + { + case PackOperAndType(GT_LSH, TYP_INT): + ins = INS_i32_shl; + break; + case PackOperAndType(GT_LSH, TYP_LONG): + ins = INS_i64_shl; + break; + + case PackOperAndType(GT_RSH, TYP_INT): + ins = INS_i32_shr_s; + break; + case PackOperAndType(GT_RSH, TYP_LONG): + ins = INS_i64_shr_s; + break; + + case PackOperAndType(GT_RSZ, TYP_INT): + ins = INS_i32_shr_u; + break; + case PackOperAndType(GT_RSZ, TYP_LONG): + ins = INS_i64_shr_u; + break; + + case PackOperAndType(GT_ROL, TYP_INT): + ins = INS_i32_rotl; + break; + case PackOperAndType(GT_ROL, TYP_LONG): + ins = INS_i64_rotl; + break; + + case PackOperAndType(GT_ROR, TYP_INT): + ins = INS_i32_rotr; + break; + case PackOperAndType(GT_ROR, TYP_LONG): + ins = INS_i64_rotr; + break; + + default: + ins = INS_none; + NYI_WASM("genCodeForShiftOrRotate"); + break; + } + + GetEmitter()->emitIns(ins); + genProduceReg(treeNode); +} + //------------------------------------------------------------------------ // genCodeForLclVar: Produce code for a GT_LCL_VAR node. //