diff options
author | Alon Zakai <azakai@google.com> | 2023-10-17 09:31:14 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-17 09:31:14 -0700 |
commit | b816ac563de6b1c53087796335fce593a96f569a (patch) | |
tree | a1369d4c609e6b2f6a0c0ca3dfa14bb43bc93445 /src | |
parent | ede148eaa505d3681abd67b0b4d7de1b82ec05ff (diff) | |
download | binaryen-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.cpp | 51 |
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) { |