Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
35d9d13
thunks don't need a personality
rainers Dec 21, 2015
7e9d60b
MSVC/x86 EH support using __CxxFrameHandler3 personality
rainers Dec 21, 2015
00d21ca
fix MSVC-EH again, disable inlining and tail call optimization for fu…
rainers Dec 29, 2015
9b6c80d
inside a cleanup block, convert "unreachable" to a branch to "cleanup…
rainers Dec 30, 2015
3858976
fix build for LLVM < 3.8
rainers Dec 30, 2015
d2e9a80
avoid replacing library functions in funclet, it doesn't copy the "fu…
rainers Dec 31, 2015
b939952
remove setting NoBuiltin attribute, fixed in LLVM
rainers Jan 6, 2016
a8a4550
use catch-all and rethrow instead of cleanup pads, they don't work co…
rainers Jan 8, 2016
f13f121
- add a global condition to cleanup pads to avoid them being inferred…
rainers Jan 10, 2016
996281d
replace _d_skipCleanup var with callbacks _d_enter_cleanup, _d_leave_…
rainers Jan 15, 2016
7c4c106
- add classinfo argument to _d_eh_enter_catch
rainers Jan 22, 2016
da817ae
eh unwinding: don't alloc data in parent frame, just use nullptr for now
rainers Feb 13, 2016
9c6e894
avoid outlining catch handler
rainers Feb 15, 2016
d2e3942
_d_enter_catch can throw, so it might have to be invoked
rainers Feb 19, 2016
ae110f8
fix compilation after merge
rainers Feb 27, 2016
b4df086
cleanup obsolete changes
rainers Mar 1, 2016
bc43f7f
fix ordering of overloads
rainers Mar 3, 2016
7e5431f
add debug info to thunks as a workaround for https://llvm.org/bugs/sh…
rainers Mar 4, 2016
0de73a8
fix function name mangling for debug info
rainers Mar 5, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 59 additions & 12 deletions gen/dibuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -645,23 +645,70 @@ ldc::DISubprogram ldc::DIBuilder::EmitSubProgram(FuncDeclaration *fd) {

ldc::DIFile file(CreateFile(fd->loc));

std::string mangledName(getIrFunc(fd)->func->getName());

// Create subroutine type
ldc::DISubroutineType DIFnType =
CreateFunctionType(static_cast<TypeFunction *>(fd->type));
CreateFunctionType(static_cast<TypeFunction *>(fd->type));

// FIXME: duplicates?
return DBuilder.createFunction(
CU, // context
fd->toPrettyChars(), // name
mangledName, // linkage name
file, // file
fd->loc.linnum, // line no
DIFnType, // type
fd->protection.kind == PROTprivate, // is local to unit
true, // isdefinition
fd->loc.linnum, // FIXME: scope line
DIFlags::FlagPrototyped, // Flags
isOptimizationEnabled() // isOptimized
#if LDC_LLVM_VER < 308
,
getIrFunc(fd)->func
#endif
);
}

ldc::DISubprogram ldc::DIBuilder::EmitThunk(llvm::Function *Thunk,
FuncDeclaration *fd) {
if (!global.params.symdebug) {
#if LDC_LLVM_VER >= 307
return nullptr;
#else
return llvm::DISubprogram();
#endif
}

Logger::println("Thunk to dwarf subprogram");
LOG_SCOPE;

ldc::DICompileUnit CU(GetCU());
assert(CU &&
"Compilation unit missing or corrupted in DIBuilder::EmitThunk");

ldc::DIFile file(CreateFile(fd->loc));

// Create subroutine type (thunk has same type as wrapped function)
ldc::DISubroutineType DIFnType = CreateFunctionType(fd->type);

std::string name(fd->toPrettyChars());
name.append(".__thunk");

// FIXME: duplicates?
return DBuilder.createFunction(
CU, // context
fd->toPrettyChars(), // name
mangleExact(fd), // linkage name
file, // file
fd->loc.linnum, // line no
DIFnType, // type
fd->protection.kind == PROTprivate, // is local to unit
true, // isdefinition
fd->loc.linnum, // FIXME: scope line
DIFlags::FlagPrototyped, // Flags
isOptimizationEnabled() // isOptimized
CU, // context
name, // name
Thunk->getName(), // linkage name
file, // file
fd->loc.linnum, // line no
DIFnType, // type
fd->protection.kind == PROTprivate, // is local to unit
true, // isdefinition
fd->loc.linnum, // FIXME: scope line
DIFlags::FlagPrototyped, // Flags
isOptimizationEnabled() // isOptimized
#if LDC_LLVM_VER < 308
,
getIrFunc(fd)->func
Expand Down
7 changes: 7 additions & 0 deletions gen/dibuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ class DIBuilder {
/// \returns the Dwarf subprogram global.
DISubprogram EmitSubProgram(FuncDeclaration *fd); // FIXME

/// \brief Emit the Dwarf subprogram global for a thunk.
/// \param Thunk llvm::Function pointer.
/// \param fd The function wrapped by this thunk.
/// \returns the Dwarf subprogram global.
DISubprogram EmitThunk(llvm::Function *Thunk,
FuncDeclaration *fd); // FIXME

/// \brief Emit the Dwarf subprogram global for a module ctor.
/// This is used for generated functions like moduleinfoctors,
/// module ctors/dtors and unittests.
Expand Down
6 changes: 6 additions & 0 deletions gen/irstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,12 @@ struct IRState {
#else
llvm::SmallVector<llvm::Value *, 5> LinkerMetadataArgs;
#endif

#if LDC_LLVM_VER >= 308
// MS C++ compatible type descriptors
llvm::DenseMap<size_t, llvm::StructType *> TypeDescriptorTypeMap;
llvm::DenseMap<llvm::Constant *, llvm::GlobalVariable *> TypeDescriptorMap;
#endif
};

void Statement_toIR(Statement *s, IRState *irs);
Expand Down
189 changes: 189 additions & 0 deletions gen/ms-cxx-helper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
//===-- ms-cxx-helper.cpp -------------------------------------------------===//
//
// LDC � the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//

#include "gen/ms-cxx-helper.h"
#include "gen/llvm.h"
#include "gen/llvmhelpers.h"
#include "gen/irstate.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"

#if LDC_LLVM_VER >= 308
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/IR/CFG.h"

llvm::BasicBlock *getUnwindDest(llvm::Instruction *I) {
if (auto II = llvm::dyn_cast<llvm::InvokeInst> (I))
return II->getUnwindDest();
else if (auto CSI = llvm::dyn_cast<llvm::CatchSwitchInst> (I))
return CSI->getUnwindDest();
else if (auto CRPI = llvm::dyn_cast<llvm::CleanupReturnInst> (I))
return CRPI->getUnwindDest();
return nullptr;
}

// return all basic blocks that are reachable from bb, but don't pass through
// ebb and don't follow unwinding target
void findSuccessors(std::vector<llvm::BasicBlock *> &blocks,
llvm::BasicBlock *bb, llvm::BasicBlock *ebb) {
blocks.push_back(bb);
if (bb != ebb) {
assert(bb->getTerminator());
for (size_t pos = 0; pos < blocks.size(); ++pos) {
bb = blocks[pos];
if (auto term = bb->getTerminator()) {
llvm::BasicBlock *unwindDest = getUnwindDest(term);
unsigned cnt = term->getNumSuccessors();
for (unsigned s = 0; s < cnt; s++) {
llvm::BasicBlock *succ = term->getSuccessor(s);
if (succ != ebb && succ != unwindDest &&
std::find(blocks.begin(), blocks.end(), succ) == blocks.end()) {
blocks.push_back(succ);
}
}
}
}
blocks.push_back(ebb);
}
}

// remap values in all instructions of all blocks
void remapBlocks(std::vector<llvm::BasicBlock *> &blocks,
llvm::ValueToValueMapTy &VMap, llvm::BasicBlock *unwindTo,
llvm::Value *funclet) {
for (llvm::BasicBlock *bb : blocks)
for (llvm::BasicBlock::iterator I = bb->begin(); I != bb->end(); ++I) {
llvm::RemapInstruction(&*I, VMap, llvm::RF_IgnoreMissingEntries |
llvm::RF_NoModuleLevelChanges);
}
}

void remapBlocksValue(std::vector<llvm::BasicBlock *> &blocks,
llvm::Value *from, llvm::Value *to) {
llvm::ValueToValueMapTy VMap;
VMap[from] = to;
remapBlocks(blocks, VMap, nullptr, nullptr);
}

// make a copy of all blocks and instructions in srcblocks
// - map values to clones
// - redirect srcTarget to continueWith
// - set "funclet" attribute inside catch/cleanup pads
// - inside funclets, replace "unreachable" with "branch cleanupret"
// - disable inlining inside a funclet
void cloneBlocks(const std::vector<llvm::BasicBlock *> &srcblocks,
std::vector<llvm::BasicBlock *> &blocks,
llvm::BasicBlock *continueWith, llvm::BasicBlock *unwindTo,
llvm::Value *funclet) {
llvm::ValueToValueMapTy VMap;
// map the terminal branch to the new target
if (continueWith)
if (auto term = srcblocks.back()->getTerminator())
if (auto succ = term->getSuccessor(0))
VMap[succ] = continueWith;

for (size_t b = 0; b < srcblocks.size(); b++) {
llvm::BasicBlock *bb = srcblocks[b];
llvm::Function* F = bb->getParent();

auto nbb = llvm::BasicBlock::Create(bb->getContext(), bb->getName());
// Loop over all instructions, and copy them over.
for (auto II = bb->begin(), IE = bb->end(); II != IE; ++II) {
llvm::Instruction *Inst = &*II;
llvm::Instruction *newInst = nullptr;
if (funclet && !llvm::isa<llvm::DbgInfoIntrinsic>(Inst)) { // IntrinsicInst?
if (auto IInst = llvm::dyn_cast<llvm::InvokeInst> (Inst)) {
auto invoke = llvm::InvokeInst::Create(
IInst, llvm::OperandBundleDef("funclet", funclet));
invoke->setIsNoInline();
newInst = invoke;
} else if (auto CInst = llvm::dyn_cast<llvm::CallInst> (Inst)) {
auto call = llvm::CallInst::Create(
CInst, llvm::OperandBundleDef("funclet", funclet));
call->setIsNoInline();
newInst = call;
} else if (funclet && llvm::isa<llvm::UnreachableInst>(Inst)) {
newInst = llvm::BranchInst::Create(continueWith); // to cleanupret
}
}
if (!newInst)
newInst = Inst->clone();

nbb->getInstList().push_back(newInst);
VMap[Inst] = newInst; // Add instruction map to value.
if (unwindTo)
if (auto dest = getUnwindDest(Inst))
VMap[dest] = unwindTo;
}
nbb->insertInto(F, continueWith);
VMap[bb] = nbb;
blocks.push_back(nbb);
}

remapBlocks(blocks, VMap, unwindTo, funclet);
}

bool isCatchSwitchBlock(llvm::BasicBlock* bb) {
if (bb->empty())
return false;
return llvm::dyn_cast<llvm::CatchSwitchInst>(&bb->front());
}

// copy from clang/.../MicrosoftCXXABI.cpp

// routines for constructing the llvm types for MS RTTI structs.
llvm::StructType *getTypeDescriptorType(IRState &irs,
llvm::Constant *classInfoPtr,
llvm::StringRef TypeInfoString) {
llvm::SmallString<256> TDTypeName("rtti.TypeDescriptor");
TDTypeName += llvm::utostr(TypeInfoString.size());
llvm::StructType *&TypeDescriptorType =
irs.TypeDescriptorTypeMap[TypeInfoString.size()];
if (TypeDescriptorType)
return TypeDescriptorType;
auto int8Ty = LLType::getInt8Ty(gIR->context());
llvm::Type *FieldTypes[] = {
classInfoPtr->getType(), // CGM.Int8PtrPtrTy,
getPtrToType(int8Ty), // CGM.Int8PtrTy,
llvm::ArrayType::get(int8Ty, TypeInfoString.size() + 1)};
TypeDescriptorType =
llvm::StructType::create(gIR->context(), FieldTypes, TDTypeName);
return TypeDescriptorType;
}

llvm::GlobalVariable *getTypeDescriptor(IRState &irs, ClassDeclaration *cd) {

auto classInfoPtr = getIrAggr(cd, true)->getClassInfoSymbol();
llvm::GlobalVariable *&Var = irs.TypeDescriptorMap[classInfoPtr];
if (Var)
return Var;

// first character skipped in debugger output, so we add 'D' as prefix
std::string TypeNameString = "D";
TypeNameString.append(cd->toPrettyChars());
std::string TypeDescName = TypeNameString + "@TypeDescriptor";

// Declare and initialize the TypeDescriptor.
llvm::Constant *Fields[] = {
classInfoPtr, // VFPtr
llvm::ConstantPointerNull::get(
LLType::getInt8PtrTy(gIR->context())), // Runtime data
llvm::ConstantDataArray::getString(gIR->context(), TypeNameString)};
llvm::StructType *TypeDescriptorType =
getTypeDescriptorType(irs, classInfoPtr, TypeNameString);
Var = new llvm::GlobalVariable(
gIR->module, TypeDescriptorType, /*Constant=*/false,
LLGlobalVariable::InternalLinkage, // getLinkageForRTTI(Type),
llvm::ConstantStruct::get(TypeDescriptorType, Fields), TypeDescName);
return Var;
}

#endif // LDC_LLVM_VER >= 308
33 changes: 33 additions & 0 deletions gen/ms-cxx-helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//===-- ms-cxx-helper.h ---------------------------------------------------===//
//
// LDC � the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//

#ifndef LDC_GEN_MS_CXX_HELPER_H
#define LDC_GEN_MS_CXX_HELPER_H

#include "gen/irstate.h"

llvm::StructType *getTypeDescriptorType(IRState &irs,
llvm::Constant *classInfoPtr,
llvm::StringRef TypeInfoString);
llvm::GlobalVariable *getTypeDescriptor(IRState &irs, ClassDeclaration *cd);

void findSuccessors(std::vector<llvm::BasicBlock *> &blocks,
llvm::BasicBlock *bb, llvm::BasicBlock *ebb);

void remapBlocksValue(std::vector<llvm::BasicBlock *> &blocks,
llvm::Value *from, llvm::Value *to);

void cloneBlocks(const std::vector<llvm::BasicBlock *> &srcblocks,
std::vector<llvm::BasicBlock *> &blocks,
llvm::BasicBlock *continueWith, llvm::BasicBlock *unwindTo,
llvm::Value *funclet);

bool isCatchSwitchBlock(llvm::BasicBlock* bb);

#endif // LDC_GEN_MS_CXX_HELPER_H
28 changes: 22 additions & 6 deletions gen/runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "ir/irfunction.h"
#include "ir/irtype.h"
#include "ir/irtypefunction.h"
#include "llvm/Bitcode/ReaderWriter.h"
Expand Down Expand Up @@ -620,9 +621,11 @@ static void buildRuntimeModule() {
// int _d_eh_personality(...)
{
if (global.params.targetTriple->isWindowsMSVCEnvironment()) {
const char *fname =
useMSVCEH() ? "__CxxFrameHandler3" : "_d_eh_personality";
// (ptr ExceptionRecord, ptr EstablisherFrame, ptr ContextRecord,
// ptr DispatcherContext)
createFwdDecl(LINKc, intTy, {"_d_eh_personality"},
createFwdDecl(LINKc, intTy, {fname},
{voidPtrTy, voidPtrTy, voidPtrTy, voidPtrTy});
} else if (global.params.targetTriple->getArch() == llvm::Triple::arm) {
// (int state, ptr ucb, ptr context)
Expand All @@ -635,12 +638,25 @@ static void buildRuntimeModule() {
}
}

// void _d_eh_resume_unwind(ptr)
createFwdDecl(LINKc, voidTy, {"_d_eh_resume_unwind"}, {voidPtrTy});
if (useMSVCEH()) {
// _d_enter_cleanup(ptr frame)
createFwdDecl(LINKc, boolTy, {"_d_enter_cleanup"}, {voidPtrTy});

// Object _d_eh_enter_catch(ptr)
createFwdDecl(LINKc, objectTy, {"_d_eh_enter_catch"}, {voidPtrTy}, {},
Attr_NoUnwind);
// _d_leave_cleanup(ptr frame)
createFwdDecl(LINKc, voidTy, {"_d_leave_cleanup"}, {voidPtrTy});

// Object _d_eh_enter_catch(ptr exception, ClassInfo catchType)
createFwdDecl(LINKc, objectTy, {"_d_eh_enter_catch"},
{voidPtrTy, classInfoTy}, {});
} else {

// void _d_eh_resume_unwind(ptr)
createFwdDecl(LINKc, voidTy, {"_d_eh_resume_unwind"}, {voidPtrTy});

// Object _d_eh_enter_catch(ptr)
createFwdDecl(LINKc, objectTy, {"_d_eh_enter_catch"}, {voidPtrTy}, {},
Attr_NoUnwind);
}

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
Expand Down
Loading