From 9f064354cef7a35cb438e415c47225399d99922f Mon Sep 17 00:00:00 2001
From: Prakalp Srivastava <psrivas2@illinois.edu>
Date: Sun, 20 Mar 2016 14:32:20 -0500
Subject: [PATCH] Added support for umin and umax visc intrinsics

---
 llvm/include/llvm/IR/IntrinsicsVISC.td        |  8 ++++
 .../DFG2LLVM_NVPTX/DFG2LLVM_NVPTX.cpp         | 39 +++++++++++++++----
 llvm/lib/Transforms/GenVISC/GenVISC.cpp       |  8 ++++
 llvm/test/VISC/parboil/common/include/visc.h  |  2 +
 .../datasets/histo/large/input/DESCRIPTION    |  2 +-
 5 files changed, 50 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/IR/IntrinsicsVISC.td b/llvm/include/llvm/IR/IntrinsicsVISC.td
index cb30dffe52..218f34d7da 100644
--- a/llvm/include/llvm/IR/IntrinsicsVISC.td
+++ b/llvm/include/llvm/IR/IntrinsicsVISC.td
@@ -205,10 +205,18 @@ let TargetPrefix = "visc" in {
   def int_visc_atomic_min: Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty],
                                     []>;
 
+  /* i32 llvm.visc.atomic.umin(i32*, i32)*/
+  def int_visc_atomic_umin: Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty],
+                                    []>;
+
   /* i32 llvm.visc.atomic.maxi32*, i32)*/
   def int_visc_atomic_max: Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty],
                                     []>;
 
+  /* i32 llvm.visc.atomic.umaxi32*, i32)*/
+  def int_visc_atomic_umax: Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty],
+                                    []>;
+
   // Atomic bitwise operations
 
   /* i32 llvm.visc.atomic.and(i32*, i32)*/
diff --git a/llvm/lib/Transforms/DFG2LLVM_NVPTX/DFG2LLVM_NVPTX.cpp b/llvm/lib/Transforms/DFG2LLVM_NVPTX/DFG2LLVM_NVPTX.cpp
index 1660493aa0..dac22fe3d8 100644
--- a/llvm/lib/Transforms/DFG2LLVM_NVPTX/DFG2LLVM_NVPTX.cpp
+++ b/llvm/lib/Transforms/DFG2LLVM_NVPTX/DFG2LLVM_NVPTX.cpp
@@ -1314,7 +1314,9 @@ void CGT_NVPTX::codeGen(DFLeafNode* N) {
       case Intrinsic::visc_atomic_sub:
       case Intrinsic::visc_atomic_xchg:
       case Intrinsic::visc_atomic_min:
+      case Intrinsic::visc_atomic_umin:
       case Intrinsic::visc_atomic_max:
+      case Intrinsic::visc_atomic_umax:
       case Intrinsic::visc_atomic_and:
       case Intrinsic::visc_atomic_or:
       case Intrinsic::visc_atomic_xor:
@@ -1694,24 +1696,40 @@ void CGT_NVPTX::transformFunctionToVoid(Function* F) {
 // 1. No stores
 // 2. Loads not dependent on getNodeInstanceID itrinsic
 
-static bool findLoadStoreUses(Value* V, std::vector<Value*>*UseList) {
- for(Value::use_iterator ui = V->use_begin(), ue = V->use_end();
+static bool findLoadStoreUses(Value* V, std::vector<Value*>*UseList, std::vector<Value*>*VisitedList) {
+  if(std::find(VisitedList->begin(), VisitedList->end(), V) != VisitedList->end()) {
+    DEBUG(errs() << "\tAlready visited value: " << *V << "\n");
+    return false;
+  }
+  VisitedList->push_back(V);
+  for(Value::use_iterator ui = V->use_begin(), ue = V->use_end();
       ui != ue; ++ui) {
-    Value* I = *ui;
+    Instruction* I = dyn_cast<Instruction>(*ui);
+    if(!I) {
+      // if use is not an instruction, then skip it
+      continue;
+    }
     DEBUG(errs() << "\t" << *I << "\n");
     if(isa<LoadInst>(I)) {
       DEBUG(errs() << "\tFound load instruction: " << *I << "\n");
       DEBUG(errs() << "\tAdd to use list: " << *V << "\n");
       UseList->push_back(V);
     }
-    else if(isa<StoreInst>(I)) {
+    else if(isa<StoreInst>(I) || isa<AtomicRMWInst>(I)) {
       // found a store in use chain
-      DEBUG(errs() << "Found store instruction: " << *I << "\n");
+      errs() << "Found store/atomicrmw instruction: " << *I << "\n";
+      return true;
+    }
+    else if(BuildDFG::isViscIntrinsic(I)) {
+      // If it is an atomic intrinsic, we found a store
+      IntrinsicInst* II = dyn_cast<IntrinsicInst>(I);
+      assert(II && II->getCalledValue()->getName().startswith("llvm.visc.atomic")
+          && "Only visc atomic intrinsics can have an argument as input");
       return true;
     }
     else {
-      DEBUG(errs() << "\tTraverse use chain of: " << *I << "\n");
-      if(findLoadStoreUses(I, UseList))
+      errs() << "\tTraverse use chain of: " << *I << "\n";
+      if(findLoadStoreUses(I, UseList, VisitedList))
         return true;
     }
   }
@@ -1762,11 +1780,12 @@ static bool isDependentOnNodeInstanceID(Value* V, std::vector<Value*>*Dependence
 static bool canBePromoted(Argument* arg, Function* F) {
   errs() << "OPT: Check if Argument " << *arg << " can be changed to constant memory\n";
   std::vector<Value*> UseList;
+  std::vector<Value*> VisitedList;
   // recursively traverse use chain
   // if find a store instruction return false, everything fails, cannot be
   // promoted
   // if find a load instruction as use, add the GEP instruction to list
-  bool foundStore = findLoadStoreUses(arg, &UseList);
+  bool foundStore = findLoadStoreUses(arg, &UseList, &VisitedList);
   if(foundStore == true)
     return false;
   // See that the GEP instructions are not dependent on getNodeInstanceID
@@ -1950,8 +1969,12 @@ static AtomicRMWInst::BinOp getAtomicOp(Intrinsic::ID ID) {
     return AtomicRMWInst::Sub;
   case Intrinsic::visc_atomic_min:
     return AtomicRMWInst::Min;
+  case Intrinsic::visc_atomic_umin:
+    return AtomicRMWInst::UMin;
   case Intrinsic::visc_atomic_max:
     return AtomicRMWInst::Max;
+  case Intrinsic::visc_atomic_umax:
+    return AtomicRMWInst::UMax;
   //case Intrinsic::visc_atomic_inc: return AtomicRMWInst::Inc;
   //case Intrinsic::visc_atomic_dec: return AtomicRMWInst::Dec;
   case Intrinsic::visc_atomic_xchg:
diff --git a/llvm/lib/Transforms/GenVISC/GenVISC.cpp b/llvm/lib/Transforms/GenVISC/GenVISC.cpp
index 459dd3a721..6e532d457e 100644
--- a/llvm/lib/Transforms/GenVISC/GenVISC.cpp
+++ b/llvm/lib/Transforms/GenVISC/GenVISC.cpp
@@ -129,6 +129,8 @@ IS_VISC_CALL(atomic_inc)
 IS_VISC_CALL(atomic_dec)
 IS_VISC_CALL(atomic_min)
 IS_VISC_CALL(atomic_max)
+IS_VISC_CALL(atomic_umin)
+IS_VISC_CALL(atomic_umax)
 IS_VISC_CALL(atomic_and)
 IS_VISC_CALL(atomic_or)
 IS_VISC_CALL(atomic_xor)
@@ -1161,9 +1163,15 @@ bool GenVISC::runOnModule(Module &M) {
       if (isVISCCall_atomic_min(I)) {
         ReplaceCallWithIntrinsic(I, Intrinsic::visc_atomic_min, &toBeErased);
       }
+      if (isVISCCall_atomic_umin(I)) {
+        ReplaceCallWithIntrinsic(I, Intrinsic::visc_atomic_umin, &toBeErased);
+      }
       if (isVISCCall_atomic_max(I)) {
         ReplaceCallWithIntrinsic(I, Intrinsic::visc_atomic_max, &toBeErased);
       }
+      if (isVISCCall_atomic_umax(I)) {
+        ReplaceCallWithIntrinsic(I, Intrinsic::visc_atomic_umax, &toBeErased);
+      }
       if (isVISCCall_atomic_and(I)) {
         ReplaceCallWithIntrinsic(I, Intrinsic::visc_atomic_and, &toBeErased);
       }
diff --git a/llvm/test/VISC/parboil/common/include/visc.h b/llvm/test/VISC/parboil/common/include/visc.h
index 302001348e..29b5be348c 100644
--- a/llvm/test/VISC/parboil/common/include/visc.h
+++ b/llvm/test/VISC/parboil/common/include/visc.h
@@ -57,6 +57,8 @@ int __visc__atomic_inc(int*);
 int __visc__atomic_dec(int*);
 int __visc__atomic_min(int*, int);
 int __visc__atomic_max(int*, int);
+int __visc__atomic_umax(int*, int);
+int __visc__atomic_umin(int*, int);
 int __visc__atomic_and(int*, int);
 int __visc__atomic_or(int*, int);
 int __visc__atomic_xor(int*, int);
diff --git a/llvm/test/VISC/parboil/datasets/histo/large/input/DESCRIPTION b/llvm/test/VISC/parboil/datasets/histo/large/input/DESCRIPTION
index 8942e754cb..87567ca4a5 100755
--- a/llvm/test/VISC/parboil/datasets/histo/large/input/DESCRIPTION
+++ b/llvm/test/VISC/parboil/datasets/histo/large/input/DESCRIPTION
@@ -1,2 +1,2 @@
 Inputs: img.bin
-Parameters: -- 1000 4
+Parameters: -- 10000 4
-- 
GitLab