Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions llvm/include/llvm/IR/GenericConvergenceVerifierImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,6 @@ void GenericConvergenceVerifier<ContextT>::visit(const InstructionT &I) {
SeenFirstConvOp = true;

if (TokenDef || ConvOp != CONV_NONE) {
Check(isConvergent(I),
"Convergence control token can only be used in a convergent call.",
{Context.print(&I)});
Check(ConvergenceKind != UncontrolledConvergence,
"Cannot mix controlled and uncontrolled convergence in the same "
"function.",
Expand Down
7 changes: 7 additions & 0 deletions llvm/test/Assembler/convergence-control.ll
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ define void @mixed2() {
ret void
}

; convergence control token can be used on non-convergent calls,
; but it has no effect.
define void @mixed3() {
%t05_tok1 = call token @llvm.experimental.convergence.anchor()
call void @g() [ "convergencectrl"(token %t05_tok1) ]
ret void
}

define void @region_nesting1(i1 %arg) convergent {
A:
Expand Down
93 changes: 93 additions & 0 deletions llvm/test/Transforms/ADCE/convergence.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 5
; RUN: opt %s -passes=adce -S | FileCheck %s

define i32 @foo(i32 %a) #0 {
; CHECK-LABEL: define i32 @foo(
; CHECK-SAME: i32 [[A:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: ret i32 [[A]]
;
entry:
%tk = call token @llvm.experimental.convergence.entry()
ret i32 %a
}

define void @bar() #0 {
; CHECK-LABEL: define void @bar(
; CHECK-SAME: ) #[[ATTR0]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: ret void
;
entry:
%tk = call token @llvm.experimental.convergence.anchor()
ret void
}

define void @baz() #0 {
; CHECK-LABEL: define void @baz(
; CHECK-SAME: ) #[[ATTR0]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br label %[[HEADER:.*]]
; CHECK: [[HEADER]]:
; CHECK-NEXT: br i1 true, label %[[BODY:.*]], label %[[EXIT:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: br label %[[HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
%tk0 = call token @llvm.experimental.convergence.entry()
br label %header

header:
%tk1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %tk0) ]
br i1 true, label %body, label %exit

body:
br label %header

exit:
ret void
}

define void @indirect_inner() #0 {
; CHECK-LABEL: define void @indirect_inner(
; CHECK-SAME: ) #[[ATTR0]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: ret void
;
entry:
%tk0 = call token @llvm.experimental.convergence.entry()
ret void
}

define void @indirect() #0 {
; CHECK-LABEL: define void @indirect(
; CHECK-SAME: ) #[[ATTR0]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TK0:%.*]] = call token @llvm.experimental.convergence.entry()
; CHECK-NEXT: [[VAR:%.*]] = alloca ptr, align 8
; CHECK-NEXT: store ptr @indirect_inner, ptr [[VAR]], align 8
; CHECK-NEXT: [[PTR:%.*]] = load ptr, ptr [[VAR]], align 8
; CHECK-NEXT: call void [[PTR]]() #[[ATTR0]] [ "convergencectrl"(token [[TK0]]) ]
; CHECK-NEXT: ret void
;
entry:
%tk0 = call token @llvm.experimental.convergence.entry()
%var = alloca ptr, align 8
store ptr @indirect_inner, ptr %var, align 8
%ptr = load ptr, ptr %var, align 8
call void %ptr() convergent [ "convergencectrl"(token %tk0) ]
ret void
}

declare token @llvm.experimental.convergence.entry() #1
declare token @llvm.experimental.convergence.anchor() #1
declare token @llvm.experimental.convergence.loop() #1

attributes #0 = { convergent }
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
;.
; CHECK: attributes #[[ATTR0]] = { convergent }
; CHECK: attributes #[[ATTR1:[0-9]+]] = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
;.
62 changes: 62 additions & 0 deletions llvm/test/Transforms/BDCE/convergence.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 5
; RUN: opt %s -passes=bdce -S | FileCheck %s

define i32 @foo(i32 %a) #0 {
; CHECK-LABEL: define i32 @foo(
; CHECK-SAME: i32 [[A:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: ret i32 [[A]]
;
entry:
%tk0 = call token @llvm.experimental.convergence.entry()
ret i32 %a
}

define void @bar() #0 {
; CHECK-LABEL: define void @bar(
; CHECK-SAME: ) #[[ATTR0]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: ret void
;
entry:
%tk0 = call token @llvm.experimental.convergence.anchor()
ret void
}

define void @baz() #0 {
; CHECK-LABEL: define void @baz(
; CHECK-SAME: ) #[[ATTR0]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br label %[[HEADER:.*]]
; CHECK: [[HEADER]]:
; CHECK-NEXT: br i1 true, label %[[BODY:.*]], label %[[EXIT:.*]]
; CHECK: [[BODY]]:
; CHECK-NEXT: br label %[[HEADER]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
entry:
%tk0 = call token @llvm.experimental.convergence.entry()
br label %header

header:
%tk1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %tk0) ]
br i1 true, label %body, label %exit

body:
br label %header

exit:
ret void
}

declare token @llvm.experimental.convergence.entry() #1
declare token @llvm.experimental.convergence.anchor() #1
declare token @llvm.experimental.convergence.loop() #1

attributes #0 = { convergent }
attributes #1 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
;.
; CHECK: attributes #[[ATTR0]] = { convergent }
; CHECK: attributes #[[ATTR1:[0-9]+]] = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
;.
42 changes: 41 additions & 1 deletion llvm/test/Transforms/FunctionAttrs/convergent.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
; RUN: opt -passes=function-attrs -S < %s | FileCheck %s

define i32 @nonleaf() convergent {
Expand Down Expand Up @@ -129,3 +129,43 @@ define i32 @noopt_friend() convergent {
%a = call i32 @noopt()
ret i32 0
}


; A function which is stripped of its convergent attribute, even
; if used in a controlled convergence call.
; This should be OK.
define i32 @leaf_noconvergent_used() convergent {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@leaf_noconvergent_used
; CHECK-SAME: () #[[ATTR0]] {
; CHECK-NEXT: ret i32 0
;
ret i32 0
}

define i32 @nonleaf_convergent() convergent {
; CHECK: Function Attrs: convergent mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@nonleaf_convergent
; CHECK-SAME: () #[[ATTR7:[0-9]+]] {
; CHECK-NEXT: [[TMP1:%.*]] = call token @llvm.experimental.convergence.entry()
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @leaf_noconvergent_used() [ "convergencectrl"(token [[TMP1]]) ]
; CHECK-NEXT: ret i32 0
;
%1 = call token @llvm.experimental.convergence.entry()
%2 = call i32 @leaf_noconvergent_used() [ "convergencectrl"(token %1) ]
ret i32 0
}


declare token @llvm.experimental.convergence.entry() #1
;.
; CHECK: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; CHECK: attributes #[[ATTR1]] = { convergent }
; CHECK: attributes #[[ATTR2]] = { norecurse }
; CHECK: attributes #[[ATTR3:[0-9]+]] = { convergent nocallback nounwind }
; CHECK: attributes #[[ATTR4]] = { convergent norecurse nounwind }
; CHECK: attributes #[[ATTR5]] = { nofree nosync nounwind memory(none) }
; CHECK: attributes #[[ATTR6]] = { convergent noinline optnone }
; CHECK: attributes #[[ATTR7]] = { convergent mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; CHECK: attributes #[[ATTR8:[0-9]+]] = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
;.
8 changes: 0 additions & 8 deletions llvm/test/Verifier/convergencectrl-invalid.ll
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,6 @@ define void @wrong_token() {
ret void
}

; CHECK: Convergence control token can only be used in a convergent call.
; CHECK-NEXT call void @g(){{.*}}%t05_tok1
define void @missing.attribute() {
%t05_tok1 = call token @llvm.experimental.convergence.anchor()
call void @g() [ "convergencectrl"(token %t05_tok1) ]
ret void
}

; CHECK: The 'convergencectrl' bundle requires exactly one token use.
; CHECK-NEXT: call void @g()
define void @multiple_tokens() {
Expand Down