1

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.

1 Answer 1

2

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':

  1. The fn has different arguments in the two modules: i32 vs i32, ...
  2. The other issue is that 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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks a lot! @AlexDenisov. However that doesn't seem to be the problem. Adding extern "C" does demangle the function name but the linked file still contains only the contents of fn_ir.ll. 'llvm-link' just ignores main_ir.ll
@droptop I added another comment, that should fix the issue you are having :)
thanks a lot mate it worked. I still don't know how I missed the externallinkage thing... :) :) :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.