From 94603e96fea98148fd614f74eb69752dfcc0dd65 Mon Sep 17 00:00:00 2001 From: Yifan Zhao <yifanz16@illinois.edu> Date: Sun, 20 Oct 2019 20:30:49 -0500 Subject: [PATCH] Added intrinsics for image processing --- llvm/include/llvm/IR/IntrinsicsVISC.td | 21 ++++ .../DFG2LLVM_WrapperAPI.cpp | 96 +++++++++++++++++++ llvm/lib/Transforms/GenVISC/GenVISC.cpp | 29 ++++++ .../VISC/DNN_Benchmarks/common/include/visc.h | 8 ++ 4 files changed, 154 insertions(+) diff --git a/llvm/include/llvm/IR/IntrinsicsVISC.td b/llvm/include/llvm/IR/IntrinsicsVISC.td index ab22372d80..e0d4971f3e 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 7ea0c1dce2..e8714c128f 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 faab312087..9e41ca494a 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 ab4787ffa2..095b3d6f89 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> -- GitLab