This is an archive of the discontinued LLVM Phabricator instance.

[SimplifyCFG] Thread branches on same condition in more cases (PR54980)
ClosedPublic

Authored by nikic on Apr 21 2022, 3:55 AM.

Details

Summary

SimplifyCFG implements basic jump threading, if a branch is performed on a phi node with constant operands. However, InstCombine canonicalizes such phis to the condition value of a previous branch, if possible. SimplifyCFG does support this as well, but only in the very limited case where the same condition is used in a direct predecessor -- notably, this does not include the common diamond pattern (i.e. two consecutive if/elses on the same condition).

This patch extends the code to look back a limited number of blocks to find a branch on the same value, rather than only looking at the direct predecessor.

Fixes https://github.com/llvm/llvm-project/issues/54980.

Diff Detail

Event Timeline

nikic created this revision.Apr 21 2022, 3:55 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 21 2022, 3:55 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
nikic requested review of this revision.Apr 21 2022, 3:55 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 21 2022, 3:55 AM
nikic added inline comments.Apr 21 2022, 3:56 AM
llvm/test/CodeGen/AArch64/arm64-andCmpBrToTBZ.ll
39

There is a branch on %tobool.i.i.i higher up that would get threaded -- as that doesn't seem like the point of the test, I've replaced it with a different condition.

nikic updated this revision to Diff 424179.Apr 21 2022, 6:34 AM

Update some clang tests. Nothing actually changes there, there are only some differences in block order/naming. And it doesn't look like update_cc_test_checks works for these tests :/

fhahn accepted this revision.Apr 28 2022, 5:53 AM

LGTM, thanks!

This revision is now accepted and ready to land.Apr 28 2022, 5:53 AM
This revision was landed with ongoing or failed builds.Apr 29 2022, 12:44 AM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptApr 29 2022, 12:44 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript

HI, the following code get infinite loop after this commit.

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes="simplifycfg<bonus-inst-threshold=1;forward-switch-cond;switch-range-to-icmp;switch-to-lookup;no-keep-loops;hoist-common-insts;sink-common-insts>" -S < %s | FileCheck %s

define void @_Z10alignedboxl(i1 %cmp.a, i1 %cmp.b, i1 %cmp.c) {
; CHECK-LABEL: @_Z10alignedboxl(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    br label [[WHILE_COND:%.*]]
; CHECK:       while.cond:
; CHECK-NEXT:    br i1 [[CMP_A:%.*]], label [[FOR:%.*]], label [[WHILE_BODY_THREAD:%.*]]
; CHECK:       for.body:
; CHECK-NEXT:    br i1 [[CMP_B:%.*]], label [[WHILE_BODY:%.*]], label [[FOR_BODY:%.*]]
; CHECK:       for:
; CHECK-NEXT:    tail call void @XXX()
; CHECK-NEXT:    br label [[FOR_BODY]]
; CHECK:       while.body:
; CHECK-NEXT:    br i1 [[CMP_C:%.*]], label [[C_EXIT:%.*]], label [[LAND:%.*]]
; CHECK:       while.body.thread:
; CHECK-NEXT:    br i1 [[CMP_C]], label [[WHILE_COND]], label [[LAND]]
; CHECK:       land:
; CHECK-NEXT:    tail call void @XXX()
; CHECK-NEXT:    br label [[WHILE_COND]]
; CHECK:       c.exit:
; CHECK-NEXT:    br i1 [[CMP_A]], label [[FOR_D:%.*]], label [[WHILE_BODY_THREAD]]
; CHECK:       for.d:
; CHECK-NEXT:    ret void
;
entry:
  br label %while.cond

while.cond:                                       ; preds = %land, %while.body.thread, %entry
  br i1 %cmp.a, label %for, label %while.body.thread

for.body:                                         ; preds = %for, %for.body
  br i1 %cmp.b, label %while.body, label %for.body

for:                                              ; preds = %while.cond
  tail call void @XXX()
  br label %for.body

while.body:                                       ; preds = %for.body
  br i1 %cmp.c, label %c.exit, label %land

while.body.thread:                                ; preds = %c.exit, %while.cond
  br i1 %cmp.c, label %while.cond, label %land

land:                                             ; preds = %while.body.thread, %while.body
  tail call void @XXX()
  br label %while.cond

c.exit:                                           ; preds = %while.body
  br i1 %cmp.a, label %for.d, label %while.cond

for.d:                                            ; preds = %c.exit
  ret void
}

declare void @XXX()
nikic added a comment.Jul 5 2022, 5:38 AM

@HanKuanChen Thanks for the report! I've landed a fix for this test case in https://github.com/llvm/llvm-project/commit/dc969061c68e62328607d68215ed8b9ef4a1e4b1. This is based on making SimplifyCFG behave more like JumpThreading, which does not have an infinite loop for this case. Let me know if you see further issues.

nikic added a comment.Jul 5 2022, 7:59 AM

I ended up reverting this patch in https://github.com/llvm/llvm-project/commit/a4772cbaf0dc717ab6b4639272ca2910897613f0, because I reduced another infinite loop (https://github.com/llvm/llvm-project/issues/56203) to it as well, which makes it the third one. It's probably not possible to reliably prevent infinite combine loops in this area with a dominator tree.

Should dc969061c68e62328607d68215ed8b9ef4a1e4b1 be reverted as well? I just bisected an assertion failure while building the Linux kernel for arm64 to that change:

clang: /home/nathan/cbl/src/llvm-project/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp:1136: llvm::BasicBlock *SplitBlockPredecessorsImpl(llvm::BasicBlock *, ArrayRef<llvm::BasicBlock *>, const char *, llvm::DomTreeUpdater *, llvm::DominatorTree *, llvm::LoopInfo *, llvm::MemorySSAUpdater *, bool): Assertion `!isa<CallBrInst>(Preds[i]->getTerminator()) && "Cannot split an edge from a CallBrInst"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.      Program arguments: /home/nathan/tmp/build/llvm-bisect/stage1/bin/clang -mlittle-endian -Qunused-arguments -fmacro-prefix-map=/home/nathan/cbl/src/linux/= -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE -Werror=implicit-function-declaration -Werror=implicit-int -Werror=return-type -Wno-format-security -std=gnu11 --target=aarch64-linux-gnu -fintegrated-as -Werror=unknown-warning-option -Werror=ignored-optimization-argument -mgeneral-regs-only -Wno-psabi -fno-asynchronous-unwind-tables -fno-unwind-tables -mbranch-protection=pac-ret+leaf+bti -fno-delete-null-pointer-checks -Wno-frame-address -Wno-address-of-packed-member -O2 -Wframe-larger-than=2048 -fstack-protector-strong -Wimplicit-fallthrough -Wno-gnu -Wno-unused-but-set-variable -Wno-unused-const-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang -fno-stack-clash-protection -Wdeclaration-after-statement -Wvla -Wno-pointer-sign -Wcast-function-type -fno-strict-overflow -fno-stack-check -Werror=date-time -Werror=incompatible-pointer-types -Wno-initializer-overrides -Wno-format -Wno-sign-compare -Wno-format-zero-length -Wno-pointer-to-enum-cast -Wno-tautological-constant-out-of-range-compare -Wno-unaligned-access -mstack-protector-guard=sysreg -mstack-protector-guard-reg=sp_el0 -mstack-protector-guard-offset=1184 -Wa,-march=armv8.5-a -nostdinc -I/home/nathan/cbl/src/linux/arch/arm64/include -I./arch/arm64/include/generated -I/home/nathan/cbl/src/linux/include -I./include -I/home/nathan/cbl/src/linux/arch/arm64/include/uapi -I./arch/arm64/include/generated/uapi -I/home/nathan/cbl/src/linux/include/uapi -I./include/generated/uapi -include /home/nathan/cbl/src/linux/include/linux/compiler-version.h -include /home/nathan/cbl/src/linux/include/linux/kconfig.h -include /home/nathan/cbl/src/linux/include/linux/compiler_types.h -D__KERNEL__ -DKASAN_SHADOW_SCALE_SHIFT= -DCONFIG_CC_HAS_K_CONSTRAINT=1 -DARM64_ASM_ARCH=\"armv8.5-a\" -DKASAN_SHADOW_SCALE_SHIFT= -I /home/nathan/cbl/src/linux/arch/arm64/crypto -I ./arch/arm64/crypto -DKBUILD_MODFILE=\"arch/arm64/crypto/aes-ce-cipher\" -DKBUILD_BASENAME=\"aes_ce_glue\" -DKBUILD_MODNAME=\"aes_ce_cipher\" -D__KBUILD_MODNAME=kmod_aes_ce_cipher -c -Wp,-MMD,arch/arm64/crypto/.aes-ce-glue.o.d -fcolor-diagnostics -o arch/arm64/crypto/aes-ce-glue.o /home/nathan/cbl/src/linux/arch/arm64/crypto/aes-ce-glue.c
1.      <eof> parser at end of file
2.      Optimizer
 #0 0x000055aae2db8b83 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/nathan/tmp/build/llvm-bisect/stage1/bin/clang+0x3e2fb83)
 #1 0x000055aae2db6b1e llvm::sys::RunSignalHandlers() (/home/nathan/tmp/build/llvm-bisect/stage1/bin/clang+0x3e2db1e)
 #2 0x000055aae2d40c13 (anonymous namespace)::CrashRecoveryContextImpl::HandleCrash(int, unsigned long) CrashRecoveryContext.cpp:0:0
 #3 0x000055aae2d40d8e CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
 #4 0x00007fdd27ea18e0 (/usr/lib/libc.so.6+0x3e8e0)
 #5 0x00007fdd27ef136c (/usr/lib/libc.so.6+0x8e36c)
 #6 0x00007fdd27ea1838 gsignal (/usr/lib/libc.so.6+0x3e838)
 #7 0x00007fdd27e8b535 abort (/usr/lib/libc.so.6+0x28535)
 #8 0x00007fdd27e8b45c (/usr/lib/libc.so.6+0x2845c)
 #9 0x00007fdd27e9a366 (/usr/lib/libc.so.6+0x37366)
#10 0x000055aae2dcb9b6 SplitBlockPredecessorsImpl(llvm::BasicBlock*, llvm::ArrayRef<llvm::BasicBlock*>, char const*, llvm::DomTreeUpdater*, llvm::DominatorTree*, llvm::LoopInfo*, llvm::MemorySSAUpdater*, bool) BasicBlockUtils.cpp:0:0
#11 0x000055aae2dcba4c llvm::SplitBlockPredecessors(llvm::BasicBlock*, llvm::ArrayRef<llvm::BasicBlock*>, char const*, llvm::DomTreeUpdater*, llvm::LoopInfo*, llvm::MemorySSAUpdater*, bool) (/home/nathan/tmp/build/llvm-bisect/stage1/bin/clang+0x3e42a4c)
#12 0x000055aae2ef5b01 (anonymous namespace)::SimplifyCFGOpt::simplifyCondBranch(llvm::BranchInst*, llvm::IRBuilder<llvm::ConstantFolder, llvm::IRBuilderDefaultInserter>&) SimplifyCFG.cpp:0:0
#13 0x000055aae2ee2e29 (anonymous namespace)::SimplifyCFGOpt::run(llvm::BasicBlock*) SimplifyCFG.cpp:0:0
#14 0x000055aae2edfe84 llvm::simplifyCFG(llvm::BasicBlock*, llvm::TargetTransformInfo const&, llvm::DomTreeUpdater*, llvm::SimplifyCFGOptions const&, llvm::ArrayRef<llvm::WeakVH>) (/home/nathan/tmp/build/llvm-bisect/stage1/bin/clang+0x3f56e84)
#15 0x000055aae2ce66da iterativelySimplifyCFG(llvm::Function&, llvm::TargetTransformInfo const&, llvm::DomTreeUpdater*, llvm::SimplifyCFGOptions const&) SimplifyCFGPass.cpp:0:0
#16 0x000055aae2ce6127 simplifyFunctionCFGImpl(llvm::Function&, llvm::TargetTransformInfo const&, llvm::DominatorTree*, llvm::SimplifyCFGOptions const&) SimplifyCFGPass.cpp:0:0
#17 0x000055aae2ce4d0d simplifyFunctionCFG(llvm::Function&, llvm::TargetTransformInfo const&, llvm::DominatorTree*, llvm::SimplifyCFGOptions const&) SimplifyCFGPass.cpp:0:0
#18 0x000055aae2ce4a6b llvm::SimplifyCFGPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/nathan/tmp/build/llvm-bisect/stage1/bin/clang+0x3d5ba6b)
#19 0x000055aae3f9d10d llvm::detail::PassModel<llvm::Function, llvm::SimplifyCFGPass, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) PassBuilder.cpp:0:0
#20 0x000055aae268c68d llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/home/nathan/tmp/build/llvm-bisect/stage1/bin/clang+0x370368d)
#21 0x000055aae35ccbbd llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) BackendUtil.cpp:0:0
#22 0x000055aae26ec953 llvm::CGSCCToFunctionPassAdaptor::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) (/home/nathan/tmp/build/llvm-bisect/stage1/bin/clang+0x3763953)
#23 0x000055aae3f9f50d llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::CGSCCToFunctionPassAdaptor, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) PassBuilder.cpp:0:0
#24 0x000055aae26e7067 llvm::PassManager<llvm::LazyCallGraph::SCC, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) (/home/nathan/tmp/build/llvm-bisect/stage1/bin/clang+0x375e067)
#25 0x000055aae2810d7d llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::PassManager<llvm::LazyCallGraph::SCC, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) Inliner.cpp:0:0
#26 0x000055aae26eaae8 llvm::DevirtSCCRepeatedPass::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) (/home/nathan/tmp/build/llvm-bisect/stage1/bin/clang+0x3761ae8)
#27 0x000055aae281155d llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::DevirtSCCRepeatedPass, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) Inliner.cpp:0:0
#28 0x000055aae26e9259 llvm::ModuleToPostOrderCGSCCPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/home/nathan/tmp/build/llvm-bisect/stage1/bin/clang+0x3760259)
...
# bad: [a1cd3f49b68022337c356482c8c4ec36221f4d1b] [RISCV] Use a switch statement in PreprocessISelDAG. NFC
# good: [142aca7741d5b06207e87bf4880fbe308c8d6823] [InstCombine] fold sub of min/max of sub with common operand
git bisect start 'a1cd3f49b68022337c356482c8c4ec36221f4d1b' '142aca7741d5b06207e87bf4880fbe308c8d6823'
# good: [ebb78a95cede526ece9b904e9ba623d4b963df60] [LV] Remove stray dbgs() call after  774fc63490939.
git bisect good ebb78a95cede526ece9b904e9ba623d4b963df60
# bad: [e7a0fa4df00c6386632d1395799c6150f39a3e33] [DAG] foldAddSubOfSignBit - don't bother creating the new shift node unless constant folding succeeds
git bisect bad e7a0fa4df00c6386632d1395799c6150f39a3e33
# bad: [935570b2ad808035a1fd9bf6fa894657babc8694] [ConstExpr] Don't create div/rem expressions
git bisect bad 935570b2ad808035a1fd9bf6fa894657babc8694
# bad: [6e2058e58832058f05372c93e8be50695efcc6be] [Compiler-RT]  Remove FlushViewOfFile call when unmapping gcda files on win32.
git bisect bad 6e2058e58832058f05372c93e8be50695efcc6be
# bad: [8cd79bc12c366de01cedb88e2e2fc026619e64ea] [AMDGPU][GlobalISel] Support register offsets for SMRDs.
git bisect bad 8cd79bc12c366de01cedb88e2e2fc026619e64ea
# bad: [9fbf1107cc763783a82b89953be8a45097ba3390] [pseudo] Eliminate LRTable::Action. NFC
git bisect bad 9fbf1107cc763783a82b89953be8a45097ba3390
# bad: [dc969061c68e62328607d68215ed8b9ef4a1e4b1] [SimplifyCFG] Thread all predecessors with same value at once
git bisect bad dc969061c68e62328607d68215ed8b9ef4a1e4b1
# first bad commit: [dc969061c68e62328607d68215ed8b9ef4a1e4b1] [SimplifyCFG] Thread all predecessors with same value at once

I can reduce something down if necessary.

I ended up reducing something down anyways. At the parent commit of dc969061c68e62328607d68215ed8b9ef4a1e4b1, there is no crash.

_Bool fpsimd_context_busy;
enum { false, true } arch_static_branch_jump() {
  asm goto("" : : : : l_yes);
  return false;
l_yes:
  return true;
}
_Bool __preempt_count_dec_and_test();
void preempt_schedule_notrace();
long __percpu_read_8();
_Bool may_use_simd() {
  return ({ ({ arch_static_branch_jump(); }); }) && ({
           typeof(fpsimd_context_busy) pscr_ret__ = ({
             typeof(fpsimd_context_busy) __retval = __percpu_read_8();
             if (__builtin_expect(__preempt_count_dec_and_test(), 0))
               preempt_schedule_notrace();
             __retval;
           });
           pscr_ret__;
         });
}
void aes_cipher_encrypt() {
  if (may_use_simd())
    preempt_schedule_notrace();
}
$ clang --target=aarch64-linux-gnu -O2 -c -o /dev/null aes-ce-glue.i
clang: /home/nathan/cbl/src/llvm-project/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp:1136: llvm::BasicBlock *SplitBlockPredecessorsImpl(llvm::BasicBlock *, ArrayRef<llvm::BasicBlock *>, const char *, llvm::DomTreeUpdater *, llvm::DominatorTree *, llvm::LoopInfo *, llvm::MemorySSAUpdater *, bool): Assertion `!isa<CallBrInst>(Preds[i]->getTerminator()) && "Cannot split an edge from a CallBrInst"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.      Program arguments: clang --target=aarch64-linux-gnu -O2 -c -o /dev/null aes-ce-glue.i
1.      <eof> parser at end of file
2.      Optimizer
 #0 0x0000aaaad1ad36b8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/nathan/tmp/install/llvm/dc969061c68e62328607d68215ed8b9ef4a1e4b1/bin/clang-15+0x35336b8)
 #1 0x0000aaaad1ad18d8 llvm::sys::RunSignalHandlers() (/home/nathan/tmp/install/llvm/dc969061c68e62328607d68215ed8b9ef4a1e4b1/bin/clang-15+0x35318d8)
 #2 0x0000aaaad1a5e6e4 (anonymous namespace)::CrashRecoveryContextImpl::HandleCrash(int, unsigned long) CrashRecoveryContext.cpp:0:0
 #3 0x0000aaaad1a5e894 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
 #4 0x0000ffffa099e854 (linux-vdso.so.1+0x854)
 #5 0x0000ffffa04b28a8 __pthread_kill_implementation (/lib64/libc.so.6+0x828a8)
 #6 0x0000ffffa046ae40 gsignal (/lib64/libc.so.6+0x3ae40)
 #7 0x0000ffffa04572f8 abort (/lib64/libc.so.6+0x272f8)
 #8 0x0000ffffa0464538 __assert_fail_base (/lib64/libc.so.6+0x34538)
 #9 0x0000ffffa04645a0 __assert_perror_fail (/lib64/libc.so.6+0x345a0)
#10 0x0000aaaad1ae30c0 SplitBlockPredecessorsImpl(llvm::BasicBlock*, llvm::ArrayRef<llvm::BasicBlock*>, char const*, llvm::DomTreeUpdater*, llvm::DominatorTree*, llvm::LoopInfo*, llvm::MemorySSAUpdater*, bool) BasicBlockUtils.cpp:0:0
...
nikic added a comment.Jul 6 2022, 6:46 AM

@nathanchance Thanks for the report. I've applied the obvious fix in https://github.com/llvm/llvm-project/commit/20962c1240691d25b21ce425313c81eed0b1b358. However, I think that this (and similar limitations relating to critical edge splitting) might actually be unnecessary since https://github.com/llvm/llvm-project/commit/7a7bba289521e6d4da199565cf72dc9eaed3d671. callbr has stricter semantics than indirectbr, and apparently updating successors of a callbr is supposed to be possible (because the blockaddresses used by it must be directly used in the call arguments and thus can be updated, while in the indirectbr case they may be passed indirectly).