Intrinsic prototype has incorrect number of arguments!

Hello,

I have a question, what is wrong with the following code?

__declare void @llvm.memcpy.p0i64.p0i64.i8(i64*, i64*, i8, i32, i1) nounwind__


call void @llvm.memcpy.p0i64.p0i64.i8(i64* %19, i64* %21, i8 %17, i32 0, i1 false)

According to the compiler this is the error, but I seem to miss where exactly my fault is.

Intrinsic prototype has incorrect number of arguments!
void (i64*, i64*, i8, i32, i1)* @llvm.memcpy.p0i64.p0i64.i8

Any help would be appreciated.

Filip

Something is wonky in the error message since it's the right number of arguments... in general. I don't know that your prototype is correct. What's the corresponding code?

Can you send the module on and whatever you did to construct it?

-eric

I have created the function prototype with the following code:

const uintmax_t methodNameSize = 1024;
const char methodNameTemplate = “llvm.memcpy.p0i%llu.p0i%llu.i%llu”;

char methodName[methodNameSize];

// Create the methodName.
memset(methodName, 0, methodNameSize);
sprintf(methodName, methodNameTemplate,
dstSize,
srcSize,
lengthSize);

// Search for the function or create it.
if((function = LLVMGetNamedFunction(module, methodName)) == NULL) {
LLVMTypeRef paramTypes = {
dstType,
srcType,
lengthType,
LLVMInt32TypeInContext(context),
LLVMInt1TypeInContext(context),
};

functionType = LLVMFunctionType(LLVMVoidTypeInContext(context),
paramTypes, numberOfArguments, false);

function = LLVMAddFunction(module, methodName, functionType);
LLVMRemoveAttribute(LLVMGetParam(function, 0), LLVMNoCaptureAttribute);
LLVMRemoveAttribute(LLVMGetParam(function, 1), LLVMNoCaptureAttribute);
}

And then invoked it with this:

LLVMValueRef args = {
sourcePtr,
destinationPtr,
lengthInteger,
LLVMConstInt(LLVMInt32TypeInContext(context), 0, true),
LLVMConstInt(LLVMInt1TypeInContext(context), (unsigned long long)false, true),
};

LLVMBuildCall(builder, function, args, numberOfArguments, “”);

Then you end up with the following prototype:

declare void @llvm.memcpy.p0i64.p0i64.i64(i64*, i64*, i64, i32, i1) nounwind

and this code will invoke the copy:

reallocBlock: ; preds = %entry
%5 = getelementptr inbounds %0* %0, i32 0, i32 2 ; <i64*> [#uses=1]
%6 = load i64* %5 ; [#uses=1]
%7 = add i64 %6, 25 ; [#uses=2]
%8 = getelementptr inbounds %0* %0, i32 0, i32 0 ; <i64**> [#uses=1]
%9 = load i64** %8 ; <i64*> [#uses=1]
%10 = trunc i64 %7 to i32 ; [#uses=1]
%mallocsize = mul i32 %10, ptrtoint (i64* getelementptr (i64* null, i32 1) to i32) ; [#uses=1]
%malloccall = tail call i8* @malloc(i32 %mallocsize) ; <i8*> [#uses=1]
%11 = bitcast i8* %malloccall to i64* ; <i64*> [#uses=1]
call void @llvm.memcpy.p0i64.p0i64.i64(i64* %9, i64* %11, i64 %7, i32 0, i1 false)
br label %exit

Any ideas on what I am doing wrong here ?

Why not just use something like:

        const Type *ArgPtr = Type::getInt8PtrTy(Context);
  const Type *IntPtr = getTargetData().getIntPtrType(Context);

and then:

        const Type *ArgTypes[3] = {ArgPtr, ArgPtr, IntPtr };
  Intrinsic::getDeclaration(TheModule, Intrinsic::memcpy, ArgTypes, 3)

to get the type of memcpy? Trying to declare it that way is likely confusing to the system.

-eric

The third parameter should be a pointer.

-bw

No it shouldn’t be, the LLVM assembly language reference manual declares it at follows:

declare void @llvm.memcpy.p0i8.p0i8.i32(i8* <dest>, i8* <src>,
                                          i32 <len>, i32 <align>, i1 <isvolatile>)

That won't work when you are trying to limit yourself to C and only C.
Is there an LLVM-C alternative?

Filip

Hmm... If there isn't then we can easily expand the C bindings to do it.

-eric

As far as I know, there isn't a C way to do the job (llvm 2.7).
But still, the system should recognize my method/prototype and act on it.
Since the methods are unique by name alone and you can't have 2 globals with the same name in a module...

Or is my logic completely unfounded ?

Filip