It seems that fast-isel for intel does not handle strlen. It's a general
problem in fast-isel .
~/llvmw/build/Deb~/llvmw/build/Debug+Asserts/bin/clang -O0 -mllvm
-fast-isel-verbose -mllvm -fast-isel strlen1.c
strlen1.c:12:3: warning: implicitly declaring library function 'printf'
with
type 'int (const char *, ...)'
printf("%i\n", len);
^
strlen1.c:12:3: note: include the header <stdio.h> or explicitly provide a
declaration for 'printf'
FastISel missed call: %call = call i64 @strlen(i8* %0) #3
1 warning generated.
#include <string.h>
char *hello = "hello";
int len;
void foo() {
len = strlen(hello);
}
int main() {
foo();
printf("%i\n", len);
}
This issue occurs in a many library functions.
strlen, strcmp, ... many others.
I'm surprised nobody has noticed this because many basic blocks will
fail to be compiled as fast-isel in this case.
It seems like just a bug in:
bool FastISel::selectInstruction(const Instruction *I) {
this function returns false but then it causes fast-isel to just do a
miss on the function. there is no way to override the behavior.
Since this is happening on a call instructtion, it's going to drop back
and print as a missed fast isel call.
It seems like this test in
bool FastISel::selectInstruction(const Instruction *I)
should just be deleted.
Thoughts?
// As a special case, don't handle calls to builtin library
functions that
// may be translated directly to target instructions.
if (F && !F->hasLocalLinkage() && F->hasName()
&&
LibInfo->getLibFunc(F->getName(), Func) &&
LibInfo->hasOptimizedCodeGen(Func))
return false;
This is called from void SelectionDAGISel::SelectAllBasicBlocks(const
Function &Fn)
if (FastIS->selectInstruction(Inst)) {
--NumFastIselRemaining;
++NumFastIselSuccess;
// If fast isel succeeded, skip over all the folded
instructions, and
// then see if there is a load right before the selected
instructions.
// Try to fold the load if so.
const Instruction *BeforeInst = Inst;
while (BeforeInst != Begin) {
BeforeInst = std::prev(BasicBlock::const_iterator(BeforeInst));
if (!isFoldedOrDeadInstruction(BeforeInst, FuncInfo))
break;
}
if (BeforeInst != Inst && isa<LoadInst>(BeforeInst)
&&
BeforeInst->hasOneUse() &&
FastIS->tryToFoldLoad(cast<LoadInst>(BeforeInst), Inst))
{
// If we succeeded, don't re-select the load.
BI = std::next(BasicBlock::const_iterator(BeforeInst));
--NumFastIselRemaining;
++NumFastIselSuccess;
}
continue;
}
#ifndef NDEBUG
if (EnableFastISelVerbose2)
collectFailStats(Inst);
#endif
// Then handle certain instructions as single-LLVM-Instruction
blocks.
if (isa<CallInst>(Inst)) {
if (EnableFastISelVerbose || EnableFastISelAbort) {
dbgs() << "FastISel missed call: ";
Inst->dump();
On 01/20/2015 02:35 PM, reed kotler wrote:> It seems that fast-isel for intel does not handle strlen. It's a
general
> problem in fast-isel .
>
>
> ~/llvmw/build/Deb~/llvmw/build/Debug+Asserts/bin/clang -O0 -mllvm
> -fast-isel-verbose -mllvm -fast-isel strlen1.c
> strlen1.c:12:3: warning: implicitly declaring library function
'printf'
> with
> type 'int (const char *, ...)'
> printf("%i\n", len);
> ^
> strlen1.c:12:3: note: include the header <stdio.h> or explicitly
provide a
> declaration for 'printf'
> FastISel missed call: %call = call i64 @strlen(i8* %0) #3
> 1 warning generated.
>
> #include <string.h>
>
> char *hello = "hello";
> int len;
>
> void foo() {
> len = strlen(hello);
> }
>
> int main() {
> foo();
> printf("%i\n", len);
> }
Any basic blocks with these functions are going to get passed over by
fast-isel:
bool hasOptimizedCodeGen(LibFunc::Func F) const {
if (Impl->getState(F) == TargetLibraryInfoImpl::Unavailable)
return false;
switch (F) {
default: break;
case LibFunc::copysign: case LibFunc::copysignf: case
LibFunc::copysignl:
case LibFunc::fabs: case LibFunc::fabsf: case LibFunc::fabsl:
case LibFunc::sin: case LibFunc::sinf: case LibFunc::sinl:
case LibFunc::cos: case LibFunc::cosf: case LibFunc::cosl:
case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl:
case LibFunc::sqrt_finite: case LibFunc::sqrtf_finite:
case
LibFunc::sqrtl_finite:
case LibFunc::fmax: case LibFunc::fmaxf: case LibFunc::fmaxl:
case LibFunc::fmin: case LibFunc::fminf: case LibFunc::fminl:
case LibFunc::floor: case LibFunc::floorf: case
LibFunc::floorl:
case LibFunc::nearbyint: case LibFunc::nearbyintf: case
LibFunc::nearbyintl:
case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill:
case LibFunc::rint: case LibFunc::rintf: case LibFunc::rintl:
case LibFunc::round: case LibFunc::roundf: case
LibFunc::roundl:
case LibFunc::trunc: case LibFunc::truncf: case
LibFunc::truncl:
case LibFunc::log2: case LibFunc::log2f: case LibFunc::log2l:
case LibFunc::exp2: case LibFunc::exp2f: case LibFunc::exp2l:
case LibFunc::memcmp: case LibFunc::strcmp: case
LibFunc::strcpy:
case LibFunc::stpcpy: case LibFunc::strlen: case
LibFunc::strnlen:
case LibFunc::memchr:
return true;
}
return false;
}
On 01/28/2015 11:03 AM, Reed Kotler wrote:> This issue occurs in a many library functions.
> strlen, strcmp, ... many others.
> I'm surprised nobody has noticed this because many basic blocks will
> fail to be compiled as fast-isel in this case.
>
> It seems like just a bug in:
> bool FastISel::selectInstruction(const Instruction *I) {
>
> this function returns false but then it causes fast-isel to just do a
> miss on the function. there is no way to override the behavior.
>
> Since this is happening on a call instructtion, it's going to drop back
> and print as a missed fast isel call.
>
> It seems like this test in
> bool FastISel::selectInstruction(const Instruction *I)
>
> should just be deleted.
>
> Thoughts?
>
>
> // As a special case, don't handle calls to builtin library
> functions that
> // may be translated directly to target instructions.
> if (F && !F->hasLocalLinkage() && F->hasName()
&&
> LibInfo->getLibFunc(F->getName(), Func) &&
> LibInfo->hasOptimizedCodeGen(Func))
> return false;
>
>
> This is called from void SelectionDAGISel::SelectAllBasicBlocks(const
> Function &Fn)
>
> if (FastIS->selectInstruction(Inst)) {
> --NumFastIselRemaining;
> ++NumFastIselSuccess;
> // If fast isel succeeded, skip over all the folded
> instructions, and
> // then see if there is a load right before the selected
> instructions.
> // Try to fold the load if so.
> const Instruction *BeforeInst = Inst;
> while (BeforeInst != Begin) {
> BeforeInst >
std::prev(BasicBlock::const_iterator(BeforeInst));
> if (!isFoldedOrDeadInstruction(BeforeInst, FuncInfo))
> break;
> }
> if (BeforeInst != Inst &&
isa<LoadInst>(BeforeInst) &&
> BeforeInst->hasOneUse() &&
> FastIS->tryToFoldLoad(cast<LoadInst>(BeforeInst),
Inst)) {
> // If we succeeded, don't re-select the load.
> BI = std::next(BasicBlock::const_iterator(BeforeInst));
> --NumFastIselRemaining;
> ++NumFastIselSuccess;
> }
> continue;
> }
>
> #ifndef NDEBUG
> if (EnableFastISelVerbose2)
> collectFailStats(Inst);
> #endif
>
> // Then handle certain instructions as single-LLVM-Instruction
> blocks.
> if (isa<CallInst>(Inst)) {
>
> if (EnableFastISelVerbose || EnableFastISelAbort) {
> dbgs() << "FastISel missed call: ";
> Inst->dump();
>
>
>
> On 01/20/2015 02:35 PM, reed kotler wrote:
>> It seems that fast-isel for intel does not handle strlen. It's a
general
>> problem in fast-isel .
>>
>>
>> ~/llvmw/build/Deb~/llvmw/build/Debug+Asserts/bin/clang -O0 -mllvm
>> -fast-isel-verbose -mllvm -fast-isel strlen1.c
>> strlen1.c:12:3: warning: implicitly declaring library function
'printf'
>> with
>> type 'int (const char *, ...)'
>> printf("%i\n", len);
>> ^
>> strlen1.c:12:3: note: include the header <stdio.h> or explicitly
>> provide a
>> declaration for 'printf'
>> FastISel missed call: %call = call i64 @strlen(i8* %0) #3
>> 1 warning generated.
>>
>> #include <string.h>
>>
>> char *hello = "hello";
>> int len;
>>
>> void foo() {
>> len = strlen(hello);
>> }
>>
>> int main() {
>> foo();
>> printf("%i\n", len);
>> }
Seems like it might possible to override TargetLIbraryInfo during the
creation of the fast-isel object.
I will look into this.
namespace llvm {
FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo,
const TargetLibraryInfo *libInfo) {
return new MipsFastISel(funcInfo, libInfo);
}
}
On 01/28/2015 11:03 AM, Reed Kotler wrote:> This issue occurs in a many library functions.
> strlen, strcmp, ... many others.
> I'm surprised nobody has noticed this because many basic blocks will
> fail to be compiled as fast-isel in this case.
>
> It seems like just a bug in:
> bool FastISel::selectInstruction(const Instruction *I) {
>
> this function returns false but then it causes fast-isel to just do a
> miss on the function. there is no way to override the behavior.
>
> Since this is happening on a call instructtion, it's going to drop back
> and print as a missed fast isel call.
>
> It seems like this test in
> bool FastISel::selectInstruction(const Instruction *I)
>
> should just be deleted.
>
> Thoughts?
>
>
> // As a special case, don't handle calls to builtin library
> functions that
> // may be translated directly to target instructions.
> if (F && !F->hasLocalLinkage() && F->hasName()
&&
> LibInfo->getLibFunc(F->getName(), Func) &&
> LibInfo->hasOptimizedCodeGen(Func))
> return false;
>
>
> This is called from void SelectionDAGISel::SelectAllBasicBlocks(const
> Function &Fn)
>
> if (FastIS->selectInstruction(Inst)) {
> --NumFastIselRemaining;
> ++NumFastIselSuccess;
> // If fast isel succeeded, skip over all the folded
> instructions, and
> // then see if there is a load right before the selected
> instructions.
> // Try to fold the load if so.
> const Instruction *BeforeInst = Inst;
> while (BeforeInst != Begin) {
> BeforeInst >
std::prev(BasicBlock::const_iterator(BeforeInst));
> if (!isFoldedOrDeadInstruction(BeforeInst, FuncInfo))
> break;
> }
> if (BeforeInst != Inst &&
isa<LoadInst>(BeforeInst) &&
> BeforeInst->hasOneUse() &&
> FastIS->tryToFoldLoad(cast<LoadInst>(BeforeInst),
Inst)) {
> // If we succeeded, don't re-select the load.
> BI = std::next(BasicBlock::const_iterator(BeforeInst));
> --NumFastIselRemaining;
> ++NumFastIselSuccess;
> }
> continue;
> }
>
> #ifndef NDEBUG
> if (EnableFastISelVerbose2)
> collectFailStats(Inst);
> #endif
>
> // Then handle certain instructions as single-LLVM-Instruction
> blocks.
> if (isa<CallInst>(Inst)) {
>
> if (EnableFastISelVerbose || EnableFastISelAbort) {
> dbgs() << "FastISel missed call: ";
> Inst->dump();
>
>
>
> On 01/20/2015 02:35 PM, reed kotler wrote:
>> It seems that fast-isel for intel does not handle strlen. It's a
general
>> problem in fast-isel .
>>
>>
>> ~/llvmw/build/Deb~/llvmw/build/Debug+Asserts/bin/clang -O0 -mllvm
>> -fast-isel-verbose -mllvm -fast-isel strlen1.c
>> strlen1.c:12:3: warning: implicitly declaring library function
'printf'
>> with
>> type 'int (const char *, ...)'
>> printf("%i\n", len);
>> ^
>> strlen1.c:12:3: note: include the header <stdio.h> or explicitly
>> provide a
>> declaration for 'printf'
>> FastISel missed call: %call = call i64 @strlen(i8* %0) #3
>> 1 warning generated.
>>
>> #include <string.h>
>>
>> char *hello = "hello";
>> int len;
>>
>> void foo() {
>> len = strlen(hello);
>> }
>>
>> int main() {
>> foo();
>> printf("%i\n", len);
>> }