-
Notifications
You must be signed in to change notification settings - Fork 10.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Clang] support for outputs along indirect edges of asm goto
Initial support for asm goto w/ outputs (D69876) only supported outputs along the "default" (aka "fallthrough") edge. We can support outputs along all edges by repeating the same pattern of stores along the indirect edges that we allready do for the default edge. One complication is that these indirect edges may be critical edges which would need to be split. Another issue is that mid-codgen of LLVM IR, the control flow graph might not reflect the control flow of the final function. To avoid this "chicken and the egg" problem assume that any given indirect edge may become a critical edge, and pro-actively split it. This is unnecessary if the edge does not become critical, but LLVM will optimize such cases via tail duplication. Fixes: #53562 Reviewed By: void Differential Revision: https://reviews.llvm.org/D136497
- Loading branch information
1 parent
b1bc723
commit 329ef60
Showing
6 changed files
with
228 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py | ||
// REQUIRES: x86-registered-target | ||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O0 -emit-llvm %s -o - | FileCheck %s | ||
|
||
// CHECK-LABEL: @test0( | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: [[RET:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i,~{dirflag},~{fpsr},~{flags}"() #[[ATTR1:[0-9]+]] | ||
// CHECK-NEXT: to label [[ASM_FALLTHROUGH:%.*]] [label %z.split], !srcloc !2 | ||
// CHECK: asm.fallthrough: | ||
// CHECK-NEXT: store i32 [[TMP0]], ptr [[RET]], align 4 | ||
// CHECK-NEXT: store i32 42, ptr [[RET]], align 4 | ||
// CHECK-NEXT: br label [[Z:%.*]] | ||
// CHECK: z: | ||
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[RET]], align 4 | ||
// CHECK-NEXT: ret i32 [[TMP1]] | ||
// CHECK: z.split: | ||
// CHECK-NEXT: store i32 [[TMP0]], ptr [[RET]], align 4 | ||
// CHECK-NEXT: br label [[Z]] | ||
// | ||
int test0 (void) { | ||
int ret; | ||
asm goto ("" : "=r"(ret):::z); | ||
ret = 42; | ||
z: | ||
return ret; | ||
} | ||
|
||
// CHECK-LABEL: @test1( | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: [[RET:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: [[TMP0:%.*]] = callbr { i32, i32 } asm "", "=r,=r,!i,~{dirflag},~{fpsr},~{flags}"() #[[ATTR1]] | ||
// CHECK-NEXT: to label [[ASM_FALLTHROUGH:%.*]] [label %z.split], !srcloc !3 | ||
// CHECK: asm.fallthrough: | ||
// CHECK-NEXT: [[ASMRESULT:%.*]] = extractvalue { i32, i32 } [[TMP0]], 0 | ||
// CHECK-NEXT: [[ASMRESULT1:%.*]] = extractvalue { i32, i32 } [[TMP0]], 1 | ||
// CHECK-NEXT: store i32 [[ASMRESULT]], ptr [[RET]], align 4 | ||
// CHECK-NEXT: store i32 [[ASMRESULT1]], ptr [[B]], align 4 | ||
// CHECK-NEXT: store i32 42, ptr [[RET]], align 4 | ||
// CHECK-NEXT: br label [[Z:%.*]] | ||
// CHECK: z: | ||
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[RET]], align 4 | ||
// CHECK-NEXT: ret i32 [[TMP1]] | ||
// CHECK: z.split: | ||
// CHECK-NEXT: [[ASMRESULT2:%.*]] = extractvalue { i32, i32 } [[TMP0]], 0 | ||
// CHECK-NEXT: [[ASMRESULT3:%.*]] = extractvalue { i32, i32 } [[TMP0]], 1 | ||
// CHECK-NEXT: store i32 [[ASMRESULT2]], ptr [[RET]], align 4 | ||
// CHECK-NEXT: store i32 [[ASMRESULT3]], ptr [[B]], align 4 | ||
// CHECK-NEXT: br label [[Z]] | ||
// | ||
int test1 (void) { | ||
int ret, b; | ||
asm goto ("" : "=r"(ret), "=r"(b):::z); | ||
ret = 42; | ||
z: | ||
return ret; | ||
} | ||
|
||
// CHECK-LABEL: @test2( | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: [[RET:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: [[B:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: [[TMP0:%.*]] = callbr { i32, i32 } asm "", "=r,=r,!i,~{dirflag},~{fpsr},~{flags}"() #[[ATTR1]] | ||
// CHECK-NEXT: to label [[ASM_FALLTHROUGH:%.*]] [label %z.split], !srcloc !4 | ||
// CHECK: asm.fallthrough: | ||
// CHECK-NEXT: [[ASMRESULT:%.*]] = extractvalue { i32, i32 } [[TMP0]], 0 | ||
// CHECK-NEXT: [[ASMRESULT1:%.*]] = extractvalue { i32, i32 } [[TMP0]], 1 | ||
// CHECK-NEXT: store i32 [[ASMRESULT]], ptr [[RET]], align 4 | ||
// CHECK-NEXT: store i32 [[ASMRESULT1]], ptr [[B]], align 4 | ||
// CHECK-NEXT: [[TMP1:%.*]] = callbr { i32, i32 } asm "", "=r,=r,!i,~{dirflag},~{fpsr},~{flags}"() #[[ATTR1]] | ||
// CHECK-NEXT: to label [[ASM_FALLTHROUGH4:%.*]] [label %z.split9], !srcloc !5 | ||
// CHECK: asm.fallthrough4: | ||
// CHECK-NEXT: [[ASMRESULT5:%.*]] = extractvalue { i32, i32 } [[TMP1]], 0 | ||
// CHECK-NEXT: [[ASMRESULT6:%.*]] = extractvalue { i32, i32 } [[TMP1]], 1 | ||
// CHECK-NEXT: store i32 [[ASMRESULT5]], ptr [[RET]], align 4 | ||
// CHECK-NEXT: store i32 [[ASMRESULT6]], ptr [[B]], align 4 | ||
// CHECK-NEXT: br label [[Z:%.*]] | ||
// CHECK: z: | ||
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[RET]], align 4 | ||
// CHECK-NEXT: ret i32 [[TMP2]] | ||
// CHECK: z.split: | ||
// CHECK-NEXT: [[ASMRESULT2:%.*]] = extractvalue { i32, i32 } [[TMP0]], 0 | ||
// CHECK-NEXT: [[ASMRESULT3:%.*]] = extractvalue { i32, i32 } [[TMP0]], 1 | ||
// CHECK-NEXT: store i32 [[ASMRESULT2]], ptr [[RET]], align 4 | ||
// CHECK-NEXT: store i32 [[ASMRESULT3]], ptr [[B]], align 4 | ||
// CHECK-NEXT: br label [[Z]] | ||
// CHECK: z.split9: | ||
// CHECK-NEXT: [[ASMRESULT7:%.*]] = extractvalue { i32, i32 } [[TMP1]], 0 | ||
// CHECK-NEXT: [[ASMRESULT8:%.*]] = extractvalue { i32, i32 } [[TMP1]], 1 | ||
// CHECK-NEXT: store i32 [[ASMRESULT7]], ptr [[RET]], align 4 | ||
// CHECK-NEXT: store i32 [[ASMRESULT8]], ptr [[B]], align 4 | ||
// CHECK-NEXT: br label [[Z]] | ||
// | ||
int test2 (void) { | ||
int ret, b; | ||
asm goto ("" : "=r"(ret), "=r"(b):::z); | ||
asm goto ("" : "=r"(ret), "=r"(b):::z); | ||
z: | ||
return ret; | ||
} | ||
// CHECK-LABEL: @test3( | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: [[OUT1_ADDR:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: store i32 [[OUT1:%.*]], ptr [[OUT1_ADDR]], align 4 | ||
// CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i,!i,~{dirflag},~{fpsr},~{flags}"() #[[ATTR1]] | ||
// CHECK-NEXT: to label [[ASM_FALLTHROUGH:%.*]] [label [[LABEL_TRUE_SPLIT:%.*]], label %loop.split], !srcloc !6 | ||
// CHECK: asm.fallthrough: | ||
// CHECK-NEXT: store i32 [[TMP0]], ptr [[OUT1_ADDR]], align 4 | ||
// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4 | ||
// CHECK-NEXT: br label [[RETURN:%.*]] | ||
// CHECK: label_true.split: | ||
// CHECK-NEXT: store i32 [[TMP0]], ptr [[OUT1_ADDR]], align 4 | ||
// CHECK-NEXT: br label [[LABEL_TRUE:%.*]] | ||
// CHECK: loop.split: | ||
// CHECK-NEXT: store i32 [[TMP0]], ptr [[OUT1_ADDR]], align 4 | ||
// CHECK-NEXT: br label [[LOOP:%.*]] | ||
// CHECK: loop: | ||
// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4 | ||
// CHECK-NEXT: br label [[RETURN]] | ||
// CHECK: label_true: | ||
// CHECK-NEXT: store i32 1, ptr [[RETVAL]], align 4 | ||
// CHECK-NEXT: br label [[RETURN]] | ||
// CHECK: return: | ||
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[RETVAL]], align 4 | ||
// CHECK-NEXT: ret i32 [[TMP1]] | ||
// | ||
int test3 (int out1) { | ||
asm goto("" : "=r"(out1)::: label_true, loop); | ||
return 0; | ||
loop: | ||
return 0; | ||
label_true: | ||
return 1; | ||
} | ||
|
||
// CHECK-LABEL: @test4( | ||
// CHECK-NEXT: entry: | ||
// CHECK-NEXT: [[X:%.*]] = alloca i32, align 4 | ||
// CHECK-NEXT: br label [[FOO:%.*]] | ||
// CHECK: foo: | ||
// CHECK-NEXT: [[TMP0:%.*]] = callbr i32 asm "", "=r,!i,~{dirflag},~{fpsr},~{flags}"() #[[ATTR1]] | ||
// CHECK-NEXT: to label [[ASM_FALLTHROUGH:%.*]] [label %foo.split], !srcloc !7 | ||
// CHECK: asm.fallthrough: | ||
// CHECK-NEXT: store i32 [[TMP0]], ptr [[X]], align 4 | ||
// CHECK-NEXT: ret void | ||
// CHECK: foo.split: | ||
// CHECK-NEXT: store i32 [[TMP0]], ptr [[X]], align 4 | ||
// CHECK-NEXT: br label [[FOO]] | ||
// | ||
void test4 (void) { | ||
int x; | ||
foo: | ||
asm goto ("" : "=r"(x):::foo); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters