Reputation: 1671
I've been trying to link IR generated with llvm's C++ api with a another IR file generated by Clang++. The input file to Clang is a function fn
I'm trying to call from the first IR file. But llvm-link
doesn't replace fn
's declaration with its definition.
main_ir.ll
source_filename = "top"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"
@0 = private unnamed_addr constant [5 x i8] c"%d \0A\00", align 1
declare i32 @printf(...)
declare i32 @fn(i32, ...)
define internal i32 @main() {
entrypoint:
%f_call = call i32 (i32, ...) @fn(i32 2)
%printfCall = call i32 (...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @0,
i32 0, i32 0), i32 %f_call)
br label %ProgramExit
ProgramExit: ; preds = %entrypoint
ret i32 0
}
fn_ir.ll (generated with Clang)
source_filename = "libDessin.cpp"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @_Z2fni(i32) #0 {
%2 = alloca i32, align 4
store i32 %0, i32* %2, align 4
%3 = load i32, i32* %2, align 4
%4 = mul nsw i32 %3, 2
ret i32 %4
}
attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-
math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-
width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-
math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-
math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-
cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false"
"use-soft-float"="false" }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 9.0.1-12 "}
And all llvm-link does is reproduce the contents of fn_ir.ll with the source_filename
changed to llvm-link
. I'd be real happy to know the bit I'm missing.
Upvotes: 1
Views: 151
Reputation: 4117
The answer is in the name mangling.
Your 'manually' generated IR has a function named fn
, while clang++
emits the name _Z2fni
.
You need to make the names match. Either emit the _Z2fni
in the main_ir.ll
, or (arguable better in this case) change the definition of fn
in the fn_ir
, e.g.:
extern "C" void fn(int x) {
return x * 2;
}
extern "C"
tells the compiler to use C mangling convention, this is less fragile since it will work even if you change type or number of arguments of fn
. However, it won't work if you want to pass C++ types into the fn
, then you need to emit the right function name for the main_ir.ll
.
UPD:
There two more 'discrepancies':
fn
has different arguments in the two modules: i32
vs i32, ...
main
declared as internal. I guess it is just stripped since it is internal and it is not being called by anyone.So just removing the internal
flag should do the job for you.
Upvotes: 2