forked from OSchip/llvm-project
Split memcpy/memset/memmove intrinsics into i32/i64 versions, resolving
PR709, and paving the way for future progress. llvm-svn: 26476
This commit is contained in:
parent
259d680c15
commit
093c159efb
|
@ -24,12 +24,6 @@ namespace llvm {
|
|||
class Value;
|
||||
class BasicBlock;
|
||||
|
||||
/// This function determines if the \p Name provides is a name for which the
|
||||
/// auto-upgrade to a non-overloaded name applies.
|
||||
/// @returns True if the function name is upgradeable, false otherwise.
|
||||
/// @brief Determine if a name is an upgradeable intrinsic name.
|
||||
bool IsUpgradeableIntrinsicName(const std::string& Name);
|
||||
|
||||
/// This function inspects the Function \p F to see if it is an old overloaded
|
||||
/// intrinsic. If it is, the Function's name is changed to add a suffix that
|
||||
/// indicates the kind of arguments or result that it accepts. In LLVM release
|
||||
|
@ -56,14 +50,10 @@ namespace llvm {
|
|||
/// non-overloaded names. This function inspects the CallInst \p CI to see
|
||||
/// if it is a call to an old overloaded intrinsic. If it is, a new CallInst
|
||||
/// is created that uses the correct Function and possibly casts the
|
||||
/// argument and result to an unsigned type. The caller can use the
|
||||
/// returned Instruction to replace the existing one. Note that the
|
||||
/// Instruction* returned could be a CallInst or a CastInst depending on
|
||||
/// whether casting was necessary.
|
||||
/// argument and result to an unsigned type.
|
||||
/// @param CI The CallInst to potentially auto-upgrade.
|
||||
/// @returns An instrution to replace \p CI with.
|
||||
/// @brief Get replacement instruction for overloaded intrinsic function call.
|
||||
Instruction* UpgradeIntrinsicCall(CallInst* CI, Function* newF = 0);
|
||||
void UpgradeIntrinsicCall(CallInst* CI, Function* newF = 0);
|
||||
|
||||
/// Upgrade both the function and all the calls made to it, if that function
|
||||
/// needs to be upgraded. This is like a combination of the above two
|
||||
|
|
|
@ -148,9 +148,12 @@ namespace llvm {
|
|||
static inline bool classof(const MemIntrinsic *) { return true; }
|
||||
static inline bool classof(const IntrinsicInst *I) {
|
||||
switch (I->getIntrinsicID()) {
|
||||
case Intrinsic::memcpy:
|
||||
case Intrinsic::memmove:
|
||||
case Intrinsic::memset:
|
||||
case Intrinsic::memcpy_i32:
|
||||
case Intrinsic::memcpy_i64:
|
||||
case Intrinsic::memmove_i32:
|
||||
case Intrinsic::memmove_i64:
|
||||
case Intrinsic::memset_i32:
|
||||
case Intrinsic::memset_i64:
|
||||
return true;
|
||||
default: return false;
|
||||
}
|
||||
|
@ -183,7 +186,8 @@ namespace llvm {
|
|||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const MemCpyInst *) { return true; }
|
||||
static inline bool classof(const IntrinsicInst *I) {
|
||||
return I->getIntrinsicID() == Intrinsic::memcpy;
|
||||
return I->getIntrinsicID() == Intrinsic::memcpy_i32 ||
|
||||
I->getIntrinsicID() == Intrinsic::memcpy_i64;
|
||||
}
|
||||
static inline bool classof(const Value *V) {
|
||||
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
||||
|
@ -211,14 +215,15 @@ namespace llvm {
|
|||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const MemMoveInst *) { return true; }
|
||||
static inline bool classof(const IntrinsicInst *I) {
|
||||
return I->getIntrinsicID() == Intrinsic::memmove;
|
||||
return I->getIntrinsicID() == Intrinsic::memmove_i32 ||
|
||||
I->getIntrinsicID() == Intrinsic::memmove_i64;
|
||||
}
|
||||
static inline bool classof(const Value *V) {
|
||||
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
||||
}
|
||||
};
|
||||
|
||||
/// MemSetInst - This class wraps the llvm.memcpy intrinsic.
|
||||
/// MemSetInst - This class wraps the llvm.memset intrinsic.
|
||||
///
|
||||
struct MemSetInst : public MemIntrinsic {
|
||||
/// get* - Return the arguments to the instruction.
|
||||
|
@ -234,7 +239,8 @@ namespace llvm {
|
|||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const MemSetInst *) { return true; }
|
||||
static inline bool classof(const IntrinsicInst *I) {
|
||||
return I->getIntrinsicID() == Intrinsic::memset;
|
||||
return I->getIntrinsicID() == Intrinsic::memset_i32 ||
|
||||
I->getIntrinsicID() == Intrinsic::memset_i64;
|
||||
}
|
||||
static inline bool classof(const Value *V) {
|
||||
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
||||
|
|
|
@ -59,13 +59,16 @@ namespace Intrinsic {
|
|||
dbg_declare, // Declare a local object
|
||||
|
||||
// Standard C library intrinsics.
|
||||
memcpy, // Copy non-overlapping memory blocks
|
||||
memmove, // Copy potentially overlapping memory blocks
|
||||
memset, // Fill memory with a byte value
|
||||
isunordered_f32,// Return true if either float argument is a NaN
|
||||
isunordered_f64,// Return true if either double argument is a NaN
|
||||
sqrt_f32, // Square root of float
|
||||
sqrt_f64, // Square root of double
|
||||
memcpy_i32, // Copy non-overlapping memory blocks. i32 size.
|
||||
memcpy_i64, // Copy non-overlapping memory blocks. i64 size.
|
||||
memmove_i32, // Copy potentially overlapping memory blocks. i32 size.
|
||||
memmove_i64, // Copy potentially overlapping memory blocks. i64 size.
|
||||
memset_i32, // Fill memory with a byte value. i32 size.
|
||||
memset_i64, // Fill memory with a byte value. i64 size.
|
||||
isunordered_f32, // Return true if either float argument is a NaN
|
||||
isunordered_f64, // Return true if either double argument is a NaN
|
||||
sqrt_f32, // Square root of float
|
||||
sqrt_f64, // Square root of double
|
||||
|
||||
// Bit manipulation instrinsics.
|
||||
bswap_i16, // Byteswap 16 bits
|
||||
|
|
|
@ -545,8 +545,10 @@ void GraphBuilder::visitCallSite(CallSite CS) {
|
|||
return;
|
||||
case Intrinsic::vaend:
|
||||
return; // noop
|
||||
case Intrinsic::memmove:
|
||||
case Intrinsic::memcpy: {
|
||||
case Intrinsic::memmove_i32:
|
||||
case Intrinsic::memcpy_i32:
|
||||
case Intrinsic::memmove_i64:
|
||||
case Intrinsic::memcpy_i64: {
|
||||
// Merge the first & second arguments, and mark the memory read and
|
||||
// modified.
|
||||
DSNodeHandle RetNH = getValueDest(**CS.arg_begin());
|
||||
|
@ -555,7 +557,8 @@ void GraphBuilder::visitCallSite(CallSite CS) {
|
|||
N->setModifiedMarker()->setReadMarker();
|
||||
return;
|
||||
}
|
||||
case Intrinsic::memset:
|
||||
case Intrinsic::memset_i32:
|
||||
case Intrinsic::memset_i64:
|
||||
// Mark the memory modified.
|
||||
if (DSNode *N = getValueDest(**CS.arg_begin()).getNode())
|
||||
N->setModifiedMarker();
|
||||
|
|
|
@ -99,15 +99,18 @@ void DefaultIntrinsicLowering::AddPrototypes(Module &M) {
|
|||
EnsureFunctionExists(M, "abort", I->arg_end(), I->arg_end(),
|
||||
Type::VoidTy);
|
||||
break;
|
||||
case Intrinsic::memcpy:
|
||||
case Intrinsic::memcpy_i32:
|
||||
case Intrinsic::memcpy_i64:
|
||||
EnsureFunctionExists(M, "memcpy", I->arg_begin(), --I->arg_end(),
|
||||
I->arg_begin()->getType());
|
||||
break;
|
||||
case Intrinsic::memmove:
|
||||
case Intrinsic::memmove_i32:
|
||||
case Intrinsic::memmove_i64:
|
||||
EnsureFunctionExists(M, "memmove", I->arg_begin(), --I->arg_end(),
|
||||
I->arg_begin()->getType());
|
||||
break;
|
||||
case Intrinsic::memset:
|
||||
case Intrinsic::memset_i32:
|
||||
case Intrinsic::memset_i64:
|
||||
M.getOrInsertFunction("memset", PointerType::get(Type::SByteTy),
|
||||
PointerType::get(Type::SByteTy),
|
||||
Type::IntTy, (--(--I->arg_end()))->getType(),
|
||||
|
@ -405,7 +408,8 @@ void DefaultIntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
|
|||
CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
|
||||
break; // Simply strip out debugging intrinsics
|
||||
|
||||
case Intrinsic::memcpy: {
|
||||
case Intrinsic::memcpy_i32:
|
||||
case Intrinsic::memcpy_i64: {
|
||||
// The memcpy intrinsic take an extra alignment argument that the memcpy
|
||||
// libc function does not.
|
||||
static Function *MemcpyFCache = 0;
|
||||
|
@ -413,7 +417,8 @@ void DefaultIntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
|
|||
(*(CI->op_begin()+1))->getType(), MemcpyFCache);
|
||||
break;
|
||||
}
|
||||
case Intrinsic::memmove: {
|
||||
case Intrinsic::memmove_i32:
|
||||
case Intrinsic::memmove_i64: {
|
||||
// The memmove intrinsic take an extra alignment argument that the memmove
|
||||
// libc function does not.
|
||||
static Function *MemmoveFCache = 0;
|
||||
|
@ -421,7 +426,8 @@ void DefaultIntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
|
|||
(*(CI->op_begin()+1))->getType(), MemmoveFCache);
|
||||
break;
|
||||
}
|
||||
case Intrinsic::memset: {
|
||||
case Intrinsic::memset_i32:
|
||||
case Intrinsic::memset_i64: {
|
||||
// The memset intrinsic take an extra alignment argument that the memset
|
||||
// libc function does not.
|
||||
static Function *MemsetFCache = 0;
|
||||
|
|
|
@ -955,9 +955,18 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
|
|||
case Intrinsic::longjmp:
|
||||
return "_longjmp"+!TLI.usesUnderscoreSetJmpLongJmp();
|
||||
break;
|
||||
case Intrinsic::memcpy: visitMemIntrinsic(I, ISD::MEMCPY); return 0;
|
||||
case Intrinsic::memset: visitMemIntrinsic(I, ISD::MEMSET); return 0;
|
||||
case Intrinsic::memmove: visitMemIntrinsic(I, ISD::MEMMOVE); return 0;
|
||||
case Intrinsic::memcpy_i32:
|
||||
case Intrinsic::memcpy_i64:
|
||||
visitMemIntrinsic(I, ISD::MEMCPY);
|
||||
return 0;
|
||||
case Intrinsic::memset_i32:
|
||||
case Intrinsic::memset_i64:
|
||||
visitMemIntrinsic(I, ISD::MEMSET);
|
||||
return 0;
|
||||
case Intrinsic::memmove_i32:
|
||||
case Intrinsic::memmove_i64:
|
||||
visitMemIntrinsic(I, ISD::MEMMOVE);
|
||||
return 0;
|
||||
|
||||
case Intrinsic::readport:
|
||||
case Intrinsic::readio: {
|
||||
|
|
Loading…
Reference in New Issue