[LLVMdev] Newbie question: LLVM IR, printf, and varargs

Mikael Lyngvig mikael at lyngvig.org
Tue Dec 3 16:56:57 PST 2013


That explains why I didn't need two times "i32": call i32 i32(i8*, ...)*
@printf (I actually tried that at one point).  But I sort of sensed that I
was heading for deep water when I decided to use printf; in all other
samples I've stuck with puts because of the expected difficulties with
varargs functions.  Anyways, it is now documented.  I do need to rephrase
the documentation after this clarification, though.


-- Mikael


2013/12/4 Sean Silva <chisophugis at gmail.com>

>
>
>
> On Tue, Dec 3, 2013 at 6:10 PM, Mikael Lyngvig <mikael at lyngvig.org> wrote:
>
>> Whoops...  Seems I forgot the asterisk (*) after the cast.  Or something.
>>  Because I did insert the cast and it didn't work.  But NOW it works.
>>  Thank you for spending some time on this - and also for presenting the
>> solution.
>>
>
> It's not a "cast" for any meaning of cast in the language. It's just that
> there's a hack, which is that if the type in front of the call is a
> function pointer type, then that is used *as the type of the thing being
> called*, while if it's not, then it is used *as the return type*, and the
> type of the call is inferred from the arguments present on the instruction.
> See this chunk of code in lib/AsmParser/LLParser.cpp:
>
>   // If RetType is a non-function pointer type, then this is the short
> syntax
>   // for the call, which means that RetType is just the return type.
>  Infer the
>   // rest of the function argument types from the arguments that are
> present.
>   PointerType *PFTy = 0;
>   FunctionType *Ty = 0;
>   if (!(PFTy = dyn_cast<PointerType>(RetType)) ||
>       !(Ty = dyn_cast<FunctionType>(PFTy->getElementType()))) {
>     // Pull out the types of all of the arguments...
>     std::vector<Type*> ParamTypes;
>     for (unsigned i = 0, e = ArgList.size(); i != e; ++i)
>       ParamTypes.push_back(ArgList[i].V->getType());
>
>     if (!FunctionType::isValidReturnType(RetType))
>       return Error(RetTypeLoc, "Invalid result type for LLVM function");
>
>     Ty = FunctionType::get(RetType, ParamTypes, false);
>     PFTy = PointerType::getUnqual(Ty);
>   }
>
>
> -- Sean Silva
>
>
>>
>>
>> -- Mikael
>>
>>
>> 2013/12/4 Eli Bendersky <eliben at google.com>
>>
>>> This code:
>>>
>>> declare i32 @printf(i8* nocapture readonly, ...) nounwind
>>>
>>> define i32 @bar(i8* %c, i32 %i) #0 {
>>> entry:
>>>   %call = tail call i32 (i8*, ...)* @printf(i8* %c, i8* %c)
>>>   ret i32 %call
>>> }
>>>
>>> Is accepted without complaints by close-to-trunk llc on my Ubuntu
>>> machine.
>>>
>>> Eli
>>>
>>>
>>> On Tue, Dec 3, 2013 at 2:58 PM, Mikael Lyngvig <mikael at lyngvig.org>wrote:
>>>
>>>> I just tried adding the cast but it didn't help.  I have the feeling
>>>> that I am overlooking something very obvious, but I can't seem to figure
>>>> out what it is.  Thanks for your suggestion, though.
>>>>
>>>>
>>>> -- Mikael
>>>>
>>>>
>>>>
>>>> 2013/12/3 Eli Bendersky <eliben at google.com>
>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Tue, Dec 3, 2013 at 2:29 PM, Mikael Lyngvig <mikael at lyngvig.org>wrote:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> I am trying to print two strings using printf.  I have tried various
>>>>>> things, but keep getting this error:
>>>>>>
>>>>>>     llc: printf.ll:4:11: error: '@printf' defined with type 'i32
>>>>>> (i8*, ...)*'
>>>>>>         %1 = call i32 @printf(i8* null, i8*, i8* null)
>>>>>>
>>>>>> The code is:
>>>>>>
>>>>>>    declare i32 @printf(i8* nocapture readonly, ...) nounwind
>>>>>>
>>>>>>    define i32 @main() nounwind {
>>>>>>       %1 = call i32 @printf(i8* null, i8* null)
>>>>>>       ret i32 0
>>>>>>   }
>>>>>>
>>>>>> I am aware that the call will core dump, but I am initially only
>>>>>> trying to figure out why LLC won't accept the call itself.  I started out
>>>>>> trying with real values and then reduced it to the above to see if I could
>>>>>> make it work.  Comparing with the output of Clang didn't help; it does the
>>>>>> same - passes in two i8* pointers and declares @printf in the same way (and
>>>>>> LLC accepts the Clang output as valid input).  The Clang code goes as
>>>>>> follows (edited snippet):
>>>>>>
>>>>>> @.str = private unnamed_addr constant [11 x i8] c"Error: %s\0A\00",
>>>>>> align 1
>>>>>> @.str1 = private unnamed_addr constant [5 x i8] c"Test\00", align 1
>>>>>>
>>>>>> define i32 @main() nounwind {
>>>>>>   %1 = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds
>>>>>> ([11 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8]*
>>>>>> @.str1, i32 0, i32 0)) nounwind
>>>>>>   ret i32 0
>>>>>> }
>>>>>>
>>>>>> declare i32 @printf(i8* nocapture readonly, ...) nounwind
>>>>>>
>>>>>> A good thing about this question is that the answer will find its way
>>>>>> into the Mapping Highlevel doc, which is why I am asking it in the first
>>>>>> place.
>>>>>>
>>>>>> This is on Windows using a 32-bit version of LLVM llc v3.4 (built
>>>>>> about a week ago).
>>>>>>
>>>>>> I searched the LR, the FAQ, and Google but found nothing of relevance.
>>>>>>
>>>>>>
>>>>> You're missing the cast, IMHO. The cast appeases the LLVM type checker
>>>>> w.r.t. mismatching function type
>>>>>
>>>>> Eli
>>>>>
>>>>>
>>>>
>>>>
>>>
>>
>> _______________________________________________
>> LLVM Developers mailing list
>> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20131204/6859d895/attachment.html>


More information about the llvm-dev mailing list