How to compile and link with other c/c++ programs

Hi Everyone,
I was trying to do a small exercise (compile a mlir function and call it from c after that).
So I used the following mlir code:

#id = affine_map<(d0) -> (d0)>
#ub = affine_map<(d0) -> (d0 + 64)>

// Map used to index the buffer while computing.
// CHECK-DAG: [[$MAP_IDENTITY:map[0-9]+]] = affine_map<(d0) -> (d0)>
// CHECK-DAG: [[$MAP_PLUS_128:map[0-9]+]] = affine_map<(d0) -> (d0 + 128)>

// CHECK-LABEL: func @matmul
// FILTER-LABEL: func @matmul
func @matmul(%A: memref<256x256xf32>, %B: memref<256x256xf32>, %C: memref<256x256xf32>) -> memref<256x256xf32> {
  affine.for %i = 0 to 256 step 64 {
    affine.for %j = 0 to 256 step 64 {
      affine.for %k = 0 to 256 step 64 {
        affine.for %ii = #id(%i) to #ub(%i) {
          affine.for %jj = #id(%j) to #ub(%j) {
            affine.for %kk = #id(%k) to #ub(%k) {
              %5 = affine.load %A[%ii, %kk] : memref<256x256xf32>
              %6 = affine.load %B[%kk, %jj] : memref<256x256xf32>
              %7 = affine.load %C[%ii, %jj] : memref<256x256xf32>
              %8 = arith.mulf %5, %6 : f32
              %9 = arith.addf %7, %8 : f32
              affine.store %9, %C[%ii, %jj] : memref<256x256xf32>
            }
          }
        }
      }
    }
  }
  return %C : memref<256x256xf32>
}

and lower it to llvm ir than compile it to generate object file.

mlir-opt --lower-affine -convert-scf-to-std --convert-arith-to-llvm --convert-std-to-llvm  --convert-memref-to-llvm matmul.mlir > matmul_llvm.mlir
mlir-opt -reconcile-unrealized-casts matmul_llvm.mlir > matmul_reconcil.mlir
mlir-translate -mlir-to-llvmir matmul_reconcil.mlir>matmul.ir

llvm-as matmul.ir -o matmul.bc
llc -filetype=obj matmul.bc -o matmul.o

But when I check the signature of matmul in matmul.o by using this command:

nm -C matmul.o

I got

0000000000000000 T matmul

am I doing something wrong ?

It does not seem wrong, what else did you expect?

I expect to have

0000000000000000 T matmul(float *, float *, float *);

if not what should be the protoype of the function to be called from my c program ??

This isn’t how object files work: the native object on Linux (same for Windows/Mac) don’t know anything about the original language the binary comes from. The only thing you have is the binary blob + a symbol table that is “name to address” resolution.
Some extra meta-data (like Dwarf debug info) could help reconstructing the higher-level signature, but that’s just debug info (so best effort, and often stripped out).

Have you tried with a C file compiled with clang or gcc to see what is in the symbol table?

Hi @mehdi_amini

Yes I tried a compiled C file with gcc, for example this code:

void matmul(float * A, float *B, float *C) {
 ....
}

so the command nm -C gives:

0000000000000000 T matmul(float*, float*, float*)

same thing with clang.

I succeed to compile. I had to declare my function as extern. But now, I am having a segmentation fault.
To debug it I simplified the mlir matmul function as follows:

func @matmul(%A: memref<512x512xf32>, %B: memref<512x512xf32>, %C: memref<512x512xf32>) -> memref<512x512xf32> {

  affine.for %i= 0 to 512 step 1 {
    affine.for %j =0 to 512 step 1 { 
      %8 = arith.constant 1.5: f32
      affine.store %8, %C[%i,%j]: memref<512x512xf32>
    }
  }
  return %C : memref<512x512xf32>
}

and my C program is :

#include <iostream>

using namespace std;

static const int N=512;
extern "C" {void matmul(float *A, float *B,float *C );}


int main(){

    float *A = new float[N*N],  *B= new float[N*N], *C= new float[N*N];
    for(int i=0;i<N*N;i++){
        A[i] = 1.;
        B[i] = 1.;
        C[i] = 0.;
    }
    matmul(A,B,C);

    cout<<C[0]<<endl;

    return 0;
}

I have a segmentation fault in matmul. I think even that I can compile the whole program the signature of matmul that I am providing on my c program is not correct

Memref is a not pointer, yet your code tries to pass a pointer instead. This segfaults.

Take a look at LLVM IR Target - MLIR and at the generated LLVM IR to understand what you are expected to pass in. There is also an attribute to emit more human-friendly ABI for memrefs and a bench of helpers in CRunnerUtils.h.

I believe you compiled a C++ file and not a C file here. If you remove the -C option and you will see the real name for the symbol.

As Alex said, the issue is the signature. We should probably add a standalone example doing this in the examples folder though: patches welcome! :wink:

thank you @mehdi_amini and @ftynse, I found the right signature.
@mehdi_amini yes you are right it is C++.