Skip to content
Merged
Changes from 1 commit
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
Next Next commit
start
  • Loading branch information
kripken committed Feb 15, 2024
commit aefdf037466f36d5fade8a00bcde9b226ac8c783
42 changes: 41 additions & 1 deletion src/passes/DeNaN.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ struct DeNaN : public WalkerPass<
// Adds calls.
bool addsEffects() override { return true; }

Name deNan32, deNan64;
Name deNan32, deNan64, deNan128;

void visitExpression(Expression* expr) {
// If the expression returns a floating-point value, ensure it is not a
Expand Down Expand Up @@ -67,6 +67,9 @@ struct DeNaN : public WalkerPass<
} else {
replacement = builder.makeCall(deNan64, {expr}, Type::f64);
}
} else if (expr->type == Type::v128) {
// Assume anything can be a nan TODO: optimize
replacement = builder.makeCall(deNan128, {expr}, Type::v128);
}
if (replacement) {
// We can't do this outside of a function, like in a global initializer,
Expand Down Expand Up @@ -98,6 +101,11 @@ struct DeNaN : public WalkerPass<
i,
builder.makeCall(
deNan64, {builder.makeLocalGet(i, Type::f64)}, Type::f64)));
} else if (func->getLocalType(i) == Type::v128) {
fixes.push_back(builder.makeLocalSet(
i,
builder.makeCall(
deNan128, {builder.makeLocalGet(i, Type::v128)}, Type::v128)));
}
}
if (!fixes.empty()) {
Expand All @@ -115,6 +123,7 @@ struct DeNaN : public WalkerPass<
// Pick names for the helper functions.
deNan32 = Names::getValidFunctionName(*module, "deNan32");
deNan64 = Names::getValidFunctionName(*module, "deNan64");
deNan128 = Names::getValidFunctionName(*module, "deNan128");

ControlFlowWalker<DeNaN, UnifiedExpressionVisitor<DeNaN>>::doWalkModule(
module);
Expand Down Expand Up @@ -143,6 +152,37 @@ struct DeNaN : public WalkerPass<
};
add(deNan32, Type::f32, Literal(float(0)), EqFloat32);
add(deNan64, Type::f64, Literal(double(0)), EqFloat64);

// v128 is trickier as the 128 bits may contain f32s or f64s, and we need to
// check for nans both ways.
{
auto func = Builder::makeFunction(deNan128, Signature(Type::v128, Type::v128), {});

// Compare f32s to themselves, giving all 1's where equal and all 0's for
// a nan.
Expression* test32 =
builder.makeBinary(
EqVecF32x4, builder.makeLocalGet(0, Type::v128), builder.makeLocalGet(0, Type::v128));
// Flip the bits, so that all 1's mean a nan.
test32 = builder.makeUnary(NotVec128, test32);
// Any 1 means we have a nan.
test32 = builder.makeUnary(AnyTrueVec128, test32);

// Ditto for f64.
Expression* test64 =
builder.makeBinary(
EqVecF64x2, builder.makeLocalGet(0, Type::v128), builder.makeLocalGet(0, Type::v128));
test64 = builder.makeUnary(NotVec128, test64);
test64 = builder.makeUnary(AnyTrueVec128, test64);

// If either is a nan, we have a nan situation.
auto* testBoth = builder.makeBinary(OrInt32, test32, test64);

func->body = builder.makeIf(
testBoth,
builder.makeConst(Literal({0, 0, 0, 0})));
module->addFunction(std::move(func));
}
}
};

Expand Down