From 0a613536b19d90e12e87154345b083d8f2e28e80 Mon Sep 17 00:00:00 2001 From: Jingyue Wu Date: Mon, 31 Aug 2015 06:10:27 +0000 Subject: [PATCH] [JumpThreading] make jump threading respect convergent annotation. Summary: JumpThreading shouldn't duplicate a convergent call, because that would move a convergent call into a control-inequivalent location. For example, if (cond) { ... } else { ... } convergent_call(); if (cond) { ... } else { ... } should not be optimized to if (cond) { ... convergent_call(); ... } else { ... convergent_call(); ... } Test Plan: test/Transforms/JumpThreading/basic.ll Patch by Xuetian Weng. Reviewers: resistor, arsenm, jingyue Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D12484 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@246415 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/Instructions.h | 6 +++++ lib/Transforms/Scalar/JumpThreading.cpp | 2 +- test/Transforms/JumpThreading/basic.ll | 34 ++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/include/llvm/IR/Instructions.h b/include/llvm/IR/Instructions.h index 7037d898fdd..f9dce102787 100644 --- a/include/llvm/IR/Instructions.h +++ b/include/llvm/IR/Instructions.h @@ -1634,6 +1634,12 @@ public: addAttribute(AttributeSet::FunctionIndex, Attribute::NoDuplicate); } + /// \brief Determine if the call is convergent + bool isConvergent() const { return hasFnAttr(Attribute::Convergent); } + void setConvergent() { + addAttribute(AttributeSet::FunctionIndex, Attribute::Convergent); + } + /// \brief Determine if the call returns a structure through first /// pointer argument. bool hasStructRetAttr() const { diff --git a/lib/Transforms/Scalar/JumpThreading.cpp b/lib/Transforms/Scalar/JumpThreading.cpp index b87f4766e8d..2d5aef88470 100644 --- a/lib/Transforms/Scalar/JumpThreading.cpp +++ b/lib/Transforms/Scalar/JumpThreading.cpp @@ -273,7 +273,7 @@ static unsigned getJumpThreadDuplicationCost(const BasicBlock *BB, // as having cost of 2 total, and if they are a vector intrinsic, we model // them as having cost 1. if (const CallInst *CI = dyn_cast(I)) { - if (CI->cannotDuplicate()) + if (CI->cannotDuplicate() || CI->isConvergent()) // Blocks with NoDuplicate are modelled as having infinite cost, so they // are never duplicated. return ~0U; diff --git a/test/Transforms/JumpThreading/basic.ll b/test/Transforms/JumpThreading/basic.ll index 32cc4de9285..46c92bc1f57 100644 --- a/test/Transforms/JumpThreading/basic.ll +++ b/test/Transforms/JumpThreading/basic.ll @@ -483,7 +483,7 @@ declare void @g() declare void @j() declare void @k() -; CHECK: define void @h(i32 %p) { +; CHECK-LABEL: define void @h(i32 %p) { define void @h(i32 %p) { %x = icmp ult i32 %p, 5 br i1 %x, label %l1, label %l2 @@ -513,4 +513,36 @@ l5: ; CHECK: } } +; CHECK-LABEL: define void @h_con(i32 %p) { +define void @h_con(i32 %p) { + %x = icmp ult i32 %p, 5 + br i1 %x, label %l1, label %l2 + +l1: + call void @j() + br label %l3 + +l2: + call void @k() + br label %l3 + +l3: +; CHECK: call void @g() [[CON:#[0-9]+]] +; CHECK-NOT: call void @g() [[CON]] + call void @g() convergent + %y = icmp ult i32 %p, 5 + br i1 %y, label %l4, label %l5 + +l4: + call void @j() + ret void + +l5: + call void @k() + ret void +; CHECK: } +} + + ; CHECK: attributes [[NOD]] = { noduplicate } +; CHECK: attributes [[CON]] = { convergent } -- 2.34.1