Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions src/coreclr/jit/codegenwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
genCatchArg(treeNode);
break;

case GT_CKFINITE:
genCkfinite(treeNode);
break;

default:
#ifdef DEBUG
if (JitConfig.JitWasmNyiToR2RUnsupported())
Expand Down Expand Up @@ -1845,6 +1849,70 @@ void CodeGen::genCodeForBitCast(GenTreeOp* tree)
WasmProduceReg(tree);
}

//------------------------------------------------------------------------
// genCkfinite: Generate code for ckfinite opcode.
//
// Arguments:
// treeNode - The GT_CKFINITE node
//
// Notes:
// The operand is expected to be marked MultiplyUsed so that codegen can
// re-use its value (via "local.get") after the check.
//
void CodeGen::genCkfinite(GenTree* treeNode)
{
assert(treeNode->OperIs(GT_CKFINITE));

GenTree* op1 = treeNode->AsOp()->gtOp1;
var_types targetType = treeNode->TypeGet();
assert(varTypeIsFloating(targetType));

// Push the operand value on the wasm stack. Because op1 was flagged as
// MultiplyUsed during lowering, "WasmProduceReg" will tee it into a
// temporary local so we can re-read it for the exponent check.
//
genConsumeOperands(treeNode->AsOp());

// Re-read the operand to feed the finiteness check.
//
regNumber op1Reg = GetMultiUseOperandReg(op1);
emitter* emit = GetEmitter();
Comment on lines +1870 to +1879

// Compute "!(|x| < +Inf)". This is true for NaN and +/-Inf, false for
// every finite value. We rely on wasm's IEEE-754 comparison semantics
// where any comparison involving a NaN (other than "ne") returns 0.
//
// Note: IF_F32/IF_F64 both expect the +Inf constant as a double bit
// pattern (IF_F32 reinterprets and truncates to float during emission).
//
const int64_t infBits = 0x7FF0000000000000LL;
if (targetType == TYP_FLOAT)
{
emit->emitIns_I(INS_local_get, EA_4BYTE, WasmRegToIndex(op1Reg));
emit->emitIns(INS_f32_abs);
emit->emitIns_I(INS_f32_const, EA_4BYTE, infBits);
emit->emitIns(INS_f32_lt);
}
else
{
assert(targetType == TYP_DOUBLE);
emit->emitIns_I(INS_local_get, EA_8BYTE, WasmRegToIndex(op1Reg));
emit->emitIns(INS_f64_abs);
emit->emitIns_I(INS_f64_const, EA_8BYTE, infBits);
emit->emitIns(INS_f64_lt);
}
emit->emitIns(INS_i32_eqz);

// If "!(|x| < +Inf)", the value is NaN or +/-Inf; throw.
//
genJumpToThrowHlpBlk(SCK_ARITH_EXCPN);

// The operand value is still on the wasm stack from genConsumeOperands;
// produce it as the result of the GT_CKFINITE node.
//
WasmProduceReg(treeNode);
Comment on lines +1910 to +1913
}

//------------------------------------------------------------------------
// genCodeForNegNot: Generate code for a neg/not
//
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,10 @@ GenTree* Lowering::LowerNode(GenTree* node)
case GT_INDEX_ADDR:
LowerIndexAddr(node->AsIndexAddr());
break;

case GT_CKFINITE:
LowerCkfinite(node->AsOp());
break;
#endif // defined(TARGET_WASM)

default:
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/lower.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ class Lowering final : public Phase
static void SetMultiplyUsed(GenTree* node DEBUGARG(const char* reason));
GenTree* LowerNeg(GenTreeOp* node);
void LowerIndexAddr(GenTreeIndexAddr* indexAddr);
void LowerCkfinite(GenTreeOp* node);
#endif

bool TryCreateAddrMode(GenTree* addr, bool isContainable, GenTree* parent);
Expand Down
15 changes: 15 additions & 0 deletions src/coreclr/jit/lowerwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,21 @@ void Lowering::LowerRotate(GenTree* tree)
ContainCheckShiftRotate(tree->AsOp());
}

//------------------------------------------------------------------------
// LowerCkfinite: Lowers a GT_CKFINITE node.
//
// Mark the operand as multiply-used since codegen needs to read it twice:
// once for the finiteness check and once for the produced value.
//
// Arguments:
// node - the GT_CKFINITE node to be lowered
//
void Lowering::LowerCkfinite(GenTreeOp* node)
{
assert(node->OperIs(GT_CKFINITE));
SetMultiplyUsed(node->gtGetOp1() DEBUGARG("LowerCkfinite op1 (finiteness check)"));
}

//------------------------------------------------------------------------
// LowerIndexAddr: Lowers a GT_INDEX_ADDR node
//
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/regallocwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,10 @@ void WasmRegAlloc::CollectReferencesForNode(GenTree* node)
CollectReferencesForIndexAddr(node->AsIndexAddr());
break;

case GT_CKFINITE:
ConsumeTemporaryRegForOperand(node->gtGetOp1() DEBUGARG("ckfinite finiteness check"));
break;

default:
assert(!node->OperIsLocalStore());
break;
Expand Down
Loading