//===-- 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 "dmd/target.h" #include "gen/irstate.h" #include "gen/llvm.h" #include "gen/llvmhelpers.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/CFG.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/Cloning.h" llvm::BasicBlock *getUnwindDest(llvm::Instruction *I) { if (auto II = llvm::dyn_cast(I)) return II->getUnwindDest(); if (auto CSI = llvm::dyn_cast(I)) return CSI->getUnwindDest(); if (auto CRPI = llvm::dyn_cast(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 &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 &blocks, llvm::ValueToValueMapTy &VMap) { for (llvm::BasicBlock *bb : blocks) for (auto &I : *bb) { llvm::RemapInstruction(&I, VMap, llvm::RF_IgnoreMissingLocals | llvm::RF_NoModuleLevelChanges); } } void remapBlocksValue(std::vector &blocks, llvm::Value *from, llvm::Value *to) { llvm::ValueToValueMapTy VMap; VMap[from] = to; remapBlocks(blocks, VMap); } // 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" void cloneBlocks(const std::vector &srcblocks, std::vector &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 (auto bb : srcblocks) { 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) { llvm::Instruction *Inst = &II; llvm::Instruction *newInst = nullptr; if (funclet && !llvm::isa(Inst)) { // IntrinsicInst? if (auto IInst = llvm::dyn_cast(Inst)) { auto invoke = llvm::InvokeInst::Create( IInst, llvm::OperandBundleDef("funclet", funclet)); newInst = invoke; } else if (auto CInst = llvm::dyn_cast(Inst)) { auto call = llvm::CallInst::Create( CInst, llvm::OperandBundleDef("funclet", funclet)); newInst = call; } else if (funclet && llvm::isa(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); } bool isCatchSwitchBlock(llvm::BasicBlock *bb) { if (bb->empty()) return false; return llvm::dyn_cast(&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) { if (cd->isCPPclass()) { const char *name = target.cpp.typeInfoMangle(cd); return declareGlobal(cd->loc, irs.module, getVoidPtrType(), name, /*isConstant=*/true); } 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); const LinkageWithCOMDAT lwc = {LLGlobalVariable::LinkOnceODRLinkage, true}; Var = defineGlobal(cd->loc, gIR->module, TypeDescName, llvm::ConstantStruct::get(TypeDescriptorType, Fields), lwc.first, /*isConstant=*/true); setLinkage(lwc, Var); return Var; }