Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit 57933e3

Browse files
committed
SimplifyCFG: Don't generate invalid code for switch used to initialize
two variables where the first variable is returned and the second ignored. I don't think this occurs in practice (other passes should have cleaned up the unused phi node), but it should still be handled correctly. Also make the logic for determining if we should return early less sketchy. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@164225 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent adb4a40 commit 57933e3

File tree

2 files changed

+42
-9
lines changed

2 files changed

+42
-9
lines changed

lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3258,17 +3258,16 @@ static bool SwitchToLookupTable(SwitchInst *SI,
32583258
"switch.gep");
32593259
Value *Result = Builder.CreateLoad(GEP, "switch.load");
32603260

3261-
// If the result is only going to be used to return from the function,
3262-
// we want to do that right here.
3263-
if (PHI->hasOneUse() && isa<ReturnInst>(*PHI->use_begin())) {
3264-
if (CommonDest->getFirstNonPHIOrDbg() == CommonDest->getTerminator()) {
3265-
Builder.CreateRet(Result);
3266-
ReturnedEarly = true;
3267-
}
3261+
// If the result is used to return immediately from the function, we want to
3262+
// do that right here.
3263+
if (PHI->hasOneUse() && isa<ReturnInst>(*PHI->use_begin()) &&
3264+
*PHI->use_begin() == CommonDest->getFirstNonPHIOrDbg()) {
3265+
Builder.CreateRet(Result);
3266+
ReturnedEarly = true;
3267+
break;
32683268
}
32693269

3270-
if (!ReturnedEarly)
3271-
PHI->addIncoming(Result, LookupBB);
3270+
PHI->addIncoming(Result, LookupBB);
32723271
}
32733272

32743273
if (!ReturnedEarly)

test/Transforms/SimplifyCFG/switch_to_lookup_table.ll

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ target triple = "x86_64-unknown-linux-gnu"
1515
; The table for @foostring
1616
; CHECK: @switch.table3 = private unnamed_addr constant [4 x i8*] [i8* getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8]* @.str1, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8]* @.str2, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8]* @.str3, i64 0, i64 0)]
1717

18+
; The table for @earlyreturncrash
19+
; CHECK: @switch.table4 = private unnamed_addr constant [4 x i32] [i32 42, i32 9, i32 88, i32 5]
20+
1821
; A simple int-to-int selection switch.
1922
; It is dense enough to be replaced by table lookup.
2023
; The result is directly by a ret from an otherwise empty bb,
@@ -138,3 +141,34 @@ return:
138141
; CHECK-NEXT: %switch.load = load i8** %switch.gep
139142
; CHECK-NEXT: ret i8* %switch.load
140143
}
144+
145+
; Switch used to initialize two values. The first value is returned, the second
146+
; value is not used. This used to make the transformation generate illegal code.
147+
148+
define i32 @earlyreturncrash(i32 %x) {
149+
entry:
150+
switch i32 %x, label %sw.default [
151+
i32 0, label %sw.epilog
152+
i32 1, label %sw.bb1
153+
i32 2, label %sw.bb2
154+
i32 3, label %sw.bb3
155+
]
156+
157+
sw.bb1: br label %sw.epilog
158+
sw.bb2: br label %sw.epilog
159+
sw.bb3: br label %sw.epilog
160+
sw.default: br label %sw.epilog
161+
162+
sw.epilog:
163+
%a.0 = phi i32 [ 7, %sw.default ], [ 5, %sw.bb3 ], [ 88, %sw.bb2 ], [ 9, %sw.bb1 ], [ 42, %entry ]
164+
%b.0 = phi i32 [ 10, %sw.default ], [ 5, %sw.bb3 ], [ 1, %sw.bb2 ], [ 4, %sw.bb1 ], [ 3, %entry ]
165+
ret i32 %a.0
166+
167+
; CHECK: @earlyreturncrash
168+
; CHECK: switch.lookup:
169+
; CHECK-NEXT: %switch.gep = getelementptr inbounds [4 x i32]* @switch.table4, i32 0, i32 %switch.tableidx
170+
; CHECK-NEXT: %switch.load = load i32* %switch.gep
171+
; CHECK-NEXT: ret i32 %switch.load
172+
; CHECK: sw.epilog:
173+
; CHECK-NEXT: ret i32 7
174+
}

0 commit comments

Comments
 (0)