// Loop through the inline asm constraints and look for something that clobbers // ctr. static bool asmClobbersCTR(InlineAsm *IA) { InlineAsm::ConstraintInfoVector CIV = IA->ParseConstraints(); for (unsigned i = 0, ie = CIV.size(); i < ie; ++i) { InlineAsm::ConstraintInfo &C = CIV[i]; if (C.Type != InlineAsm::isInput) for (unsigned j = 0, je = C.Codes.size(); j < je; ++j) if (StringRef(C.Codes[j]).equals_lower("{ctr}")) return true; } return false; }
/// hasInlineAsmMemConstraint - Return true if the inline asm instruction being /// processed uses a memory 'm' constraint. bool llvm::hasInlineAsmMemConstraint(InlineAsm::ConstraintInfoVector &CInfos, const TargetLowering &TLI) { for (unsigned i = 0, e = CInfos.size(); i != e; ++i) { InlineAsm::ConstraintInfo &CI = CInfos[i]; for (unsigned j = 0, ee = CI.Codes.size(); j != ee; ++j) { TargetLowering::ConstraintType CType = TLI.getConstraintType(CI.Codes[j]); if (CType == TargetLowering::C_Memory) return true; } // Indirect operand accesses access memory. if (CI.isIndirect) return true; } return false; }
bool PPCCTRLoops::mightUseCTR(const Triple &TT, BasicBlock *BB) { for (BasicBlock::iterator J = BB->begin(), JE = BB->end(); J != JE; ++J) { if (CallInst *CI = dyn_cast<CallInst>(J)) { if (InlineAsm *IA = dyn_cast<InlineAsm>(CI->getCalledValue())) { // Inline ASM is okay, unless it clobbers the ctr register. InlineAsm::ConstraintInfoVector CIV = IA->ParseConstraints(); for (unsigned i = 0, ie = CIV.size(); i < ie; ++i) { InlineAsm::ConstraintInfo &C = CIV[i]; if (C.Type != InlineAsm::isInput) for (unsigned j = 0, je = C.Codes.size(); j < je; ++j) if (StringRef(C.Codes[j]).equals_lower("{ctr}")) return true; } continue; } if (!TM) return true; const TargetLowering *TLI = TM->getTargetLowering(); if (Function *F = CI->getCalledFunction()) { // Most intrinsics don't become function calls, but some might. // sin, cos, exp and log are always calls. unsigned Opcode; if (F->getIntrinsicID() != Intrinsic::not_intrinsic) { switch (F->getIntrinsicID()) { default: continue; // VisualStudio defines setjmp as _setjmp #if defined(_MSC_VER) && defined(setjmp) && \ !defined(setjmp_undefined_for_msvc) # pragma push_macro("setjmp") # undef setjmp # define setjmp_undefined_for_msvc #endif case Intrinsic::setjmp: #if defined(_MSC_VER) && defined(setjmp_undefined_for_msvc) // let's return it to _setjmp state # pragma pop_macro("setjmp") # undef setjmp_undefined_for_msvc #endif case Intrinsic::longjmp: // Exclude eh_sjlj_setjmp; we don't need to exclude eh_sjlj_longjmp // because, although it does clobber the counter register, the // control can't then return to inside the loop unless there is also // an eh_sjlj_setjmp. case Intrinsic::eh_sjlj_setjmp: case Intrinsic::memcpy: case Intrinsic::memmove: case Intrinsic::memset: case Intrinsic::powi: case Intrinsic::log: case Intrinsic::log2: case Intrinsic::log10: case Intrinsic::exp: case Intrinsic::exp2: case Intrinsic::pow: case Intrinsic::sin: case Intrinsic::cos: return true; case Intrinsic::copysign: if (CI->getArgOperand(0)->getType()->getScalarType()-> isPPC_FP128Ty()) return true; else continue; // ISD::FCOPYSIGN is never a library call. case Intrinsic::sqrt: Opcode = ISD::FSQRT; break; case Intrinsic::floor: Opcode = ISD::FFLOOR; break; case Intrinsic::ceil: Opcode = ISD::FCEIL; break; case Intrinsic::trunc: Opcode = ISD::FTRUNC; break; case Intrinsic::rint: Opcode = ISD::FRINT; break; case Intrinsic::nearbyint: Opcode = ISD::FNEARBYINT; break; case Intrinsic::round: Opcode = ISD::FROUND; break; } } // PowerPC does not use [US]DIVREM or other library calls for // operations on regular types which are not otherwise library calls // (i.e. soft float or atomics). If adapting for targets that do, // additional care is required here. LibFunc::Func Func; if (!F->hasLocalLinkage() && F->hasName() && LibInfo && LibInfo->getLibFunc(F->getName(), Func) && LibInfo->hasOptimizedCodeGen(Func)) { // Non-read-only functions are never treated as intrinsics. if (!CI->onlyReadsMemory()) return true; // Conversion happens only for FP calls. if (!CI->getArgOperand(0)->getType()->isFloatingPointTy()) return true; switch (Func) { default: return true; case LibFunc::copysign: case LibFunc::copysignf: continue; // ISD::FCOPYSIGN is never a library call. case LibFunc::copysignl: return true; case LibFunc::fabs: case LibFunc::fabsf: case LibFunc::fabsl: continue; // ISD::FABS is never a library call. case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl: Opcode = ISD::FSQRT; break; case LibFunc::floor: case LibFunc::floorf: case LibFunc::floorl: Opcode = ISD::FFLOOR; break; case LibFunc::nearbyint: case LibFunc::nearbyintf: case LibFunc::nearbyintl: Opcode = ISD::FNEARBYINT; break; case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill: Opcode = ISD::FCEIL; break; case LibFunc::rint: case LibFunc::rintf: case LibFunc::rintl: Opcode = ISD::FRINT; break; case LibFunc::round: case LibFunc::roundf: case LibFunc::roundl: Opcode = ISD::FROUND; break; case LibFunc::trunc: case LibFunc::truncf: case LibFunc::truncl: Opcode = ISD::FTRUNC; break; } MVT VTy = TLI->getSimpleValueType(CI->getArgOperand(0)->getType(), true); if (VTy == MVT::Other) return true; if (TLI->isOperationLegalOrCustom(Opcode, VTy)) continue; else if (VTy.isVector() && TLI->isOperationLegalOrCustom(Opcode, VTy.getScalarType())) continue; return true; } } return true; } else if (isa<BinaryOperator>(J) && J->getType()->getScalarType()->isPPC_FP128Ty()) { // Most operations on ppc_f128 values become calls. return true; } else if (isa<UIToFPInst>(J) || isa<SIToFPInst>(J) || isa<FPToUIInst>(J) || isa<FPToSIInst>(J)) { CastInst *CI = cast<CastInst>(J); if (CI->getSrcTy()->getScalarType()->isPPC_FP128Ty() || CI->getDestTy()->getScalarType()->isPPC_FP128Ty() || (TT.isArch32Bit() && (CI->getSrcTy()->getScalarType()->isIntegerTy(64) || CI->getDestTy()->getScalarType()->isIntegerTy(64)) )) return true; } else if (TT.isArch32Bit() && J->getType()->getScalarType()->isIntegerTy(64) && (J->getOpcode() == Instruction::UDiv || J->getOpcode() == Instruction::SDiv || J->getOpcode() == Instruction::URem || J->getOpcode() == Instruction::SRem)) { return true; } else if (isa<IndirectBrInst>(J) || isa<InvokeInst>(J)) { // On PowerPC, indirect jumps use the counter register. return true; } else if (SwitchInst *SI = dyn_cast<SwitchInst>(J)) { if (!TM) return true; const TargetLowering *TLI = TM->getTargetLowering(); if (TLI->supportJumpTables() && SI->getNumCases()+1 >= (unsigned) TLI->getMinimumJumpTableEntries()) return true; } } return false; }
/// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the /// fields in this structure. If the constraint string is not understood, /// return true, otherwise return false. bool InlineAsm::ConstraintInfo::Parse(StringRef Str, InlineAsm::ConstraintInfoVector &ConstraintsSoFar) { StringRef::iterator I = Str.begin(), E = Str.end(); unsigned multipleAlternativeCount = Str.count('|') + 1; unsigned multipleAlternativeIndex = 0; ConstraintCodeVector *pCodes = &Codes; // Initialize isMultipleAlternative = multipleAlternativeCount > 1; if (isMultipleAlternative) { multipleAlternatives.resize(multipleAlternativeCount); pCodes = &multipleAlternatives[0].Codes; } Type = isInput; isEarlyClobber = false; MatchingInput = -1; isCommutative = false; isIndirect = false; currentAlternativeIndex = 0; // Parse prefixes. if (*I == '~') { Type = isClobber; ++I; // '{' must immediately follow '~'. if (I != E && *I != '{') return true; } else if (*I == '=') { ++I; Type = isOutput; } if (*I == '*') { isIndirect = true; ++I; } if (I == E) return true; // Just a prefix, like "==" or "~". // Parse the modifiers. bool DoneWithModifiers = false; while (!DoneWithModifiers) { switch (*I) { default: DoneWithModifiers = true; break; case '&': // Early clobber. if (Type != isOutput || // Cannot early clobber anything but output. isEarlyClobber) // Reject &&&&&& return true; isEarlyClobber = true; break; case '%': // Commutative. if (Type == isClobber || // Cannot commute clobbers. isCommutative) // Reject %%%%% return true; isCommutative = true; break; case '#': // Comment. case '*': // Register preferencing. return true; // Not supported. } if (!DoneWithModifiers) { ++I; if (I == E) return true; // Just prefixes and modifiers! } } // Parse the various constraints. while (I != E) { if (*I == '{') { // Physical register reference. // Find the end of the register name. StringRef::iterator ConstraintEnd = std::find(I+1, E, '}'); if (ConstraintEnd == E) return true; // "{foo" pCodes->push_back(std::string(I, ConstraintEnd+1)); I = ConstraintEnd+1; } else if (isdigit(static_cast<unsigned char>(*I))) { // Matching Constraint // Maximal munch numbers. StringRef::iterator NumStart = I; while (I != E && isdigit(static_cast<unsigned char>(*I))) ++I; pCodes->push_back(std::string(NumStart, I)); unsigned N = atoi(pCodes->back().c_str()); // Check that this is a valid matching constraint! if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput|| Type != isInput) return true; // Invalid constraint number. // If Operand N already has a matching input, reject this. An output // can't be constrained to the same value as multiple inputs. if (isMultipleAlternative) { if (multipleAlternativeIndex >= ConstraintsSoFar[N].multipleAlternatives.size()) return true; InlineAsm::SubConstraintInfo &scInfo = ConstraintsSoFar[N].multipleAlternatives[multipleAlternativeIndex]; if (scInfo.MatchingInput != -1) return true; // Note that operand #n has a matching input. scInfo.MatchingInput = ConstraintsSoFar.size(); } else { if (ConstraintsSoFar[N].hasMatchingInput() && (size_t)ConstraintsSoFar[N].MatchingInput != ConstraintsSoFar.size()) return true; // Note that operand #n has a matching input. ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size(); } } else if (*I == '|') { multipleAlternativeIndex++; pCodes = &multipleAlternatives[multipleAlternativeIndex].Codes; ++I; } else if (*I == '^') { // Multi-letter constraint // FIXME: For now assuming these are 2-character constraints. pCodes->push_back(std::string(I+1, I+3)); I += 3; } else { // Single letter constraint. pCodes->push_back(std::string(I, I+1)); ++I; } } return false; }