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); >> }