Merge remote-tracking branch 'origin/master' into feature_use_module_based_dispatch_instead_of_pfe
# Conflicts: # src/hip_module.cpp
This commit is contained in:
+6
-1
@@ -8,6 +8,11 @@ We have attempted to document known bugs and limitations - in particular the [HI
|
||||
|
||||
## Revision History:
|
||||
|
||||
===================================================================================================
|
||||
Release: 1.5
|
||||
Date:
|
||||
- HIP texture support equivalent to CUDA texture driver APIs
|
||||
|
||||
===================================================================================================
|
||||
Release: 1.4
|
||||
Date: 2017.10.06
|
||||
@@ -23,7 +28,7 @@ Date: 2017.10.06
|
||||
Release: 1.3
|
||||
Date: 2017.08.16
|
||||
- hipcc now auto-detects amdgcn arch. No need to specify the arch when building for same system.
|
||||
- HIP texture support
|
||||
- HIP texture support (run-time APIs)
|
||||
- Implemented __threadfence_support
|
||||
- Improvements in HIP context management logic
|
||||
- Bug fixes in several APIs including hipDeviceGetPCIBusId, hipEventDestroy, hipMemcpy2DAsync
|
||||
|
||||
@@ -231,3 +231,45 @@ int main(){
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## HIP Module and Texture Driver API
|
||||
|
||||
HIP supports texture driver APIs however texture reference should be declared in host scope. Following code explains the use of texture reference for __HIP_PLATFORM_HCC__ platform.
|
||||
|
||||
```
|
||||
// Code to generate code object
|
||||
|
||||
#include "hip/hip_runtime.h"
|
||||
extern texture<float, 2, hipReadModeElementType> tex;
|
||||
|
||||
__global__ void tex2dKernel(hipLaunchParm lp, float* outputData,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
int x = hipBlockIdx_x*hipBlockDim_x + hipThreadIdx_x;
|
||||
int y = hipBlockIdx_y*hipBlockDim_y + hipThreadIdx_y;
|
||||
outputData[y*width + x] = tex2D(tex, x, y);
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
// Host code:
|
||||
|
||||
texture<float, 2, hipReadModeElementType> tex;
|
||||
|
||||
void myFunc ()
|
||||
{
|
||||
// ...
|
||||
|
||||
textureReference* texref;
|
||||
hipModuleGetTexRef(&texref, Module1, "tex");
|
||||
hipTexRefSetAddressMode(texref, 0, hipAddressModeWrap);
|
||||
hipTexRefSetAddressMode(texref, 1, hipAddressModeWrap);
|
||||
hipTexRefSetFilterMode(texref, hipFilterModePoint);
|
||||
hipTexRefSetFlags(texref, 0);
|
||||
hipTexRefSetFormat(texref, HIP_AD_FORMAT_FLOAT, 1);
|
||||
hipTexRefSetArray(texref, array, HIP_TRSA_OVERRIDE_FORMAT);
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
@@ -465,34 +465,36 @@ a performance impact.
|
||||
|
||||
### Textures and Cache Control
|
||||
|
||||
>Texture support is under-development and not yet supported by HIP.
|
||||
|
||||
Compute programs sometimes use textures either to access dedicated texture caches or to use the texture-sampling hardware for interpolation and clamping. The former approach uses simple point samplers with linear interpolation, essentially only reading a single point. The latter approach uses the sampler hardware to interpolate and combine multiple
|
||||
point samples. AMD hardware, as well as recent competing hardware,
|
||||
has a unified texture/L1 cache, so it no longer has a dedicated texture cache. But the nvcc path often caches global loads in the L2 cache, and some programs may benefit from explicit control of the L1 cache contents. We recommend the __ldg instruction for this purpose.
|
||||
|
||||
HIP currently lacks texture support; a future revision will add this capability. Also, AMD compilers currently load all data into both the L1 and L2 caches, so __ldg is treated as a no-op.
|
||||
AMD compilers currently load all data into both the L1 and L2 caches, so __ldg is treated as a no-op.
|
||||
|
||||
We recommend the following for functional portability:
|
||||
|
||||
- For programs that use textures only to benefit from improved caching, use the __ldg instruction
|
||||
- Alternatively, use conditional compilation (see [Identify HIP Target Platform](#identify-hip-target-platform))
|
||||
- For the `__HIP_PLATFORM_NVCC__` path, use the full texture path
|
||||
- For the `__HIP_PLATFORM_HCC__` path, pass an additional pointer to the kernel and reference it using regular device memory-load instructions rather than texture loads. Some applications may already take this step, since it allows experimentation with caching behavior.
|
||||
- Programs that use texture object APIs, work well on HIP
|
||||
- For program that use texture reference APIs, use conditional compilation (see [Identify HIP Target Platform](#identify-hip-target-platform))
|
||||
- For the `__HIP_PLATFORM_HCC__` path, pass an additional argument to the kernel and in texture fetch API inside kernel as shown below:-
|
||||
|
||||
```
|
||||
texture<float, 1, cudaReadModeElementType> t_features;
|
||||
texture<float, 2, hipReadModeElementType> tex;
|
||||
|
||||
void __global__ MyKernel(float *d_features /* pass pointer parameter, if not already available */...)
|
||||
{
|
||||
// ...
|
||||
|
||||
#ifdef __HIP_PLATFORM_NVCC__
|
||||
float tval = tex1Dfetch(t_features,addr);
|
||||
#else
|
||||
float tval = d_features[addr];
|
||||
__global__ void tex2DKernel(float* outputData,
|
||||
#ifdef __HIP_PLATFORM_HCC__
|
||||
hipTextureObject_t textureObject,
|
||||
#endif
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
int x = blockIdx.x*blockDim.x + threadIdx.x;
|
||||
int y = blockIdx.y*blockDim.y + threadIdx.y;
|
||||
#ifdef __HIP_PLATFORM_HCC__
|
||||
outputData[y*width + x] = tex2D(tex, textureObject, x, y);
|
||||
#else
|
||||
outputData[y*width + x] = tex2D(tex, x, y);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// Host code:
|
||||
@@ -500,23 +502,15 @@ void myFunc ()
|
||||
{
|
||||
// ...
|
||||
|
||||
#ifdef __HIP_PLATFORM_NVCC__
|
||||
cudaChannelFormatDesc chDesc0 = cudaCreateChannelDesc<float>();
|
||||
t_features.filterMode = cudaFilterModePoint;
|
||||
t_features.normalized = false;
|
||||
t_features.channelDesc = chDesc0;
|
||||
|
||||
cudaBindTexture(NULL, &t_features, d_features, &chDesc0, npoints*nfeatures*sizeof(float));
|
||||
#ifdef __HIP_PLATFORM_HCC__
|
||||
hipLaunchKernelGGL(tex2DKernel, dim3(dimGrid), dim3(dimBlock), 0, 0, dData, tex.textureObject, width, height);
|
||||
#else
|
||||
hipLaunchKernelGGL(tex2DKernel, dim3(dimGrid), dim3(dimBlock), 0, 0, dData, width, height);
|
||||
#endif
|
||||
|
||||
|
||||
```
|
||||
|
||||
Additionally, many of the Rodinia benchmarks demonstrate how to modify hipified programs so that textures are not required - search for USE_TEXTURES define in the rodinia source directory.
|
||||
For example, [here
|
||||
|
||||
|
||||
Cuda programs that employ sampler hardware must either wait for hcc texture support or use more-sophisticated workarounds.
|
||||
|
||||
## More Tips
|
||||
### HIPTRACE Mode
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "ArgParse.h"
|
||||
|
||||
cl::OptionCategory ToolTemplateCategory("CUDA to HIP source translator options");
|
||||
|
||||
cl::opt<std::string> OutputFilename("o",
|
||||
cl::desc("Output filename"),
|
||||
cl::value_desc("filename"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
cl::opt<bool> Inplace("inplace",
|
||||
cl::desc("Modify input file inplace, replacing input with hipified output, save backup in .prehip file"),
|
||||
cl::value_desc("inplace"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
cl::opt<bool> NoBackup("no-backup",
|
||||
cl::desc("Don't create a backup file for the hipified source"),
|
||||
cl::value_desc("no-backup"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
cl::opt<bool> NoOutput("no-output",
|
||||
cl::desc("Don't write any translated output to stdout"),
|
||||
cl::value_desc("no-output"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
cl::opt<bool> PrintStats("print-stats",
|
||||
cl::desc("Print translation statistics"),
|
||||
cl::value_desc("print-stats"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
cl::opt<std::string> OutputStatsFilename("o-stats",
|
||||
cl::desc("Output filename for statistics"),
|
||||
cl::value_desc("filename"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
cl::opt<bool> Examine("examine",
|
||||
cl::desc("Combines -no-output and -print-stats options"),
|
||||
cl::value_desc("examine"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
cl::extrahelp CommonHelp(ct::CommonOptionsParser::HelpMessage);
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
namespace cl = llvm::cl;
|
||||
namespace ct = clang::tooling;
|
||||
|
||||
extern cl::OptionCategory ToolTemplateCategory;
|
||||
|
||||
extern cl::opt<std::string> OutputFilename;
|
||||
extern cl::opt<bool> Inplace;
|
||||
extern cl::opt<bool> NoBackup;
|
||||
extern cl::opt<bool> NoOutput;
|
||||
extern cl::opt<bool> PrintStats;
|
||||
extern cl::opt<std::string> OutputStatsFilename;
|
||||
extern cl::opt<bool> Examine;
|
||||
|
||||
extern cl::extrahelp CommonHelp;
|
||||
@@ -2684,7 +2684,6 @@ const std::map<llvm::StringRef, hipCounter>& CUDA_RENAMES_MAP() {
|
||||
|
||||
// First run, so compute the union map.
|
||||
ret = CUDA_IDENTIFIER_MAP;
|
||||
ret.insert(CUDA_INCLUDE_MAP.begin(), CUDA_INCLUDE_MAP.end());
|
||||
ret.insert(CUDA_TYPE_NAME_MAP.begin(), CUDA_TYPE_NAME_MAP.end());
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -1,861 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015-2017 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* @file Cuda2Hip.cpp
|
||||
*
|
||||
* This file is compiled and linked into clang based hipify tool.
|
||||
*/
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Lex/MacroArgs.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/PPCallbacks.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Rewrite/Core/Rewriter.h"
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "clang/Tooling/Refactoring.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "CUDA2HipMap.h"
|
||||
#include "LLVMCompat.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace clang::ast_matchers;
|
||||
using namespace clang::tooling;
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "cuda2hip"
|
||||
|
||||
|
||||
// Set up the command line options
|
||||
static cl::OptionCategory ToolTemplateCategory("CUDA to HIP source translator options");
|
||||
|
||||
static cl::opt<std::string> OutputFilename("o",
|
||||
cl::desc("Output filename"),
|
||||
cl::value_desc("filename"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
static cl::opt<bool> Inplace("inplace",
|
||||
cl::desc("Modify input file inplace, replacing input with hipified output, save backup in .prehip file"),
|
||||
cl::value_desc("inplace"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
static cl::opt<bool> NoBackup("no-backup",
|
||||
cl::desc("Don't create a backup file for the hipified source"),
|
||||
cl::value_desc("no-backup"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
static cl::opt<bool> NoOutput("no-output",
|
||||
cl::desc("Don't write any translated output to stdout"),
|
||||
cl::value_desc("no-output"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
static cl::opt<bool> PrintStats("print-stats",
|
||||
cl::desc("Print translation statistics"),
|
||||
cl::value_desc("print-stats"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
static cl::opt<std::string> OutputStatsFilename("o-stats",
|
||||
cl::desc("Output filename for statistics"),
|
||||
cl::value_desc("filename"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
static cl::opt<bool> Examine("examine",
|
||||
cl::desc("Combines -no-output and -print-stats options"),
|
||||
cl::value_desc("examine"),
|
||||
cl::cat(ToolTemplateCategory));
|
||||
|
||||
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
|
||||
|
||||
class Cuda2Hip {
|
||||
public:
|
||||
Cuda2Hip(Replacements& R, const std::string &srcFileName) :
|
||||
Replace(R), mainFileName(srcFileName) {}
|
||||
|
||||
enum msgTypes {
|
||||
HIPIFY_ERROR = 0,
|
||||
HIPIFY_WARNING
|
||||
};
|
||||
|
||||
std::string getMsgType(msgTypes type) {
|
||||
switch (type) {
|
||||
case HIPIFY_ERROR: return "error";
|
||||
default:
|
||||
case HIPIFY_WARNING: return "warning";
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
Replacements& Replace;
|
||||
std::string mainFileName;
|
||||
|
||||
virtual void insertReplacement(const Replacement &rep, const FullSourceLoc &fullSL) {
|
||||
llcompat::insertReplacement(Replace, rep);
|
||||
if (PrintStats) {
|
||||
rep.getLength();
|
||||
Statistics::current().lineTouched(fullSL.getExpansionLineNumber());
|
||||
Statistics::current().bytesChanged(rep.getLength());
|
||||
}
|
||||
}
|
||||
void insertHipHeaders(Cuda2Hip *owner, const SourceManager &SM) {
|
||||
if (Replace.size() > 0) {
|
||||
std::string repName = "#include <hip/hip_runtime.h>";
|
||||
Statistics::current().incrementCounter({repName, ConvTypes::CONV_INCLUDE_CUDA_MAIN_H, ApiTypes::API_RUNTIME}, "#include <cuda>");
|
||||
SourceLocation sl = SM.getLocForStartOfFile(SM.getMainFileID());
|
||||
FullSourceLoc fullSL(sl, SM);
|
||||
Replacement Rep(SM, sl, 0, repName + "\n");
|
||||
insertReplacement(Rep, fullSL);
|
||||
}
|
||||
}
|
||||
|
||||
void printHipifyMessage(const SourceManager &SM, const SourceLocation &sl, const std::string &message, msgTypes msgType = HIPIFY_WARNING) {
|
||||
FullSourceLoc fullSL(sl, SM);
|
||||
llvm::errs() << "[HIPIFY] " << getMsgType(msgType) << ": " << mainFileName << ":" << fullSL.getExpansionLineNumber() << ":" << fullSL.getExpansionColumnNumber() << ": " << message << "\n";
|
||||
}
|
||||
|
||||
void processString(StringRef s, SourceManager &SM, SourceLocation start) {
|
||||
size_t begin = 0;
|
||||
while ((begin = s.find("cu", begin)) != StringRef::npos) {
|
||||
const size_t end = s.find_first_of(" ", begin + 4);
|
||||
StringRef name = s.slice(begin, end);
|
||||
const auto found = CUDA_RENAMES_MAP().find(name);
|
||||
if (found != CUDA_RENAMES_MAP().end()) {
|
||||
StringRef repName = found->second.hipName;
|
||||
hipCounter counter = {"[string literal]", ConvTypes::CONV_LITERAL, ApiTypes::API_RUNTIME, found->second.unsupported};
|
||||
Statistics::current().incrementCounter(counter, name.str());
|
||||
if (!counter.unsupported) {
|
||||
SourceLocation sl = start.getLocWithOffset(begin + 1);
|
||||
Replacement Rep(SM, sl, name.size(), repName);
|
||||
FullSourceLoc fullSL(sl, SM);
|
||||
insertReplacement(Rep, fullSL);
|
||||
}
|
||||
}
|
||||
|
||||
if (end == StringRef::npos) {
|
||||
break;
|
||||
}
|
||||
begin = end + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Cuda2HipCallback;
|
||||
|
||||
class HipifyPPCallbacks : public PPCallbacks, public SourceFileCallbacks, public Cuda2Hip {
|
||||
public:
|
||||
HipifyPPCallbacks(Replacements& R, const std::string &mainFileName)
|
||||
: Cuda2Hip(R, mainFileName) {}
|
||||
|
||||
virtual bool handleBeginSource(CompilerInstance &CI
|
||||
#if LLVM_VERSION_MAJOR <= 4
|
||||
, StringRef Filename
|
||||
#endif
|
||||
) override {
|
||||
Preprocessor &PP = CI.getPreprocessor();
|
||||
SourceManager &SM = CI.getSourceManager();
|
||||
setSourceManager(&SM);
|
||||
PP.addPPCallbacks(std::unique_ptr<HipifyPPCallbacks>(this));
|
||||
setPreprocessor(&PP);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void handleEndSource() override;
|
||||
|
||||
virtual void InclusionDirective(SourceLocation hash_loc,
|
||||
const Token &include_token,
|
||||
StringRef file_name, bool is_angled,
|
||||
CharSourceRange filename_range,
|
||||
const FileEntry *file, StringRef search_path,
|
||||
StringRef relative_path,
|
||||
const clang::Module *imported) override {
|
||||
if (!_sm->isWrittenInMainFile(hash_loc) || !is_angled) {
|
||||
return; // We're looking to rewrite angle-includes in the main file to point to hip.
|
||||
}
|
||||
|
||||
const auto found = CUDA_INCLUDE_MAP.find(file_name);
|
||||
if (found == CUDA_INCLUDE_MAP.end()) {
|
||||
// Not a CUDA include - don't touch it.
|
||||
return;
|
||||
}
|
||||
|
||||
Statistics::current().incrementCounter(found->second, file_name.str());
|
||||
if (found->second.unsupported) {
|
||||
// An unsupported CUDA header? Oh dear. Print a warning.
|
||||
printHipifyMessage(*_sm, hash_loc, "Unsupported CUDA header used: " + file_name.str());
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef repName = found->second.hipName;
|
||||
DEBUG(dbgs() << "Include file found: " << file_name << "\n"
|
||||
<< "SourceLocation: "
|
||||
<< filename_range.getBegin().printToString(*_sm) << "\n"
|
||||
<< "Will be replaced with " << repName << "\n");
|
||||
SourceLocation sl = filename_range.getBegin();
|
||||
SourceLocation sle = filename_range.getEnd();
|
||||
const char *B = _sm->getCharacterData(sl);
|
||||
const char *E = _sm->getCharacterData(sle);
|
||||
SmallString<128> tmpData;
|
||||
Replacement Rep(*_sm, sl, E - B, Twine("<" + repName + ">").toStringRef(tmpData));
|
||||
FullSourceLoc fullSL(sl, *_sm);
|
||||
insertReplacement(Rep, fullSL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at, and consider altering, a given token.
|
||||
*
|
||||
* If it's not a CUDA identifier, nothing happens.
|
||||
* If it's an unsupported CUDA identifier, a warning is emitted.
|
||||
* Otherwise, the source file is updated with the corresponding hipification.
|
||||
*/
|
||||
void RewriteToken(Token t) {
|
||||
// String literals containing CUDA references need fixing...
|
||||
if (t.is(tok::string_literal)) {
|
||||
StringRef s(t.getLiteralData(), t.getLength());
|
||||
processString(unquoteStr(s), *_sm, t.getLocation());
|
||||
return;
|
||||
} else if (!t.isAnyIdentifier()) {
|
||||
// If it's neither a string nor an identifier, we don't care.
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef name = t.getIdentifierInfo()->getName();
|
||||
const auto found = CUDA_RENAMES_MAP().find(name);
|
||||
if (found == CUDA_RENAMES_MAP().end()) {
|
||||
// So it's an identifier, but not CUDA? Boring.
|
||||
return;
|
||||
}
|
||||
Statistics::current().incrementCounter(found->second, name.str());
|
||||
|
||||
SourceLocation sl = t.getLocation();
|
||||
if (found->second.unsupported) {
|
||||
// An unsupported identifier? Curses! Warn the user.
|
||||
printHipifyMessage(*_sm, sl, "Unsupported CUDA identifier used: " + name.str());
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef repName = found->second.hipName;
|
||||
Replacement Rep(*_sm, sl, name.size(), repName);
|
||||
FullSourceLoc fullSL(sl, *_sm);
|
||||
insertReplacement(Rep, fullSL);
|
||||
}
|
||||
|
||||
virtual void MacroDefined(const Token &MacroNameTok,
|
||||
const MacroDirective *MD) override {
|
||||
if (!_sm->isWrittenInMainFile(MD->getLocation()) ||
|
||||
MD->getKind() != MacroDirective::MD_Define) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto T : MD->getMacroInfo()->tokens()) {
|
||||
RewriteToken(T);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void MacroExpands(const Token &MacroNameTok,
|
||||
const MacroDefinition &MD, SourceRange Range,
|
||||
const MacroArgs *Args) override {
|
||||
|
||||
if (!_sm->isWrittenInMainFile(MacroNameTok.getLocation())) {
|
||||
return; // Macros in headers are not our concern.
|
||||
}
|
||||
|
||||
// Is the macro itself a CUDA identifier? If so, rewrite it
|
||||
RewriteToken(MacroNameTok);
|
||||
|
||||
// If it's a macro with arguments, rewrite all the arguments as hip, too.
|
||||
for (unsigned int i = 0; Args && i < MD.getMacroInfo()->GET_NUM_ARGS(); i++) {
|
||||
std::vector<Token> toks;
|
||||
// Code below is a kind of stolen from 'MacroArgs::getPreExpArgument'
|
||||
// to workaround the 'const' MacroArgs passed into this hook.
|
||||
const Token *start = Args->getUnexpArgument(i);
|
||||
size_t len = Args->getArgLength(start) + 1;
|
||||
llcompat::EnterPreprocessorTokenStream(*_pp, start, len, false);
|
||||
|
||||
do {
|
||||
toks.push_back(Token());
|
||||
Token &tk = toks.back();
|
||||
_pp->Lex(tk);
|
||||
} while (toks.back().isNot(tok::eof));
|
||||
|
||||
_pp->RemoveTopOfLexerStack();
|
||||
// end of stolen code
|
||||
|
||||
for (auto tok : toks) {
|
||||
RewriteToken(tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EndOfMainFile() override {}
|
||||
|
||||
void setSourceManager(SourceManager *sm) { _sm = sm; }
|
||||
void setPreprocessor(Preprocessor *pp) { _pp = pp; }
|
||||
void setMatch(Cuda2HipCallback *match) { Match = match; }
|
||||
|
||||
private:
|
||||
SourceManager *_sm = nullptr;
|
||||
Preprocessor *_pp = nullptr;
|
||||
Cuda2HipCallback *Match = nullptr;
|
||||
};
|
||||
|
||||
class Cuda2HipCallback : public MatchFinder::MatchCallback, public Cuda2Hip {
|
||||
private:
|
||||
bool cudaCall(const MatchFinder::MatchResult &Result) {
|
||||
const CallExpr *call = Result.Nodes.getNodeAs<CallExpr>("cudaCall");
|
||||
if (!call) {
|
||||
return false; // Another handler will do it.
|
||||
}
|
||||
|
||||
const FunctionDecl *funcDcl = call->getDirectCallee();
|
||||
std::string name = funcDcl->getDeclName().getAsString();
|
||||
SourceManager *SM = Result.SourceManager;
|
||||
SourceLocation sl = call->getLocStart();
|
||||
|
||||
// TODO: Make a lookup table just for functions to improve performance.
|
||||
const auto found = CUDA_IDENTIFIER_MAP.find(name);
|
||||
if (found == CUDA_IDENTIFIER_MAP.end()) {
|
||||
std::string msg = "the following reference is not handled: '" + name + "' [function call].";
|
||||
printHipifyMessage(*SM, sl, msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
const hipCounter& hipCtr = found->second;
|
||||
Statistics::current().incrementCounter(hipCtr, name);
|
||||
|
||||
if (hipCtr.unsupported) {
|
||||
return true; // Silently fail when you find an unsupported member.
|
||||
// TODO: Print a warning with the diagnostics API?
|
||||
}
|
||||
|
||||
size_t length = name.size();
|
||||
Replacement Rep(*SM, sl, length, hipCtr.hipName);
|
||||
FullSourceLoc fullSL(sl, *SM);
|
||||
insertReplacement(Rep, fullSL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SourceRange getReadRange(clang::SourceManager &SM, const SourceRange &exprRange) {
|
||||
SourceLocation begin = exprRange.getBegin();
|
||||
SourceLocation end = exprRange.getEnd();
|
||||
|
||||
bool beginSafe = !SM.isMacroBodyExpansion(begin) || Lexer::isAtStartOfMacroExpansion(begin, SM, LangOptions{});
|
||||
bool endSafe = !SM.isMacroBodyExpansion(end) || Lexer::isAtEndOfMacroExpansion(end, SM, LangOptions{});
|
||||
|
||||
if (beginSafe && endSafe) {
|
||||
return {SM.getFileLoc(begin), SM.getFileLoc(end)};
|
||||
} else {
|
||||
return {SM.getSpellingLoc(begin), SM.getSpellingLoc(end)};
|
||||
}
|
||||
}
|
||||
|
||||
SourceRange getWriteRange(clang::SourceManager &SM, const SourceRange &exprRange) {
|
||||
SourceLocation begin = exprRange.getBegin();
|
||||
SourceLocation end = exprRange.getEnd();
|
||||
|
||||
// If the range is contained within a macro, update the macro definition.
|
||||
// Otherwise, use the file location and hope for the best.
|
||||
if (!SM.isMacroBodyExpansion(begin) || !SM.isMacroBodyExpansion(end)) {
|
||||
return {SM.getFileLoc(begin), SM.getFileLoc(end)};
|
||||
}
|
||||
|
||||
return {SM.getSpellingLoc(begin), SM.getSpellingLoc(end)};
|
||||
}
|
||||
|
||||
StringRef readSourceText(clang::SourceManager& SM, const SourceRange& exprRange) {
|
||||
return Lexer::getSourceText(CharSourceRange::getTokenRange(getReadRange(SM, exprRange)), SM, LangOptions(), nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string representation of the expression `arg`, unless it's a defaulting function
|
||||
* call argument, in which case get a 0. Used for building argument lists to kernel calls.
|
||||
*/
|
||||
std::string stringifyZeroDefaultedArg(SourceManager& SM, const Expr* arg) {
|
||||
if (isa<CXXDefaultArgExpr>(arg)) {
|
||||
return "0";
|
||||
} else {
|
||||
return readSourceText(SM, arg->getSourceRange());
|
||||
}
|
||||
}
|
||||
|
||||
bool cudaLaunchKernel(const MatchFinder::MatchResult &Result) {
|
||||
StringRef refName = "cudaLaunchKernel";
|
||||
if (const CUDAKernelCallExpr *launchKernel = Result.Nodes.getNodeAs<CUDAKernelCallExpr>(refName)) {
|
||||
SmallString<40> XStr;
|
||||
raw_svector_ostream OS(XStr);
|
||||
|
||||
LangOptions DefaultLangOptions;
|
||||
SourceManager *SM = Result.SourceManager;
|
||||
|
||||
const Expr& calleeExpr = *(launchKernel->getCallee());
|
||||
OS << "hipLaunchKernelGGL(" << readSourceText(*SM, calleeExpr.getSourceRange()) << ", ";
|
||||
|
||||
// Next up are the four kernel configuration parameters, the last two of which are optional and default to zero.
|
||||
const CallExpr& config = *(launchKernel->getConfig());
|
||||
|
||||
// Copy the two dimensional arguments verbatim.
|
||||
OS << "dim3(" << readSourceText(*SM, config.getArg(0)->getSourceRange()) << "), ";
|
||||
OS << "dim3(" << readSourceText(*SM, config.getArg(1)->getSourceRange()) << "), ";
|
||||
|
||||
// The stream/memory arguments default to zero if omitted.
|
||||
OS << stringifyZeroDefaultedArg(*SM, config.getArg(2)) << ", ";
|
||||
OS << stringifyZeroDefaultedArg(*SM, config.getArg(3));
|
||||
|
||||
// If there are ordinary arguments to the kernel, just copy them verbatim into our new call.
|
||||
int numArgs = launchKernel->getNumArgs();
|
||||
if (numArgs > 0) {
|
||||
OS << ", ";
|
||||
|
||||
// Start of the first argument.
|
||||
SourceLocation argStart = launchKernel->getArg(0)->getLocStart();
|
||||
|
||||
// End of the last argument.
|
||||
SourceLocation argEnd = launchKernel->getArg(numArgs - 1)->getLocEnd();
|
||||
|
||||
OS << readSourceText(*SM, {argStart, argEnd});
|
||||
}
|
||||
|
||||
OS << ")";
|
||||
|
||||
SourceRange replacementRange = getWriteRange(*SM, {launchKernel->getLocStart(), launchKernel->getLocEnd()});
|
||||
SourceLocation launchStart = replacementRange.getBegin();
|
||||
SourceLocation launchEnd = replacementRange.getEnd();
|
||||
|
||||
size_t length = SM->getCharacterData(Lexer::getLocForEndOfToken(
|
||||
launchEnd, 0, *SM, DefaultLangOptions)) -
|
||||
SM->getCharacterData(launchStart);
|
||||
|
||||
Replacement Rep(*SM, launchStart, length, OS.str());
|
||||
FullSourceLoc fullSL(launchStart, *SM);
|
||||
insertReplacement(Rep, fullSL);
|
||||
hipCounter counter = {"hipLaunchKernelGGL", ConvTypes::CONV_KERN, ApiTypes::API_RUNTIME};
|
||||
Statistics::current().incrementCounter(counter, refName.str());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cudaBuiltin(const MatchFinder::MatchResult &Result) {
|
||||
if (const MemberExpr *threadIdx = Result.Nodes.getNodeAs<MemberExpr>("cudaBuiltin")) {
|
||||
if (const OpaqueValueExpr *refBase =
|
||||
dyn_cast<OpaqueValueExpr>(threadIdx->getBase())) {
|
||||
if (const DeclRefExpr *declRef =
|
||||
dyn_cast<DeclRefExpr>(refBase->getSourceExpr())) {
|
||||
SourceLocation sl = threadIdx->getLocStart();
|
||||
SourceManager *SM = Result.SourceManager;
|
||||
StringRef name = declRef->getDecl()->getName();
|
||||
StringRef memberName = threadIdx->getMemberDecl()->getName();
|
||||
size_t pos = memberName.find_first_not_of("__fetch_builtin_");
|
||||
memberName = memberName.slice(pos, memberName.size());
|
||||
SmallString<128> tmpData;
|
||||
name = Twine(name + "." + memberName).toStringRef(tmpData);
|
||||
|
||||
// TODO: Make a lookup table just for builtins to improve performance.
|
||||
const auto found = CUDA_IDENTIFIER_MAP.find(name);
|
||||
if (found != CUDA_IDENTIFIER_MAP.end()) {
|
||||
Statistics::current().incrementCounter(found->second, name.str());
|
||||
if (!found->second.unsupported) {
|
||||
StringRef repName = found->second.hipName;
|
||||
Replacement Rep(*SM, sl, name.size(), repName);
|
||||
FullSourceLoc fullSL(sl, *SM);
|
||||
insertReplacement(Rep, fullSL);
|
||||
}
|
||||
} else {
|
||||
std::string msg = "the following reference is not handled: '" + name.str() + "' [builtin].";
|
||||
printHipifyMessage(*SM, sl, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cudaEnumConstantRef(const MatchFinder::MatchResult &Result) {
|
||||
if (const DeclRefExpr *enumConstantRef = Result.Nodes.getNodeAs<DeclRefExpr>("cudaEnumConstantRef")) {
|
||||
StringRef name = enumConstantRef->getDecl()->getName();
|
||||
SourceLocation sl = enumConstantRef->getLocStart();
|
||||
SourceManager *SM = Result.SourceManager;
|
||||
|
||||
// TODO: Make a lookup table just for enum values to improve performance.
|
||||
const auto found = CUDA_IDENTIFIER_MAP.find(name);
|
||||
if (found != CUDA_IDENTIFIER_MAP.end()) {
|
||||
Statistics::current().incrementCounter(found->second, name.str());
|
||||
if (!found->second.unsupported) {
|
||||
StringRef repName = found->second.hipName;
|
||||
Replacement Rep(*SM, sl, name.size(), repName);
|
||||
FullSourceLoc fullSL(sl, *SM);
|
||||
insertReplacement(Rep, fullSL);
|
||||
}
|
||||
} else {
|
||||
std::string msg = "the following reference is not handled: '" + name.str() + "' [enum constant ref].";
|
||||
printHipifyMessage(*SM, sl, msg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cudaType(const MatchFinder::MatchResult& Result) {
|
||||
const clang::TypeLoc* ret = Result.Nodes.getNodeAs<TypeLoc>("cudaType");
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore qualifiers - they don't alter our decision to rename.
|
||||
clang::UnqualTypeLoc tl = ret->getUnqualifiedLoc();
|
||||
const Type& typeObject = *(tl.getTypePtr());
|
||||
|
||||
std::string typeName = tl.getType().getAsString();
|
||||
|
||||
// Irritatingly, enum/struct types are identified as `enum/struct <something>`, and unlike most compound
|
||||
// types (such as pointers or references), there isn't another type node inside. So we have
|
||||
// to make do with what we've got. There's probably a better way of doing this...
|
||||
if (typeObject.isEnumeralType()) {
|
||||
removePrefixIfPresent(typeName, "enum ");
|
||||
}
|
||||
if (typeObject.isStructureType()) {
|
||||
removePrefixIfPresent(typeName, "struct ");
|
||||
}
|
||||
|
||||
// Do we have a replacement for this type?
|
||||
const auto found = CUDA_TYPE_NAME_MAP.find(typeName);
|
||||
if (found == CUDA_TYPE_NAME_MAP.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SourceManager &SM = *(Result.SourceManager);
|
||||
|
||||
// Start of the type expression to replace.
|
||||
SourceLocation sl = tl.getBeginLoc();
|
||||
|
||||
const hipCounter& hipCtr = found->second;
|
||||
if (hipCtr.unsupported) {
|
||||
printHipifyMessage(SM, sl, "Unsupported CUDA '" + typeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Apply the rename!
|
||||
Replacement Rep(SM, sl, typeName.size(), hipCtr.hipName);
|
||||
FullSourceLoc fullSL(sl, SM);
|
||||
insertReplacement(Rep, fullSL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cudaSharedIncompleteArrayVar(const MatchFinder::MatchResult &Result) {
|
||||
StringRef refName = "cudaSharedIncompleteArrayVar";
|
||||
if (const VarDecl *sharedVar = Result.Nodes.getNodeAs<VarDecl>(refName)) {
|
||||
// Example: extern __shared__ uint sRadix1[];
|
||||
if (sharedVar->hasExternalFormalLinkage()) {
|
||||
QualType QT = sharedVar->getType();
|
||||
std::string typeName;
|
||||
if (QT->isIncompleteArrayType()) {
|
||||
const ArrayType *AT = QT.getTypePtr()->getAsArrayTypeUnsafe();
|
||||
QT = AT->getElementType();
|
||||
if (QT.getTypePtr()->isBuiltinType()) {
|
||||
QT = QT.getCanonicalType();
|
||||
const BuiltinType *BT = dyn_cast<BuiltinType>(QT);
|
||||
if (BT) {
|
||||
LangOptions LO;
|
||||
LO.CUDA = true;
|
||||
PrintingPolicy policy(LO);
|
||||
typeName = BT->getName(policy);
|
||||
}
|
||||
} else {
|
||||
typeName = QT.getAsString();
|
||||
}
|
||||
}
|
||||
if (!typeName.empty()) {
|
||||
SourceLocation slStart = sharedVar->getLocStart();
|
||||
SourceLocation slEnd = sharedVar->getLocEnd();
|
||||
SourceManager *SM = Result.SourceManager;
|
||||
size_t repLength = SM->getCharacterData(slEnd) - SM->getCharacterData(slStart) + 1;
|
||||
std::string varName = sharedVar->getNameAsString();
|
||||
std::string repName = "HIP_DYNAMIC_SHARED(" + typeName + ", " + varName + ")";
|
||||
Replacement Rep(*SM, slStart, repLength, repName);
|
||||
FullSourceLoc fullSL(slStart, *SM);
|
||||
insertReplacement(Rep, fullSL);
|
||||
hipCounter counter = { "HIP_DYNAMIC_SHARED", ConvTypes::CONV_MEM, ApiTypes::API_RUNTIME };
|
||||
Statistics::current().incrementCounter(counter, refName.str());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool stringLiteral(const MatchFinder::MatchResult &Result) {
|
||||
if (const clang::StringLiteral *sLiteral = Result.Nodes.getNodeAs<clang::StringLiteral>("stringLiteral")) {
|
||||
if (sLiteral->getCharByteWidth() == 1) {
|
||||
StringRef s = sLiteral->getString();
|
||||
SourceManager *SM = Result.SourceManager;
|
||||
processString(s, *SM, sLiteral->getLocStart());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
Cuda2HipCallback(Replacements& Replace, ast_matchers::MatchFinder *parent, HipifyPPCallbacks *PPCallbacks, const std::string &mainFileName)
|
||||
: Cuda2Hip(Replace, mainFileName), owner(parent), PP(PPCallbacks) {
|
||||
PP->setMatch(this);
|
||||
}
|
||||
|
||||
void run(const MatchFinder::MatchResult &Result) override {
|
||||
if (cudaType(Result)) return;
|
||||
if (cudaCall(Result)) return;
|
||||
if (cudaBuiltin(Result)) return;
|
||||
if (cudaEnumConstantRef(Result)) return;
|
||||
if (cudaLaunchKernel(Result)) return;
|
||||
if (cudaSharedIncompleteArrayVar(Result)) return;
|
||||
if (stringLiteral(Result)) return;
|
||||
}
|
||||
|
||||
private:
|
||||
ast_matchers::MatchFinder *owner;
|
||||
HipifyPPCallbacks *PP;
|
||||
};
|
||||
|
||||
void HipifyPPCallbacks::handleEndSource() {
|
||||
insertHipHeaders(Match, *_sm);
|
||||
}
|
||||
|
||||
void addAllMatchers(ast_matchers::MatchFinder &Finder, Cuda2HipCallback *Callback) {
|
||||
// Rewrite CUDA api calls to hip ones.
|
||||
Finder.addMatcher(
|
||||
callExpr(
|
||||
isExpansionInMainFile(),
|
||||
callee(
|
||||
functionDecl(
|
||||
matchesName("cu.*"),
|
||||
unless(
|
||||
// Clang generates structs with functions on them to represent things like
|
||||
// threadIdx.x. We have other logic to handle those builtins directly, so
|
||||
// we need to suppress the call-handling.
|
||||
// We can't handle those directly in the call-handler without special-casing
|
||||
// it unpleasantly, since the names of the functions are unique only per-struct.
|
||||
matchesName("__fetch_builtin.*")
|
||||
)
|
||||
)
|
||||
)
|
||||
).bind("cudaCall"),
|
||||
Callback
|
||||
);
|
||||
|
||||
// Rewrite all references to CUDA types to their corresponding hip types.
|
||||
Finder.addMatcher(
|
||||
typeLoc(
|
||||
isExpansionInMainFile()
|
||||
).bind("cudaType"),
|
||||
Callback
|
||||
);
|
||||
|
||||
// Replace references to CUDA names in string literals with the equivalent hip names.
|
||||
Finder.addMatcher(stringLiteral(isExpansionInMainFile()).bind("stringLiteral"), Callback);
|
||||
|
||||
// Replace the <<<...>>> language extension with a hip kernel launch
|
||||
Finder.addMatcher(cudaKernelCallExpr(isExpansionInMainFile()).bind("cudaLaunchKernel"), Callback);
|
||||
|
||||
// Replace cuda builtins.
|
||||
Finder.addMatcher(
|
||||
memberExpr(
|
||||
isExpansionInMainFile(),
|
||||
hasObjectExpression(
|
||||
hasType(
|
||||
cxxRecordDecl(
|
||||
matchesName("__cuda_builtin_")
|
||||
)
|
||||
)
|
||||
)
|
||||
).bind("cudaBuiltin"),
|
||||
Callback
|
||||
);
|
||||
|
||||
// Map CUDA enum _values_ to their hip equivalents.
|
||||
Finder.addMatcher(
|
||||
declRefExpr(
|
||||
isExpansionInMainFile(),
|
||||
to(
|
||||
enumConstantDecl(
|
||||
matchesName("cu.*|CU.*")
|
||||
)
|
||||
)
|
||||
).bind("cudaEnumConstantRef"),
|
||||
Callback
|
||||
);
|
||||
|
||||
Finder.addMatcher(
|
||||
varDecl(
|
||||
isExpansionInMainFile(),
|
||||
allOf(
|
||||
hasAttr(attr::CUDAShared),
|
||||
hasType(incompleteArrayType())
|
||||
)
|
||||
).bind("cudaSharedIncompleteArrayVar"),
|
||||
Callback
|
||||
);
|
||||
}
|
||||
|
||||
void copyFile(const std::string& src, const std::string& dst) {
|
||||
std::ifstream source(src, std::ios::binary);
|
||||
std::ofstream dest(dst, std::ios::binary);
|
||||
dest << source.rdbuf();
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
llcompat::PrintStackTraceOnErrorSignal();
|
||||
|
||||
CommonOptionsParser OptionsParser(argc, argv, ToolTemplateCategory, llvm::cl::OneOrMore);
|
||||
std::vector<std::string> fileSources = OptionsParser.getSourcePathList();
|
||||
std::string dst = OutputFilename;
|
||||
if (!dst.empty() && fileSources.size() > 1) {
|
||||
llvm::errs() << "[HIPIFY] conflict: -o and multiple source files are specified.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (NoOutput) {
|
||||
if (Inplace) {
|
||||
llvm::errs() << "[HIPIFY] conflict: both -no-output and -inplace options are specified.\n";
|
||||
return 1;
|
||||
}
|
||||
if (!dst.empty()) {
|
||||
llvm::errs() << "[HIPIFY] conflict: both -no-output and -o options are specified.\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Examine) {
|
||||
NoOutput = PrintStats = true;
|
||||
}
|
||||
|
||||
int Result = 0;
|
||||
|
||||
// Arguments for the Statistics print routines.
|
||||
std::unique_ptr<std::ostream> csv = nullptr;
|
||||
llvm::raw_ostream* statPrint = nullptr;
|
||||
if (!OutputStatsFilename.empty()) {
|
||||
csv = std::unique_ptr<std::ostream>(new std::ofstream(OutputStatsFilename, std::ios_base::trunc));
|
||||
}
|
||||
if (PrintStats) {
|
||||
statPrint = &llvm::errs();
|
||||
}
|
||||
|
||||
for (const auto & src : fileSources) {
|
||||
if (dst.empty()) {
|
||||
if (Inplace) {
|
||||
dst = src;
|
||||
} else {
|
||||
dst = src + ".hip";
|
||||
}
|
||||
} else if (Inplace) {
|
||||
llvm::errs() << "[HIPIFY] conflict: both -o and -inplace options are specified.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string tmpFile = src + ".hipify-tmp";
|
||||
|
||||
// Create a copy of the file to work on. When we're done, we'll move this onto the
|
||||
// output (which may mean overwriting the input, if we're in-place).
|
||||
// Should we fail for some reason, we'll just leak this file and not corrupt the input.
|
||||
copyFile(src, tmpFile);
|
||||
|
||||
// Initialise the statistics counters for this file.
|
||||
Statistics::setActive(src);
|
||||
|
||||
// RefactoringTool operates on the file in-place. Giving it the output path is no good,
|
||||
// because that'll break relative includes, and we don't want to overwrite the input file.
|
||||
// So what we do is operate on a copy, which we then move to the output.
|
||||
RefactoringTool Tool(OptionsParser.getCompilations(), tmpFile);
|
||||
ast_matchers::MatchFinder Finder;
|
||||
|
||||
// The Replacements to apply to the file `src`.
|
||||
Replacements& replacementsToUse = llcompat::getReplacements(Tool, tmpFile);
|
||||
HipifyPPCallbacks* PPCallbacks = new HipifyPPCallbacks(replacementsToUse, tmpFile);
|
||||
Cuda2HipCallback Callback(replacementsToUse, &Finder, PPCallbacks, tmpFile);
|
||||
|
||||
addAllMatchers(Finder, &Callback);
|
||||
|
||||
auto action = newFrontendActionFactory(&Finder, PPCallbacks);
|
||||
|
||||
Tool.appendArgumentsAdjuster(getInsertArgumentAdjuster("--cuda-host-only", ArgumentInsertPosition::BEGIN));
|
||||
|
||||
// Ensure at least c++11 is used.
|
||||
Tool.appendArgumentsAdjuster(getInsertArgumentAdjuster("-std=c++11", ArgumentInsertPosition::BEGIN));
|
||||
#if defined(HIPIFY_CLANG_RES)
|
||||
Tool.appendArgumentsAdjuster(getInsertArgumentAdjuster("-resource-dir=" HIPIFY_CLANG_RES));
|
||||
#endif
|
||||
Tool.appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
|
||||
Result += Tool.run(action.get());
|
||||
Tool.clearArgumentsAdjusters();
|
||||
|
||||
LangOptions DefaultLangOptions;
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
|
||||
TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
|
||||
DiagnosticsEngine Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts, &DiagnosticPrinter, false);
|
||||
|
||||
SourceManager SM(Diagnostics, Tool.getFiles());
|
||||
|
||||
Rewriter Rewrite(SM, DefaultLangOptions);
|
||||
if (!Tool.applyAllReplacements(Rewrite)) {
|
||||
DEBUG(dbgs() << "Skipped some replacements.\n");
|
||||
}
|
||||
|
||||
// Either move the tmpfile to the output, or remove it.
|
||||
if (!NoOutput) {
|
||||
Result += Rewrite.overwriteChangedFiles();
|
||||
rename(tmpFile.c_str(), dst.c_str());
|
||||
} else {
|
||||
remove(tmpFile.c_str());
|
||||
}
|
||||
|
||||
Statistics::current().markCompletion();
|
||||
Statistics::current().print(csv.get(), statPrint);
|
||||
|
||||
dst.clear();
|
||||
}
|
||||
|
||||
if (fileSources.size() > 1) {
|
||||
Statistics::printAggregate(csv.get(), statPrint);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
#include "HipifyAction.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
|
||||
#include "LLVMCompat.h"
|
||||
#include "CUDA2HipMap.h"
|
||||
#include "StringUtils.h"
|
||||
#include "ArgParse.h"
|
||||
|
||||
namespace ct = clang::tooling;
|
||||
namespace mat = clang::ast_matchers;
|
||||
|
||||
void HipifyAction::RewriteString(StringRef s, clang::SourceLocation start) {
|
||||
clang::SourceManager& SM = getCompilerInstance().getSourceManager();
|
||||
|
||||
size_t begin = 0;
|
||||
while ((begin = s.find("cu", begin)) != StringRef::npos) {
|
||||
const size_t end = s.find_first_of(" ", begin + 4);
|
||||
StringRef name = s.slice(begin, end);
|
||||
const auto found = CUDA_RENAMES_MAP().find(name);
|
||||
if (found != CUDA_RENAMES_MAP().end()) {
|
||||
StringRef repName = found->second.hipName;
|
||||
hipCounter counter = {"[string literal]", ConvTypes::CONV_LITERAL, ApiTypes::API_RUNTIME, found->second.unsupported};
|
||||
Statistics::current().incrementCounter(counter, name.str());
|
||||
|
||||
if (!counter.unsupported) {
|
||||
clang::SourceLocation sl = start.getLocWithOffset(begin + 1);
|
||||
ct::Replacement Rep(SM, sl, name.size(), repName);
|
||||
clang::FullSourceLoc fullSL(sl, SM);
|
||||
insertReplacement(Rep, fullSL);
|
||||
}
|
||||
}
|
||||
|
||||
if (end == StringRef::npos) {
|
||||
break;
|
||||
}
|
||||
|
||||
begin = end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at, and consider altering, a given token.
|
||||
*
|
||||
* If it's not a CUDA identifier, nothing happens.
|
||||
* If it's an unsupported CUDA identifier, a warning is emitted.
|
||||
* Otherwise, the source file is updated with the corresponding hipification.
|
||||
*/
|
||||
void HipifyAction::RewriteToken(const clang::Token& t) {
|
||||
clang::SourceManager& SM = getCompilerInstance().getSourceManager();
|
||||
|
||||
// String literals containing CUDA references need fixing...
|
||||
if (t.is(clang::tok::string_literal)) {
|
||||
StringRef s(t.getLiteralData(), t.getLength());
|
||||
RewriteString(unquoteStr(s), t.getLocation());
|
||||
return;
|
||||
} else if (!t.isAnyIdentifier()) {
|
||||
// If it's neither a string nor an identifier, we don't care.
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef name = t.getRawIdentifier();
|
||||
const auto found = CUDA_RENAMES_MAP().find(name);
|
||||
if (found == CUDA_RENAMES_MAP().end()) {
|
||||
// So it's an identifier, but not CUDA? Boring.
|
||||
return;
|
||||
}
|
||||
|
||||
Statistics::current().incrementCounter(found->second, name.str());
|
||||
|
||||
clang::SourceLocation sl = t.getLocation();
|
||||
if (found->second.unsupported) {
|
||||
// An unsupported identifier? Curses! Warn the user.
|
||||
clang::DiagnosticsEngine& DE = getCompilerInstance().getDiagnostics();
|
||||
const auto ID = DE.getCustomDiagID(clang::DiagnosticsEngine::Warning, "CUDA identifier unsupported in hip");
|
||||
DE.Report(sl, ID);
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef repName = found->second.hipName;
|
||||
ct::Replacement Rep(SM, sl, name.size(), repName);
|
||||
clang::FullSourceLoc fullSL(sl, SM);
|
||||
insertReplacement(Rep, fullSL);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
clang::SourceRange getReadRange(clang::SourceManager& SM, const clang::SourceRange& exprRange) {
|
||||
clang::SourceLocation begin = exprRange.getBegin();
|
||||
clang::SourceLocation end = exprRange.getEnd();
|
||||
|
||||
bool beginSafe = !SM.isMacroBodyExpansion(begin) || clang::Lexer::isAtStartOfMacroExpansion(begin, SM, clang::LangOptions{});
|
||||
bool endSafe = !SM.isMacroBodyExpansion(end) || clang::Lexer::isAtEndOfMacroExpansion(end, SM, clang::LangOptions{});
|
||||
|
||||
if (beginSafe && endSafe) {
|
||||
return {SM.getFileLoc(begin), SM.getFileLoc(end)};
|
||||
} else {
|
||||
return {SM.getSpellingLoc(begin), SM.getSpellingLoc(end)};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
clang::SourceRange getWriteRange(clang::SourceManager& SM, const clang::SourceRange& exprRange) {
|
||||
clang::SourceLocation begin = exprRange.getBegin();
|
||||
clang::SourceLocation end = exprRange.getEnd();
|
||||
|
||||
// If the range is contained within a macro, update the macro definition.
|
||||
// Otherwise, use the file location and hope for the best.
|
||||
if (!SM.isMacroBodyExpansion(begin) || !SM.isMacroBodyExpansion(end)) {
|
||||
return {SM.getFileLoc(begin), SM.getFileLoc(end)};
|
||||
}
|
||||
|
||||
return {SM.getSpellingLoc(begin), SM.getSpellingLoc(end)};
|
||||
}
|
||||
|
||||
|
||||
StringRef readSourceText(clang::SourceManager& SM, const clang::SourceRange& exprRange) {
|
||||
return clang::Lexer::getSourceText(clang::CharSourceRange::getTokenRange(getReadRange(SM, exprRange)), SM, clang::LangOptions(), nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string representation of the expression `arg`, unless it's a defaulting function
|
||||
* call argument, in which case get a 0. Used for building argument lists to kernel calls.
|
||||
*/
|
||||
std::string stringifyZeroDefaultedArg(clang::SourceManager& SM, const clang::Expr* arg) {
|
||||
if (clang::isa<clang::CXXDefaultArgExpr>(arg)) {
|
||||
return "0";
|
||||
} else {
|
||||
return readSourceText(SM, arg->getSourceRange());
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
void HipifyAction::InclusionDirective(clang::SourceLocation hash_loc,
|
||||
const clang::Token&,
|
||||
StringRef file_name,
|
||||
bool is_angled,
|
||||
clang::CharSourceRange filename_range,
|
||||
const clang::FileEntry*, StringRef,
|
||||
StringRef, const clang::Module*) {
|
||||
clang::SourceManager& SM = getCompilerInstance().getSourceManager();
|
||||
if (!SM.isWrittenInMainFile(hash_loc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto found = CUDA_INCLUDE_MAP.find(file_name);
|
||||
if (found == CUDA_INCLUDE_MAP.end()) {
|
||||
// Not a CUDA include - don't touch it.
|
||||
return;
|
||||
}
|
||||
|
||||
// Special-casing to avoid duplication of the hip_runtime include.
|
||||
if (found->second.hipName == "hip/hip_runtime.h") {
|
||||
if (insertedRuntimeHeader) {
|
||||
return;
|
||||
}
|
||||
|
||||
insertedRuntimeHeader = true;
|
||||
}
|
||||
|
||||
Statistics::current().incrementCounter(found->second, file_name.str());
|
||||
|
||||
clang::SourceLocation sl = filename_range.getBegin();
|
||||
if (found->second.unsupported) {
|
||||
// An unsupported CUDA header? Oh dear. Print a warning.
|
||||
clang::DiagnosticsEngine& DE = getCompilerInstance().getDiagnostics();
|
||||
DE.Report(sl, DE.getCustomDiagID(clang::DiagnosticsEngine::Warning, "Unsupported CUDA header"));
|
||||
return;
|
||||
}
|
||||
|
||||
const char *B = SM.getCharacterData(sl);
|
||||
const char *E = SM.getCharacterData(filename_range.getEnd());
|
||||
clang::SmallString<128> includeBuffer;
|
||||
clang::StringRef newInclude;
|
||||
|
||||
// Keep the same include type that the user gave.
|
||||
if (is_angled) {
|
||||
newInclude = llvm::Twine("<" + found->second.hipName + ">").toStringRef(includeBuffer);
|
||||
} else {
|
||||
newInclude = llvm::Twine("\"" + found->second.hipName + "\"").toStringRef(includeBuffer);
|
||||
}
|
||||
|
||||
ct::Replacement Rep(SM, sl, E - B, newInclude);
|
||||
insertReplacement(Rep, clang::FullSourceLoc{sl, SM});
|
||||
}
|
||||
|
||||
|
||||
bool HipifyAction::cudaLaunchKernel(const clang::ast_matchers::MatchFinder::MatchResult& Result) {
|
||||
StringRef refName = "cudaLaunchKernel";
|
||||
|
||||
const auto* launchKernel = Result.Nodes.getNodeAs<clang::CUDAKernelCallExpr>(refName);
|
||||
if (!launchKernel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
clang::SmallString<40> XStr;
|
||||
llvm::raw_svector_ostream OS(XStr);
|
||||
|
||||
clang::LangOptions DefaultLangOptions;
|
||||
clang::SourceManager* SM = Result.SourceManager;
|
||||
|
||||
const clang::Expr& calleeExpr = *(launchKernel->getCallee());
|
||||
OS << "hipLaunchKernelGGL(" << readSourceText(*SM, calleeExpr.getSourceRange()) << ", ";
|
||||
|
||||
// Next up are the four kernel configuration parameters, the last two of which are optional and default to zero.
|
||||
const clang::CallExpr& config = *(launchKernel->getConfig());
|
||||
|
||||
// Copy the two dimensional arguments verbatim.
|
||||
OS << "dim3(" << readSourceText(*SM, config.getArg(0)->getSourceRange()) << "), ";
|
||||
OS << "dim3(" << readSourceText(*SM, config.getArg(1)->getSourceRange()) << "), ";
|
||||
|
||||
// The stream/memory arguments default to zero if omitted.
|
||||
OS << stringifyZeroDefaultedArg(*SM, config.getArg(2)) << ", ";
|
||||
OS << stringifyZeroDefaultedArg(*SM, config.getArg(3));
|
||||
|
||||
// If there are ordinary arguments to the kernel, just copy them verbatim into our new call.
|
||||
int numArgs = launchKernel->getNumArgs();
|
||||
if (numArgs > 0) {
|
||||
OS << ", ";
|
||||
|
||||
// Start of the first argument.
|
||||
clang::SourceLocation argStart = launchKernel->getArg(0)->getLocStart();
|
||||
|
||||
// End of the last argument.
|
||||
clang::SourceLocation argEnd = launchKernel->getArg(numArgs - 1)->getLocEnd();
|
||||
|
||||
OS << readSourceText(*SM, {argStart, argEnd});
|
||||
}
|
||||
|
||||
OS << ")";
|
||||
|
||||
clang::SourceRange replacementRange = getWriteRange(*SM, {launchKernel->getLocStart(), launchKernel->getLocEnd()});
|
||||
clang::SourceLocation launchStart = replacementRange.getBegin();
|
||||
clang::SourceLocation launchEnd = replacementRange.getEnd();
|
||||
|
||||
size_t length = SM->getCharacterData(clang::Lexer::getLocForEndOfToken(launchEnd, 0, *SM, DefaultLangOptions)) - SM->getCharacterData(launchStart);
|
||||
|
||||
ct::Replacement Rep(*SM, launchStart, length, OS.str());
|
||||
clang::FullSourceLoc fullSL(launchStart, *SM);
|
||||
insertReplacement(Rep, fullSL);
|
||||
hipCounter counter = {"hipLaunchKernelGGL", ConvTypes::CONV_KERN, ApiTypes::API_RUNTIME};
|
||||
Statistics::current().incrementCounter(counter, refName.str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HipifyAction::cudaBuiltin(const clang::ast_matchers::MatchFinder::MatchResult& Result) {
|
||||
const clang::MemberExpr* threadIdx = Result.Nodes.getNodeAs<clang::MemberExpr>("cudaBuiltin");
|
||||
if (!threadIdx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const clang::OpaqueValueExpr* refBase = clang::dyn_cast<clang::OpaqueValueExpr>(threadIdx->getBase());
|
||||
if (!refBase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const clang::DeclRefExpr* declRef = clang::dyn_cast<clang::DeclRefExpr>(refBase->getSourceExpr());
|
||||
if (!declRef) {
|
||||
return false;
|
||||
}
|
||||
|
||||
clang::SourceLocation sl = threadIdx->getLocStart();
|
||||
clang::SourceManager* SM = Result.SourceManager;
|
||||
StringRef name = declRef->getDecl()->getName();
|
||||
StringRef memberName = threadIdx->getMemberDecl()->getName();
|
||||
size_t pos = memberName.find_first_not_of("__fetch_builtin_");
|
||||
memberName = memberName.slice(pos, memberName.size());
|
||||
clang::SmallString<128> tmpData;
|
||||
name = clang::Twine(name + "." + memberName).toStringRef(tmpData);
|
||||
|
||||
const auto found = CUDA_IDENTIFIER_MAP.find(name);
|
||||
if (found != CUDA_IDENTIFIER_MAP.end()) {
|
||||
Statistics::current().incrementCounter(found->second, name.str());
|
||||
if (!found->second.unsupported) {
|
||||
StringRef repName = found->second.hipName;
|
||||
ct::Replacement Rep(*SM, sl, name.size(), repName);
|
||||
clang::FullSourceLoc fullSL(sl, *SM);
|
||||
insertReplacement(Rep, fullSL);
|
||||
}
|
||||
} else {
|
||||
clang::DiagnosticsEngine& DE = getCompilerInstance().getDiagnostics();
|
||||
const auto ID = DE.getCustomDiagID(clang::DiagnosticsEngine::Warning, "Unknown CUDA builtin");
|
||||
DE.Report(sl, ID);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HipifyAction::cudaSharedIncompleteArrayVar(const clang::ast_matchers::MatchFinder::MatchResult& Result) {
|
||||
StringRef refName = "cudaSharedIncompleteArrayVar";
|
||||
auto* sharedVar = Result.Nodes.getNodeAs<clang::VarDecl>(refName);
|
||||
if (!sharedVar) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Example: extern __shared__ uint sRadix1[];
|
||||
if (!sharedVar->hasExternalFormalLinkage()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
clang::QualType QT = sharedVar->getType();
|
||||
std::string typeName;
|
||||
if (QT->isIncompleteArrayType()) {
|
||||
const clang::ArrayType* AT = QT.getTypePtr()->getAsArrayTypeUnsafe();
|
||||
QT = AT->getElementType();
|
||||
if (QT.getTypePtr()->isBuiltinType()) {
|
||||
QT = QT.getCanonicalType();
|
||||
const auto* BT = clang::dyn_cast<clang::BuiltinType>(QT);
|
||||
if (BT) {
|
||||
clang::LangOptions LO;
|
||||
LO.CUDA = true;
|
||||
clang::PrintingPolicy policy(LO);
|
||||
typeName = BT->getName(policy);
|
||||
}
|
||||
} else {
|
||||
typeName = QT.getAsString();
|
||||
}
|
||||
}
|
||||
|
||||
if (!typeName.empty()) {
|
||||
clang::SourceLocation slStart = sharedVar->getLocStart();
|
||||
clang::SourceLocation slEnd = sharedVar->getLocEnd();
|
||||
clang::SourceManager* SM = Result.SourceManager;
|
||||
size_t repLength = SM->getCharacterData(slEnd) - SM->getCharacterData(slStart) + 1;
|
||||
std::string varName = sharedVar->getNameAsString();
|
||||
std::string repName = "HIP_DYNAMIC_SHARED(" + typeName + ", " + varName + ")";
|
||||
ct::Replacement Rep(*SM, slStart, repLength, repName);
|
||||
clang::FullSourceLoc fullSL(slStart, *SM);
|
||||
insertReplacement(Rep, fullSL);
|
||||
hipCounter counter = {"HIP_DYNAMIC_SHARED", ConvTypes::CONV_MEM, ApiTypes::API_RUNTIME};
|
||||
Statistics::current().incrementCounter(counter, refName.str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HipifyAction::insertReplacement(const ct::Replacement& rep, const clang::FullSourceLoc& fullSL) {
|
||||
llcompat::insertReplacement(*replacements, rep);
|
||||
if (PrintStats) {
|
||||
rep.getLength();
|
||||
Statistics::current().lineTouched(fullSL.getExpansionLineNumber());
|
||||
Statistics::current().bytesChanged(rep.getLength());
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<clang::ASTConsumer> HipifyAction::CreateASTConsumer(clang::CompilerInstance& CI, llvm::StringRef) {
|
||||
Finder.reset(new clang::ast_matchers::MatchFinder);
|
||||
|
||||
// Replace the <<<...>>> language extension with a hip kernel launch
|
||||
Finder->addMatcher(mat::cudaKernelCallExpr(mat::isExpansionInMainFile()).bind("cudaLaunchKernel"), this);
|
||||
|
||||
// Replace cuda builtins.
|
||||
Finder->addMatcher(
|
||||
mat::memberExpr(
|
||||
mat::isExpansionInMainFile(),
|
||||
mat::hasObjectExpression(
|
||||
mat::hasType(
|
||||
mat::cxxRecordDecl(
|
||||
mat::matchesName("__cuda_builtin_")
|
||||
)
|
||||
)
|
||||
)
|
||||
).bind("cudaBuiltin"),
|
||||
this
|
||||
);
|
||||
|
||||
Finder->addMatcher(
|
||||
mat::varDecl(
|
||||
mat::isExpansionInMainFile(),
|
||||
mat::allOf(
|
||||
mat::hasAttr(clang::attr::CUDAShared),
|
||||
mat::hasType(mat::incompleteArrayType())
|
||||
)
|
||||
).bind("cudaSharedIncompleteArrayVar"),
|
||||
this
|
||||
);
|
||||
|
||||
// Ownership is transferred to the caller...
|
||||
return Finder->newASTConsumer();
|
||||
}
|
||||
|
||||
void HipifyAction::EndSourceFileAction() {
|
||||
// Insert the hip header, if we didn't already do it by accident during substitution.
|
||||
if (!insertedRuntimeHeader) {
|
||||
// It's not sufficient to just replace CUDA headers with hip ones, because numerous CUDA headers are
|
||||
// implicitly included by the compiler. Instead, we _delete_ CUDA headers, and unconditionally insert
|
||||
// one copy of the hip include into every file.
|
||||
clang::SourceManager& SM = getCompilerInstance().getSourceManager();
|
||||
|
||||
clang::SourceLocation sl = SM.getLocForStartOfFile(SM.getMainFileID());
|
||||
clang::FullSourceLoc fullSL(sl, SM);
|
||||
ct::Replacement Rep(SM, sl, 0, "#include <hip/hip_runtime.h>\n");
|
||||
insertReplacement(Rep, fullSL);
|
||||
}
|
||||
|
||||
clang::ASTFrontendAction::EndSourceFileAction();
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* A silly little class to proxy PPCallbacks back to the HipifyAction class.
|
||||
*/
|
||||
class PPCallbackProxy : public clang::PPCallbacks {
|
||||
HipifyAction& hipifyAction;
|
||||
|
||||
public:
|
||||
explicit PPCallbackProxy(HipifyAction& action): hipifyAction(action) {}
|
||||
|
||||
void InclusionDirective(clang::SourceLocation hash_loc, const clang::Token& include_token,
|
||||
StringRef file_name, bool is_angled, clang::CharSourceRange filename_range,
|
||||
const clang::FileEntry* file, StringRef search_path, StringRef relative_path,
|
||||
const clang::Module* imported) override {
|
||||
hipifyAction.InclusionDirective(hash_loc, include_token, file_name, is_angled, filename_range, file, search_path, relative_path, imported);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void HipifyAction::ExecuteAction() {
|
||||
clang::Preprocessor& PP = getCompilerInstance().getPreprocessor();
|
||||
clang::SourceManager& SM = getCompilerInstance().getSourceManager();
|
||||
|
||||
// Start lexing the specified input file.
|
||||
const llvm::MemoryBuffer* FromFile = SM.getBuffer(SM.getMainFileID());
|
||||
clang::Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts());
|
||||
RawLex.SetKeepWhitespaceMode(true);
|
||||
|
||||
// Perform a token-level rewrite of CUDA identifiers to hip ones. The raw-mode lexer gives us enough
|
||||
// information to tell the difference between identifiers, string literals, and "other stuff". It also
|
||||
// ignores preprocessor directives, so this transformation will operate inside preprocessor-deleted
|
||||
// code.
|
||||
clang::Token RawTok;
|
||||
RawLex.LexFromRawLexer(RawTok);
|
||||
while (RawTok.isNot(clang::tok::eof)) {
|
||||
RewriteToken(RawTok);
|
||||
RawLex.LexFromRawLexer(RawTok);
|
||||
}
|
||||
|
||||
// Register yourself as the preprocessor callback, by proxy.
|
||||
PP.addPPCallbacks(std::unique_ptr<PPCallbackProxy>(new PPCallbackProxy(*this)));
|
||||
|
||||
// Now we're done futzing with the lexer, have the subclass proceeed with Sema and AST matching.
|
||||
clang::ASTFrontendAction::ExecuteAction();
|
||||
}
|
||||
|
||||
void HipifyAction::run(const clang::ast_matchers::MatchFinder::MatchResult& Result) {
|
||||
if (cudaBuiltin(Result)) return;
|
||||
if (cudaLaunchKernel(Result)) return;
|
||||
if (cudaSharedIncompleteArrayVar(Result)) return;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include "clang/Lex/PPCallbacks.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "clang/Tooling/Core/Replacement.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "ReplacementsFrontendActionFactory.h"
|
||||
|
||||
namespace ct = clang::tooling;
|
||||
|
||||
/**
|
||||
* A FrontendAction that hipifies CUDA programs.
|
||||
*/
|
||||
class HipifyAction : public clang::ASTFrontendAction,
|
||||
public clang::ast_matchers::MatchFinder::MatchCallback {
|
||||
private:
|
||||
ct::Replacements* replacements;
|
||||
std::unique_ptr<clang::ast_matchers::MatchFinder> Finder;
|
||||
|
||||
/// CUDA implicitly adds its runtime header. We rewrite explicitly-provided CUDA includes with equivalent
|
||||
// ones, and track - using this flag - if the result led to us including the hip runtime header. If it did
|
||||
// not, we insert it at the top of the file when we finish processing it.
|
||||
// This approach means we do the best it's possible to do w.r.t preserving the user's include order.
|
||||
bool insertedRuntimeHeader = false;
|
||||
|
||||
/**
|
||||
* Rewrite a string literal to refer to hip, not CUDA.
|
||||
*/
|
||||
void RewriteString(StringRef s, clang::SourceLocation start);
|
||||
|
||||
/**
|
||||
* Replace a CUDA identifier with the corresponding hip identifier, if applicable.
|
||||
*/
|
||||
void RewriteToken(const clang::Token &t);
|
||||
|
||||
public:
|
||||
explicit HipifyAction(ct::Replacements *replacements):
|
||||
clang::ASTFrontendAction(),
|
||||
replacements(replacements) {}
|
||||
|
||||
// MatchCallback listeners
|
||||
bool cudaBuiltin(const clang::ast_matchers::MatchFinder::MatchResult& Result);
|
||||
bool cudaLaunchKernel(const clang::ast_matchers::MatchFinder::MatchResult& Result);
|
||||
bool cudaSharedIncompleteArrayVar(const clang::ast_matchers::MatchFinder::MatchResult& Result);
|
||||
|
||||
/**
|
||||
* Called by the preprocessor for each include directive during the non-raw lexing pass.
|
||||
*/
|
||||
void InclusionDirective(clang::SourceLocation hash_loc,
|
||||
const clang::Token &include_token,
|
||||
StringRef file_name,
|
||||
bool is_angled,
|
||||
clang::CharSourceRange filename_range,
|
||||
const clang::FileEntry *file,
|
||||
StringRef search_path,
|
||||
StringRef relative_path,
|
||||
const clang::Module *imported);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Add a Replacement for the current file. These will all be applied after executing the FrontendAction.
|
||||
*/
|
||||
void insertReplacement(const ct::Replacement& rep, const clang::FullSourceLoc& fullSL);
|
||||
|
||||
/**
|
||||
* FrontendAction entry point.
|
||||
*/
|
||||
void ExecuteAction() override;
|
||||
|
||||
/**
|
||||
* Called at the start of each new file to process.
|
||||
*/
|
||||
void EndSourceFileAction() override;
|
||||
|
||||
/**
|
||||
* MatchCallback API entry point. Called by the AST visitor while searching the AST for things we registered an
|
||||
* interest for.
|
||||
*/
|
||||
void run(const clang::ast_matchers::MatchFinder::MatchResult& Result) override;
|
||||
|
||||
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &CI, llvm::StringRef InFile) override;
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "clang/Frontend/FrontendAction.h"
|
||||
#include "clang/Tooling/Core/Replacement.h"
|
||||
|
||||
namespace ct = clang::tooling;
|
||||
|
||||
|
||||
/**
|
||||
* A FrontendActionFactory that propagates a set of Replacements into the FrontendAction.
|
||||
* This is necessary boilerplate for using a custom FrontendAction with a RefactoringTool.
|
||||
*
|
||||
* @tparam T The FrontendAction to create.
|
||||
*/
|
||||
template <typename T>
|
||||
class ReplacementsFrontendActionFactory : public ct::FrontendActionFactory {
|
||||
ct::Replacements* replacements;
|
||||
|
||||
public:
|
||||
explicit ReplacementsFrontendActionFactory(ct::Replacements* r):
|
||||
ct::FrontendActionFactory(),
|
||||
replacements(r) {}
|
||||
|
||||
clang::FrontendAction* create() override {
|
||||
return new T(replacements);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
Copyright (c) 2015-2017 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* @file Cuda2Hip.cpp
|
||||
*
|
||||
* This file is compiled and linked into clang based hipify tool.
|
||||
*/
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "CUDA2HipMap.h"
|
||||
#include "LLVMCompat.h"
|
||||
#include "HipifyAction.h"
|
||||
#include "ArgParse.h"
|
||||
|
||||
#define DEBUG_TYPE "cuda2hip"
|
||||
|
||||
namespace ct = clang::tooling;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
void copyFile(const std::string& src, const std::string& dst) {
|
||||
std::ifstream source(src, std::ios::binary);
|
||||
std::ofstream dest(dst, std::ios::binary);
|
||||
dest << source.rdbuf();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
llcompat::PrintStackTraceOnErrorSignal();
|
||||
|
||||
ct::CommonOptionsParser OptionsParser(argc, argv, ToolTemplateCategory, llvm::cl::OneOrMore);
|
||||
std::vector<std::string> fileSources = OptionsParser.getSourcePathList();
|
||||
std::string dst = OutputFilename;
|
||||
if (!dst.empty() && fileSources.size() > 1) {
|
||||
llvm::errs() << "[HIPIFY] conflict: -o and multiple source files are specified.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (NoOutput) {
|
||||
if (Inplace) {
|
||||
llvm::errs() << "[HIPIFY] conflict: both -no-output and -inplace options are specified.\n";
|
||||
return 1;
|
||||
}
|
||||
if (!dst.empty()) {
|
||||
llvm::errs() << "[HIPIFY] conflict: both -no-output and -o options are specified.\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Examine) {
|
||||
NoOutput = PrintStats = true;
|
||||
}
|
||||
|
||||
int Result = 0;
|
||||
|
||||
// Arguments for the Statistics print routines.
|
||||
std::unique_ptr<std::ostream> csv = nullptr;
|
||||
llvm::raw_ostream* statPrint = nullptr;
|
||||
if (!OutputStatsFilename.empty()) {
|
||||
csv = std::unique_ptr<std::ostream>(new std::ofstream(OutputStatsFilename, std::ios_base::trunc));
|
||||
}
|
||||
if (PrintStats) {
|
||||
statPrint = &llvm::errs();
|
||||
}
|
||||
|
||||
for (const auto & src : fileSources) {
|
||||
if (dst.empty()) {
|
||||
if (Inplace) {
|
||||
dst = src;
|
||||
} else {
|
||||
dst = src + ".hip";
|
||||
}
|
||||
} else if (Inplace) {
|
||||
llvm::errs() << "[HIPIFY] conflict: both -o and -inplace options are specified.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string tmpFile = src + ".hipify-tmp";
|
||||
|
||||
// Create a copy of the file to work on. When we're done, we'll move this onto the
|
||||
// output (which may mean overwriting the input, if we're in-place).
|
||||
// Should we fail for some reason, we'll just leak this file and not corrupt the input.
|
||||
copyFile(src, tmpFile);
|
||||
|
||||
// Initialise the statistics counters for this file.
|
||||
Statistics::setActive(src);
|
||||
|
||||
// RefactoringTool operates on the file in-place. Giving it the output path is no good,
|
||||
// because that'll break relative includes, and we don't want to overwrite the input file.
|
||||
// So what we do is operate on a copy, which we then move to the output.
|
||||
ct::RefactoringTool Tool(OptionsParser.getCompilations(), tmpFile);
|
||||
ct::Replacements& replacementsToUse = llcompat::getReplacements(Tool, tmpFile);
|
||||
|
||||
ReplacementsFrontendActionFactory<HipifyAction> actionFactory(&replacementsToUse);
|
||||
|
||||
Tool.appendArgumentsAdjuster(ct::getInsertArgumentAdjuster("--cuda-host-only", ct::ArgumentInsertPosition::BEGIN));
|
||||
|
||||
// Ensure at least c++11 is used.
|
||||
Tool.appendArgumentsAdjuster(ct::getInsertArgumentAdjuster("-std=c++11", ct::ArgumentInsertPosition::BEGIN));
|
||||
#if defined(HIPIFY_CLANG_RES)
|
||||
Tool.appendArgumentsAdjuster(ct::getInsertArgumentAdjuster("-resource-dir=" HIPIFY_CLANG_RES));
|
||||
#endif
|
||||
Tool.appendArgumentsAdjuster(ct::getClangSyntaxOnlyAdjuster());
|
||||
|
||||
// Hipify _all_ the things!
|
||||
if (Tool.runAndSave(&actionFactory)) {
|
||||
DEBUG(llvm::dbgs() << "Skipped some replacements.\n");
|
||||
}
|
||||
|
||||
// Either move the tmpfile to the output, or remove it.
|
||||
if (!NoOutput) {
|
||||
rename(tmpFile.c_str(), dst.c_str());
|
||||
} else {
|
||||
remove(tmpFile.c_str());
|
||||
}
|
||||
|
||||
Statistics::current().markCompletion();
|
||||
Statistics::current().print(csv.get(), statPrint);
|
||||
|
||||
dst.clear();
|
||||
}
|
||||
|
||||
if (fileSources.size() > 1) {
|
||||
Statistics::printAggregate(csv.get(), statPrint);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -23,6 +23,7 @@ THE SOFTWARE.
|
||||
#ifndef HIP_INCLUDE_HIP_HCC_DETAIL_DRIVER_TYPES_H
|
||||
#define HIP_INCLUDE_HIP_HCC_DETAIL_DRIVER_TYPES_H
|
||||
|
||||
typedef void* hipDeviceptr_t;
|
||||
enum hipChannelFormatKind
|
||||
{
|
||||
hipChannelFormatKindSigned = 0,
|
||||
@@ -40,6 +41,29 @@ struct hipChannelFormatDesc
|
||||
enum hipChannelFormatKind f;
|
||||
};
|
||||
|
||||
#define HIP_TRSF_NORMALIZED_COORDINATES 0x02
|
||||
#define HIP_TRSF_READ_AS_INTEGER 0x01
|
||||
#define HIP_TRSA_OVERRIDE_FORMAT 0x01
|
||||
|
||||
enum hipArray_Format
|
||||
{
|
||||
HIP_AD_FORMAT_UNSIGNED_INT8 = 0x01,
|
||||
HIP_AD_FORMAT_UNSIGNED_INT16 = 0x02,
|
||||
HIP_AD_FORMAT_UNSIGNED_INT32 = 0x03,
|
||||
HIP_AD_FORMAT_SIGNED_INT8 = 0x08,
|
||||
HIP_AD_FORMAT_SIGNED_INT16 = 0x09,
|
||||
HIP_AD_FORMAT_SIGNED_INT32 = 0x0a,
|
||||
HIP_AD_FORMAT_HALF = 0x10,
|
||||
HIP_AD_FORMAT_FLOAT = 0x20
|
||||
};
|
||||
|
||||
struct HIP_ARRAY_DESCRIPTOR {
|
||||
enum hipArray_Format format;
|
||||
unsigned int numChannels;
|
||||
size_t width;
|
||||
size_t height;
|
||||
};
|
||||
|
||||
struct hipArray {
|
||||
void* data; //FIXME: generalize this
|
||||
struct hipChannelFormatDesc desc;
|
||||
@@ -47,8 +71,30 @@ struct hipArray {
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int depth;
|
||||
struct HIP_ARRAY_DESCRIPTOR drvDesc;
|
||||
bool isDrv;
|
||||
};
|
||||
|
||||
typedef struct hip_Memcpy2D {
|
||||
size_t height;
|
||||
size_t widthInBytes;
|
||||
hipArray* dstArray;
|
||||
hipDeviceptr_t dstDevice;
|
||||
void * dstHost;
|
||||
hipMemoryType dstMemoryType;
|
||||
size_t dstPitch;
|
||||
size_t dstXInBytes;
|
||||
size_t dstY;
|
||||
hipArray* srcArray;
|
||||
hipDeviceptr_t srcDevice;
|
||||
const void * srcHost;
|
||||
hipMemoryType srcMemoryType;
|
||||
size_t srcPitch;
|
||||
size_t srcXInBytes;
|
||||
size_t srcY;
|
||||
}hip_Memcpy2D;
|
||||
|
||||
|
||||
typedef struct hipArray* hipArray_t;
|
||||
|
||||
typedef const struct hipArray* hipArray_const_t;
|
||||
|
||||
@@ -84,8 +84,6 @@ typedef struct ihipModule_t *hipModule_t;
|
||||
|
||||
typedef struct ihipModuleSymbol_t *hipFunction_t;
|
||||
|
||||
typedef void* hipDeviceptr_t;
|
||||
|
||||
typedef struct ihipEvent_t *hipEvent_t;
|
||||
|
||||
enum hipLimit_t
|
||||
@@ -621,7 +619,7 @@ hipError_t hipStreamQuery(hipStream_t stream);
|
||||
*
|
||||
* This command is host-synchronous : the host will block until the specified stream is empty.
|
||||
*
|
||||
* This command follows standard null-stream semantics. Specifically, specifying the null stream will cause the
|
||||
* This command follows standard null-stream semantics. Specifically, specifying the null stream will cause the
|
||||
* command to wait for other streams on the same device to complete all pending operations.
|
||||
*
|
||||
* This command honors the hipDeviceLaunchBlocking flag, which controls whether the wait is active or blocking.
|
||||
@@ -644,9 +642,9 @@ hipError_t hipStreamSynchronize(hipStream_t stream);
|
||||
* This function inserts a wait operation into the specified stream.
|
||||
* All future work submitted to @p stream will wait until @p event reports completion before beginning execution.
|
||||
*
|
||||
* This function only waits for commands in the current stream to complete. Notably,, this function does
|
||||
* not impliciy wait for commands in the default stream to complete, even if the specified stream is
|
||||
* created with hipStreamNonBlocking = 0.
|
||||
* This function only waits for commands in the current stream to complete. Notably,, this function does
|
||||
* not impliciy wait for commands in the default stream to complete, even if the specified stream is
|
||||
* created with hipStreamNonBlocking = 0.
|
||||
*
|
||||
* @see hipStreamCreate, hipStreamCreateWithFlags, hipStreamSynchronize, hipStreamDestroy
|
||||
*/
|
||||
@@ -756,7 +754,7 @@ hipError_t hipEventCreate(hipEvent_t* event);
|
||||
* If hipEventRecord() has been previously called on this event, then this call will overwrite any existing state in event.
|
||||
*
|
||||
* If this function is called on a an event that is currently being recorded, results are undefined - either
|
||||
* outstanding recording may save state into the event, and the order is not guaranteed.
|
||||
* outstanding recording may save state into the event, and the order is not guaranteed.
|
||||
*
|
||||
* @see hipEventCreate, hipEventCreateWithFlags, hipEventQuery, hipEventSynchronize, hipEventDestroy, hipEventElapsedTime
|
||||
*
|
||||
@@ -1318,6 +1316,7 @@ hipError_t hipMallocArray(hipArray** array, const hipChannelFormatDesc* desc,
|
||||
hipError_t hipMallocArray(hipArray** array, const struct hipChannelFormatDesc* desc,
|
||||
size_t width, size_t height, unsigned int flags);
|
||||
#endif
|
||||
hipError_t hipArrayCreate ( hipArray** pHandle, const HIP_ARRAY_DESCRIPTOR* pAllocateArray );
|
||||
/**
|
||||
* @brief Frees an array on the device.
|
||||
*
|
||||
@@ -1359,6 +1358,7 @@ hipError_t hipMalloc3DArray(hipArray_t *array,
|
||||
* @see hipMemcpy, hipMemcpyToArray, hipMemcpy2DToArray, hipMemcpyFromArray, hipMemcpyToSymbol, hipMemcpyAsync
|
||||
*/
|
||||
hipError_t hipMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, hipMemcpyKind kind);
|
||||
hipError_t hipMemcpyParam2D(const hip_Memcpy2D* pCopy);
|
||||
|
||||
/**
|
||||
* @brief Copies data between host and device.
|
||||
@@ -1968,6 +1968,7 @@ hipError_t hipModuleGetFunction(hipFunction_t *function, hipModule_t module, con
|
||||
*/
|
||||
hipError_t hipModuleGetGlobal(hipDeviceptr_t *dptr, size_t *bytes, hipModule_t hmod, const char *name);
|
||||
|
||||
hipError_t hipModuleGetTexRef(textureReference** texRef, hipModule_t hmod, const char* name);
|
||||
/**
|
||||
* @brief builds module from code object which resides in host memory. Image is pointer to that location.
|
||||
*
|
||||
@@ -2172,12 +2173,9 @@ hipError_t ihipBindTextureImpl(int dim,
|
||||
enum hipTextureReadMode readMode,
|
||||
size_t *offset,
|
||||
const void *devPtr,
|
||||
const struct hipChannelFormatDesc& desc,
|
||||
const struct hipChannelFormatDesc* desc,
|
||||
size_t size,
|
||||
enum hipTextureAddressMode addressMode,
|
||||
enum hipTextureFilterMode filterMode,
|
||||
int normalizedCoords,
|
||||
hipTextureObject_t& textureObject);
|
||||
textureReference* tex);
|
||||
|
||||
/*
|
||||
* @brief hipBindTexture Binds size bytes of the memory area pointed to by @p devPtr to the texture reference tex.
|
||||
@@ -2199,9 +2197,7 @@ hipError_t hipBindTexture(size_t *offset,
|
||||
const struct hipChannelFormatDesc& desc,
|
||||
size_t size = UINT_MAX)
|
||||
{
|
||||
return ihipBindTextureImpl(dim, readMode, offset, devPtr, desc, size,
|
||||
tex.addressMode[0], tex.filterMode, tex.normalized,
|
||||
tex.textureObject);
|
||||
return ihipBindTextureImpl(dim, readMode, offset, devPtr, &desc, size, &tex);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2222,9 +2218,7 @@ hipError_t hipBindTexture(size_t *offset,
|
||||
const void *devPtr,
|
||||
size_t size = UINT_MAX)
|
||||
{
|
||||
return ihipBindTextureImpl(dim, readMode, offset, devPtr, tex.channelDesc, size,
|
||||
tex.addressMode[0], tex.filterMode, tex.normalized,
|
||||
tex.textureObject);
|
||||
return ihipBindTextureImpl(dim, readMode, offset, devPtr, &(tex.channelDesc), size, &tex);
|
||||
}
|
||||
|
||||
// C API
|
||||
@@ -2240,13 +2234,10 @@ hipError_t ihipBindTexture2DImpl(int dim,
|
||||
enum hipTextureReadMode readMode,
|
||||
size_t *offset,
|
||||
const void *devPtr,
|
||||
const struct hipChannelFormatDesc& desc,
|
||||
const struct hipChannelFormatDesc* desc,
|
||||
size_t width,
|
||||
size_t height,
|
||||
enum hipTextureAddressMode addressMode,
|
||||
enum hipTextureFilterMode filterMode,
|
||||
int normalizedCoords,
|
||||
hipTextureObject_t& textureObject);
|
||||
textureReference* tex);
|
||||
|
||||
template <class T, int dim, enum hipTextureReadMode readMode>
|
||||
hipError_t hipBindTexture2D(size_t *offset,
|
||||
@@ -2256,9 +2247,7 @@ hipError_t hipBindTexture2D(size_t *offset,
|
||||
size_t height,
|
||||
size_t pitch)
|
||||
{
|
||||
return ihipBindTexture2DImpl(dim, readMode, offset, devPtr, tex.channelDesc, width, height,
|
||||
tex.addressMode[0], tex.filterMode, tex.normalized,
|
||||
tex.textureObject);
|
||||
return ihipBindTexture2DImpl(dim, readMode, offset, devPtr, &(tex.channelDesc), width, height, &tex);
|
||||
}
|
||||
|
||||
template <class T, int dim, enum hipTextureReadMode readMode>
|
||||
@@ -2270,9 +2259,7 @@ hipError_t hipBindTexture2D(size_t *offset,
|
||||
size_t height,
|
||||
size_t pitch)
|
||||
{
|
||||
return ihipBindTexture2DImpl(dim, readMode, offset, devPtr, desc, width, height,
|
||||
tex.addressMode[0], tex.filterMode, tex.normalized,
|
||||
tex.textureObject);
|
||||
return ihipBindTexture2DImpl(dim, readMode, offset, devPtr, &desc, width, height, &tex);
|
||||
}
|
||||
|
||||
//C API
|
||||
@@ -2284,18 +2271,13 @@ hipError_t ihipBindTextureToArrayImpl(int dim,
|
||||
enum hipTextureReadMode readMode,
|
||||
hipArray_const_t array,
|
||||
const struct hipChannelFormatDesc& desc,
|
||||
enum hipTextureAddressMode addressMode,
|
||||
enum hipTextureFilterMode filterMode,
|
||||
int normalizedCoords,
|
||||
hipTextureObject_t& textureObject);
|
||||
textureReference* tex);
|
||||
|
||||
template <class T, int dim, enum hipTextureReadMode readMode>
|
||||
hipError_t hipBindTextureToArray(struct texture<T, dim, readMode>& tex,
|
||||
hipArray_const_t array)
|
||||
{
|
||||
return ihipBindTextureToArrayImpl(dim, readMode, array, tex.channelDesc,
|
||||
tex.addressMode[0], tex.filterMode, tex.normalized,
|
||||
tex.textureObject);
|
||||
return ihipBindTextureToArrayImpl(dim, readMode, array, tex.channelDesc, &tex);
|
||||
}
|
||||
|
||||
template <class T, int dim, enum hipTextureReadMode readMode>
|
||||
@@ -2303,9 +2285,7 @@ hipError_t hipBindTextureToArray(struct texture<T, dim, readMode>& tex,
|
||||
hipArray_const_t array,
|
||||
const struct hipChannelFormatDesc& desc)
|
||||
{
|
||||
return ihipBindTextureToArrayImpl(dim, readMode, array, desc,
|
||||
tex.addressMode[0], tex.filterMode, tex.normalized,
|
||||
tex.textureObject);
|
||||
return ihipBindTextureToArrayImpl(dim, readMode, array, desc, &tex);
|
||||
}
|
||||
|
||||
//C API
|
||||
@@ -2359,6 +2339,19 @@ hipError_t hipDestroyTextureObject(hipTextureObject_t textureObject);
|
||||
hipError_t hipGetTextureObjectResourceDesc(hipResourceDesc* pResDesc, hipTextureObject_t textureObject);
|
||||
hipError_t hipGetTextureObjectResourceViewDesc(hipResourceViewDesc* pResViewDesc, hipTextureObject_t textureObject);
|
||||
hipError_t hipGetTextureObjectTextureDesc(hipTextureDesc* pTexDesc, hipTextureObject_t textureObject);
|
||||
hipError_t hipTexRefSetArray ( textureReference* tex, hipArray_const_t array, unsigned int flags );
|
||||
|
||||
hipError_t hipTexRefSetAddressMode ( textureReference* tex, int dim, hipTextureAddressMode am );
|
||||
|
||||
hipError_t hipTexRefSetFilterMode ( textureReference* tex, hipTextureFilterMode fm );
|
||||
|
||||
hipError_t hipTexRefSetFlags ( textureReference* tex, unsigned int flags );
|
||||
|
||||
hipError_t hipTexRefSetFormat (textureReference* tex, hipArray_Format fmt, int NumPackedComponents );
|
||||
|
||||
hipError_t hipTexRefSetAddress( size_t* offset, textureReference* tex, hipDeviceptr_t devPtr, size_t size );
|
||||
|
||||
hipError_t hipTexRefSetAddress2D( textureReference* tex, const HIP_ARRAY_DESCRIPTOR* desc, hipDeviceptr_t devPtr, size_t pitch );
|
||||
|
||||
// doxygen end Texture
|
||||
/**
|
||||
|
||||
تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
Diff را بارگزاری کن
@@ -93,6 +93,8 @@ struct textureReference
|
||||
float maxMipmapLevelClamp;
|
||||
|
||||
hipTextureObject_t textureObject;
|
||||
int numChannels;
|
||||
enum hipArray_Format format;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -116,8 +116,10 @@ typedef struct hipDeviceProp_t {
|
||||
* Memory type (for pointer attributes)
|
||||
*/
|
||||
enum hipMemoryType {
|
||||
hipMemoryTypeHost, ///< Memory is physically located on host
|
||||
hipMemoryTypeDevice ///< Memory is physically located on device. (see deviceId for specific device)
|
||||
hipMemoryTypeHost, ///< Memory is physically located on host
|
||||
hipMemoryTypeDevice, ///< Memory is physically located on device. (see deviceId for specific device)
|
||||
hipMemoryTypeArray, ///< Array memory, physically located on device. (see deviceId for specific device)
|
||||
hipMemoryTypeUnified ///< Not used currently
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
HIP_PATH?= $(wildcard /opt/rocm/hip)
|
||||
ifeq (,$(HIP_PATH))
|
||||
HIP_PATH=../../..
|
||||
endif
|
||||
HIPCC=$(HIP_PATH)/bin/hipcc
|
||||
HIP_PLATFORM=$(shell $(HIP_PATH)/bin/hipconfig --compiler)
|
||||
|
||||
all: tex2dKernel.code texture2dDrv.out
|
||||
|
||||
texture2dDrv.out: texture2dDrv.cpp
|
||||
$(HIPCC) $(HIPCC_FLAGS) $< -o $@
|
||||
|
||||
tex2dKernel.code: tex2dKernel.cpp
|
||||
$(HIPCC) --genco $(GENCO_FLAGS) $^ -o $@
|
||||
|
||||
clean:
|
||||
rm -f *.code *.out
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright (c) 2015 - present Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hip/hip_runtime.h"
|
||||
extern texture<float, 2, hipReadModeElementType> tex;
|
||||
|
||||
__global__ void tex2dKernel(hipLaunchParm lp, float* outputData,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
int x = hipBlockIdx_x*hipBlockDim_x + hipThreadIdx_x;
|
||||
int y = hipBlockIdx_y*hipBlockDim_y + hipThreadIdx_y;
|
||||
outputData[y*width + x] = tex2D(tex, x, y);
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
Copyright (c) 2015 - present Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hip/hip_runtime.h"
|
||||
#include "hip/hip_runtime_api.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <hip/hip_hcc.h>
|
||||
|
||||
#define fileName "tex2dKernel.code"
|
||||
|
||||
texture<float, 2, hipReadModeElementType> tex;
|
||||
bool testResult = false;
|
||||
|
||||
#define HIP_CHECK(cmd) \
|
||||
{\
|
||||
hipError_t status = cmd;\
|
||||
if(status != hipSuccess) {std::cout<<"error: #"<<status<<" ("<< hipGetErrorString(status) << ") at line:"<<__LINE__<<": "<<#cmd<<std::endl;abort();}\
|
||||
}
|
||||
|
||||
bool runTest(int argc, char **argv)
|
||||
{
|
||||
unsigned int width = 256;
|
||||
unsigned int height = 256;
|
||||
unsigned int size = width * height * sizeof(float);
|
||||
float* hData = (float*) malloc(size);
|
||||
memset(hData, 0, size);
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
hData[i*width+j] = i*width+j;
|
||||
}
|
||||
}
|
||||
hipModule_t Module;
|
||||
HIP_CHECK(hipModuleLoad(&Module, fileName));
|
||||
|
||||
hipArray* array;
|
||||
HIP_ARRAY_DESCRIPTOR desc;
|
||||
desc.format = HIP_AD_FORMAT_FLOAT;
|
||||
desc.numChannels = 1;
|
||||
desc.width = width;
|
||||
desc.height = height;
|
||||
hipArrayCreate(&array, &desc);
|
||||
|
||||
hip_Memcpy2D copyParam;
|
||||
memset(©Param, 0, sizeof(copyParam));
|
||||
copyParam.dstMemoryType = hipMemoryTypeArray;
|
||||
copyParam.dstArray = array;
|
||||
copyParam.srcMemoryType = hipMemoryTypeHost;
|
||||
copyParam.srcHost = hData;
|
||||
copyParam.srcPitch = width * sizeof(float);
|
||||
copyParam.widthInBytes = copyParam.srcPitch;
|
||||
copyParam.height = height;
|
||||
hipMemcpyParam2D(©Param);
|
||||
|
||||
textureReference* texref;
|
||||
hipModuleGetTexRef(&texref, Module, "tex");
|
||||
hipTexRefSetAddressMode(texref, 0, hipAddressModeWrap);
|
||||
hipTexRefSetAddressMode(texref, 1, hipAddressModeWrap);
|
||||
hipTexRefSetFilterMode(texref, hipFilterModePoint);
|
||||
hipTexRefSetFlags(texref, 0);
|
||||
hipTexRefSetFormat(texref, HIP_AD_FORMAT_FLOAT, 1);
|
||||
hipTexRefSetArray(texref, array, HIP_TRSA_OVERRIDE_FORMAT);
|
||||
|
||||
float* dData = NULL;
|
||||
hipMalloc((void **) &dData, size);
|
||||
|
||||
#ifdef __HIP_PLATFORM_HCC__
|
||||
|
||||
struct {
|
||||
uint32_t _hidden[6]; // genco path + wrapper-gen pass used hidden arguments.
|
||||
void * _Ad;
|
||||
unsigned int _Bd;
|
||||
unsigned int _Cd;
|
||||
} args;
|
||||
args._Ad = dData;
|
||||
args._Bd = width;
|
||||
args._Cd = height;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __HIP_PLATFORM_NVCC__
|
||||
struct {
|
||||
uint32_t _hidden[1];
|
||||
void * _Ad;
|
||||
unsigned int _Bd;
|
||||
unsigned int _Cd;
|
||||
} args;
|
||||
|
||||
args._hidden[0] = 0;
|
||||
args._Ad = dData;
|
||||
args._Bd = width;
|
||||
args._Cd = height;
|
||||
#endif
|
||||
|
||||
|
||||
size_t sizeTemp = sizeof(args);
|
||||
|
||||
void *config[] = {
|
||||
HIP_LAUNCH_PARAM_BUFFER_POINTER, &args,
|
||||
HIP_LAUNCH_PARAM_BUFFER_SIZE, &sizeTemp,
|
||||
HIP_LAUNCH_PARAM_END
|
||||
};
|
||||
|
||||
hipFunction_t Function;
|
||||
HIP_CHECK(hipModuleGetFunction(&Function, Module, "tex2dKernel"));
|
||||
|
||||
int temp1= width/16;
|
||||
int temp2 = height/16;
|
||||
HIP_CHECK(hipModuleLaunchKernel(Function, 16, 16, 1, temp1, temp2, 1, 0, 0, NULL, (void**)&config));
|
||||
hipDeviceSynchronize();
|
||||
|
||||
float *hOutputData = (float *) malloc(size);
|
||||
memset(hOutputData, 0, size);
|
||||
hipMemcpy(hOutputData, dData, size, hipMemcpyDeviceToHost);
|
||||
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
if (hData[i*width+j] != hOutputData[i*width+j]) {
|
||||
printf("Difference [ %d %d ]:%f ----%f\n",i, j, hData[i*width+j] , hOutputData[i*width+j]);
|
||||
testResult = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
hipFree(dData);
|
||||
hipFreeArray(array);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
hipInit(0);
|
||||
testResult = runTest(argc, argv);
|
||||
printf("%s ...\n", testResult ? "PASSED" : "FAILED");
|
||||
exit(testResult ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
@@ -23,6 +23,11 @@ THE SOFTWARE.
|
||||
#include <hc_math.hpp>
|
||||
#include "device_util.h"
|
||||
|
||||
extern "C" float __ocml_floor_f32(float);
|
||||
extern "C" float __ocml_rint_f32(float);
|
||||
extern "C" float __ocml_ceil_f32(float);
|
||||
extern "C" float __ocml_trunc_f32(float);
|
||||
|
||||
struct holder64Bit{
|
||||
union{
|
||||
double d;
|
||||
@@ -163,19 +168,19 @@ __device__ long long int __double_as_longlong(double x)
|
||||
|
||||
__device__ int __float2int_rd(float x)
|
||||
{
|
||||
return (int)x;
|
||||
return (int)__ocml_floor_f32(x);
|
||||
}
|
||||
__device__ int __float2int_rn(float x)
|
||||
{
|
||||
return (int)x;
|
||||
return (int)__ocml_rint_f32(x);
|
||||
}
|
||||
__device__ int __float2int_ru(float x)
|
||||
{
|
||||
return (int)x;
|
||||
return (int)__ocml_ceil_f32(x);
|
||||
}
|
||||
__device__ int __float2int_rz(float x)
|
||||
{
|
||||
return (int)x;
|
||||
return (int)__ocml_trunc_f32(x);
|
||||
}
|
||||
|
||||
__device__ long long int __float2ll_rd(float x)
|
||||
|
||||
@@ -25,8 +25,9 @@ THE SOFTWARE.
|
||||
|
||||
#include <hc.hpp>
|
||||
#include <hsa/hsa.h>
|
||||
#include "hsa/hsa_ext_amd.h"
|
||||
#include <unordered_map>
|
||||
|
||||
#include "hsa/hsa_ext_amd.h"
|
||||
#include "hip/hip_runtime.h"
|
||||
#include "hip_util.h"
|
||||
#include "env.h"
|
||||
@@ -373,13 +374,14 @@ public:
|
||||
|
||||
class ihipModule_t {
|
||||
public:
|
||||
hsa_executable_t executable;
|
||||
hsa_code_object_t object;
|
||||
std::string fileName;
|
||||
void *ptr;
|
||||
size_t size;
|
||||
std::list<hipFunction_t> funcTrack;
|
||||
ihipModule_t() : executable(), object(), fileName(), ptr(nullptr), size(0) {}
|
||||
hsa_executable_t executable;
|
||||
hsa_code_object_t object;
|
||||
std::string fileName;
|
||||
void *ptr;
|
||||
size_t size;
|
||||
std::list<hipFunction_t> funcTrack;
|
||||
std::unordered_map<std::string, uintptr_t> coGlobals;
|
||||
ihipModule_t() : executable(), object(), fileName(), ptr(nullptr), size(0) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
+134
-10
@@ -407,8 +407,113 @@ hipChannelFormatDesc hipCreateChannelDesc(int x, int y, int z, int w, hipChannel
|
||||
|
||||
extern void getChannelOrderAndType(const hipChannelFormatDesc& desc,
|
||||
enum hipTextureReadMode readMode,
|
||||
hsa_ext_image_channel_order_t& channelOrder,
|
||||
hsa_ext_image_channel_type_t& channelType);
|
||||
hsa_ext_image_channel_order_t* channelOrder,
|
||||
hsa_ext_image_channel_type_t* channelType);
|
||||
|
||||
hipError_t hipArrayCreate ( hipArray** array, const HIP_ARRAY_DESCRIPTOR* pAllocateArray )
|
||||
{
|
||||
HIP_INIT_SPECIAL_API((TRACE_MEM), array, pAllocateArray);
|
||||
HIP_SET_DEVICE();
|
||||
hipError_t hip_status = hipSuccess;
|
||||
if(pAllocateArray->width >0) {
|
||||
auto ctx = ihipGetTlsDefaultCtx();
|
||||
*array = (hipArray*)malloc(sizeof(hipArray));
|
||||
array[0]->drvDesc = *pAllocateArray;
|
||||
array[0]->width = pAllocateArray->width;
|
||||
array[0]->height = pAllocateArray->height;
|
||||
array[0]->isDrv = true;
|
||||
void ** ptr = &array[0]->data;
|
||||
if (ctx) {
|
||||
const unsigned am_flags = 0;
|
||||
size_t size = pAllocateArray->width;
|
||||
if(pAllocateArray->height > 0) {
|
||||
size = size * pAllocateArray->height;
|
||||
}
|
||||
hsa_ext_image_channel_type_t channelType;
|
||||
size_t allocSize = 0;
|
||||
switch(pAllocateArray->format) {
|
||||
case HIP_AD_FORMAT_UNSIGNED_INT8:
|
||||
allocSize = size * sizeof(uint8_t);
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_UNSIGNED_INT8;
|
||||
break;
|
||||
case HIP_AD_FORMAT_UNSIGNED_INT16:
|
||||
allocSize = size * sizeof(uint16_t);
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_UNSIGNED_INT16;
|
||||
break;
|
||||
case HIP_AD_FORMAT_UNSIGNED_INT32:
|
||||
allocSize = size * sizeof(uint32_t);
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_UNSIGNED_INT32;
|
||||
break;
|
||||
case HIP_AD_FORMAT_SIGNED_INT8:
|
||||
allocSize = size * sizeof(int8_t);
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_SIGNED_INT8;
|
||||
break;
|
||||
case HIP_AD_FORMAT_SIGNED_INT16:
|
||||
allocSize = size * sizeof(int16_t);
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_SIGNED_INT16;
|
||||
break;
|
||||
case HIP_AD_FORMAT_SIGNED_INT32:
|
||||
allocSize = size * sizeof(int32_t);
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_SIGNED_INT32;
|
||||
break;
|
||||
case HIP_AD_FORMAT_HALF:
|
||||
allocSize = size * sizeof(int16_t);
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_HALF_FLOAT;
|
||||
break;
|
||||
case HIP_AD_FORMAT_FLOAT:
|
||||
allocSize = size * sizeof(float);
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_FLOAT;
|
||||
break;
|
||||
default:
|
||||
hip_status = hipErrorUnknown;
|
||||
break;
|
||||
}
|
||||
hc::accelerator acc = ctx->getDevice()->_acc;
|
||||
hsa_agent_t* agent =static_cast<hsa_agent_t*>(acc.get_hsa_agent());
|
||||
|
||||
size_t allocGranularity = 0;
|
||||
hsa_amd_memory_pool_t *allocRegion = static_cast<hsa_amd_memory_pool_t*>(acc.get_hsa_am_region());
|
||||
hsa_amd_memory_pool_get_info(*allocRegion, HSA_AMD_MEMORY_POOL_INFO_RUNTIME_ALLOC_GRANULE, &allocGranularity);
|
||||
|
||||
hsa_ext_image_descriptor_t imageDescriptor;
|
||||
|
||||
imageDescriptor.width = pAllocateArray->width;
|
||||
imageDescriptor.height = pAllocateArray->height;
|
||||
imageDescriptor.depth = 0;
|
||||
imageDescriptor.array_size = 0;
|
||||
|
||||
imageDescriptor.geometry = HSA_EXT_IMAGE_GEOMETRY_2D;
|
||||
|
||||
hsa_ext_image_channel_order_t channelOrder;
|
||||
|
||||
if (pAllocateArray->numChannels == 4) {
|
||||
channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_RGBA;
|
||||
} else if (pAllocateArray->numChannels == 2) {
|
||||
channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_RG;
|
||||
} else if (pAllocateArray->numChannels == 1) {
|
||||
channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_R;
|
||||
}
|
||||
imageDescriptor.format.channel_order = channelOrder;
|
||||
imageDescriptor.format.channel_type = channelType;
|
||||
|
||||
hsa_access_permission_t permission = HSA_ACCESS_PERMISSION_RW;
|
||||
hsa_ext_image_data_info_t imageInfo;
|
||||
hsa_status_t status = hsa_ext_image_data_get_info(*agent, &imageDescriptor, permission, &imageInfo);
|
||||
size_t alignment = imageInfo.alignment <= allocGranularity ? 0 : imageInfo.alignment;
|
||||
|
||||
*ptr = hip_internal::allocAndSharePtr("device_array", allocSize, ctx, false/*shareWithAll*/, am_flags, 0, alignment);
|
||||
if (size && (*ptr == NULL)) {
|
||||
hip_status = hipErrorMemoryAllocation;
|
||||
}
|
||||
} else {
|
||||
hip_status = hipErrorMemoryAllocation;
|
||||
}
|
||||
} else {
|
||||
hip_status = hipErrorInvalidValue;
|
||||
}
|
||||
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
hipError_t hipMallocArray(hipArray** array, const hipChannelFormatDesc* desc,
|
||||
size_t width, size_t height, unsigned int flags)
|
||||
@@ -425,6 +530,7 @@ hipError_t hipMallocArray(hipArray** array, const hipChannelFormatDesc* desc,
|
||||
array[0]->height = height;
|
||||
array[0]->depth = 1;
|
||||
array[0]->desc = *desc;
|
||||
array[0]->isDrv = false;
|
||||
|
||||
void ** ptr = &array[0]->data;
|
||||
|
||||
@@ -480,7 +586,7 @@ hipError_t hipMallocArray(hipArray** array, const hipChannelFormatDesc* desc,
|
||||
}
|
||||
hsa_ext_image_channel_order_t channelOrder;
|
||||
hsa_ext_image_channel_type_t channelType;
|
||||
getChannelOrderAndType(*desc, hipReadModeElementType, channelOrder, channelType);
|
||||
getChannelOrderAndType(*desc, hipReadModeElementType, &channelOrder, &channelType);
|
||||
imageDescriptor.format.channel_order = channelOrder;
|
||||
imageDescriptor.format.channel_type = channelType;
|
||||
|
||||
@@ -577,7 +683,7 @@ hipError_t hipMalloc3DArray(hipArray_t *array,
|
||||
}
|
||||
hsa_ext_image_channel_order_t channelOrder;
|
||||
hsa_ext_image_channel_type_t channelType;
|
||||
getChannelOrderAndType(*desc, hipReadModeElementType, channelOrder, channelType);
|
||||
getChannelOrderAndType(*desc, hipReadModeElementType, &channelOrder, &channelType);
|
||||
imageDescriptor.format.channel_order = channelOrder;
|
||||
imageDescriptor.format.channel_type = channelType;
|
||||
|
||||
@@ -1005,13 +1111,11 @@ hipError_t hipMemcpyDtoHAsync(void* dst, hipDeviceptr_t src, size_t sizeBytes, h
|
||||
}
|
||||
|
||||
// TODO - review and optimize
|
||||
hipError_t hipMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch,
|
||||
size_t width, size_t height, hipMemcpyKind kind) {
|
||||
|
||||
HIP_INIT_SPECIAL_API((TRACE_MCMD), dst, dpitch, src, spitch, width, height, kind);
|
||||
|
||||
hipError_t ihipMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch,
|
||||
size_t width, size_t height, hipMemcpyKind kind)
|
||||
{
|
||||
if(width > dpitch || width > spitch)
|
||||
return ihipLogStatus(hipErrorUnknown);
|
||||
return hipErrorUnknown;
|
||||
|
||||
hipStream_t stream = ihipSyncAndResolveStream(hipStreamNull);
|
||||
|
||||
@@ -1028,6 +1132,26 @@ hipError_t hipMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch,
|
||||
e = ex._code;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
hipError_t hipMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch,
|
||||
size_t width, size_t height, hipMemcpyKind kind)
|
||||
{
|
||||
HIP_INIT_SPECIAL_API((TRACE_MCMD), dst, dpitch, src, spitch, width, height, kind);
|
||||
hipError_t e = hipSuccess;
|
||||
e = ihipMemcpy2D(dst,dpitch, src, spitch, width, height, kind);
|
||||
return ihipLogStatus(e);
|
||||
}
|
||||
|
||||
hipError_t hipMemcpyParam2D(const hip_Memcpy2D* pCopy)
|
||||
{
|
||||
HIP_INIT_SPECIAL_API((TRACE_MCMD), pCopy);
|
||||
hipError_t e = hipSuccess;
|
||||
if(pCopy == nullptr) {
|
||||
e = hipErrorInvalidValue;
|
||||
}
|
||||
e = ihipMemcpy2D(pCopy->dstArray->data, pCopy->widthInBytes, pCopy->srcHost, pCopy->srcPitch, pCopy->widthInBytes, pCopy->height, hipMemcpyDefault);
|
||||
return ihipLogStatus(e);
|
||||
}
|
||||
|
||||
|
||||
+25
-9
@@ -120,18 +120,15 @@ namespace hipdrv {
|
||||
uint64_t PrintSymbolSizes(const void *emi, const char *name){
|
||||
using namespace ELFIO;
|
||||
|
||||
const ELFIO::Elf64_Ehdr *ehdr = (const ELFIO::Elf64_Ehdr*)emi;
|
||||
const Elf64_Ehdr *ehdr = (const Elf64_Ehdr*)emi;
|
||||
if(NULL == ehdr || EV_CURRENT != ehdr->e_version){}
|
||||
const ELFIO::Elf64_Shdr * shdr =
|
||||
(const ELFIO::Elf64_Shdr*)((char*)emi + ehdr->e_shoff);
|
||||
const Elf64_Shdr * shdr = (const Elf64_Shdr*)((char*)emi + ehdr->e_shoff);
|
||||
for(uint16_t i=0;i<ehdr->e_shnum;++i){
|
||||
if(shdr[i].sh_type == SHT_SYMTAB){
|
||||
const ELFIO::Elf64_Sym *syms =
|
||||
(const ELFIO::Elf64_Sym*)((char*)emi + shdr[i].sh_offset);
|
||||
const Elf64_Sym *syms = (const Elf64_Sym*)((char*)emi + shdr[i].sh_offset);
|
||||
assert(syms);
|
||||
uint64_t numSyms = shdr[i].sh_size/shdr[i].sh_entsize;
|
||||
const char* strtab =
|
||||
(const char*)((char*)emi + shdr[shdr[i].sh_link].sh_offset);
|
||||
const char* strtab = (const char*)((char*)emi + shdr[shdr[i].sh_link].sh_offset);
|
||||
assert(strtab);
|
||||
for(uint64_t i=0;i<numSyms;++i){
|
||||
const char *symname = strtab + syms[i].st_name;
|
||||
@@ -149,8 +146,8 @@ uint64_t PrintSymbolSizes(const void *emi, const char *name){
|
||||
uint64_t ElfSize(const void *emi){
|
||||
using namespace ELFIO;
|
||||
|
||||
const ELFIO::Elf64_Ehdr *ehdr = (const ELFIO::Elf64_Ehdr*)emi;
|
||||
const ELFIO::Elf64_Shdr *shdr = (const ELFIO::Elf64_Shdr*)((char*)emi + ehdr->e_shoff);
|
||||
const Elf64_Ehdr *ehdr = (const Elf64_Ehdr*)emi;
|
||||
const Elf64_Shdr *shdr = (const Elf64_Shdr*)((char*)emi + ehdr->e_shoff);
|
||||
|
||||
uint64_t max_offset = ehdr->e_shoff;
|
||||
uint64_t total_size = max_offset + ehdr->e_shentsize * ehdr->e_shnum;
|
||||
@@ -717,3 +714,22 @@ hipError_t hipModuleLoadDataEx(hipModule_t *module, const void *image, unsigned
|
||||
{
|
||||
return hipModuleLoadData(module, image);
|
||||
}
|
||||
|
||||
hipError_t hipModuleGetTexRef(textureReference** texRef, hipModule_t hmod, const char* name)
|
||||
{
|
||||
HIP_INIT_API(texRef, hmod, name);
|
||||
hipError_t ret = hipErrorNotFound;
|
||||
if(texRef == NULL){
|
||||
ret = hipErrorInvalidValue;
|
||||
} else {
|
||||
if(name == NULL || hmod == NULL){
|
||||
ret = hipErrorNotInitialized;
|
||||
} else{
|
||||
const auto it = hmod->coGlobals.find(name);
|
||||
if (it == hmod->coGlobals.end()) return ihipLogStatus(hipErrorInvalidValue);
|
||||
*texRef = reinterpret_cast<textureReference*>(it->second);
|
||||
ret = hipSuccess;
|
||||
}
|
||||
}
|
||||
return ihipLogStatus(ret);
|
||||
}
|
||||
|
||||
+190
-88
@@ -32,19 +32,61 @@ void saveTextureInfo(const hipTexture* pTexture,
|
||||
}
|
||||
}
|
||||
|
||||
void getDrvChannelOrderAndType(const enum hipArray_Format Format,
|
||||
unsigned int NumChannels,
|
||||
hsa_ext_image_channel_order_t* channelOrder,
|
||||
hsa_ext_image_channel_type_t* channelType)
|
||||
{
|
||||
switch(Format) {
|
||||
case HIP_AD_FORMAT_UNSIGNED_INT8:
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_UNSIGNED_INT8;
|
||||
break;
|
||||
case HIP_AD_FORMAT_UNSIGNED_INT16:
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_UNSIGNED_INT16;
|
||||
break;
|
||||
case HIP_AD_FORMAT_UNSIGNED_INT32:
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_UNSIGNED_INT32;
|
||||
break;
|
||||
case HIP_AD_FORMAT_SIGNED_INT8:
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_SIGNED_INT8;
|
||||
break;
|
||||
case HIP_AD_FORMAT_SIGNED_INT16:
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_SIGNED_INT16;
|
||||
break;
|
||||
case HIP_AD_FORMAT_SIGNED_INT32:
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_SIGNED_INT32;
|
||||
break;
|
||||
case HIP_AD_FORMAT_HALF:
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_HALF_FLOAT;
|
||||
break;
|
||||
case HIP_AD_FORMAT_FLOAT:
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_FLOAT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (NumChannels == 4) {
|
||||
*channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_RGBA;
|
||||
} else if (NumChannels == 2) {
|
||||
*channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_RG;
|
||||
} else if (NumChannels == 1) {
|
||||
*channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_R;
|
||||
}
|
||||
}
|
||||
void getChannelOrderAndType(const hipChannelFormatDesc& desc,
|
||||
enum hipTextureReadMode readMode,
|
||||
hsa_ext_image_channel_order_t& channelOrder,
|
||||
hsa_ext_image_channel_type_t& channelType)
|
||||
hsa_ext_image_channel_order_t* channelOrder,
|
||||
hsa_ext_image_channel_type_t* channelType)
|
||||
{
|
||||
if (desc.x != 0 && desc.y != 0 && desc.z != 0 && desc.w != 0) {
|
||||
channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_RGBA;
|
||||
*channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_RGBA;
|
||||
} else if (desc.x != 0 && desc.y != 0 && desc.z != 0 && desc.w == 0) {
|
||||
channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_RGB;
|
||||
*channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_RGB;
|
||||
} else if (desc.x != 0 && desc.y != 0 && desc.z == 0 && desc.w == 0) {
|
||||
channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_RG;
|
||||
*channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_RG;
|
||||
} else if (desc.x != 0 && desc.y == 0 && desc.z == 0 && desc.w == 0) {
|
||||
channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_R;
|
||||
*channelOrder = HSA_EXT_IMAGE_CHANNEL_ORDER_R;
|
||||
} else {
|
||||
}
|
||||
|
||||
@@ -52,49 +94,49 @@ void getChannelOrderAndType(const hipChannelFormatDesc& desc,
|
||||
case hipChannelFormatKindUnsigned:
|
||||
switch(desc.x) {
|
||||
case 32:
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_UNSIGNED_INT32;
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_UNSIGNED_INT32;
|
||||
break;
|
||||
case 16:
|
||||
channelType = readMode == hipReadModeNormalizedFloat ? HSA_EXT_IMAGE_CHANNEL_TYPE_UNORM_INT16 :
|
||||
*channelType = readMode == hipReadModeNormalizedFloat ? HSA_EXT_IMAGE_CHANNEL_TYPE_UNORM_INT16 :
|
||||
HSA_EXT_IMAGE_CHANNEL_TYPE_UNSIGNED_INT16;
|
||||
break;
|
||||
case 8:
|
||||
channelType = readMode == hipReadModeNormalizedFloat ? HSA_EXT_IMAGE_CHANNEL_TYPE_UNORM_INT8 :
|
||||
*channelType = readMode == hipReadModeNormalizedFloat ? HSA_EXT_IMAGE_CHANNEL_TYPE_UNORM_INT8 :
|
||||
HSA_EXT_IMAGE_CHANNEL_TYPE_UNSIGNED_INT8;
|
||||
break;
|
||||
default:
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_UNSIGNED_INT32;
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_UNSIGNED_INT32;
|
||||
}
|
||||
break;
|
||||
case hipChannelFormatKindSigned:
|
||||
switch(desc.x) {
|
||||
case 32:
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_SIGNED_INT32;
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_SIGNED_INT32;
|
||||
break;
|
||||
case 16:
|
||||
channelType = readMode == hipReadModeNormalizedFloat ? HSA_EXT_IMAGE_CHANNEL_TYPE_SNORM_INT16 :
|
||||
*channelType = readMode == hipReadModeNormalizedFloat ? HSA_EXT_IMAGE_CHANNEL_TYPE_SNORM_INT16 :
|
||||
HSA_EXT_IMAGE_CHANNEL_TYPE_SIGNED_INT16;
|
||||
break;
|
||||
case 8:
|
||||
channelType = readMode == hipReadModeNormalizedFloat ? HSA_EXT_IMAGE_CHANNEL_TYPE_SNORM_INT8 :
|
||||
*channelType = readMode == hipReadModeNormalizedFloat ? HSA_EXT_IMAGE_CHANNEL_TYPE_SNORM_INT8 :
|
||||
HSA_EXT_IMAGE_CHANNEL_TYPE_SIGNED_INT8;
|
||||
break;
|
||||
default:
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_SIGNED_INT32;
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_SIGNED_INT32;
|
||||
}
|
||||
break;
|
||||
case hipChannelFormatKindFloat:
|
||||
switch(desc.x) {
|
||||
case 32:
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_FLOAT;
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_FLOAT;
|
||||
break;
|
||||
case 16:
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_HALF_FLOAT;
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_HALF_FLOAT;
|
||||
break;
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_FLOAT;
|
||||
*channelType = HSA_EXT_IMAGE_CHANNEL_TYPE_FLOAT;
|
||||
}
|
||||
break;
|
||||
case hipChannelFormatKindNone:
|
||||
@@ -168,8 +210,6 @@ hipError_t hipCreateTextureObject(hipTextureObject_t* pTexObject,
|
||||
const hipResourceViewDesc* pResViewDesc)
|
||||
{
|
||||
HIP_INIT_API(pTexObject, pResDesc, pTexDesc, pResViewDesc);
|
||||
HIP_SET_DEVICE();
|
||||
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
auto ctx = ihipGetTlsDefaultCtx();
|
||||
@@ -215,7 +255,7 @@ hipError_t hipCreateTextureObject(hipTextureObject_t* pTexObject,
|
||||
imageDescriptor.array_size = 0;
|
||||
break;
|
||||
}
|
||||
getChannelOrderAndType(pResDesc->res.array.array->desc, pTexDesc->readMode, channelOrder, channelType);
|
||||
getChannelOrderAndType(pResDesc->res.array.array->desc, pTexDesc->readMode, &channelOrder, &channelType);
|
||||
break;
|
||||
case hipResourceTypeMipmappedArray:
|
||||
devPtr = pResDesc->res.mipmap.mipmap->data;
|
||||
@@ -224,7 +264,7 @@ hipError_t hipCreateTextureObject(hipTextureObject_t* pTexObject,
|
||||
imageDescriptor.depth = pResDesc->res.mipmap.mipmap->depth;
|
||||
imageDescriptor.array_size = 0;
|
||||
imageDescriptor.geometry = HSA_EXT_IMAGE_GEOMETRY_2D;
|
||||
getChannelOrderAndType(pResDesc->res.mipmap.mipmap->desc, pTexDesc->readMode, channelOrder, channelType);
|
||||
getChannelOrderAndType(pResDesc->res.mipmap.mipmap->desc, pTexDesc->readMode, &channelOrder, &channelType);
|
||||
break;
|
||||
case hipResourceTypeLinear:
|
||||
devPtr = pResDesc->res.linear.devPtr;
|
||||
@@ -233,7 +273,7 @@ hipError_t hipCreateTextureObject(hipTextureObject_t* pTexObject,
|
||||
imageDescriptor.depth = 0;
|
||||
imageDescriptor.array_size = 0;
|
||||
imageDescriptor.geometry = HSA_EXT_IMAGE_GEOMETRY_1D; // ? HSA_EXT_IMAGE_DATA_LAYOUT_LINEAR
|
||||
getChannelOrderAndType(pResDesc->res.linear.desc, pTexDesc->readMode, channelOrder, channelType);
|
||||
getChannelOrderAndType(pResDesc->res.linear.desc, pTexDesc->readMode, &channelOrder, &channelType);
|
||||
break;
|
||||
case hipResourceTypePitch2D:
|
||||
devPtr = pResDesc->res.pitch2D.devPtr;
|
||||
@@ -242,7 +282,7 @@ hipError_t hipCreateTextureObject(hipTextureObject_t* pTexObject,
|
||||
imageDescriptor.depth = 0;
|
||||
imageDescriptor.array_size = 0;
|
||||
imageDescriptor.geometry = HSA_EXT_IMAGE_GEOMETRY_2D;
|
||||
getChannelOrderAndType(pResDesc->res.pitch2D.desc, pTexDesc->readMode, channelOrder, channelType);
|
||||
getChannelOrderAndType(pResDesc->res.pitch2D.desc, pTexDesc->readMode, &channelOrder, &channelType);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -271,7 +311,6 @@ hipError_t hipCreateTextureObject(hipTextureObject_t* pTexObject,
|
||||
hipError_t hipDestroyTextureObject(hipTextureObject_t textureObject)
|
||||
{
|
||||
HIP_INIT_API(textureObject);
|
||||
HIP_SET_DEVICE();
|
||||
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
@@ -296,8 +335,6 @@ hipError_t hipDestroyTextureObject(hipTextureObject_t textureObject)
|
||||
hipError_t hipGetTextureObjectResourceDesc(hipResourceDesc* pResDesc, hipTextureObject_t textureObject)
|
||||
{
|
||||
HIP_INIT_API(pResDesc, textureObject);
|
||||
HIP_SET_DEVICE();
|
||||
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
auto ctx = ihipGetTlsDefaultCtx();
|
||||
@@ -313,8 +350,6 @@ hipError_t hipGetTextureObjectResourceDesc(hipResourceDesc* pResDesc, hipTexture
|
||||
hipError_t hipGetTextureObjectResourceViewDesc(hipResourceViewDesc* pResViewDesc, hipTextureObject_t textureObject)
|
||||
{
|
||||
HIP_INIT_API(pResViewDesc, textureObject);
|
||||
HIP_SET_DEVICE();
|
||||
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
auto ctx = ihipGetTlsDefaultCtx();
|
||||
@@ -330,7 +365,6 @@ hipError_t hipGetTextureObjectResourceViewDesc(hipResourceViewDesc* pResViewDesc
|
||||
hipError_t hipGetTextureObjectTextureDesc(hipTextureDesc* pTexDesc, hipTextureObject_t textureObject)
|
||||
{
|
||||
HIP_INIT_API(pTexDesc, textureObject);
|
||||
HIP_SET_DEVICE();
|
||||
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
@@ -349,18 +383,14 @@ hipError_t ihipBindTextureImpl(int dim,
|
||||
enum hipTextureReadMode readMode,
|
||||
size_t *offset,
|
||||
const void *devPtr,
|
||||
const struct hipChannelFormatDesc& desc,
|
||||
size_t size,
|
||||
enum hipTextureAddressMode addressMode,
|
||||
enum hipTextureFilterMode filterMode,
|
||||
int normalizedCoords,
|
||||
hipTextureObject_t& textureObject)
|
||||
const struct hipChannelFormatDesc* desc,
|
||||
size_t size, textureReference* tex )
|
||||
{
|
||||
HIP_INIT_API();
|
||||
HIP_SET_DEVICE();
|
||||
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
enum hipTextureAddressMode addressMode = tex->addressMode[0];
|
||||
enum hipTextureFilterMode filterMode = tex->filterMode;
|
||||
int normalizedCoords = tex->normalized;
|
||||
hipTextureObject_t& textureObject = tex->textureObject;
|
||||
auto ctx = ihipGetTlsDefaultCtx();
|
||||
if (ctx) {
|
||||
hc::accelerator acc = ctx->getDevice()->_acc;
|
||||
@@ -385,7 +415,11 @@ hipError_t ihipBindTextureImpl(int dim,
|
||||
|
||||
hsa_ext_image_channel_order_t channelOrder;
|
||||
hsa_ext_image_channel_type_t channelType;
|
||||
getChannelOrderAndType(desc, readMode, channelOrder, channelType);
|
||||
if(NULL == desc) {
|
||||
getDrvChannelOrderAndType(tex->format, tex->numChannels, &channelOrder, &channelType);
|
||||
} else {
|
||||
getChannelOrderAndType(*desc, readMode, &channelOrder, &channelType);
|
||||
}
|
||||
imageDescriptor.format.channel_order = channelOrder;
|
||||
imageDescriptor.format.channel_type = channelType;
|
||||
|
||||
@@ -396,13 +430,13 @@ hipError_t ihipBindTextureImpl(int dim,
|
||||
|
||||
if (HSA_STATUS_SUCCESS != hsa_ext_image_create_with_layout(*agent, &imageDescriptor, devPtr, permission, HSA_EXT_IMAGE_DATA_LAYOUT_LINEAR, 0, 0, &(pTexture->image)) ||
|
||||
HSA_STATUS_SUCCESS != hsa_ext_sampler_create(*agent, &samplerDescriptor, &(pTexture->sampler))) {
|
||||
return ihipLogStatus(hipErrorRuntimeOther);
|
||||
return hipErrorRuntimeOther;
|
||||
}
|
||||
getHipTextureObject(&textureObject, pTexture->image, pTexture->sampler);
|
||||
textureHash[textureObject] = pTexture;
|
||||
}
|
||||
|
||||
return ihipLogStatus(hip_status);
|
||||
return hip_status;
|
||||
}
|
||||
|
||||
hipError_t hipBindTexture(size_t* offset,
|
||||
@@ -411,30 +445,28 @@ hipError_t hipBindTexture(size_t* offset,
|
||||
const hipChannelFormatDesc* desc,
|
||||
size_t size)
|
||||
{
|
||||
HIP_INIT_API(offset, tex, devPtr, desc, size);
|
||||
hipError_t hip_status = hipSuccess;
|
||||
// TODO: hipReadModeElementType is default.
|
||||
return ihipBindTextureImpl(hipTextureType1D, hipReadModeElementType,
|
||||
offset, devPtr, *desc, size,
|
||||
tex->addressMode[0], tex->filterMode, tex->normalized,
|
||||
tex->textureObject);
|
||||
hip_status = ihipBindTextureImpl(hipTextureType1D, hipReadModeElementType,
|
||||
offset, devPtr, desc, size, tex);
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
hipError_t ihipBindTexture2DImpl(int dim,
|
||||
enum hipTextureReadMode readMode,
|
||||
size_t *offset,
|
||||
const void *devPtr,
|
||||
const struct hipChannelFormatDesc& desc,
|
||||
const struct hipChannelFormatDesc* desc,
|
||||
size_t width,
|
||||
size_t height,
|
||||
enum hipTextureAddressMode addressMode,
|
||||
enum hipTextureFilterMode filterMode,
|
||||
int normalizedCoords,
|
||||
hipTextureObject_t& textureObject)
|
||||
textureReference* tex)
|
||||
{
|
||||
HIP_INIT_API();
|
||||
HIP_SET_DEVICE();
|
||||
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
enum hipTextureAddressMode addressMode = tex->addressMode[0];
|
||||
enum hipTextureFilterMode filterMode = tex->filterMode;
|
||||
int normalizedCoords = tex->normalized;
|
||||
hipTextureObject_t& textureObject = tex->textureObject;
|
||||
auto ctx = ihipGetTlsDefaultCtx();
|
||||
if (ctx) {
|
||||
hc::accelerator acc = ctx->getDevice()->_acc;
|
||||
@@ -459,7 +491,12 @@ hipError_t ihipBindTexture2DImpl(int dim,
|
||||
|
||||
hsa_ext_image_channel_order_t channelOrder;
|
||||
hsa_ext_image_channel_type_t channelType;
|
||||
getChannelOrderAndType(desc, readMode, channelOrder, channelType);
|
||||
|
||||
if(NULL == desc) {
|
||||
getDrvChannelOrderAndType(tex->format, tex->numChannels, &channelOrder, &channelType);
|
||||
} else {
|
||||
getChannelOrderAndType(*desc, readMode, &channelOrder, &channelType);
|
||||
}
|
||||
imageDescriptor.format.channel_order = channelOrder;
|
||||
imageDescriptor.format.channel_type = channelType;
|
||||
|
||||
@@ -470,13 +507,13 @@ hipError_t ihipBindTexture2DImpl(int dim,
|
||||
|
||||
if (HSA_STATUS_SUCCESS != hsa_ext_image_create_with_layout(*agent, &imageDescriptor, devPtr, permission, HSA_EXT_IMAGE_DATA_LAYOUT_LINEAR, 0, 0, &(pTexture->image)) ||
|
||||
HSA_STATUS_SUCCESS != hsa_ext_sampler_create(*agent, &samplerDescriptor, &(pTexture->sampler))) {
|
||||
return ihipLogStatus(hipErrorRuntimeOther);
|
||||
return hipErrorRuntimeOther;
|
||||
}
|
||||
getHipTextureObject(&textureObject, pTexture->image, pTexture->sampler);
|
||||
textureHash[textureObject] = pTexture;
|
||||
}
|
||||
|
||||
return ihipLogStatus(hip_status);
|
||||
return hip_status;
|
||||
}
|
||||
|
||||
hipError_t hipBindTexture2D(size_t* offset,
|
||||
@@ -487,27 +524,24 @@ hipError_t hipBindTexture2D(size_t* offset,
|
||||
size_t height,
|
||||
size_t pitch)
|
||||
{
|
||||
// TODO: hipReadModeElementType is default.
|
||||
return ihipBindTexture2DImpl(hipTextureType2D, hipReadModeElementType,
|
||||
offset, devPtr, *desc, width, height,
|
||||
tex->addressMode[0], tex->filterMode, tex->normalized,
|
||||
tex->textureObject);
|
||||
HIP_INIT_API(offset, tex, devPtr, desc, width, height, pitch);
|
||||
hipError_t hip_status = hipSuccess;
|
||||
hip_status = ihipBindTexture2DImpl(hipTextureType2D, hipReadModeElementType,
|
||||
offset, devPtr, desc, width, height, tex);
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
hipError_t ihipBindTextureToArrayImpl(int dim,
|
||||
enum hipTextureReadMode readMode,
|
||||
hipArray_const_t array,
|
||||
const struct hipChannelFormatDesc& desc,
|
||||
enum hipTextureAddressMode addressMode,
|
||||
enum hipTextureFilterMode filterMode,
|
||||
int normalizedCoords,
|
||||
hipTextureObject_t& textureObject)
|
||||
textureReference* tex)
|
||||
{
|
||||
HIP_INIT_API();
|
||||
HIP_SET_DEVICE();
|
||||
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
enum hipTextureAddressMode addressMode = tex->addressMode[0];
|
||||
enum hipTextureFilterMode filterMode = tex->filterMode;
|
||||
int normalizedCoords = tex->normalized;
|
||||
hipTextureObject_t& textureObject = tex->textureObject;
|
||||
auto ctx = ihipGetTlsDefaultCtx();
|
||||
if (ctx) {
|
||||
hc::accelerator acc = ctx->getDevice()->_acc;
|
||||
@@ -558,7 +592,11 @@ hipError_t ihipBindTextureToArrayImpl(int dim,
|
||||
|
||||
hsa_ext_image_channel_order_t channelOrder;
|
||||
hsa_ext_image_channel_type_t channelType;
|
||||
getChannelOrderAndType(desc, readMode, channelOrder, channelType);
|
||||
if(array->isDrv) {
|
||||
getDrvChannelOrderAndType(array->drvDesc.format, array->drvDesc.numChannels, &channelOrder, &channelType);
|
||||
} else {
|
||||
getChannelOrderAndType(desc, readMode, &channelOrder, &channelType);
|
||||
}
|
||||
imageDescriptor.format.channel_order = channelOrder;
|
||||
imageDescriptor.format.channel_type = channelType;
|
||||
|
||||
@@ -569,38 +607,38 @@ hipError_t ihipBindTextureToArrayImpl(int dim,
|
||||
|
||||
if (HSA_STATUS_SUCCESS != hsa_ext_image_create_with_layout(*agent, &imageDescriptor, array->data, permission, HSA_EXT_IMAGE_DATA_LAYOUT_LINEAR, 0, 0, &(pTexture->image)) ||
|
||||
HSA_STATUS_SUCCESS != hsa_ext_sampler_create(*agent, &samplerDescriptor, &(pTexture->sampler))) {
|
||||
return ihipLogStatus(hipErrorRuntimeOther);
|
||||
return hipErrorRuntimeOther;
|
||||
}
|
||||
getHipTextureObject(&textureObject, pTexture->image, pTexture->sampler);
|
||||
textureHash[textureObject] = pTexture;
|
||||
}
|
||||
|
||||
return ihipLogStatus(hip_status);
|
||||
return hip_status;
|
||||
}
|
||||
|
||||
hipError_t hipBindTextureToArray(textureReference* tex,
|
||||
hipArray_const_t array,
|
||||
const hipChannelFormatDesc* desc)
|
||||
{
|
||||
HIP_INIT_API(tex, array, desc);
|
||||
hipError_t hip_status = hipSuccess;
|
||||
// TODO: hipReadModeElementType is default.
|
||||
return ihipBindTextureToArrayImpl(hipTextureType2D, hipReadModeElementType,
|
||||
array, *desc,
|
||||
tex->addressMode[0], tex->filterMode, tex->normalized,
|
||||
tex->textureObject);
|
||||
hip_status = ihipBindTextureToArrayImpl(hipTextureType2D, hipReadModeElementType,
|
||||
array, *desc, tex);
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
hipError_t hipBindTextureToMipmappedArray(textureReference* tex,
|
||||
hipMipmappedArray_const_t mipmappedArray,
|
||||
const hipChannelFormatDesc* desc)
|
||||
{
|
||||
return hipSuccess;
|
||||
HIP_INIT_API(tex, mipmappedArray, desc);
|
||||
hipError_t hip_status = hipSuccess;
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
hipError_t ihipUnbindTextureImpl(const hipTextureObject_t& textureObject)
|
||||
{
|
||||
HIP_INIT_API();
|
||||
HIP_SET_DEVICE();
|
||||
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
auto ctx = ihipGetTlsDefaultCtx();
|
||||
@@ -619,19 +657,20 @@ hipError_t ihipUnbindTextureImpl(const hipTextureObject_t& textureObject)
|
||||
}
|
||||
}
|
||||
|
||||
return ihipLogStatus(hip_status);
|
||||
return hip_status;
|
||||
}
|
||||
|
||||
hipError_t hipUnbindTexture(const textureReference* tex)
|
||||
{
|
||||
return ihipUnbindTextureImpl(tex->textureObject);
|
||||
HIP_INIT_API(tex);
|
||||
hipError_t hip_status = hipSuccess;
|
||||
hip_status = ihipUnbindTextureImpl(tex->textureObject);
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
hipError_t hipGetChannelDesc(hipChannelFormatDesc* desc, hipArray_const_t array)
|
||||
{
|
||||
HIP_INIT_API(desc, array);
|
||||
HIP_SET_DEVICE();
|
||||
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
auto ctx = ihipGetTlsDefaultCtx();
|
||||
@@ -644,7 +683,6 @@ hipError_t hipGetChannelDesc(hipChannelFormatDesc* desc, hipArray_const_t array)
|
||||
hipError_t hipGetTextureAlignmentOffset(size_t* offset, const textureReference* tex)
|
||||
{
|
||||
HIP_INIT_API(offset, tex);
|
||||
HIP_SET_DEVICE();
|
||||
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
@@ -657,7 +695,6 @@ hipError_t hipGetTextureAlignmentOffset(size_t* offset, const textureReference*
|
||||
hipError_t hipGetTextureReference(const textureReference** tex, const void* symbol)
|
||||
{
|
||||
HIP_INIT_API(tex, symbol);
|
||||
HIP_SET_DEVICE();
|
||||
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
@@ -666,3 +703,68 @@ hipError_t hipGetTextureReference(const textureReference** tex, const void* symb
|
||||
}
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
hipError_t hipTexRefSetFormat (textureReference* tex, hipArray_Format fmt, int NumPackedComponents )
|
||||
{
|
||||
HIP_INIT_API(tex, fmt, NumPackedComponents);
|
||||
hipError_t hip_status = hipSuccess;
|
||||
tex->format = fmt;
|
||||
tex->numChannels = NumPackedComponents;
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
hipError_t hipTexRefSetFlags ( textureReference* tex, unsigned int flags )
|
||||
{
|
||||
HIP_INIT_API(tex, flags);
|
||||
hipError_t hip_status = hipSuccess;
|
||||
tex->normalized = flags;
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
hipError_t hipTexRefSetFilterMode ( textureReference* tex, hipTextureFilterMode fm )
|
||||
{
|
||||
HIP_INIT_API(tex, fm);
|
||||
hipError_t hip_status = hipSuccess;
|
||||
tex->filterMode = fm;
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
hipError_t hipTexRefSetAddressMode ( textureReference* tex, int dim, hipTextureAddressMode am )
|
||||
{
|
||||
HIP_INIT_API(tex, dim, am);
|
||||
hipError_t hip_status = hipSuccess;
|
||||
tex->addressMode[dim] = am;
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
hipError_t hipTexRefSetArray ( textureReference* tex, hipArray_const_t array, unsigned int flags )
|
||||
{
|
||||
HIP_INIT_API(tex, array, flags);
|
||||
hipError_t hip_status = hipSuccess;
|
||||
|
||||
hip_status = ihipBindTextureToArrayImpl(hipTextureType2D, hipReadModeElementType,
|
||||
array, array->desc,tex );
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
|
||||
hipError_t hipTexRefSetAddress( size_t* offset, textureReference* tex, hipDeviceptr_t devPtr, size_t size )
|
||||
{
|
||||
HIP_INIT_API(offset, tex, devPtr, size);
|
||||
hipError_t hip_status = hipSuccess;
|
||||
// TODO: hipReadModeElementType is default.
|
||||
hip_status = ihipBindTextureImpl(hipTextureType1D, hipReadModeElementType,
|
||||
offset, devPtr, NULL, size, tex);
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
hipError_t hipTexRefSetAddress2D( textureReference* tex, const HIP_ARRAY_DESCRIPTOR* desc, hipDeviceptr_t devPtr, size_t pitch )
|
||||
{
|
||||
HIP_INIT_API(tex, desc, devPtr, pitch);
|
||||
size_t offset;
|
||||
hipError_t hip_status = hipSuccess;
|
||||
// TODO: hipReadModeElementType is default.
|
||||
hip_status = ihipBindTexture2DImpl(hipTextureType2D, hipReadModeElementType,
|
||||
&offset, devPtr, NULL, desc->width, desc->height, tex);
|
||||
return ihipLogStatus(hip_status);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// RUN: %run_test hipify "%s" "%t" %cuda_args
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
|
||||
/**
|
||||
* Allocate GPU memory for `count` elements of type `T`.
|
||||
*/
|
||||
template<typename T>
|
||||
static T* gpuMalloc(size_t count) {
|
||||
T* ret = nullptr;
|
||||
// CHECK: hipMalloc(&ret, count * sizeof(T));
|
||||
cudaMalloc(&ret, count * sizeof(T));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// CHECK: #include <hip/hip_runtime.h>
|
||||
#include <cuda.h>
|
||||
|
||||
#define TOKEN_PASTE(X, Y) X ## Y
|
||||
#define ARG_LIST_AS_MACRO a, device_x, device_y
|
||||
@@ -33,8 +35,13 @@ int main(int argc, char* argv[]) {
|
||||
// CHECK: hipMalloc(&device_x, kDataLen * sizeof(float));
|
||||
cudaMalloc(&device_x, kDataLen * sizeof(float));
|
||||
|
||||
#ifdef HERRING
|
||||
// CHECK: hipMalloc(&device_y, kDataLen * sizeof(float));
|
||||
cudaMalloc(&device_y, kDataLen * sizeof(float));
|
||||
#else
|
||||
// CHECK: hipMalloc(&device_y, kDataLen * sizeof(double));
|
||||
cudaMalloc(&device_y, kDataLen * sizeof(double));
|
||||
#endif
|
||||
|
||||
// CHECK: hipMemcpy(device_x, host_x, kDataLen * sizeof(float), hipMemcpyHostToDevice);
|
||||
cudaMemcpy(device_x, host_x, kDataLen * sizeof(float), cudaMemcpyHostToDevice);
|
||||
|
||||
@@ -99,6 +99,7 @@ int main(int argc, char **argv)
|
||||
// use command-line specified CUDA device, otherwise use device with highest Gflops/s
|
||||
cuda_device = findCudaDevice(argc, (const char **)argv);
|
||||
|
||||
// CHECK: hipDeviceProp_t deviceProp;
|
||||
cudaDeviceProp deviceProp;
|
||||
// CHECK: checkCudaErrors(hipGetDevice(&cuda_device));
|
||||
checkCudaErrors(cudaGetDevice(&cuda_device));
|
||||
@@ -135,6 +136,7 @@ int main(int argc, char **argv)
|
||||
checkCudaErrors(cudaStreamCreate(&(streams[i])));
|
||||
}
|
||||
|
||||
// CHECK: hipEvent_t start_event, stop_event;
|
||||
// create CUDA event handles
|
||||
cudaEvent_t start_event, stop_event;
|
||||
|
||||
|
||||
@@ -14,7 +14,9 @@ texture<float, 2, hipReadModeElementType> tex;
|
||||
bool testResult = true;
|
||||
|
||||
__global__ void tex2DKernel(float* outputData,
|
||||
#ifdef __HIP_PLATFORM_HCC__
|
||||
hipTextureObject_t textureObject,
|
||||
#endif
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
@@ -78,7 +80,7 @@ void runTest(int argc, char **argv)
|
||||
#ifdef __HIP_PLATFORM_HCC__
|
||||
hipLaunchKernelGGL(tex2DKernel, dim3(dimGrid), dim3(dimBlock), 0, 0, dData, tex.textureObject, width, height);
|
||||
#else
|
||||
hipLaunchKernelGGL(tex2DKernel, dim3(dimGrid), dim3(dimBlock), 0, 0, dData, 0, width, height);
|
||||
hipLaunchKernelGGL(tex2DKernel, dim3(dimGrid), dim3(dimBlock), 0, 0, dData, width, height);
|
||||
#endif
|
||||
hipDeviceSynchronize();
|
||||
|
||||
|
||||
مرجع در شماره جدید
Block a user