Coroutines: don't infer function attrs before lowering

Coroutines have weird semantics that don't quite match normal LLVM functions,
so trying to infer even simple attributes based on thier contents can go wrong.
This commit is contained in:
Tim Northover 2021-10-22 09:13:02 +01:00
parent 5f32a851fb
commit 3d39612b3d
4 changed files with 21 additions and 3 deletions

View File

@ -1752,7 +1752,8 @@ static SCCNodesResult createSCCNodeSet(ArrayRef<Function *> Functions) {
SCCNodesResult Res; SCCNodesResult Res;
Res.HasUnknownCall = false; Res.HasUnknownCall = false;
for (Function *F : Functions) { for (Function *F : Functions) {
if (!F || F->hasOptNone() || F->hasFnAttribute(Attribute::Naked)) { if (!F || F->hasOptNone() || F->hasFnAttribute(Attribute::Naked) ||
F->isPresplitCoroutine()) {
// Treat any function we're trying not to optimize as if it were an // Treat any function we're trying not to optimize as if it were an
// indirect call and omit it from the node set used below. // indirect call and omit it from the node set used below.
Res.HasUnknownCall = true; Res.HasUnknownCall = true;

View File

@ -10,7 +10,7 @@ define {i8*, i8*, i32} @f(i8* %buffer, i32 %n) {
; CHECK-NEXT: [[N_VAL_SPILL_ADDR:%.*]] = getelementptr inbounds i8, i8* [[BUFFER:%.*]], i64 8 ; CHECK-NEXT: [[N_VAL_SPILL_ADDR:%.*]] = getelementptr inbounds i8, i8* [[BUFFER:%.*]], i64 8
; CHECK-NEXT: [[TMP0:%.*]] = bitcast i8* [[N_VAL_SPILL_ADDR]] to i32* ; CHECK-NEXT: [[TMP0:%.*]] = bitcast i8* [[N_VAL_SPILL_ADDR]] to i32*
; CHECK-NEXT: store i32 [[N:%.*]], i32* [[TMP0]], align 4 ; CHECK-NEXT: store i32 [[N:%.*]], i32* [[TMP0]], align 4
; CHECK-NEXT: [[TMP1:%.*]] = tail call i8* @allocate(i32 [[N]]) #[[ATTR0:[0-9]+]] ; CHECK-NEXT: [[TMP1:%.*]] = tail call i8* @allocate(i32 [[N]])
; CHECK-NEXT: [[DOTSPILL_ADDR:%.*]] = bitcast i8* [[BUFFER]] to i8** ; CHECK-NEXT: [[DOTSPILL_ADDR:%.*]] = bitcast i8* [[BUFFER]] to i8**
; CHECK-NEXT: store i8* [[TMP1]], i8** [[DOTSPILL_ADDR]], align 8 ; CHECK-NEXT: store i8* [[TMP1]], i8** [[DOTSPILL_ADDR]], align 8
; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { i8*, i8*, i32 } { i8* bitcast ({ i8*, i8*, i32 } (i8*, i1)* @f.resume.0 to i8*), i8* undef, i32 undef }, i8* [[TMP1]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { i8*, i8*, i32 } { i8* bitcast ({ i8*, i8*, i32 } (i8*, i1)* @f.resume.0 to i8*), i8* undef, i32 undef }, i8* [[TMP1]], 1

View File

@ -72,7 +72,7 @@ entry:
define hidden { i8*, i8* } @g(i8* %buffer, i16* %ptr) { define hidden { i8*, i8* } @g(i8* %buffer, i16* %ptr) {
; CHECK-LABEL: @g( ; CHECK-LABEL: @g(
; CHECK-NEXT: coro.return: ; CHECK-NEXT: coro.return:
; CHECK-NEXT: [[TMP0:%.*]] = tail call i8* @allocate(i32 8) #[[ATTR0:[0-9]+]] ; CHECK-NEXT: [[TMP0:%.*]] = tail call i8* @allocate(i32 8)
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i8* [[BUFFER:%.*]] to i8** ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i8* [[BUFFER:%.*]] to i8**
; CHECK-NEXT: store i8* [[TMP0]], i8** [[TMP1]], align 8 ; CHECK-NEXT: store i8* [[TMP0]], i8** [[TMP1]], align 8
; CHECK-NEXT: [[PTR_SPILL_ADDR:%.*]] = bitcast i8* [[TMP0]] to i16** ; CHECK-NEXT: [[PTR_SPILL_ADDR:%.*]] = bitcast i8* [[TMP0]] to i16**

View File

@ -71,3 +71,20 @@ define void @callsite_noreturn() {
call i32 @f() noreturn call i32 @f() noreturn
ret void ret void
} }
; CHECK: Function Attrs: {{.*}}noreturn
; CHECK-NEXT: @unreachable
define void @unreachable() {
unreachable
}
; CHECK-NOT: Function Attrs: {{.*}}noreturn
; CHECK: @coro
define void @coro() "coroutine.presplit"="1" {
call token @llvm.coro.id.retcon.once(i32 0, i32 0, i8* null, i8* bitcast(void() *@coro to i8*), i8* null, i8* null)
call i1 @llvm.coro.end(i8* null, i1 false)
unreachable
}
declare token @llvm.coro.id.retcon.once(i32 %size, i32 %align, i8* %buffer, i8* %prototype, i8* %alloc, i8* %free)
declare i1 @llvm.coro.end(i8*, i1)