[dcomptue] codegen (#2126)

* code generation

* simplify logic

* apply clang-format

* Undo completely inane choice by clang-format

* Guard the use of the command line args.
This commit is contained in:
Nicholas Wilson 2017-05-24 08:55:32 +08:00 committed by GitHub
parent cae9ccd9a4
commit ae6ff33fc1
23 changed files with 378 additions and 92 deletions

View file

@ -25,6 +25,11 @@ math(EXPR LDC_LLVM_VER ${LLVM_VERSION_MAJOR}*100+${LLVM_VERSION_MINOR})
string(REGEX MATCH "^-.*LLVMTableGen[^;]*;|;-.*LLVMTableGen[^;]*" LLVM_TABLEGEN_LIBRARY "${LLVM_LIBRARIES}") string(REGEX MATCH "^-.*LLVMTableGen[^;]*;|;-.*LLVMTableGen[^;]*" LLVM_TABLEGEN_LIBRARY "${LLVM_LIBRARIES}")
string(REGEX REPLACE "^-.*LLVMTableGen[^;]*;|;-.*LLVMTableGen[^;]*" "" LLVM_LIBRARIES "${LLVM_LIBRARIES}") string(REGEX REPLACE "^-.*LLVMTableGen[^;]*;|;-.*LLVMTableGen[^;]*" "" LLVM_LIBRARIES "${LLVM_LIBRARIES}")
# Information about which targets LLVM was built to target
foreach(LLVM_SUPPORTED_TARGET ${LLVM_TARGETS_TO_BUILD})
add_definitions("-DLDC_LLVM_SUPPORTED_TARGET_${LLVM_SUPPORTED_TARGET}=1")
endforeach()
# #
# Get info about used Linux distribution. # Get info about used Linux distribution.
# #
@ -330,6 +335,7 @@ set(DRV_SRC
driver/cl_options.cpp driver/cl_options.cpp
driver/codegenerator.cpp driver/codegenerator.cpp
driver/configfile.cpp driver/configfile.cpp
driver/dcomputecodegenerator.cpp
driver/exe_path.cpp driver/exe_path.cpp
driver/targetmachine.cpp driver/targetmachine.cpp
driver/toobj.cpp driver/toobj.cpp
@ -345,6 +351,7 @@ set(DRV_HDR
driver/cl_options.h driver/cl_options.h
driver/codegenerator.h driver/codegenerator.h
driver/configfile.h driver/configfile.h
driver/dcomputecodegenerator.h
driver/exe_path.h driver/exe_path.h
driver/ldc-version.h driver/ldc-version.h
driver/archiver.h driver/archiver.h

View file

@ -505,6 +505,15 @@ cl::opt<std::string>
"of optimizations performed by LLVM"), "of optimizations performed by LLVM"),
cl::ValueOptional); cl::ValueOptional);
#endif #endif
#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX
cl::list<std::string>
dcomputeTargets("mdcompute-targets", cl::CommaSeparated,
cl::desc("Generates code for the specified DCompute target"
" list. Use 'ocl-xy0' for OpenCL x.y, and "
"'cuda-xy0' for CUDA CC x.y"),
cl::value_desc("targets"));
#endif
static cl::extrahelp footer( static cl::extrahelp footer(
"\n" "\n"

View file

@ -124,5 +124,8 @@ inline bool isUsingThinLTO() { return false; }
#if LDC_LLVM_VER >= 400 #if LDC_LLVM_VER >= 400
extern cl::opt<std::string> saveOptimizationRecord; extern cl::opt<std::string> saveOptimizationRecord;
#endif #endif
#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX
extern cl::list<std::string> dcomputeTargets;
#endif
} }
#endif #endif

View file

@ -0,0 +1,74 @@
//===-- driver/dcomputecodegenerator.cpp ----------------------------------===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "driver/dcomputecodegenerator.h"
#include "driver/cl_options.h"
#include "ddmd/errors.h"
#include "gen/cl_helpers.h"
#include "ir/irdsymbol.h"
#include "llvm/Support/CommandLine.h"
#include <array>
#include <string>
#include <algorithm>
DComputeTarget *
DComputeCodeGenManager::createComputeTarget(const std::string &s) {
int v;
#define OCL_VALID_VER_INIT 100, 110, 120, 200, 210, 220
const std::array<int, 6> valid_ocl_versions = {{OCL_VALID_VER_INIT}};
#define CUDA_VALID_VER_INIT 100, 110, 120, 130, 200, 210, 300, 350, 370,\
500, 520, 600, 610, 620
const std::array<int, 14> vaild_cuda_versions = {{CUDA_VALID_VER_INIT}};
if (s.substr(0, 4) == "ocl-") {
v = atoi(s.c_str() + 4);
if (std::find(valid_ocl_versions.begin(), valid_ocl_versions.end(), v) !=
valid_ocl_versions.end()) {
return createOCLTarget(ctx, v);
}
} else if (s.substr(0, 5) == "cuda-") {
v = atoi(s.c_str() + 5);
if (std::find(vaild_cuda_versions.begin(), vaild_cuda_versions.end(), v) !=
vaild_cuda_versions.end()) {
return createCUDATarget(ctx, v);
}
}
#define XSTR(x) #x
#define STR(x) XSTR((x))
error(Loc(),
"unrecognised or invalid DCompute targets: the format is ocl-xy0 "
"for OpenCl x.y and cuda-xy0 for CUDA CC x.y. Valid versions "
"for OpenCl are " STR(OCL_VALID_VER_INIT) ". Valid versions for CUDA "
"are " STR(CUDA_VALID_VER_INIT));
fatal();
return nullptr;
}
DComputeCodeGenManager::DComputeCodeGenManager(llvm::LLVMContext &c) : ctx(c) {
#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX
for (auto &option : opts::dcomputeTargets) {
targets.push_back(createComputeTarget(option));
}
#endif
}
void DComputeCodeGenManager::emit(Module *m) {
for (auto &target : targets) {
target->emit(m);
IrDsymbol::resetAll();
}
}
void DComputeCodeGenManager::writeModules() {
for (auto &target : targets) {
target->writeModule();
}
}

View file

@ -0,0 +1,31 @@
//===-- driver/dcomputecodegenerator.h - LDC --------------------*- C++ -*-===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#ifndef LDC_DRIVER_DCOMPUTECODEGENERATOR_H
#define LDC_DRIVER_DCOMPUTECODEGENERATOR_H
#include "gen/dcompute/target.h"
#include "llvm/ADT/SmallVector.h"
// gets run on modules marked @compute
// All @compute D modules are emitted into one LLVM module once per target.
class DComputeCodeGenManager {
llvm::LLVMContext &ctx;
llvm::SmallVector<DComputeTarget *, 2> targets;
DComputeTarget *createComputeTarget(const std::string &s);
public:
void emit(Module *m);
void writeModules();
DComputeCodeGenManager(llvm::LLVMContext &c);
};
#endif

View file

@ -23,6 +23,7 @@
#include "driver/cl_options.h" #include "driver/cl_options.h"
#include "driver/codegenerator.h" #include "driver/codegenerator.h"
#include "driver/configfile.h" #include "driver/configfile.h"
#include "driver/dcomputecodegenerator.h"
#include "driver/exe_path.h" #include "driver/exe_path.h"
#include "driver/ldc-version.h" #include "driver/ldc-version.h"
#include "driver/linker.h" #include "driver/linker.h"
@ -40,6 +41,7 @@
#include "gen/optimizer.h" #include "gen/optimizer.h"
#include "gen/passes/Passes.h" #include "gen/passes/Passes.h"
#include "gen/runtime.h" #include "gen/runtime.h"
#include "gen/uda.h"
#include "gen/abi.h" #include "gen/abi.h"
#include "llvm/InitializePasses.h" #include "llvm/InitializePasses.h"
#include "llvm/LinkAllPasses.h" #include "llvm/LinkAllPasses.h"
@ -879,6 +881,9 @@ void registerPredefinedVersions() {
VersionCondition::addPredefinedGlobalIdent("LDC"); VersionCondition::addPredefinedGlobalIdent("LDC");
VersionCondition::addPredefinedGlobalIdent("all"); VersionCondition::addPredefinedGlobalIdent("all");
VersionCondition::addPredefinedGlobalIdent("D_Version2"); VersionCondition::addPredefinedGlobalIdent("D_Version2");
#if LDC_LLVM_SUPPORTED_TARGET_SPIRV || LDC_LLVM_SUPPORTED_TARGET_NVPTX
VersionCondition::addPredefinedGlobalIdent("LDC_DCompute");
#endif
if (global.params.doDocComments) { if (global.params.doDocComments) {
VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); VersionCondition::addPredefinedGlobalIdent("D_Ddoc");
@ -1034,10 +1039,11 @@ void addDefaultVersionIdentifiers() {
} }
void codegenModules(Modules &modules) { void codegenModules(Modules &modules) {
// Generate one or more object/IR/bitcode files. // Generate one or more object/IR/bitcode files/dcompute kernels.
if (global.params.obj && !modules.empty()) { if (global.params.obj && !modules.empty()) {
ldc::CodeGenerator cg(getGlobalContext(), global.params.oneobj); ldc::CodeGenerator cg(getGlobalContext(), global.params.oneobj);
DComputeCodeGenManager dccg(getGlobalContext());
std::vector<Module *> computeModules;
// When inlining is enabled, we are calling semantic3 on function // When inlining is enabled, we are calling semantic3 on function
// declarations, which may _add_ members to the first module in the modules // declarations, which may _add_ members to the first module in the modules
// array. These added functions must be codegenned, because these functions // array. These added functions must be codegenned, because these functions
@ -1051,11 +1057,25 @@ void codegenModules(Modules &modules) {
if (global.params.verbose) if (global.params.verbose)
fprintf(global.stdmsg, "code %s\n", m->toChars()); fprintf(global.stdmsg, "code %s\n", m->toChars());
cg.emit(m); const auto atCompute = hasComputeAttr(m);
if (atCompute == DComputeCompileFor::hostOnly ||
atCompute == DComputeCompileFor::hostAndDevice)
{
cg.emit(m);
}
if (atCompute != DComputeCompileFor::hostOnly)
computeModules.push_back(m);
if (global.errors) if (global.errors)
fatal(); fatal();
} }
if (!computeModules.empty()) {
for (auto& mod : computeModules)
dccg.emit(mod);
dccg.writeModules();
}
} }
cache::pruneCache(); cache::pruneCache();

View file

@ -23,6 +23,7 @@
#include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetOptions.h"
#include "llvm/IR/Module.h"
#include "mars.h" #include "mars.h"
#include "gen/logger.h" #include "gen/logger.h"
@ -632,3 +633,13 @@ createTargetMachine(std::string targetTriple, std::string arch, std::string cpu,
targetOptions, relocModel, codeModel, targetOptions, relocModel, codeModel,
codeGenOptLevel); codeGenOptLevel);
} }
ComputeBackend::Type getComputeTargetType(llvm::Module* m) {
llvm::Triple::ArchType a = llvm::Triple(m->getTargetTriple()).getArch();
if (a == llvm::Triple::spir || a == llvm::Triple::spir64)
return ComputeBackend::SPIRV;
else if (a == llvm::Triple::nvptx || a == llvm::Triple::nvptx64)
return ComputeBackend::NVPTX;
else
return ComputeBackend::None;
}

View file

@ -38,8 +38,15 @@ namespace llvm {
class Triple; class Triple;
class Target; class Target;
class TargetMachine; class TargetMachine;
class Module;
} }
namespace ComputeBackend {
enum Type { None, SPIRV, NVPTX };
}
ComputeBackend::Type getComputeTargetType(llvm::Module*);
/** /**
* Creates an LLVM TargetMachine suitable for the given (usually command-line) * Creates an LLVM TargetMachine suitable for the given (usually command-line)
* parameters and the host platform defaults. * parameters and the host platform defaults.

View file

@ -39,6 +39,9 @@
#if LDC_LLVM_VER >= 307 #if LDC_LLVM_VER >= 307
#include "llvm/Support/Path.h" #include "llvm/Support/Path.h"
#endif #endif
#ifdef LDC_LLVM_SUPPORTED_TARGET_SPIRV
#include "llvm/Support/SPIRV.h"
#endif
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
#if LDC_LLVM_VER >= 307 #if LDC_LLVM_VER >= 307
#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/TargetTransformInfo.h"
@ -75,7 +78,19 @@ static void codegenModule(llvm::TargetMachine &Target, llvm::Module &m,
legacy:: legacy::
#endif #endif
PassManager Passes; PassManager Passes;
ComputeBackend::Type cb = getComputeTargetType(&m);
if (cb == ComputeBackend::SPIRV) {
#ifdef LDC_LLVM_SUPPORTED_TARGET_SPIRV
IF_LOG Logger::println("running createSPIRVWriterPass()");
llvm::createSPIRVWriterPass(out)->runOnModule(m);
IF_LOG Logger::println("Success.");
#else
error(Loc(), "Trying to target SPIRV, but LDC is not built to do so!");
#endif
return;
}
#if LDC_LLVM_VER >= 307 #if LDC_LLVM_VER >= 307
// The DataLayout is already set at the module (in module.cpp, // The DataLayout is already set at the module (in module.cpp,
// method Module::genLLVMModule()) // method Module::genLLVMModule())
@ -107,7 +122,11 @@ static void codegenModule(llvm::TargetMachine &Target, llvm::Module &m,
#else #else
fout, fout,
#endif #endif
fileType, codeGenOptLevel())) { // Always generate assembly for ptx as it is an assembly format
// The PTX backend fails if we pass anything else.
(cb == ComputeBackend::NVPTX) ? llvm::TargetMachine::CGFT_AssemblyFile
: fileType,
codeGenOptLevel())) {
llvm_unreachable("no support for asm output"); llvm_unreachable("no support for asm output");
} }

View file

@ -23,13 +23,13 @@
#include "gen/dcompute/druntime.h" #include "gen/dcompute/druntime.h"
struct DComputePointerRewrite : ABIRewrite { struct DComputePointerRewrite : ABIRewrite {
LLType* type(Type* t) override { LLType *type(Type *t) override {
auto ptr = toDcomputePointer(static_cast<TypeStruct*>(t)->sym); auto ptr = toDcomputePointer(static_cast<TypeStruct *>(t)->sym);
return ptr->toLLVMType(); return ptr->toLLVMType(true);
} }
LLValue *getLVal(Type *dty, LLValue *v) override { LLValue *getLVal(Type *dty, LLValue *v) override {
// TODO: Is this correct? // TODO: Is this correct?
return DtoBitCast(v,this->type(dty)); return DtoBitCast(v, this->type(dty));
} }
LLValue *put(DValue *dv) override { LLValue *put(DValue *dv) override {
LLValue *address = getAddressOf(dv); LLValue *address = getAddressOf(dv);

View file

@ -32,16 +32,14 @@ bool isFromLDC_DCompute(Dsymbol *sym) {
return false; return false;
return moduleDecl->id == Id::dcompute; return moduleDecl->id == Id::dcompute;
} }
llvm::Optional<DcomputePointer> toDcomputePointer(StructDeclaration *sd) llvm::Optional<DcomputePointer> toDcomputePointer(StructDeclaration *sd) {
{
if (sd->ident != Id::dcPointer || !isFromLDC_DCompute(sd)) if (sd->ident != Id::dcPointer || !isFromLDC_DCompute(sd))
return llvm::Optional<DcomputePointer>(llvm::None); return llvm::Optional<DcomputePointer>(llvm::None);
TemplateInstance *ti = sd->isInstantiated(); TemplateInstance *ti = sd->isInstantiated();
int addrspace = isExpression((*ti->tiargs)[0])->toInteger(); int addrspace = isExpression((*ti->tiargs)[0])->toInteger();
Type* type = isType((*ti->tiargs)[1]); Type *type = isType((*ti->tiargs)[1]);
return llvm::Optional<DcomputePointer>(DcomputePointer(addrspace,type)); return llvm::Optional<DcomputePointer>(DcomputePointer(addrspace, type));
} }

View file

@ -15,22 +15,26 @@
#include "ddmd/aggregate.h" #include "ddmd/aggregate.h"
#include "ddmd/mtype.h" #include "ddmd/mtype.h"
#include "llvm/ADT/Optional.h" #include "llvm/ADT/Optional.h"
#include "gen/dcompute/target.h"
#include "gen/irstate.h"
#include "gen/llvm.h" #include "gen/llvm.h"
#include "gen/tollvm.h" #include "gen/tollvm.h"
class Dsymbol; class Dsymbol;
class Type; class Type;
bool isFromLDC_DCompute(Dsymbol *sym); bool isFromLDC_DCompute(Dsymbol *sym);
struct DcomputePointer { struct DcomputePointer {
int addrspace; int addrspace;
Type* type; Type *type;
DcomputePointer(int as,Type* ty) : addrspace(as),type(ty) {} DcomputePointer(int as, Type *ty) : addrspace(as), type(ty) {}
LLType *toLLVMType() { LLType *toLLVMType(bool translate) {
auto llType = DtoMemType(type); auto llType = DtoMemType(type);
return llType->getPointerElementType()->getPointerTo(addrspace); int as = addrspace;
if (translate)
as = gIR->dcomputetarget->mapping[as];
return llType->getPointerElementType()->getPointerTo(as);
} }
}; };
llvm::Optional<DcomputePointer> toDcomputePointer(StructDeclaration *sd); llvm::Optional<DcomputePointer> toDcomputePointer(StructDeclaration *sd);

View file

@ -30,7 +30,6 @@ void DComputeTarget::doCodeGen(Module *m) {
if (global.errors) if (global.errors)
fatal(); fatal();
} }
void DComputeTarget::emit(Module *m) { void DComputeTarget::emit(Module *m) {

View file

@ -38,8 +38,8 @@ public:
DComputeTarget(llvm::LLVMContext &c, int v, ID id, const char *_short_name, DComputeTarget(llvm::LLVMContext &c, int v, ID id, const char *_short_name,
const char *suffix, TargetABI *a, std::array<int, 5> map) const char *suffix, TargetABI *a, std::array<int, 5> map)
: ctx(c), tversion(v), target(id), short_name(_short_name), : ctx(c), tversion(v), target(id), short_name(_short_name),
binSuffix(suffix), abi(a), mapping(map), _ir(nullptr) { } binSuffix(suffix), abi(a), mapping(map), _ir(nullptr) {}
void emit(Module *m); void emit(Module *m);
void doCodeGen(Module *m); void doCodeGen(Module *m);

View file

@ -21,17 +21,20 @@ namespace {
class TargetCUDA : public DComputeTarget { class TargetCUDA : public DComputeTarget {
public: public:
TargetCUDA(llvm::LLVMContext &c, int sm) TargetCUDA(llvm::LLVMContext &c, int sm)
: DComputeTarget( : DComputeTarget(
c, sm, CUDA, "cuda", "ptx", createNVPTXABI(), c, sm, CUDA, "cuda", "ptx", createNVPTXABI(),
// Map from nominal DCompute address space to NVPTX address space. // Map from nominal DCompute address space to NVPTX address space.
// see $LLVM_ROOT/docs/docs/NVPTXUsage.rst section Address Spaces // see $LLVM_ROOT/docs/docs/NVPTXUsage.rst section Address Spaces
{{5, 1, 3, 4, 0}}) { {{5, 1, 3, 4, 0}}) {
std::string dl = global.params.is64bit ? std::string dl =
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-" global.params.is64bit
"f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64" : ? "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:"
"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-" "32-"
"f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"; "f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
: "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:"
"32-"
"f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64";
_ir = new IRState("dcomputeTargetCUDA", ctx); _ir = new IRState("dcomputeTargetCUDA", ctx);
_ir->module.setTargetTriple(global.params.is64bit ? "nvptx64-nvidia-cuda" _ir->module.setTargetTriple(global.params.is64bit ? "nvptx64-nvidia-cuda"
@ -40,20 +43,20 @@ public:
_ir->dcomputetarget = this; _ir->dcomputetarget = this;
} }
void addMetadata() override { void addMetadata() override {
// sm version? // sm version?
} }
void setGTargetMachine() override { void setGTargetMachine() override {
char buf[8]; char buf[8];
bool is64 = global.params.is64bit; bool is64 = global.params.is64bit;
snprintf(buf, sizeof(buf), "sm_%d", tversion / 10); snprintf(buf, sizeof(buf), "sm_%d", tversion / 10);
gTargetMachine = createTargetMachine( gTargetMachine = createTargetMachine(
is64 ? "nvptx64-nvidia-cuda" : "nvptx-nvidia-cuda", is64 ? "nvptx64-nvidia-cuda" : "nvptx-nvidia-cuda",
is64 ? "nvptx64" : "nvptx", buf, {}, is64 ? "nvptx64" : "nvptx", buf, {},
is64 ? ExplicitBitness::M64 : ExplicitBitness::M32, ::FloatABI::Hard, is64 ? ExplicitBitness::M64 : ExplicitBitness::M32, ::FloatABI::Hard,
llvm::Reloc::Static, llvm::CodeModel::Medium, codeGenOptLevel(), false, llvm::Reloc::Static, llvm::CodeModel::Medium, codeGenOptLevel(), false,
false); false);
} }
void addKernelMetadata(FuncDeclaration *df, llvm::Function *llf) override { void addKernelMetadata(FuncDeclaration *df, llvm::Function *llf) override {
// Fix 3.5.2 build failures. Remove when dropping 3.5 support. // Fix 3.5.2 build failures. Remove when dropping 3.5 support.

View file

@ -52,10 +52,10 @@ public:
} }
void setGTargetMachine() override { gTargetMachine = nullptr; } void setGTargetMachine() override { gTargetMachine = nullptr; }
// Adapted from clang // Adapted from clang
void addMetadata() override { void addMetadata() override {
// Fix 3.5.2 build failures. Remove when dropping 3.5 support. // Fix 3.5.2 build failures. Remove when dropping 3.5 support.
// OCL is only supported for 3.6.1 and 3.8 anyway. // OCL is only supported for 3.6.1 and 3.8 anyway.
#if LDC_LLVM_VER >= 306 #if LDC_LLVM_VER >= 306
// opencl.ident? // opencl.ident?
// spirv.Source // debug only // spirv.Source // debug only
@ -70,7 +70,7 @@ public:
llvm::ConstantAsMetadata::get( llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(llvm::Type::getInt32Ty(ctx), 2))}; llvm::ConstantInt::get(llvm::Type::getInt32Ty(ctx), 2))};
llvm::NamedMDNode *SPIRVerMD = llvm::NamedMDNode *SPIRVerMD =
_ir->module.getOrInsertNamedMetadata("opencl.spir.version"); _ir->module.getOrInsertNamedMetadata("opencl.spir.version");
SPIRVerMD->addOperand(llvm::MDNode::get(ctx, SPIRVerElts)); SPIRVerMD->addOperand(llvm::MDNode::get(ctx, SPIRVerElts));
// Add OpenCL version // Add OpenCL version
@ -81,7 +81,7 @@ public:
llvm::Type::getInt32Ty(ctx), (tversion % 100) / 10))}; llvm::Type::getInt32Ty(ctx), (tversion % 100) / 10))};
llvm::NamedMDNode *OCLVerMD = llvm::NamedMDNode *OCLVerMD =
_ir->module.getOrInsertNamedMetadata("opencl.ocl.version"); _ir->module.getOrInsertNamedMetadata("opencl.ocl.version");
OCLVerMD->addOperand(llvm::MDNode::get(ctx, OCLVerElts)); OCLVerMD->addOperand(llvm::MDNode::get(ctx, OCLVerElts));
#endif #endif
} }
@ -93,20 +93,20 @@ public:
KernArgMD_type_qual, KernArgMD_type_qual,
KernArgMD_name, KernArgMD_name,
count_KernArgMD count_KernArgMD
}; };
void addKernelMetadata(FuncDeclaration *fd, llvm::Function *llf) override { void addKernelMetadata(FuncDeclaration *fd, llvm::Function *llf) override {
// By the time we get here the ABI should have rewritten the function // By the time we get here the ABI should have rewritten the function
// type so that the magic types in ldc.dcompute are transformed into // type so that the magic types in ldc.dcompute are transformed into
// what the LLVM backend expects. // what the LLVM backend expects.
// Fix 3.5.2 build failures. Remove when dropping 3.5 support. // Fix 3.5.2 build failures. Remove when dropping 3.5 support.
#if LDC_LLVM_VER >= 306 #if LDC_LLVM_VER >= 306
unsigned i = 0; unsigned i = 0;
// TODO: Handle Function attibutes // TODO: Handle Function attibutes
llvm::SmallVector<llvm::Metadata *, 8> kernelMDArgs; llvm::SmallVector<llvm::Metadata *, 8> kernelMDArgs;
kernelMDArgs.push_back(llvm::ConstantAsMetadata::get(llf)); kernelMDArgs.push_back(llvm::ConstantAsMetadata::get(llf));
// MDNode for the kernel argument address space qualifiers. // MDNode for the kernel argument address space qualifiers.
std::array<llvm::SmallVector<llvm::Metadata *, 8>,count_KernArgMD> paramArgs; std::array<llvm::SmallVector<llvm::Metadata *, 8>,count_KernArgMD> paramArgs;
std::array<const char*,count_KernArgMD> args = { std::array<const char*,count_KernArgMD> args = {
"kernel_arg_addr_space", "kernel_arg_addr_space",
@ -125,17 +125,17 @@ public:
VarDeclarations *vs = fd->parameters; VarDeclarations *vs = fd->parameters;
for (i = 0; i < vs->dim; i++) { for (i = 0; i < vs->dim; i++) {
VarDeclaration *v = (*vs)[i]; VarDeclaration *v = (*vs)[i];
decodeTypes(paramArgs,v); decodeTypes(paramArgs, v);
} }
for (auto& md : paramArgs) for (auto &md : paramArgs)
kernelMDArgs.push_back(llvm::MDNode::get(ctx, md)); kernelMDArgs.push_back(llvm::MDNode::get(ctx, md));
///------------------------------- ///-------------------------------
/// TODO: Handle Function attibutes /// TODO: Handle Function attibutes
///------------------------------- ///-------------------------------
llvm::MDNode *kernelMDNode = llvm::MDNode::get(ctx, kernelMDArgs); llvm::MDNode *kernelMDNode = llvm::MDNode::get(ctx, kernelMDArgs);
llvm::NamedMDNode *OpenCLKernelMetadata = llvm::NamedMDNode *OpenCLKernelMetadata =
_ir->module.getOrInsertNamedMetadata("opencl.kernels"); _ir->module.getOrInsertNamedMetadata("opencl.kernels");
OpenCLKernelMetadata->addOperand(kernelMDNode); OpenCLKernelMetadata->addOperand(kernelMDNode);
#endif #endif
} }
@ -147,19 +147,23 @@ public:
std::string basicTypeToString(Type *t) { std::string basicTypeToString(Type *t) {
std::stringstream ss; std::stringstream ss;
auto ty = t->ty; auto ty = t->ty;
if (ty == Tint8) ss << "char"; if (ty == Tint8)
else if (ty == Tuns8) ss << "uchar"; ss << "char";
else if (ty == Tuns8)
ss << "uchar";
else if (ty == Tvector) { else if (ty == Tvector) {
TypeVector* vec = static_cast<TypeVector*>(t); TypeVector *vec = static_cast<TypeVector *>(t);
auto size = vec->size(Loc()); auto size = vec->size(Loc());
auto basety = vec->basetype->ty; auto basety = vec->basetype->ty;
if (basety == Tint8) ss << "char"; if (basety == Tint8)
else if (basety == Tuns8) ss << "uchar"; ss << "char";
else ss << vec->basetype->toChars(); else if (basety == Tuns8)
ss << "uchar";
else
ss << vec->basetype->toChars();
ss << (int)size; ss << (int)size;
} } else
else ss << t->toChars();
ss << t->toChars();
return ss.str(); return ss.str();
} }
#if LDC_LLVM_VER >= 306 #if LDC_LLVM_VER >= 306
@ -173,17 +177,14 @@ public:
std::string accessQual = "none"; std::string accessQual = "none";
int addrspace = 0; int addrspace = 0;
if (v->type->ty == Tstruct && if (v->type->ty == Tstruct &&
(ptr = toDcomputePointer(static_cast<TypeStruct*>(v->type)->sym))) (ptr = toDcomputePointer(static_cast<TypeStruct *>(v->type)->sym))) {
{
addrspace = ptr->addrspace; addrspace = ptr->addrspace;
tyName = basicTypeToString(ptr->type) + "*"; tyName = basicTypeToString(ptr->type) + "*";
baseTyName = tyName; baseTyName = tyName;
// there is no volatile or restrict (yet) in D // there is no volatile or restrict (yet) in D
typeQuals = mod2str(ptr->type->mod); typeQuals = mod2str(ptr->type->mod);
// TODO: Images and Pipes They are global pointers to opaques // TODO: Images and Pipes They are global pointers to opaques
} } else {
else
{
tyName = basicTypeToString(v->type); tyName = basicTypeToString(v->type);
baseTyName = tyName; baseTyName = tyName;
typeQuals = mod2str(v->type->mod); typeQuals = mod2str(v->type->mod);

View file

@ -67,6 +67,8 @@ public:
decl->toPrettyChars()); decl->toPrettyChars());
LOG_SCOPE LOG_SCOPE
assert(!irs->dcomputetarget);
if (decl->ir->isDefined()) { if (decl->ir->isDefined()) {
return; return;
} }
@ -125,14 +127,18 @@ public:
m->accept(this); m->accept(this);
} }
// Define the __initZ symbol. // Skip __initZ and typeinfo for @compute device code.
IrAggr *ir = getIrAggr(decl); // TODO: support global variables and thus __initZ
llvm::GlobalVariable *initZ = ir->getInitSymbol(); if (!irs->dcomputetarget) {
initZ->setInitializer(ir->getDefaultInit()); // Define the __initZ symbol.
setLinkage(decl, initZ); IrAggr *ir = getIrAggr(decl);
llvm::GlobalVariable *initZ = ir->getInitSymbol();
initZ->setInitializer(ir->getDefaultInit());
setLinkage(decl, initZ);
// emit typeinfo // emit typeinfo
DtoTypeInfoOf(decl->type); DtoTypeInfoOf(decl->type);
}
// Emit __xopEquals/__xopCmp/__xtoHash. // Emit __xopEquals/__xopCmp/__xtoHash.
if (decl->xeq && decl->xeq != decl->xerreq) { if (decl->xeq && decl->xeq != decl->xerreq) {
@ -153,6 +159,8 @@ public:
decl->toPrettyChars()); decl->toPrettyChars());
LOG_SCOPE LOG_SCOPE
assert(!irs->dcomputetarget);
if (decl->ir->isDefined()) { if (decl->ir->isDefined()) {
return; return;
} }
@ -245,6 +253,7 @@ public:
assert(!(decl->storage_class & STCmanifest) && assert(!(decl->storage_class & STCmanifest) &&
"manifest constant being codegen'd!"); "manifest constant being codegen'd!");
assert(!irs->dcomputetarget);
IrGlobal *irGlobal = getIrGlobal(decl); IrGlobal *irGlobal = getIrGlobal(decl);
LLGlobalVariable *gvar = llvm::cast<LLGlobalVariable>(irGlobal->value); LLGlobalVariable *gvar = llvm::cast<LLGlobalVariable>(irGlobal->value);
@ -412,7 +421,8 @@ public:
void visit(PragmaDeclaration *decl) LLVM_OVERRIDE { void visit(PragmaDeclaration *decl) LLVM_OVERRIDE {
if (decl->ident == Id::lib) { if (decl->ident == Id::lib) {
assert(decl->args && decl->args->dim == 1); assert(decl->args && decl->args->dim == 1);
assert(!irs->dcomputetarget);
Expression *e = static_cast<Expression *>(decl->args->data[0]); Expression *e = static_cast<Expression *>(decl->args->data[0]);
assert(e->op == TOKstring); assert(e->op == TOKstring);
@ -473,7 +483,7 @@ public:
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void visit(TypeInfoDeclaration *decl) LLVM_OVERRIDE { void visit(TypeInfoDeclaration *decl) LLVM_OVERRIDE {
if (isSpeculativeType(decl->tinfo)) { if (irs->dcomputetarget || isSpeculativeType(decl->tinfo)) {
return; return;
} }
TypeInfoDeclaration_codegen(decl, irs); TypeInfoDeclaration_codegen(decl, irs);
@ -482,7 +492,7 @@ public:
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void visit(TypeInfoClassDeclaration *decl) LLVM_OVERRIDE { void visit(TypeInfoClassDeclaration *decl) LLVM_OVERRIDE {
if (isSpeculativeType(decl->tinfo)) { if (irs->dcomputetarget || isSpeculativeType(decl->tinfo)) {
return; return;
} }
TypeInfoClassDeclaration_codegen(decl, irs); TypeInfoClassDeclaration_codegen(decl, irs);

View file

@ -22,6 +22,7 @@
#include "gen/abi.h" #include "gen/abi.h"
#include "gen/arrays.h" #include "gen/arrays.h"
#include "gen/classes.h" #include "gen/classes.h"
#include "gen/dcompute/target.h"
#include "gen/dvalue.h" #include "gen/dvalue.h"
#include "gen/funcgenstate.h" #include "gen/funcgenstate.h"
#include "gen/function-inlining.h" #include "gen/function-inlining.h"
@ -977,7 +978,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
#if LDC_LLVM_VER >= 500 #if LDC_LLVM_VER >= 500
0, // Address space 0, // Address space
#endif #endif
"alloca point", beginbb); "alloca_point", beginbb);
funcGen.allocapoint = allocaPoint; funcGen.allocapoint = allocaPoint;
// debug info - after all allocas, but before any llvm.dbg.declare etc // debug info - after all allocas, but before any llvm.dbg.declare etc
@ -1127,6 +1128,11 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
} }
gIR->scopes.pop_back(); gIR->scopes.pop_back();
if (gIR->dcomputetarget && hasKernelAttr(fd)) {
auto fn = gIR->module.getFunction(fd->mangleString);
gIR->dcomputetarget->addKernelMetadata(fd, fn);
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -12,6 +12,7 @@
#include "gen/cl_helpers.h" #include "gen/cl_helpers.h"
#include "gen/logger.h" #include "gen/logger.h"
#include "gen/passes/Passes.h" #include "gen/passes/Passes.h"
#include "driver/targetmachine.h"
#include "llvm/LinkAllPasses.h" #include "llvm/LinkAllPasses.h"
#if LDC_LLVM_VER >= 307 #if LDC_LLVM_VER >= 307
#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/LegacyPassManager.h"
@ -341,6 +342,16 @@ bool ldc_optimize_module(llvm::Module *M) {
#endif #endif
PassManager mpm; PassManager mpm;
// Dont optimise spirv modules because turning GEPs into extracts triggers
// asserts in the IR -> SPIR-V translation pass. SPIRV doesn't have a target
// machine, so any optimisation passes that rely on it to provide analysis,
// like DCE can't be run.
// The optimisation is supposed to happen between the SPIRV -> native machine
// code pass of the consumer of the binary.
// TODO: run rudimentary optimisations to improve IR debuggability.
if (getComputeTargetType(M) == ComputeBackend::SPIRV)
return false;
#if LDC_LLVM_VER >= 307 #if LDC_LLVM_VER >= 307
// Add an appropriate TargetLibraryInfo pass for the module's triple. // Add an appropriate TargetLibraryInfo pass for the module's triple.
TargetLibraryInfoImpl *tlii = TargetLibraryInfoImpl *tlii =

View file

@ -16,6 +16,7 @@
#include "gen/arrays.h" #include "gen/arrays.h"
#include "gen/classes.h" #include "gen/classes.h"
#include "gen/coverage.h" #include "gen/coverage.h"
#include "gen/dcompute/target.h"
#include "gen/dvalue.h" #include "gen/dvalue.h"
#include "gen/funcgenstate.h" #include "gen/funcgenstate.h"
#include "gen/irstate.h" #include "gen/irstate.h"
@ -24,6 +25,7 @@
#include "gen/logger.h" #include "gen/logger.h"
#include "gen/runtime.h" #include "gen/runtime.h"
#include "gen/tollvm.h" #include "gen/tollvm.h"
#include "id.h"
#include "ir/irfunction.h" #include "ir/irfunction.h"
#include "ir/irmodule.h" #include "ir/irmodule.h"
#include "llvm/IR/CFG.h" #include "llvm/IR/CFG.h"
@ -317,6 +319,18 @@ public:
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
bool dcomputeReflectMatches(CallExp *ce) {
auto arg1 = (DComputeTarget::ID)(*ce->arguments)[0]->toInteger();
auto arg2 = (*ce->arguments)[1]->toInteger();
auto dct = irs->dcomputetarget;
if (!dct) {
return arg1 == DComputeTarget::Host;
}
else {
return arg1 == dct->target && (!arg2 || arg2 == dct->tversion);
}
}
void visit(IfStatement *stmt) LLVM_OVERRIDE { void visit(IfStatement *stmt) LLVM_OVERRIDE {
IF_LOG Logger::println("IfStatement::toIR(): %s", stmt->loc.toChars()); IF_LOG Logger::println("IfStatement::toIR(): %s", stmt->loc.toChars());
@ -332,6 +346,22 @@ public:
irs->DBuilder.EmitBlockStart(stmt->loc); irs->DBuilder.EmitBlockStart(stmt->loc);
emitCoverageLinecountInc(stmt->loc); emitCoverageLinecountInc(stmt->loc);
// This is a (dirty) hack to get codegen time conditional
// compilation, on account of the fact that we are trying
// to target multiple backends "simultaneously" with one
// pass through the front end, to have a single "static"
// context.
if (stmt->condition->op == TOKcall) {
auto ce = (CallExp *)stmt->condition;
if (ce->f && ce->f->ident == Id::dcReflect) {
if (dcomputeReflectMatches(ce))
stmt->ifbody->accept(this);
else if (stmt->elsebody)
stmt->elsebody->accept(this);
return;
}
}
DValue *cond_e = toElemDtor(stmt->condition); DValue *cond_e = toElemDtor(stmt->condition);
LLValue *cond_val = DtoRVal(cond_e); LLValue *cond_val = DtoRVal(cond_e);
@ -745,10 +775,15 @@ public:
irs->DBuilder.EmitBlockStart(stmt->finalbody->loc); irs->DBuilder.EmitBlockStart(stmt->finalbody->loc);
stmt->finalbody->accept(this); stmt->finalbody->accept(this);
irs->DBuilder.EmitBlockEnd(); irs->DBuilder.EmitBlockEnd();
CleanupCursor cleanupBefore;
CleanupCursor cleanupBefore = irs->funcGen().scopes.currentCleanupScope(); // For @compute code, don't emit any exception handling as there are no
irs->funcGen().scopes.pushCleanup(finallybb, irs->scopebb()); // exceptions anyway.
const bool computeCode = !!irs->dcomputetarget;
if (!computeCode) {
cleanupBefore = irs->funcGen().scopes.currentCleanupScope();
irs->funcGen().scopes.pushCleanup(finallybb, irs->scopebb());
}
// Emit the try block. // Emit the try block.
irs->scope() = IRScope(trybb); irs->scope() = IRScope(trybb);
@ -758,12 +793,14 @@ public:
irs->DBuilder.EmitBlockEnd(); irs->DBuilder.EmitBlockEnd();
if (successbb) { if (successbb) {
irs->funcGen().scopes.runCleanups(cleanupBefore, successbb); if (!computeCode)
irs->funcGen().scopes.runCleanups(cleanupBefore, successbb);
irs->scope() = IRScope(successbb); irs->scope() = IRScope(successbb);
// PGO counter tracks the continuation of the try-finally statement // PGO counter tracks the continuation of the try-finally statement
PGO.emitCounterIncrement(stmt); PGO.emitCounterIncrement(stmt);
} }
irs->funcGen().scopes.popCleanups(cleanupBefore); if (!computeCode)
irs->funcGen().scopes.popCleanups(cleanupBefore);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -772,6 +809,7 @@ public:
IF_LOG Logger::println("TryCatchStatement::toIR(): %s", IF_LOG Logger::println("TryCatchStatement::toIR(): %s",
stmt->loc.toChars()); stmt->loc.toChars());
LOG_SCOPE; LOG_SCOPE;
assert(!irs->dcomputetarget);
auto &PGO = irs->funcGen().pgo; auto &PGO = irs->funcGen().pgo;
@ -812,6 +850,7 @@ public:
void visit(ThrowStatement *stmt) LLVM_OVERRIDE { void visit(ThrowStatement *stmt) LLVM_OVERRIDE {
IF_LOG Logger::println("ThrowStatement::toIR(): %s", stmt->loc.toChars()); IF_LOG Logger::println("ThrowStatement::toIR(): %s", stmt->loc.toChars());
LOG_SCOPE; LOG_SCOPE;
assert(!irs->dcomputetarget);
auto &PGO = irs->funcGen().pgo; auto &PGO = irs->funcGen().pgo;
PGO.setCurrentStmt(stmt); PGO.setCurrentStmt(stmt);
@ -871,6 +910,7 @@ public:
const bool isStringSwitch = !stmt->condition->type->isintegral(); const bool isStringSwitch = !stmt->condition->type->isintegral();
if (isStringSwitch) { if (isStringSwitch) {
Logger::println("is string switch"); Logger::println("is string switch");
assert(!irs->dcomputetarget);
// Sort the cases, taking care not to modify the original AST. // Sort the cases, taking care not to modify the original AST.
cases = cases->copy(); cases = cases->copy();
@ -1597,7 +1637,8 @@ public:
IF_LOG Logger::println("SwitchErrorStatement::toIR(): %s", IF_LOG Logger::println("SwitchErrorStatement::toIR(): %s",
stmt->loc.toChars()); stmt->loc.toChars());
LOG_SCOPE; LOG_SCOPE;
assert(!irs->dcomputetarget);
auto &PGO = irs->funcGen().pgo; auto &PGO = irs->funcGen().pgo;
PGO.setCurrentStmt(stmt); PGO.setCurrentStmt(stmt);
@ -1616,11 +1657,15 @@ public:
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void visit(AsmStatement *stmt) LLVM_OVERRIDE { AsmStatement_toIR(stmt, irs); } void visit(AsmStatement *stmt) LLVM_OVERRIDE {
assert(!irs->dcomputetarget);
AsmStatement_toIR(stmt, irs);
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void visit(CompoundAsmStatement *stmt) LLVM_OVERRIDE { void visit(CompoundAsmStatement *stmt) LLVM_OVERRIDE {
assert(!irs->dcomputetarget);
CompoundAsmStatement_toIR(stmt, irs); CompoundAsmStatement_toIR(stmt, irs);
} }

View file

@ -418,15 +418,15 @@ bool hasWeakUDA(Dsymbol *sym) {
/// Returns 0 if 'sym' does not have the @ldc.dcompute.compute() UDA applied. /// Returns 0 if 'sym' does not have the @ldc.dcompute.compute() UDA applied.
/// Returns 1 + n if 'sym' does and is @compute(n). /// Returns 1 + n if 'sym' does and is @compute(n).
int hasComputeAttr(Dsymbol *sym) { DComputeCompileFor hasComputeAttr(Dsymbol *sym) {
auto sle = getMagicAttribute(sym, Id::udaCompute, Id::dcompute); auto sle = getMagicAttribute(sym, Id::udaCompute, Id::dcompute);
if (!sle) if (!sle)
return 0; return DComputeCompileFor::hostOnly;
checkStructElems(sle, {Type::tint32}); checkStructElems(sle, {Type::tint32});
return 1 + (*sle->elements)[0]->toInteger(); return static_cast<DComputeCompileFor>(1 + (*sle->elements)[0]->toInteger());
} }
/// Checks whether 'sym' has the @ldc.dcompute._kernel() UDA applied. /// Checks whether 'sym' has the @ldc.dcompute._kernel() UDA applied.
@ -437,7 +437,8 @@ bool hasKernelAttr(Dsymbol *sym) {
checkStructElems(sle, {}); checkStructElems(sle, {});
if (!sym->isFuncDeclaration() && !hasComputeAttr(sym->getModule())) if (!sym->isFuncDeclaration() &&
hasComputeAttr(sym->getModule()) != DComputeCompileFor::hostOnly)
sym->error("@ldc.dcompute.kernel can only be applied to functions" sym->error("@ldc.dcompute.kernel can only be applied to functions"
" in modules marked @ldc.dcompute.compute"); " in modules marked @ldc.dcompute.compute");

View file

@ -27,7 +27,13 @@ void applyFuncDeclUDAs(FuncDeclaration *decl, IrFunction *irFunc);
void applyVarDeclUDAs(VarDeclaration *decl, llvm::GlobalVariable *gvar); void applyVarDeclUDAs(VarDeclaration *decl, llvm::GlobalVariable *gvar);
bool hasWeakUDA(Dsymbol *sym); bool hasWeakUDA(Dsymbol *sym);
int hasComputeAttr(Dsymbol *sym);
bool hasKernelAttr(Dsymbol *sym); bool hasKernelAttr(Dsymbol *sym);
/// Must match ldc.attributes.Compilefor + 1 == DComputeCompileFor
enum class DComputeCompileFor
{
hostOnly = 0,
deviceOnly = 1,
hostAndDevice = 2
};
DComputeCompileFor hasComputeAttr(Dsymbol *sym);
#endif #endif

View file

@ -15,11 +15,14 @@
#include "declaration.h" #include "declaration.h"
#include "init.h" #include "init.h"
#include "mtype.h" #include "mtype.h"
#include "template.h"
#include "gen/irstate.h" #include "gen/irstate.h"
#include "gen/tollvm.h" #include "gen/tollvm.h"
#include "gen/logger.h" #include "gen/logger.h"
#include "gen/llvmhelpers.h" #include "gen/llvmhelpers.h"
#include "gen/dcompute/target.h"
#include "gen/dcompute/druntime.h"
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -49,11 +52,29 @@ IrTypeStruct *IrTypeStruct::get(StructDeclaration *sd) {
t->packed = isPacked(sd); t->packed = isPacked(sd);
} }
AggrTypeBuilder builder(t->packed); // For ldc.dcomptetypes.Pointer!(uint n,T),
builder.addAggregate(sd); // emit { T addrspace(gIR->dcomputetarget->mapping[n])* }
builder.addTailPadding(sd->structsize); llvm::Optional<DcomputePointer> p;
isaStruct(t->type)->setBody(builder.defaultTypes(), t->packed); if (gIR->dcomputetarget && (p = toDcomputePointer(sd))) {
t->varGEPIndices = builder.varGEPIndices();
// Translate the virtual dcompute address space into the real one for
// the target
int realAS = gIR->dcomputetarget->mapping[p->addrspace];
llvm::SmallVector<LLType *, 1> body;
body.push_back(DtoMemType(p->type)->getPointerTo(realAS));
isaStruct(t->type)->setBody(body, t->packed);
VarGEPIndices v;
v[sd->fields[0]] = 0;
t->varGEPIndices = v;
} else {
AggrTypeBuilder builder(t->packed);
builder.addAggregate(sd);
builder.addTailPadding(sd->structsize);
isaStruct(t->type)->setBody(builder.defaultTypes(), t->packed);
t->varGEPIndices = builder.varGEPIndices();
}
IF_LOG Logger::cout() << "final struct type: " << *t->type << std::endl; IF_LOG Logger::cout() << "final struct type: " << *t->type << std::endl;