summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitaly Buka <vitalybuka@google.com>2019-09-05 22:49:34 +0000
committerVitaly Buka <vitalybuka@google.com>2019-09-05 22:49:34 +0000
commit9020f113770598f2064c1f19730aea5c1db754f6 (patch)
treeba593a68bd80f3f3c433238b2fd4ee0c33b20f98
parentf54daffc2d73866312e6f50b75fe15035e62b4e8 (diff)
downloadbcm5719-llvm-9020f113770598f2064c1f19730aea5c1db754f6.tar.gz
bcm5719-llvm-9020f113770598f2064c1f19730aea5c1db754f6.zip
[SimplifyCFG] Don't SimplifyBranchOnICmpChain with ExtraCase
Summary: Here we try to avoid issues with "explicit branch" with SimplifyBranchOnICmpChain which can check on undef. Msan by design reports branches on uninitialized memory and undefs, so we have false report here. In general msan does not like when we convert ``` // If at least one of them is true we can MSAN is ok if another is undefs if (a || b) return; ``` into ``` // If 'a' is undef MSAN will complain even if 'b' is true if (a) return; if (b) return; ``` Example Before optimization we had something like this: ``` while (true) { bool maybe_undef = doStuff(); while (true) { char c = getChar(); if (c != 10 && c != 13) continue break; } // we know that c == 10 || c == 13 if we get here, // so msan know that branch is not affected by maybe_undef if (maybe_undef || c == 10 || c == 13) continue; return; } ``` SimplifyBranchOnICmpChain will convert that into ``` while (true) { bool maybe_undef = doStuff(); while (true) { char c = getChar(); if (c != 10 && c != 13) continue; break; } // however msan will complain here: if (maybe_undef) continue; // we know that c == 10 || c == 13, so either way we will get continue switch(c) { case 10: continue; case 13: continue; } return; } ``` Reviewers: eugenis, efriedma Reviewed By: eugenis, efriedma Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67205 llvm-svn: 371138
-rw-r--r--llvm/lib/Transforms/Utils/SimplifyCFG.cpp7
-rw-r--r--llvm/test/Transforms/SimplifyCFG/switch_msan.ll102
2 files changed, 108 insertions, 1 deletions
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 3a18b52a4de..bcf52198e94 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -3729,12 +3729,17 @@ static bool SimplifyBranchOnICmpChain(BranchInst *BI, IRBuilder<> &Builder,
BasicBlock *BB = BI->getParent();
+ // MSAN does not like undefs as branch condition which can be introduced
+ // with "explicit branch".
+ if (ExtraCase && BB->getParent()->hasFnAttribute(Attribute::SanitizeMemory))
+ return false;
+
LLVM_DEBUG(dbgs() << "Converting 'icmp' chain with " << Values.size()
<< " cases into SWITCH. BB is:\n"
<< *BB);
// If there are any extra values that couldn't be folded into the switch
- // then we evaluate them with an explicit branch first. Split the block
+ // then we evaluate them with an explicit branch first. Split the block
// right before the condbr to handle it.
if (ExtraCase) {
BasicBlock *NewBB =
diff --git a/llvm/test/Transforms/SimplifyCFG/switch_msan.ll b/llvm/test/Transforms/SimplifyCFG/switch_msan.ll
new file mode 100644
index 00000000000..96e79828977
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/switch_msan.ll
@@ -0,0 +1,102 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -simplifycfg < %s | FileCheck %s
+
+declare i8 @next_char();
+
+define void @test_no_msan() {
+; CHECK-LABEL: @test_no_msan(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
+; CHECK: while.body:
+; CHECK-NEXT: br label [[WHILE_BODY_I:%.*]]
+; CHECK: while.body.i:
+; CHECK-NEXT: [[MAYBE_UNDEF:%.*]] = phi i1 [ undef, [[WHILE_BODY]] ], [ [[NEXT_MAYBE_UNDEF:%.*]], [[WHILE_BODY_I]] ]
+; CHECK-NEXT: [[C:%.*]] = call fastcc signext i8 @next_char()
+; CHECK-NEXT: [[C_10:%.*]] = icmp eq i8 [[C]], 10
+; CHECK-NEXT: [[C_13:%.*]] = icmp eq i8 [[C]], 13
+; CHECK-NEXT: [[C_10_OR_13:%.*]] = or i1 [[C_10]], [[C_13]]
+; CHECK-NEXT: [[NEXT_MAYBE_UNDEF]] = or i1 [[MAYBE_UNDEF]], [[C_10_OR_13]]
+; CHECK-NEXT: [[C_NOT_10_OR_13:%.*]] = xor i1 [[C_10_OR_13]], true
+; CHECK-NEXT: br i1 [[C_NOT_10_OR_13]], label [[WHILE_BODY_I]], label [[WHILE_BODY_I_BREAK:%.*]]
+; CHECK: while.body.i.break:
+; CHECK-NEXT: br i1 [[MAYBE_UNDEF]], label [[WHILE_BODY]], label [[SWITCH_EARLY_TEST:%.*]]
+; CHECK: switch.early.test:
+; CHECK-NEXT: switch i8 [[C]], label [[RETURN:%.*]] [
+; CHECK-NEXT: i8 13, label [[WHILE_BODY]]
+; CHECK-NEXT: i8 10, label [[WHILE_BODY]]
+; CHECK-NEXT: ]
+; CHECK: return:
+; CHECK-NEXT: ret void
+;
+
+entry:
+ br label %while.body
+
+while.body:
+ br label %while.body.i
+
+while.body.i:
+ %maybe_undef = phi i1 [ undef, %while.body ], [ %next_maybe_undef, %while.body.i ]
+ %c = call fastcc signext i8 @next_char()
+ %c_10 = icmp eq i8 %c, 10
+ %c_13 = icmp eq i8 %c, 13
+ %c_10_or_13 = or i1 %c_10, %c_13
+ %next_maybe_undef = or i1 %maybe_undef, %c_10_or_13
+ %c_not_10_or_13 = xor i1 %c_10_or_13, true
+ br i1 %c_not_10_or_13, label %while.body.i, label %while.body.i.break
+
+while.body.i.break:
+ ; NEXT_MAYBE_UNDEF is never undef if here
+ br i1 %next_maybe_undef, label %while.body, label %return
+
+
+return:
+ ret void
+}
+
+
+define void @test_msan() sanitize_memory {
+; CHECK-LABEL: @test_msan(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
+; CHECK: while.body:
+; CHECK-NEXT: br label [[WHILE_BODY_I:%.*]]
+; CHECK: while.body.i:
+; CHECK-NEXT: [[MAYBE_UNDEF:%.*]] = phi i1 [ undef, [[WHILE_BODY]] ], [ [[NEXT_MAYBE_UNDEF:%.*]], [[WHILE_BODY_I]] ]
+; CHECK-NEXT: [[C:%.*]] = call fastcc signext i8 @next_char()
+; CHECK-NEXT: [[C_10:%.*]] = icmp eq i8 [[C]], 10
+; CHECK-NEXT: [[C_13:%.*]] = icmp eq i8 [[C]], 13
+; CHECK-NEXT: [[C_10_OR_13:%.*]] = or i1 [[C_10]], [[C_13]]
+; CHECK-NEXT: [[NEXT_MAYBE_UNDEF]] = or i1 [[MAYBE_UNDEF]], [[C_10_OR_13]]
+; CHECK-NEXT: [[C_NOT_10_OR_13:%.*]] = xor i1 [[C_10_OR_13]], true
+; CHECK-NEXT: br i1 [[C_NOT_10_OR_13]], label [[WHILE_BODY_I]], label [[WHILE_BODY_I_BREAK:%.*]]
+; CHECK: while.body.i.break:
+; CHECK-NEXT: br i1 [[NEXT_MAYBE_UNDEF]], label [[WHILE_BODY]], label [[RETURN:%.*]]
+; CHECK: return:
+; CHECK-NEXT: ret void
+;
+
+entry:
+ br label %while.body
+
+while.body:
+ br label %while.body.i
+
+while.body.i:
+ %maybe_undef = phi i1 [ undef, %while.body ], [ %next_maybe_undef, %while.body.i ]
+ %c = call fastcc signext i8 @next_char()
+ %c_10 = icmp eq i8 %c, 10
+ %c_13 = icmp eq i8 %c, 13
+ %c_10_or_13 = or i1 %c_10, %c_13
+ %next_maybe_undef = or i1 %maybe_undef, %c_10_or_13
+ %c_not_10_or_13 = xor i1 %c_10_or_13, true
+ br i1 %c_not_10_or_13, label %while.body.i, label %while.body.i.break
+
+while.body.i.break:
+ ; NEXT_MAYBE_UNDEF is never undef if here
+ br i1 %next_maybe_undef, label %while.body, label %return
+
+
+return:
+ ret void
+}
OpenPOWER on IntegriCloud