diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -4176,11 +4176,6 @@ 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); @@ -4191,6 +4186,7 @@ // then we evaluate them with an explicit branch first. Split the block // right before the condbr to handle it. if (ExtraCase) { + bool ExtraCaseNeedsFreeze = !isGuaranteedNotToBeUndefOrPoison(ExtraCase, Options.AC, BB->getTerminator()); BasicBlock *NewBB = SplitBlock(BB, BI, DTU, /*LI=*/nullptr, /*MSSAU=*/nullptr, "switch.early.test"); @@ -4198,6 +4194,9 @@ Instruction *OldTI = BB->getTerminator(); Builder.SetInsertPoint(OldTI); + if (ExtraCaseNeedsFreeze) + ExtraCase = Builder.CreateFreeze(ExtraCase, ExtraCase->getName() + ".fr"); + if (TrueWhenEqual) Builder.CreateCondBr(ExtraCase, EdgeBB, NewBB); else diff --git a/llvm/test/Transforms/SimplifyCFG/switch_create-custom-dl.ll b/llvm/test/Transforms/SimplifyCFG/switch_create-custom-dl.ll --- a/llvm/test/Transforms/SimplifyCFG/switch_create-custom-dl.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch_create-custom-dl.ll @@ -208,7 +208,7 @@ ; CHECK-LABEL: @test6( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP_1_I:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[I:%.*]], i64 0, i32 1 -; CHECK-NEXT: [[TMP_2_I:%.*]] = load i32, i32* [[TMP_1_I]] +; CHECK-NEXT: [[TMP_2_I:%.*]] = load i32, i32* [[TMP_1_I]], align 4 ; CHECK-NEXT: [[TMP_2_I_OFF:%.*]] = add i32 [[TMP_2_I]], -14 ; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i32 [[TMP_2_I_OFF]], 6 ; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[SWITCH]], i1 true, i1 false @@ -246,14 +246,15 @@ ; CHECK-LABEL: @test7( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 32 -; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]] +; CHECK-NEXT: [[CMP_FR:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[CMP_FR]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i8 [[C:%.*]], label [[IF_END:%.*]] [ ; CHECK-NEXT: i8 99, label [[IF_THEN]] ; CHECK-NEXT: i8 97, label [[IF_THEN]] ; CHECK-NEXT: ] ; CHECK: if.then: -; CHECK-NEXT: tail call void @foo1() #2 +; CHECK-NEXT: tail call void @foo1() [[ATTR2:#.*]] ; CHECK-NEXT: ret void ; CHECK: if.end: ; CHECK-NEXT: ret void @@ -281,7 +282,8 @@ ; CHECK-NEXT: br i1 [[C:%.*]], label [[N:%.*]], label [[IF_THEN:%.*]] ; CHECK: N: ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 32 -; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN]], label [[SWITCH_EARLY_TEST:%.*]] +; CHECK-NEXT: [[CMP_FR:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[CMP_FR]], label [[IF_THEN]], label [[SWITCH_EARLY_TEST:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i8 [[C:%.*]], label [[IF_END:%.*]] [ ; CHECK-NEXT: i8 99, label [[IF_THEN]] @@ -289,7 +291,7 @@ ; CHECK-NEXT: ] ; CHECK: if.then: ; CHECK-NEXT: [[A:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 42, [[SWITCH_EARLY_TEST]] ], [ 42, [[N]] ], [ 42, [[SWITCH_EARLY_TEST]] ] -; CHECK-NEXT: tail call void @foo1() #2 +; CHECK-NEXT: tail call void @foo1() [[ATTR2]] ; CHECK-NEXT: ret i32 [[A]] ; CHECK: if.end: ; CHECK-NEXT: ret i32 0 @@ -319,7 +321,8 @@ ; CHECK-LABEL: @test9( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[C:%.*]], 33 -; CHECK-NEXT: br i1 [[CMP]], label [[LOR_END:%.*]], label [[SWITCH_EARLY_TEST:%.*]] +; CHECK-NEXT: [[CMP_FR:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[CMP_FR]], label [[LOR_END:%.*]], label [[SWITCH_EARLY_TEST:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i8 [[C]], label [[LOR_RHS:%.*]] [ ; CHECK-NEXT: i8 92, label [[LOR_END]] @@ -389,7 +392,8 @@ define i32 @test10(i32 %mode, i1 %Cond) { ; CHECK-LABEL: @test10( -; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]] +; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[COND_FR]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i32 [[MODE:%.*]], label [[T:%.*]] [ ; CHECK-NEXT: i32 51, label [[F]] @@ -465,8 +469,8 @@ define void @test12() nounwind { ; CHECK-LABEL: @test12( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[A_OLD:%.*]] = icmp eq i32 undef, undef -; CHECK-NEXT: br i1 [[A_OLD]], label [[BB55_US_US:%.*]], label [[MALFORMED:%.*]] +; CHECK-NEXT: [[DOTOLD:%.*]] = icmp eq i32 undef, undef +; CHECK-NEXT: br i1 [[DOTOLD]], label [[BB55_US_US:%.*]], label [[MALFORMED:%.*]] ; CHECK: bb55.us.us: ; CHECK-NEXT: [[B:%.*]] = icmp ugt i32 undef, undef ; CHECK-NEXT: [[A:%.*]] = icmp eq i32 undef, undef @@ -506,7 +510,7 @@ ; CHECK-NEXT: i32 0, label [[IF_THEN]] ; CHECK-NEXT: ] ; CHECK: if.then: -; CHECK-NEXT: call void @foo1() #3 +; CHECK-NEXT: call void @foo1() [[ATTR3:#.*]] ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: ; CHECK-NEXT: ret void @@ -548,7 +552,7 @@ ; CHECK-NEXT: i32 0, label [[IF_THEN]] ; CHECK-NEXT: ] ; CHECK: if.then: -; CHECK-NEXT: call void @foo1() #3 +; CHECK-NEXT: call void @foo1() [[ATTR3]] ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: ; CHECK-NEXT: ret void diff --git a/llvm/test/Transforms/SimplifyCFG/switch_create.ll b/llvm/test/Transforms/SimplifyCFG/switch_create.ll --- a/llvm/test/Transforms/SimplifyCFG/switch_create.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch_create.ll @@ -296,7 +296,8 @@ ; CHECK-LABEL: @test7( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 32 -; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]] +; CHECK-NEXT: [[CMP_FR:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[CMP_FR]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i8 [[C:%.*]], label [[IF_END:%.*]] [ ; CHECK-NEXT: i8 99, label [[IF_THEN]] @@ -331,7 +332,8 @@ ; CHECK-NEXT: br i1 [[C:%.*]], label [[N:%.*]], label [[IF_THEN:%.*]] ; CHECK: N: ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 32 -; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN]], label [[SWITCH_EARLY_TEST:%.*]] +; CHECK-NEXT: [[CMP_FR:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[CMP_FR]], label [[IF_THEN]], label [[SWITCH_EARLY_TEST:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i8 [[C:%.*]], label [[IF_END:%.*]] [ ; CHECK-NEXT: i8 99, label [[IF_THEN]] @@ -369,7 +371,8 @@ ; CHECK-LABEL: @test9( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[C:%.*]], 33 -; CHECK-NEXT: br i1 [[CMP]], label [[LOR_END:%.*]], label [[SWITCH_EARLY_TEST:%.*]] +; CHECK-NEXT: [[CMP_FR:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[CMP_FR]], label [[LOR_END:%.*]], label [[SWITCH_EARLY_TEST:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i8 [[C]], label [[LOR_RHS:%.*]] [ ; CHECK-NEXT: i8 92, label [[LOR_END]] @@ -439,7 +442,8 @@ define i32 @test10(i32 %mode, i1 %Cond) { ; CHECK-LABEL: @test10( -; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]] +; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[COND_FR]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i32 [[MODE:%.*]], label [[T:%.*]] [ ; CHECK-NEXT: i32 51, label [[F]] @@ -465,7 +469,8 @@ define i32 @test10_select(i32 %mode, i1 %Cond) { ; CHECK-LABEL: @test10_select( -; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]] +; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[COND_FR]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i32 [[MODE:%.*]], label [[T:%.*]] [ ; CHECK-NEXT: i32 51, label [[F]] @@ -492,7 +497,8 @@ ; TODO: %Cond doesn't need freeze define i32 @test10_select_and(i32 %mode, i1 %Cond) { ; CHECK-LABEL: @test10_select_and( -; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]] +; CHECK-NEXT: [[COND_FR:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[COND_FR]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i32 [[MODE:%.*]], label [[T:%.*]] [ ; CHECK-NEXT: i32 51, label [[F]] diff --git a/llvm/test/Transforms/SimplifyCFG/switch_msan.ll b/llvm/test/Transforms/SimplifyCFG/switch_msan.ll --- a/llvm/test/Transforms/SimplifyCFG/switch_msan.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch_msan.ll @@ -3,6 +3,8 @@ declare i8 @next_char(); +; test_no_msan and test_msan creates the same assembly because a frozen extra case is safe to use + define void @test_no_msan() { ; CHECK-LABEL: @test_no_msan( ; CHECK-NEXT: entry: @@ -19,7 +21,8 @@ ; 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-NEXT: [[MAYBE_UNDEF_FR:%.*]] = freeze i1 [[MAYBE_UNDEF]] +; CHECK-NEXT: br i1 [[MAYBE_UNDEF_FR]], 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]] @@ -71,7 +74,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-NEXT: [[MAYBE_UNDEF_FR:%.*]] = freeze i1 [[MAYBE_UNDEF]] +; CHECK-NEXT: br i1 [[MAYBE_UNDEF_FR]], 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 ;