<div dir="ltr">Hi,<br><br>I'm trying to inline function defined in another bitcode module via bitcode modification.<br>I'm linking multiple bitcode modules, setting inline related attributes, applying -always-inline pass, but then debug info error occurs.<br>It seems debug info metadata isn't properly updated on inlining. How can I fix it?<br>I'm using LLVM 3.8.1 on OS X (On below example target is Android but it should be same on others).<br>I'll appreciate any advice. Thanks.<br><br>* Targets<br>caller.cpp<br>-----------------------------------------------------------------<br>#include <android/log.h><br><br>#ifdef __cplusplus<br>extern "C" {<br>#endif<br><br>void caller()<br>{<br>        __android_log_print(ANDROID_LOG_DEBUG, "TEST", "%s:%d:%s", __FILE__, __LINE__, __FUNCTION__);<br>}<br><br>#ifdef __cplusplus<br>}<br>#endif<br>-----------------------------------------------------------------<br><br>callee.cpp<br>-----------------------------------------------------------------<br>#include <android/log.h><br><br>#ifdef __cplusplus<br>extern "C" {<br>#endif<br><br>void callee()<br>{<br>        __android_log_print(ANDROID_LOG_DEBUG, "TEST", "%s:%d:%s", __FILE__, __LINE__, __FUNCTION__);<br>}<br><br>#ifdef __cplusplus<br>}<br>#endif<br>-----------------------------------------------------------------<br><br>* Building bitcode<br>-----------------------------------------------------------------<br>$ clang++ (...snip target specific flags...) -emit-llvm caller.cpp -o caller.bc<br>$ clang++ (...snip target specific flags...) -emit-llvm callee.cpp -o callee.bc<br>-----------------------------------------------------------------<br><br>* Linking bitcode<br>-----------------------------------------------------------------<br>$ llvm-link caller.o callee.o -o=test.bc<br>-----------------------------------------------------------------<br><br>* Modifying bitcode<br>inliner.cpp<br>-----------------------------------------------------------------<br>#include "llvm/IR/Type.h"<br>#include "llvm/IR/Module.h"<br>#include "llvm/IR/Function.h"<br>#include "llvm/IR/GlobalValue.h"<br>#include "llvm/IR/InstIterator.h"<br>#include "llvm/IR/Instructions.h"<br>#include "llvm/IR/IRBuilder.h"<br>#include "llvm/Support/SourceMgr.h"<br>#include "llvm/IRReader/IRReader.h"<br>#include "llvm/Support/FileSystem.h"<br>#include "llvm/Bitcode/ReaderWriter.h"<br>#include "llvm/Support/raw_ostream.h"<br><br>using namespace llvm;<br><br>int main(int argc, char *argv[])<br>{<br>        SMDiagnostic error;<br>        LLVMContext context;<br>        Module *M = parseIRFile(argv[1], error, context).release();<br><br>        for (Module::iterator F = M->getFunctionList().begin(); F != M->getFunctionList().end(); F++)<br>        {<br>                if (!F->isDeclaration())<br>                {<br>                        if (F->getName() == "caller")<br>                        {<br>                                Function* callee = M->getFunction("callee");<br><br>                                inst_iterator I = inst_begin((Function *)F);<br>                                Instruction *inst = &*I;<br><br>                                CallInst::Create(callee, "", inst);<br>                        }<br><br>                        if (F->getName() == "callee")<br>                        {<br>                                F->setLinkage(GlobalValue::InternalLinkage);<br>                                F->addFnAttr(Attribute::AlwaysInline);<br>                                F->addFnAttr(Attribute::InlineHint);<br>                        }<br>                }<br>        }<br><br>        std::error_code ec;<br>        raw_fd_ostream os(argv[1], ec, sys::fs::F_None);<br>        WriteBitcodeToFile(M, os);<br>}<br>-----------------------------------------------------------------<br><br>-----------------------------------------------------------------<br>$ g++ (...snip host specific flags...) inliner.cpp -o inliner<br>$ ./inliner test.bc<br>-----------------------------------------------------------------<br><br>* Applying -always-inline pass (Debug info error occurs)<br>-----------------------------------------------------------------<br>$ opt -debug-pass=Structure -always-inline test.bc -o test.bc.inline<br>Pass Arguments:  -targetlibinfo -tti -assumption-cache-tracker -basiccg -always-inline -verify<br>Target Library Information<br>Target Transform Information<br>Assumption Cache Tracker<br>  ModulePass Manager<br>    CallGraph Construction<br>    Call Graph SCC Pass Manager<br>      Inliner for always_inline functions<br>      FunctionPass Manager<br>        Module Verifier<br>    Bitcode Writer<br>!dbg attachment points at wrong subprogram for function<br>!16 = distinct !DISubprogram(name: "caller", scope: !1, file: !1, line: 11, type: !17, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: true, variables: !19)<br>void ()* @caller<br>  %call.i = call i32 (i32, i8*, i8*, ...) @__android_log_print(i32 3, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.3, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.1.4, i32 0, i32 0), i8* getelementptr inbounds ([111 x i8], [111 x i8]* @.str.2.5, i32 0, i32 0), i32 13, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @__FUNCTION__.callee, i32 0, i32 0)) #2, !dbg !30<br>!30 = !DILocation(line: 13, column: 2, scope: !23)<br>!23 = distinct !DISubprogram(name: "callee", scope: !21, file: !21, line: 11, type: !17, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: true, variables: !19)<br>!23 = distinct !DISubprogram(name: "callee", scope: !21, file: !21, line: 11, type: !17, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: true, variables: !19)<br>LLVM ERROR: Broken function found, compilation aborted!<br>-----------------------------------------------------------------<br><br>If I add -strip-debug pass, no error occurs, but of course debug info is lost...<br>-----------------------------------------------------------------<br>$ opt -debug-pass=Structure -strip-debug -always-inline test.bc -o test.bc.inline<br>Pass Arguments:  -targetlibinfo -tti -assumption-cache-tracker -basiccg -always-inline -verify<br>Target Library Information<br>Target Transform Information<br>Assumption Cache Tracker<br>  ModulePass Manager<br>    CallGraph Construction<br>    Call Graph SCC Pass Manager<br>      Inliner for always_inline functions<br>      FunctionPass Manager<br>        Module Verifier<br>    Bitcode Writer<br>-----------------------------------------------------------------<br></div>