summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2023-10-17 09:31:14 -0700
committerGitHub <noreply@github.com>2023-10-17 09:31:14 -0700
commitb816ac563de6b1c53087796335fce593a96f569a (patch)
treea1369d4c609e6b2f6a0c0ca3dfa14bb43bc93445 /src
parentede148eaa505d3681abd67b0b4d7de1b82ec05ff (diff)
downloadbinaryen-b816ac563de6b1c53087796335fce593a96f569a.tar.gz
binaryen-b816ac563de6b1c53087796335fce593a96f569a.tar.bz2
binaryen-b816ac563de6b1c53087796335fce593a96f569a.zip
Fuzzer: Move logic for adding a new local on demand to local.get (#6008)
Previously makeTrappingRefUse would add a local on demand if one was missing for the type, and add a tee for it. This PR moves that logic to makeLocalGet so that we get those benefits any time we want to emit a local.get of a local type that does not exist (including from makeTrappingRefUse which calls makeLocalGet).
Diffstat (limited to 'src')
-rw-r--r--src/tools/fuzzing/fuzzing.cpp51
1 files changed, 36 insertions, 15 deletions
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index 2e7755848..2e4d460f7 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -1622,10 +1622,38 @@ Expression* TranslateToFuzzReader::makeCallRef(Type type) {
Expression* TranslateToFuzzReader::makeLocalGet(Type type) {
auto& locals = funcContext->typeLocals[type];
- if (locals.empty()) {
+ if (!locals.empty()) {
+ return builder.makeLocalGet(pick(locals), type);
+ }
+ // No existing local. When we want something trivial, just give up and emit a
+ // constant.
+ if (trivialNesting) {
return makeConst(type);
}
- return builder.makeLocalGet(pick(locals), type);
+
+ // Otherwise, we have 3 cases: a const, as above (we do this randomly some of
+ // the time), or emit a local.get of a new local, or emit a local.tee of a new
+ // local.
+ auto choice = upTo(3);
+ if (choice == 0) {
+ return makeConst(type);
+ }
+ // Otherwise, add a new local. If the type is not non-nullable then we may
+ // just emit a get for it (which, as this is a brand-new local, will read the
+ // default value, unless we are in a loop; for that reason for a non-
+ // nullable local we prefer a tee later down.).
+ auto index = builder.addVar(funcContext->func, type);
+ LocalSet* tee = nullptr;
+ if (choice == 1 || type.isNonNullable()) {
+ // Create the tee here before adding the local to typeLocals (or else we
+ // might end up using it prematurely inside the make() call).
+ tee = builder.makeLocalTee(index, make(type), type);
+ }
+ funcContext->typeLocals[type].push_back(index);
+ if (tee) {
+ return tee;
+ }
+ return builder.makeLocalGet(index, type);
}
Expression* TranslateToFuzzReader::makeLocalSet(Type type) {
@@ -2475,8 +2503,8 @@ Expression* TranslateToFuzzReader::makeTrappingRefUse(HeapType type) {
if (percent < 70 || !funcContext) {
return make(nonNull);
}
- // With significant probability, try to use an existing value. it is better to
- // have patterns like this:
+ // With significant probability, try to use an existing value, that is, to
+ // get a value using local.get, as it is better to have patterns like this:
//
// (local.set $ref (struct.new $..
// (struct.get (local.get $ref))
@@ -2488,17 +2516,10 @@ Expression* TranslateToFuzzReader::makeTrappingRefUse(HeapType type) {
//
// By using local values more, we get more coverage of interesting sequences
// of reads and writes to the same objects.
- auto& typeLocals = funcContext->typeLocals[nonNull];
- if (!typeLocals.empty()) {
- return builder.makeLocalGet(pick(typeLocals), nonNull);
- }
- // Add a new local and tee it, so later operations can use it.
- auto index = builder.addVar(funcContext->func, nonNull);
- // Note we must create the child ref here before adding the local to
- // typeLocals (or else we might end up using it prematurely).
- auto* tee = builder.makeLocalTee(index, make(nonNull), nonNull);
- funcContext->typeLocals[nonNull].push_back(index);
- return tee;
+ //
+ // Note that makeLocalGet will add a local if necessary, and even tee that
+ // value so it is usable later as well.
+ return makeLocalGet(nonNull);
}
Expression* TranslateToFuzzReader::buildUnary(const UnaryArgs& args) {