[LLVMdev] strlen in fast-isel is missed

Reed Kotler rkotler at mips.com
Wed Jan 28 12:20:27 PST 2015


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




More information about the llvm-dev mailing list