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 @@ -4241,11 +4241,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); @@ -4263,6 +4258,16 @@ Instruction *OldTI = BB->getTerminator(); Builder.SetInsertPoint(OldTI); + // There can be an unintended UB if extra values are Poison. Before the + // transformation, extra values may not be evaluated according to the + // condition, and it will not raise UB. But after transformation, we are + // evaluating extra values before checking the condition, and it will raise + // UB. It can be solved by adding freeze instruction to extra values. + AssumptionCache *AC = Options.AC; + + if (!isGuaranteedNotToBeUndefOrPoison(ExtraCase, AC, BI, nullptr)) + ExtraCase = Builder.CreateFreeze(ExtraCase); + 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 @@ -256,7 +256,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: [[TMP0:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i8 [[C:%.*]], label [[COMMON_RET:%.*]] [ ; CHECK-NEXT: i8 99, label [[IF_THEN]] @@ -291,7 +292,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: [[TMP0:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN]], label [[SWITCH_EARLY_TEST:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i8 [[C:%.*]], label [[COMMON_RET:%.*]] [ ; CHECK-NEXT: i8 99, label [[IF_THEN]] @@ -330,7 +332,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: [[TMP0:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[TMP0]], 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]] @@ -346,8 +349,8 @@ ; CHECK: lor.rhs: ; CHECK-NEXT: br label [[LOR_END]] ; CHECK: lor.end: -; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ true, [[SWITCH_EARLY_TEST]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY:%.*]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ] -; CHECK-NEXT: [[CONV46:%.*]] = zext i1 [[TMP0]] to i32 +; CHECK-NEXT: [[TMP1:%.*]] = phi i1 [ true, [[SWITCH_EARLY_TEST]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY:%.*]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ] +; CHECK-NEXT: [[CONV46:%.*]] = zext i1 [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[CONV46]] ; entry: @@ -400,7 +403,8 @@ define i32 @test10(i32 %mode, i1 %Cond) { ; CHECK-LABEL: @test10( -; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[TMP1]], 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_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 @@ -310,7 +310,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: [[TMP0:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i8 [[C:%.*]], label [[COMMON_RET:%.*]] [ ; CHECK-NEXT: i8 99, label [[IF_THEN]] @@ -345,7 +346,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: [[TMP0:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN]], label [[SWITCH_EARLY_TEST:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i8 [[C:%.*]], label [[COMMON_RET:%.*]] [ ; CHECK-NEXT: i8 99, label [[IF_THEN]] @@ -384,7 +386,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: [[TMP0:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[TMP0]], 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]] @@ -400,8 +403,8 @@ ; CHECK: lor.rhs: ; CHECK-NEXT: br label [[LOR_END]] ; CHECK: lor.end: -; CHECK-NEXT: [[TMP0:%.*]] = phi i1 [ true, [[SWITCH_EARLY_TEST]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY:%.*]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ] -; CHECK-NEXT: [[CONV46:%.*]] = zext i1 [[TMP0]] to i32 +; CHECK-NEXT: [[TMP1:%.*]] = phi i1 [ true, [[SWITCH_EARLY_TEST]] ], [ false, [[LOR_RHS]] ], [ true, [[ENTRY:%.*]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ], [ true, [[SWITCH_EARLY_TEST]] ] +; CHECK-NEXT: [[CONV46:%.*]] = zext i1 [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[CONV46]] ; entry: @@ -454,7 +457,8 @@ define i32 @test10(i32 %mode, i1 %Cond) { ; CHECK-LABEL: @test10( -; CHECK-NEXT: br i1 [[COND:%.*]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i32 [[MODE:%.*]], label [[T:%.*]] [ ; CHECK-NEXT: i32 51, label [[F]] @@ -486,7 +490,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: [[TMP1:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[TMP1]], label [[SWITCH_EARLY_TEST:%.*]], label [[F:%.*]] ; CHECK: switch.early.test: ; CHECK-NEXT: switch i32 [[MODE:%.*]], label [[T:%.*]] [ ; CHECK-NEXT: i32 51, label [[F]] @@ -519,7 +524,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: [[TMP1:%.*]] = freeze i1 [[COND:%.*]] +; CHECK-NEXT: br i1 [[TMP1]], 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 @@ -19,7 +19,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: [[TMP0:%.*]] = freeze i1 [[MAYBE_UNDEF]] +; CHECK-NEXT: br i1 [[TMP0]], 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 +72,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: [[TMP0:%.*]] = freeze i1 [[MAYBE_UNDEF]] +; CHECK-NEXT: br i1 [[TMP0]], 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 ;