void visit(PragmaDeclaration *pd) { if (pd->ident == Id::lib) { assert(pd->args && pd->args->dim == 1); Expression *e = (*pd->args)[0]; assert(e->op == TOKstring); StringExp *se = (StringExp *)e; char *name = (char *)mem.xmalloc(se->numberOfCodeUnits() + 1); se->writeTo(name, true); /* Embed the library names into the object file. * The linker will then automatically * search that library, too. */ if (!obj_includelib(name)) { /* The format does not allow embedded library names, * so instead append the library name to the list to be passed * to the linker. */ global.params.libfiles->push(name); } } else if (pd->ident == Id::startaddress) { assert(pd->args && pd->args->dim == 1); Expression *e = (*pd->args)[0]; Dsymbol *sa = getDsymbol(e); FuncDeclaration *f = sa->isFuncDeclaration(); assert(f); Symbol *s = toSymbol(f); obj_startaddress(s); } visit((AttribDeclaration *)pd); }
void visit(PragmaDeclaration *decl) override { if (decl->ident == Id::lib) { assert(decl->args && decl->args->dim == 1); assert(!irs->dcomputetarget); Expression *e = static_cast<Expression *>(decl->args->data[0]); assert(e->op == TOKstring); StringExp *se = static_cast<StringExp *>(e); const std::string name(se->toPtr(), se->numberOfCodeUnits()); auto nameLen = name.size(); if (global.params.targetTriple->isWindowsGNUEnvironment()) { if (nameLen > 4 && !memcmp(&name[nameLen - 4], ".lib", 4)) { // On MinGW, strip the .lib suffix, if any, to improve // compatibility with code written for DMD (we pass the name to GCC // via -l, just as on Posix). nameLen -= 4; } if (nameLen >= 7 && !memcmp(name.data(), "shell32", 7)) { // Another DMD compatibility kludge: Ignore // pragma(lib, "shell32.lib"), it is implicitly provided by // MinGW. return; } } // With LLVM 3.3 or later we can place the library name in the object // file. This seems to be supported only on Windows. if (global.params.targetTriple->isWindowsMSVCEnvironment()) { llvm::SmallString<24> LibName(name); // Win32: /DEFAULTLIB:"curl" if (LibName.endswith(".a")) { LibName = LibName.substr(0, LibName.size() - 2); } if (LibName.endswith(".lib")) { LibName = LibName.substr(0, LibName.size() - 4); } llvm::SmallString<24> tmp("/DEFAULTLIB:\""); tmp.append(LibName); tmp.append("\""); LibName = tmp; // Embed library name as linker option in object file auto Value = llvm::MDString::get(gIR->context(), LibName); gIR->LinkerMetadataArgs.push_back( llvm::MDNode::get(gIR->context(), Value)); } else { size_t const n = nameLen + 3; char *arg = static_cast<char *>(mem.xmalloc(n)); arg[0] = '-'; arg[1] = 'l'; memcpy(arg + 2, name.data(), nameLen); arg[n - 1] = 0; global.params.linkswitches.push(arg); } } visit(static_cast<AttribDeclaration *>(decl)); }
DValue *DtoInlineAsmExpr(Loc &loc, FuncDeclaration *fd, Expressions *arguments, LLValue *sretPointer) { IF_LOG Logger::println("DtoInlineAsmExpr @ %s", loc.toChars()); LOG_SCOPE; assert(fd->toParent()->isTemplateInstance() && "invalid inline __asm expr"); assert(arguments->dim >= 2 && "invalid __asm call"); // get code param Expression *e = (*arguments)[0]; IF_LOG Logger::println("code exp: %s", e->toChars()); StringExp *se = static_cast<StringExp *>(e); if (e->op != TOKstring || se->sz != 1) { e->error("`__asm` code argument is not a `char[]` string literal"); fatal(); } std::string code(se->toPtr(), se->numberOfCodeUnits()); // get constraints param e = (*arguments)[1]; IF_LOG Logger::println("constraint exp: %s", e->toChars()); se = static_cast<StringExp *>(e); if (e->op != TOKstring || se->sz != 1) { e->error("`__asm` constraints argument is not a `char[]` string literal"); fatal(); } std::string constraints(se->toPtr(), se->numberOfCodeUnits()); // build runtime arguments size_t n = arguments->dim; LLSmallVector<llvm::Value *, 8> args; args.reserve(n - 2); std::vector<LLType *> argtypes; argtypes.reserve(n - 2); for (size_t i = 2; i < n; i++) { args.push_back(DtoRVal((*arguments)[i])); argtypes.push_back(args.back()->getType()); } // build asm function type Type *type = fd->type->nextOf(); LLType *ret_type = DtoType(type->toBasetype()); llvm::FunctionType *FT = llvm::FunctionType::get(ret_type, argtypes, false); // make sure the constraints are valid if (!llvm::InlineAsm::Verify(FT, constraints)) { e->error("`__asm` constraint argument is invalid"); fatal(); } // build asm call bool sideeffect = true; llvm::InlineAsm *ia = llvm::InlineAsm::get(FT, code, constraints, sideeffect); llvm::Value *rv = gIR->ir->CreateCall(ia, args, ""); if (sretPointer) { DtoStore(rv, DtoBitCast(sretPointer, getPtrToType(ret_type))); return new DLValue(type, sretPointer); } // work around missing tuple support for users of the return value if (type->ty == Tstruct) { // make a copy llvm::Value *mem = DtoAlloca(type, ".__asm_tuple_ret"); DtoStore(rv, DtoBitCast(mem, getPtrToType(ret_type))); return new DLValue(type, mem); } // return call as im value return new DImValue(type, rv); }