mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-20 09:30:43 +00:00
bda134910a
While the term "Target" is in the name, it doesn't really have to do with the LLVM Target library -- this isn't an abstraction which LLVM targets generally need to implement or extend. It has much more to do with modeling the various runtime libraries on different OSes and with different runtime environments. The "target" in this sense is the more general sense of a target of cross compilation. This is in preparation for porting this analysis to the new pass manager. No functionality changed, and updates inbound for Clang and Polly. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@226078 91177308-0d34-0410-b5e6-96231b3b80d8
206 lines
6.2 KiB
C++
206 lines
6.2 KiB
C++
//===- llvm/Transforms/Utils/VectorUtils.h - Vector utilities -*- C++ -*-=====//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines some vectorizer utilities.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_TRANSFORMS_UTILS_VECTORUTILS_H
|
|
#define LLVM_TRANSFORMS_UTILS_VECTORUTILS_H
|
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
#include "llvm/IR/Intrinsics.h"
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
|
|
|
namespace llvm {
|
|
|
|
/// \brief Identify if the intrinsic is trivially vectorizable.
|
|
///
|
|
/// This method returns true if the intrinsic's argument types are all
|
|
/// scalars for the scalar form of the intrinsic and all vectors for
|
|
/// the vector form of the intrinsic.
|
|
static inline bool isTriviallyVectorizable(Intrinsic::ID ID) {
|
|
switch (ID) {
|
|
case Intrinsic::sqrt:
|
|
case Intrinsic::sin:
|
|
case Intrinsic::cos:
|
|
case Intrinsic::exp:
|
|
case Intrinsic::exp2:
|
|
case Intrinsic::log:
|
|
case Intrinsic::log10:
|
|
case Intrinsic::log2:
|
|
case Intrinsic::fabs:
|
|
case Intrinsic::minnum:
|
|
case Intrinsic::maxnum:
|
|
case Intrinsic::copysign:
|
|
case Intrinsic::floor:
|
|
case Intrinsic::ceil:
|
|
case Intrinsic::trunc:
|
|
case Intrinsic::rint:
|
|
case Intrinsic::nearbyint:
|
|
case Intrinsic::round:
|
|
case Intrinsic::bswap:
|
|
case Intrinsic::ctpop:
|
|
case Intrinsic::pow:
|
|
case Intrinsic::fma:
|
|
case Intrinsic::fmuladd:
|
|
case Intrinsic::ctlz:
|
|
case Intrinsic::cttz:
|
|
case Intrinsic::powi:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool hasVectorInstrinsicScalarOpd(Intrinsic::ID ID,
|
|
unsigned ScalarOpdIdx) {
|
|
switch (ID) {
|
|
case Intrinsic::ctlz:
|
|
case Intrinsic::cttz:
|
|
case Intrinsic::powi:
|
|
return (ScalarOpdIdx == 1);
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static Intrinsic::ID checkUnaryFloatSignature(const CallInst &I,
|
|
Intrinsic::ID ValidIntrinsicID) {
|
|
if (I.getNumArgOperands() != 1 ||
|
|
!I.getArgOperand(0)->getType()->isFloatingPointTy() ||
|
|
I.getType() != I.getArgOperand(0)->getType() ||
|
|
!I.onlyReadsMemory())
|
|
return Intrinsic::not_intrinsic;
|
|
|
|
return ValidIntrinsicID;
|
|
}
|
|
|
|
static Intrinsic::ID checkBinaryFloatSignature(const CallInst &I,
|
|
Intrinsic::ID ValidIntrinsicID) {
|
|
if (I.getNumArgOperands() != 2 ||
|
|
!I.getArgOperand(0)->getType()->isFloatingPointTy() ||
|
|
!I.getArgOperand(1)->getType()->isFloatingPointTy() ||
|
|
I.getType() != I.getArgOperand(0)->getType() ||
|
|
I.getType() != I.getArgOperand(1)->getType() ||
|
|
!I.onlyReadsMemory())
|
|
return Intrinsic::not_intrinsic;
|
|
|
|
return ValidIntrinsicID;
|
|
}
|
|
|
|
static Intrinsic::ID
|
|
getIntrinsicIDForCall(CallInst *CI, const TargetLibraryInfo *TLI) {
|
|
// If we have an intrinsic call, check if it is trivially vectorizable.
|
|
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(CI)) {
|
|
Intrinsic::ID ID = II->getIntrinsicID();
|
|
if (isTriviallyVectorizable(ID) || ID == Intrinsic::lifetime_start ||
|
|
ID == Intrinsic::lifetime_end || ID == Intrinsic::assume)
|
|
return ID;
|
|
else
|
|
return Intrinsic::not_intrinsic;
|
|
}
|
|
|
|
if (!TLI)
|
|
return Intrinsic::not_intrinsic;
|
|
|
|
LibFunc::Func Func;
|
|
Function *F = CI->getCalledFunction();
|
|
// We're going to make assumptions on the semantics of the functions, check
|
|
// that the target knows that it's available in this environment and it does
|
|
// not have local linkage.
|
|
if (!F || F->hasLocalLinkage() || !TLI->getLibFunc(F->getName(), Func))
|
|
return Intrinsic::not_intrinsic;
|
|
|
|
// Otherwise check if we have a call to a function that can be turned into a
|
|
// vector intrinsic.
|
|
switch (Func) {
|
|
default:
|
|
break;
|
|
case LibFunc::sin:
|
|
case LibFunc::sinf:
|
|
case LibFunc::sinl:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::sin);
|
|
case LibFunc::cos:
|
|
case LibFunc::cosf:
|
|
case LibFunc::cosl:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::cos);
|
|
case LibFunc::exp:
|
|
case LibFunc::expf:
|
|
case LibFunc::expl:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::exp);
|
|
case LibFunc::exp2:
|
|
case LibFunc::exp2f:
|
|
case LibFunc::exp2l:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::exp2);
|
|
case LibFunc::log:
|
|
case LibFunc::logf:
|
|
case LibFunc::logl:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::log);
|
|
case LibFunc::log10:
|
|
case LibFunc::log10f:
|
|
case LibFunc::log10l:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::log10);
|
|
case LibFunc::log2:
|
|
case LibFunc::log2f:
|
|
case LibFunc::log2l:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::log2);
|
|
case LibFunc::fabs:
|
|
case LibFunc::fabsf:
|
|
case LibFunc::fabsl:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::fabs);
|
|
case LibFunc::fmin:
|
|
case LibFunc::fminf:
|
|
case LibFunc::fminl:
|
|
return checkBinaryFloatSignature(*CI, Intrinsic::minnum);
|
|
case LibFunc::fmax:
|
|
case LibFunc::fmaxf:
|
|
case LibFunc::fmaxl:
|
|
return checkBinaryFloatSignature(*CI, Intrinsic::maxnum);
|
|
case LibFunc::copysign:
|
|
case LibFunc::copysignf:
|
|
case LibFunc::copysignl:
|
|
return checkBinaryFloatSignature(*CI, Intrinsic::copysign);
|
|
case LibFunc::floor:
|
|
case LibFunc::floorf:
|
|
case LibFunc::floorl:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::floor);
|
|
case LibFunc::ceil:
|
|
case LibFunc::ceilf:
|
|
case LibFunc::ceill:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::ceil);
|
|
case LibFunc::trunc:
|
|
case LibFunc::truncf:
|
|
case LibFunc::truncl:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::trunc);
|
|
case LibFunc::rint:
|
|
case LibFunc::rintf:
|
|
case LibFunc::rintl:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::rint);
|
|
case LibFunc::nearbyint:
|
|
case LibFunc::nearbyintf:
|
|
case LibFunc::nearbyintl:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::nearbyint);
|
|
case LibFunc::round:
|
|
case LibFunc::roundf:
|
|
case LibFunc::roundl:
|
|
return checkUnaryFloatSignature(*CI, Intrinsic::round);
|
|
case LibFunc::pow:
|
|
case LibFunc::powf:
|
|
case LibFunc::powl:
|
|
return checkBinaryFloatSignature(*CI, Intrinsic::pow);
|
|
}
|
|
|
|
return Intrinsic::not_intrinsic;
|
|
}
|
|
|
|
} // llvm namespace
|
|
|
|
#endif
|