Skip to content

Commit 2a3cb44

Browse files
committed
fix
1 parent 4301eae commit 2a3cb44

File tree

2 files changed

+91
-2
lines changed

2 files changed

+91
-2
lines changed

src/passes/InstrumentBranchHints.cpp

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
//
9797

9898
#include "ir/drop.h"
99+
#include "ir/effects.h"
99100
#include "ir/eh-utils.h"
100101
#include "ir/find_all.h"
101102
#include "ir/local-graph.h"
@@ -272,6 +273,8 @@ struct InstrumentationProcessor : public WalkerPass<PostWalker<Sub>> {
272273
// The condition before the instrumentation (a pointer to it, so we can
273274
// replace it).
274275
Expression** originalCondition;
276+
// The local that the original condition is stored in temporarily.
277+
Index tempLocal;
275278
// The call to the logging that the instrumentation added.
276279
Call* call;
277280
};
@@ -330,7 +333,7 @@ struct InstrumentationProcessor : public WalkerPass<PostWalker<Sub>> {
330333
return {};
331334
}
332335
// Great, this is indeed a prior instrumentation.
333-
return Instrumentation{&set->value, call};
336+
return Instrumentation{&set->value, set->index, call};
334337
}
335338
};
336339

@@ -374,7 +377,24 @@ struct DeInstrumentBranchHints
374377
// IR, and the original condition is still used in another place, until
375378
// we remove the logging calls; since we will remove the calls anyhow, we
376379
// just need some valid IR there).
377-
std::swap(curr->condition, *info->originalCondition);
380+
//
381+
// Check for dangerous effects in the condition we are about to replace,
382+
// to avoid a situation where the condition looks like this:
383+
//
384+
// (set $temp (original condition))
385+
// ..effects..
386+
// (local.get $temp)
387+
//
388+
// We cannot replace all this with the original condition, as it would
389+
// remove the effects.
390+
EffectAnalyzer effects(getPassOptions(), *getModule(), curr->condition);
391+
// The only condition we allow is a write to the temp local from the
392+
// instrumentation, which getInstrumentation() verified has no other uses
393+
// than us.
394+
effects.localsWritten.erase(info->tempLocal);
395+
if (!effects.hasUnremovableSideEffects()) {
396+
std::swap(curr->condition, *info->originalCondition);
397+
}
378398
}
379399
}
380400

@@ -403,6 +423,20 @@ struct DeInstrumentBranchHints
403423
}
404424
}
405425
}
426+
427+
void doWalkModule(Module* module) {
428+
auto logBranchImport = getLogBranchImport(module);
429+
if (!logBranchImport) {
430+
Fatal()
431+
<< "No branch hint logging import found. Was this code instrumented?";
432+
}
433+
434+
// Mark the log-branch import as having no side effects - we are removing it
435+
// entirely here, and its effect should not stop us when we compute effects.
436+
module->getFunction(logBranchImport)->effects = std::make_shared<EffectAnalyzer>(getPassOptions(), *module);
437+
438+
InstrumentationProcessor<DeInstrumentBranchHints>::doWalkModule(module);
439+
}
406440
};
407441

408442
} // anonymous namespace

test/lit/passes/deinstrument-branch-hints.wast

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
;; CHECK: (type $1 (func (param i32 i32 i32)))
99

10+
;; CHECK: (type $2 (func (result i32)))
11+
1012
;; CHECK: (import "fuzzing-support" "log-branch" (func $log (type $1) (param i32 i32 i32)))
1113
(import "fuzzing-support" "log-branch" (func $log (param i32 i32 i32)))
1214

@@ -164,4 +166,57 @@
164166
)
165167
)
166168
)
169+
170+
;; CHECK: (func $if-unreachable (type $2) (result i32)
171+
;; CHECK-NEXT: (local $0 i32)
172+
;; CHECK-NEXT: (block $block (result i32)
173+
;; CHECK-NEXT: (br_if $block
174+
;; CHECK-NEXT: (i32.const 0)
175+
;; CHECK-NEXT: (block (result i32)
176+
;; CHECK-NEXT: (block
177+
;; CHECK-NEXT: (local.set $0
178+
;; CHECK-NEXT: (i32.const 42)
179+
;; CHECK-NEXT: )
180+
;; CHECK-NEXT: (if
181+
;; CHECK-NEXT: (i32.const 1)
182+
;; CHECK-NEXT: (then
183+
;; CHECK-NEXT: (unreachable)
184+
;; CHECK-NEXT: )
185+
;; CHECK-NEXT: )
186+
;; CHECK-NEXT: )
187+
;; CHECK-NEXT: (nop)
188+
;; CHECK-NEXT: (local.get $0)
189+
;; CHECK-NEXT: )
190+
;; CHECK-NEXT: )
191+
;; CHECK-NEXT: )
192+
;; CHECK-NEXT: )
193+
(func $if-unreachable (result i32)
194+
(local $0 i32)
195+
;; The unreachable here must be executed. Normally we replace the br_if's
196+
;; entire condition, but here we only remove the call to $log.
197+
(block $block (result i32)
198+
(br_if $block
199+
(i32.const 0)
200+
(block (result i32)
201+
(block
202+
(local.set $0
203+
(i32.const 42)
204+
)
205+
(if
206+
(i32.const 1)
207+
(then
208+
(unreachable)
209+
)
210+
)
211+
)
212+
(call $log
213+
(i32.const 0)
214+
(i32.const 0)
215+
(local.get $0)
216+
)
217+
(local.get $0)
218+
)
219+
)
220+
)
221+
)
167222
)

0 commit comments

Comments
 (0)