diff --git a/llvm/include/llvm/IR/IntrinsicsVISC.td b/llvm/include/llvm/IR/IntrinsicsVISC.td
index ab22372d80ac6ae1de89c2da6c3402fd0787e181..e0d4971f3eda620d35a764d648f94f9c84290ef4 100644
--- a/llvm/include/llvm/IR/IntrinsicsVISC.td
+++ b/llvm/include/llvm/IR/IntrinsicsVISC.td
@@ -324,5 +324,26 @@ let TargetPrefix = "visc" in {
                                                             llvm_i32_ty,
                                                             llvm_i32_ty,
                                                             llvm_i32_ty], []>;
+  def int_visc_tensor_fft: Intrinsic<[llvm_ptr_ty], [
+      llvm_ptr_ty
+  ], []>;
+  def int_visc_tensor_cosineT: Intrinsic<[llvm_ptr_ty], [
+      llvm_ptr_ty
+  ], []>;
+  def int_visc_tensor_reduce: Intrinsic<[llvm_ptr_ty], [
+      llvm_ptr_ty, llvm_i32_ty, llvm_ptrptr_ty, llvm_i32_ty
+  ], []>;
+  def int_visc_tensor_projectiveT: Intrinsic<[llvm_ptr_ty], [
+      llvm_ptr_ty, llvm_ptr_ty
+  ], []>;
+  def int_visc_tensor_map1: Intrinsic<[llvm_ptr_ty], [
+      llvm_ptr_ty, llvm_ptrptr_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty
+  ], []>;
+  def int_visc_tensor_map2: Intrinsic<[llvm_ptr_ty], [
+      llvm_ptr_ty, llvm_ptr_ty, llvm_ptrptr_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty
+  ], []>;
+  def int_visc_tensor_map3: Intrinsic<[llvm_ptr_ty], [
+      llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty, llvm_ptrptr_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty
+  ], []>;
 
 }
diff --git a/llvm/lib/Transforms/DFG2LLVM_WrapperAPI/DFG2LLVM_WrapperAPI.cpp b/llvm/lib/Transforms/DFG2LLVM_WrapperAPI/DFG2LLVM_WrapperAPI.cpp
index 7ea0c1dce23cf94385df3089c499338bec281b64..e8714c128f745d7949ce0897a57475bd070de4a5 100644
--- a/llvm/lib/Transforms/DFG2LLVM_WrapperAPI/DFG2LLVM_WrapperAPI.cpp
+++ b/llvm/lib/Transforms/DFG2LLVM_WrapperAPI/DFG2LLVM_WrapperAPI.cpp
@@ -707,6 +707,67 @@ void CodeGenStateMachine::transition(IntrinsicInst *II) {
   current->transition(this, II);
 }
 
+static Constant *makeFirstArgument(Module *M, const StringRef &strRef) {
+  // All interfaces will have a string as first argument, which will be
+  // used to identify the dataflow node at runtime
+  // Create string for node name, as first argument for wrapper API call
+  Constant *ConstArray = ConstantDataArray::getString(
+      M->getContext(), strRef, true
+  );
+  GlobalVariable *GV = new GlobalVariable(
+      *M, ConstArray->getType(), true, GlobalValue::ExternalLinkage, ConstArray, ""
+  );
+  // Create GEP expression to access it
+  Constant* Int_0 = ConstantInt::get(Type::getInt32Ty(M->getContext()), 0);
+  Constant* GEPIndices[] = { Int_0, Int_0 };
+  Constant* GEPConst = ConstantExpr::getGetElementPtr(
+      GV->getType()->getPointerElementType(), GV, GEPIndices
+  );
+  return GEPConst;
+}
+
+static void pushNArgsInOrder(
+    std::vector<Value*> &args, IntrinsicInst *tensor_ii,
+    size_t count, size_t start = 0
+) {
+  for (size_t i = start; i < start + count; i++)
+    args.push_back(tensor_ii->getOperand(i));
+}
+
+static void createWrapperAndReplaceAll(
+    Module *M, Module *RtM, IntrinsicInst *TensorII, std::vector<Value*> &args, 
+    const std::string &name
+) {
+  // Create wrapper API runtime function call
+  // Appropriately set the name of the function of the runtime that you
+  // want to call
+  // Note: the Constant * is what we need to pass to the callInst.
+  // This name does not have to match, but does so for similarity.
+  StringRef name_str = StringRef(name);
+  Constant* wrapper_func = M->getOrInsertFunction(
+      name_str,
+      RtM->getFunction(name_str)->getFunctionType()
+  );
+  CallInst* CI = CallInst::Create(
+      wrapper_func, args, "", TensorII
+  );
+  // We can replace the call to hpvm.tensor.xxx with the runtime call
+  TensorII->replaceAllUsesWith(CI);
+}
+
+static void codeGenCommonRoutine(
+    Module *M, Module *RtM, Function *F, IntrinsicInst *TensorII,
+    std::vector<Value*> &args, const std::string &name, const StringRef &strRef,
+    size_t n_inorder_args
+) {
+    DEBUG(errs() << F->getName());
+    // Create argument list for the runtime call - stored in Args
+    args.push_back(makeFirstArgument(M, strRef));
+    pushNArgsInOrder(args, TensorII, n_inorder_args);
+    // Done with argument list.
+    createWrapperAndReplaceAll(M, RtM, TensorII, args, name);
+}
+
 void CodeGenStateMachine::codeGen(DFNode *N, Function *F, const StringRef &strRef,
                                   InPlaceDFGAnalysis::InPlaceDFGParameter &IPP) {
 
@@ -1122,6 +1183,41 @@ errs() << "TensorII: " << *TensorII << "\n";
         TensorII->replaceAllUsesWith(TensorII->getOperand(0));
       }
       break;
+      case Intrinsic::visc_tensor_fft:
+      {
+        codeGenCommonRoutine(M, RtM, F, TensorII, Args, "wrapper_tensorFFT", strRef, 1);
+      }
+      break;
+      case Intrinsic::visc_tensor_cosineT:
+      {
+        codeGenCommonRoutine(M, RtM, F, TensorII, Args, "wrapper_tensor_cosineT", strRef, 1);
+      }
+      break;
+      case Intrinsic::visc_tensor_reduce:
+      {
+        codeGenCommonRoutine(M, RtM, F, TensorII, Args, "wrapper_tensor_reduce", strRef, 4);
+      }
+      break;
+      case Intrinsic::visc_tensor_projectiveT:
+      {
+        codeGenCommonRoutine(M, RtM, F, TensorII, Args, "wrapper_tensor_projectiveT", strRef, 2);
+      }
+      break;
+      case Intrinsic::visc_tensor_map1:
+      {
+        codeGenCommonRoutine(M, RtM, F, TensorII, Args, "wrapper_tensor_map1", strRef, 5);
+      }
+      break;
+      case Intrinsic::visc_tensor_map2:
+      {
+        codeGenCommonRoutine(M, RtM, F, TensorII, Args, "wrapper_tensor_map2", strRef, 6);
+      }
+      break;
+      case Intrinsic::visc_tensor_map3:
+      {
+        codeGenCommonRoutine(M, RtM, F, TensorII, Args, "wrapper_tensor_map3", strRef, 7);
+      }
+      break;
 /*
       case Intrinsic::visc_image_fft_transform:
       { // llvm.hpvm.image.fft.transform - Or another image intrinsic
diff --git a/llvm/lib/Transforms/GenVISC/GenVISC.cpp b/llvm/lib/Transforms/GenVISC/GenVISC.cpp
index faab312087eade9f5d1e622555de270260f3259d..9e41ca494a4eb6495e0fc79a815abebfc2d3bbba 100644
--- a/llvm/lib/Transforms/GenVISC/GenVISC.cpp
+++ b/llvm/lib/Transforms/GenVISC/GenVISC.cpp
@@ -177,6 +177,14 @@ IS_VISC_CALL(tensor_clipped_relu)
 IS_VISC_CALL(tensor_tanh)
 IS_VISC_CALL(tensor_sigmoid)
 IS_VISC_CALL(tensor_softmax)
+// Image processing tensor operators
+IS_VISC_CALL(tensor_fft)
+IS_VISC_CALL(tensor_cosineT)
+IS_VISC_CALL(tensor_reduce)
+IS_VISC_CALL(tensor_projectiveT)
+IS_VISC_CALL(tensor_map1)
+IS_VISC_CALL(tensor_map2)
+IS_VISC_CALL(tensor_map3)
 
 // Return the constant integer represented by value V
 static unsigned getNumericValue(Value* V) {
@@ -1308,6 +1316,27 @@ bool GenVISC::runOnModule(Module &M) {
       if (isVISCCall_tensor_softmax(I)) {
         ReplaceCallWithIntrinsic(I, Intrinsic::visc_tensor_softmax, &toBeErased);
       }
+      if (isVISCCall_tensor_fft(I)) {
+        ReplaceCallWithIntrinsic(I, Intrinsic::visc_tensor_fft, &toBeErased);
+      }
+      if (isVISCCall_tensor_cosineT(I)) {
+        ReplaceCallWithIntrinsic(I, Intrinsic::visc_tensor_cosineT, &toBeErased);
+      }
+      if (isVISCCall_tensor_reduce(I)) {
+        ReplaceCallWithIntrinsic(I, Intrinsic::visc_tensor_reduce, &toBeErased);
+      }
+      if (isVISCCall_tensor_projectiveT(I)) {
+        ReplaceCallWithIntrinsic(I, Intrinsic::visc_tensor_projectiveT, &toBeErased);
+      }
+      if (isVISCCall_tensor_map1(I)) {
+        ReplaceCallWithIntrinsic(I, Intrinsic::visc_tensor_map1, &toBeErased);
+      }
+      if (isVISCCall_tensor_map2(I)) {
+        ReplaceCallWithIntrinsic(I, Intrinsic::visc_tensor_map2, &toBeErased);
+      }
+      if (isVISCCall_tensor_map3(I)) {
+        ReplaceCallWithIntrinsic(I, Intrinsic::visc_tensor_map3, &toBeErased);
+      }
     }
 
     // Erase the __visc__node calls
diff --git a/llvm/test/VISC/DNN_Benchmarks/common/include/visc.h b/llvm/test/VISC/DNN_Benchmarks/common/include/visc.h
index ab4787ffa221e225e354e3fed470dbe632a090c4..095b3d6f89a670b16467db4d0e695adb2fe207d6 100644
--- a/llvm/test/VISC/DNN_Benchmarks/common/include/visc.h
+++ b/llvm/test/VISC/DNN_Benchmarks/common/include/visc.h
@@ -101,6 +101,14 @@ void* __visc__tensor_pool_mean(void*, int, int, int, int, int, int);
 void* __visc__tensor_relu(void*);
 void* __visc__tensor_tanh(void*);
 void* __visc__tensor_softmax(void*);
+// Tensor ops for image processing
+void* __visc__tensor_fft(void*);
+void* __visc__tensor_cosineT(void*);
+void* __visc__tensor_reduce(void*, int, void**, int);
+void* __visc__tensor_projectiveT(void*, void*);
+void* __visc__tensor_map1(void*, void**, int, int, int);
+void* __visc__tensor_map2(void*, void*, void**, int, int, int);
+void* __visc__tensor_map3(void*, void*, void*, void**, int, int, int);
 
 #include <unistd.h>