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 Value;
|
||||||
class BasicBlock;
|
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
|
/// 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
|
/// 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
|
/// 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
|
/// 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
|
/// 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
|
/// is created that uses the correct Function and possibly casts the
|
||||||
/// argument and result to an unsigned type. The caller can use the
|
/// argument and result to an unsigned type.
|
||||||
/// 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.
|
|
||||||
/// @param CI The CallInst to potentially auto-upgrade.
|
/// @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.
|
/// @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
|
/// 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
|
/// 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 MemIntrinsic *) { return true; }
|
||||||
static inline bool classof(const IntrinsicInst *I) {
|
static inline bool classof(const IntrinsicInst *I) {
|
||||||
switch (I->getIntrinsicID()) {
|
switch (I->getIntrinsicID()) {
|
||||||
case Intrinsic::memcpy:
|
case Intrinsic::memcpy_i32:
|
||||||
case Intrinsic::memmove:
|
case Intrinsic::memcpy_i64:
|
||||||
case Intrinsic::memset:
|
case Intrinsic::memmove_i32:
|
||||||
|
case Intrinsic::memmove_i64:
|
||||||
|
case Intrinsic::memset_i32:
|
||||||
|
case Intrinsic::memset_i64:
|
||||||
return true;
|
return true;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
|
@ -183,7 +186,8 @@ namespace llvm {
|
||||||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||||
static inline bool classof(const MemCpyInst *) { return true; }
|
static inline bool classof(const MemCpyInst *) { return true; }
|
||||||
static inline bool classof(const IntrinsicInst *I) {
|
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) {
|
static inline bool classof(const Value *V) {
|
||||||
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(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:
|
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||||
static inline bool classof(const MemMoveInst *) { return true; }
|
static inline bool classof(const MemMoveInst *) { return true; }
|
||||||
static inline bool classof(const IntrinsicInst *I) {
|
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) {
|
static inline bool classof(const Value *V) {
|
||||||
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(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 {
|
struct MemSetInst : public MemIntrinsic {
|
||||||
/// get* - Return the arguments to the instruction.
|
/// get* - Return the arguments to the instruction.
|
||||||
|
@ -234,7 +239,8 @@ namespace llvm {
|
||||||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||||
static inline bool classof(const MemSetInst *) { return true; }
|
static inline bool classof(const MemSetInst *) { return true; }
|
||||||
static inline bool classof(const IntrinsicInst *I) {
|
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) {
|
static inline bool classof(const Value *V) {
|
||||||
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
||||||
|
|
|
@ -59,13 +59,16 @@ namespace Intrinsic {
|
||||||
dbg_declare, // Declare a local object
|
dbg_declare, // Declare a local object
|
||||||
|
|
||||||
// Standard C library intrinsics.
|
// Standard C library intrinsics.
|
||||||
memcpy, // Copy non-overlapping memory blocks
|
memcpy_i32, // Copy non-overlapping memory blocks. i32 size.
|
||||||
memmove, // Copy potentially overlapping memory blocks
|
memcpy_i64, // Copy non-overlapping memory blocks. i64 size.
|
||||||
memset, // Fill memory with a byte value
|
memmove_i32, // Copy potentially overlapping memory blocks. i32 size.
|
||||||
isunordered_f32,// Return true if either float argument is a NaN
|
memmove_i64, // Copy potentially overlapping memory blocks. i64 size.
|
||||||
isunordered_f64,// Return true if either double argument is a NaN
|
memset_i32, // Fill memory with a byte value. i32 size.
|
||||||
sqrt_f32, // Square root of float
|
memset_i64, // Fill memory with a byte value. i64 size.
|
||||||
sqrt_f64, // Square root of double
|
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.
|
// Bit manipulation instrinsics.
|
||||||
bswap_i16, // Byteswap 16 bits
|
bswap_i16, // Byteswap 16 bits
|
||||||
|
|
|
@ -545,8 +545,10 @@ void GraphBuilder::visitCallSite(CallSite CS) {
|
||||||
return;
|
return;
|
||||||
case Intrinsic::vaend:
|
case Intrinsic::vaend:
|
||||||
return; // noop
|
return; // noop
|
||||||
case Intrinsic::memmove:
|
case Intrinsic::memmove_i32:
|
||||||
case Intrinsic::memcpy: {
|
case Intrinsic::memcpy_i32:
|
||||||
|
case Intrinsic::memmove_i64:
|
||||||
|
case Intrinsic::memcpy_i64: {
|
||||||
// Merge the first & second arguments, and mark the memory read and
|
// Merge the first & second arguments, and mark the memory read and
|
||||||
// modified.
|
// modified.
|
||||||
DSNodeHandle RetNH = getValueDest(**CS.arg_begin());
|
DSNodeHandle RetNH = getValueDest(**CS.arg_begin());
|
||||||
|
@ -555,7 +557,8 @@ void GraphBuilder::visitCallSite(CallSite CS) {
|
||||||
N->setModifiedMarker()->setReadMarker();
|
N->setModifiedMarker()->setReadMarker();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case Intrinsic::memset:
|
case Intrinsic::memset_i32:
|
||||||
|
case Intrinsic::memset_i64:
|
||||||
// Mark the memory modified.
|
// Mark the memory modified.
|
||||||
if (DSNode *N = getValueDest(**CS.arg_begin()).getNode())
|
if (DSNode *N = getValueDest(**CS.arg_begin()).getNode())
|
||||||
N->setModifiedMarker();
|
N->setModifiedMarker();
|
||||||
|
|
|
@ -99,15 +99,18 @@ void DefaultIntrinsicLowering::AddPrototypes(Module &M) {
|
||||||
EnsureFunctionExists(M, "abort", I->arg_end(), I->arg_end(),
|
EnsureFunctionExists(M, "abort", I->arg_end(), I->arg_end(),
|
||||||
Type::VoidTy);
|
Type::VoidTy);
|
||||||
break;
|
break;
|
||||||
case Intrinsic::memcpy:
|
case Intrinsic::memcpy_i32:
|
||||||
|
case Intrinsic::memcpy_i64:
|
||||||
EnsureFunctionExists(M, "memcpy", I->arg_begin(), --I->arg_end(),
|
EnsureFunctionExists(M, "memcpy", I->arg_begin(), --I->arg_end(),
|
||||||
I->arg_begin()->getType());
|
I->arg_begin()->getType());
|
||||||
break;
|
break;
|
||||||
case Intrinsic::memmove:
|
case Intrinsic::memmove_i32:
|
||||||
|
case Intrinsic::memmove_i64:
|
||||||
EnsureFunctionExists(M, "memmove", I->arg_begin(), --I->arg_end(),
|
EnsureFunctionExists(M, "memmove", I->arg_begin(), --I->arg_end(),
|
||||||
I->arg_begin()->getType());
|
I->arg_begin()->getType());
|
||||||
break;
|
break;
|
||||||
case Intrinsic::memset:
|
case Intrinsic::memset_i32:
|
||||||
|
case Intrinsic::memset_i64:
|
||||||
M.getOrInsertFunction("memset", PointerType::get(Type::SByteTy),
|
M.getOrInsertFunction("memset", PointerType::get(Type::SByteTy),
|
||||||
PointerType::get(Type::SByteTy),
|
PointerType::get(Type::SByteTy),
|
||||||
Type::IntTy, (--(--I->arg_end()))->getType(),
|
Type::IntTy, (--(--I->arg_end()))->getType(),
|
||||||
|
@ -405,7 +408,8 @@ void DefaultIntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
|
||||||
CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
|
CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
|
||||||
break; // Simply strip out debugging intrinsics
|
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
|
// The memcpy intrinsic take an extra alignment argument that the memcpy
|
||||||
// libc function does not.
|
// libc function does not.
|
||||||
static Function *MemcpyFCache = 0;
|
static Function *MemcpyFCache = 0;
|
||||||
|
@ -413,7 +417,8 @@ void DefaultIntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
|
||||||
(*(CI->op_begin()+1))->getType(), MemcpyFCache);
|
(*(CI->op_begin()+1))->getType(), MemcpyFCache);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Intrinsic::memmove: {
|
case Intrinsic::memmove_i32:
|
||||||
|
case Intrinsic::memmove_i64: {
|
||||||
// The memmove intrinsic take an extra alignment argument that the memmove
|
// The memmove intrinsic take an extra alignment argument that the memmove
|
||||||
// libc function does not.
|
// libc function does not.
|
||||||
static Function *MemmoveFCache = 0;
|
static Function *MemmoveFCache = 0;
|
||||||
|
@ -421,7 +426,8 @@ void DefaultIntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
|
||||||
(*(CI->op_begin()+1))->getType(), MemmoveFCache);
|
(*(CI->op_begin()+1))->getType(), MemmoveFCache);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Intrinsic::memset: {
|
case Intrinsic::memset_i32:
|
||||||
|
case Intrinsic::memset_i64: {
|
||||||
// The memset intrinsic take an extra alignment argument that the memset
|
// The memset intrinsic take an extra alignment argument that the memset
|
||||||
// libc function does not.
|
// libc function does not.
|
||||||
static Function *MemsetFCache = 0;
|
static Function *MemsetFCache = 0;
|
||||||
|
|
|
@ -955,9 +955,18 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
|
||||||
case Intrinsic::longjmp:
|
case Intrinsic::longjmp:
|
||||||
return "_longjmp"+!TLI.usesUnderscoreSetJmpLongJmp();
|
return "_longjmp"+!TLI.usesUnderscoreSetJmpLongJmp();
|
||||||
break;
|
break;
|
||||||
case Intrinsic::memcpy: visitMemIntrinsic(I, ISD::MEMCPY); return 0;
|
case Intrinsic::memcpy_i32:
|
||||||
case Intrinsic::memset: visitMemIntrinsic(I, ISD::MEMSET); return 0;
|
case Intrinsic::memcpy_i64:
|
||||||
case Intrinsic::memmove: visitMemIntrinsic(I, ISD::MEMMOVE); return 0;
|
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::readport:
|
||||||
case Intrinsic::readio: {
|
case Intrinsic::readio: {
|
||||||
|
|
Loading…
Reference in New Issue