summaryrefslogtreecommitdiffstats
path: root/llvm/lib/IR
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/IR')
-rw-r--r--llvm/lib/IR/AutoUpgrade.cpp70
-rw-r--r--llvm/lib/IR/IRBuilder.cpp36
-rw-r--r--llvm/lib/IR/Verifier.cpp19
3 files changed, 104 insertions, 21 deletions
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index bf96e772394..5d219995aed 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -22,6 +22,7 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instruction.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
@@ -522,6 +523,37 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) {
return true;
}
}
+ // Updating the memory intrinsics (memcpy/memmove/memset) that have an
+ // alignment parameter to embedding the alignment as an attribute of
+ // the pointer args.
+ if (Name.startswith("memcpy.") && F->arg_size() == 5) {
+ rename(F);
+ // Get the types of dest, src, and len
+ ArrayRef<Type *> ParamTypes = F->getFunctionType()->params().slice(0, 3);
+ NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::memcpy,
+ ParamTypes);
+ return true;
+ }
+ if (Name.startswith("memmove.") && F->arg_size() == 5) {
+ rename(F);
+ // Get the types of dest, src, and len
+ ArrayRef<Type *> ParamTypes = F->getFunctionType()->params().slice(0, 3);
+ NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::memmove,
+ ParamTypes);
+ return true;
+ }
+ if (Name.startswith("memset.") && F->arg_size() == 5) {
+ rename(F);
+ // Get the types of dest, and len
+ const auto *FT = F->getFunctionType();
+ Type *ParamTypes[2] = {
+ FT->getParamType(0), // Dest
+ FT->getParamType(2) // len
+ };
+ NewFn = Intrinsic::getDeclaration(F->getParent(), Intrinsic::memset,
+ ParamTypes);
+ return true;
+ }
break;
}
case 'n': {
@@ -2198,14 +2230,17 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) {
return;
}
- CallInst *NewCall = nullptr;
- switch (NewFn->getIntrinsicID()) {
- default: {
+ const auto &DefaultCase = [&NewFn, &CI]() -> void {
// Handle generic mangling change, but nothing else
assert(
(CI->getCalledFunction()->getName() != NewFn->getName()) &&
"Unknown function for CallInst upgrade and isn't just a name change");
CI->setCalledFunction(NewFn);
+ };
+ CallInst *NewCall = nullptr;
+ switch (NewFn->getIntrinsicID()) {
+ default: {
+ DefaultCase();
return;
}
@@ -2346,6 +2381,35 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) {
NewCall = Builder.CreateCall(NewFn, Args);
break;
}
+
+ case Intrinsic::memcpy:
+ case Intrinsic::memmove:
+ case Intrinsic::memset: {
+ // We have to make sure that the call signature is what we're expecting.
+ // We only want to change the old signatures by removing the alignment arg:
+ // @llvm.mem[cpy|move]...(i8*, i8*, i[32|i64], i32, i1)
+ // -> @llvm.mem[cpy|move]...(i8*, i8*, i[32|i64], i1)
+ // @llvm.memset...(i8*, i8, i[32|64], i32, i1)
+ // -> @llvm.memset...(i8*, i8, i[32|64], i1)
+ // Note: i8*'s in the above can be any pointer type
+ if (CI->getNumArgOperands() != 5) {
+ DefaultCase();
+ return;
+ }
+ // Remove alignment argument (3), and add alignment attributes to the
+ // dest/src pointers.
+ Value *Args[4] = {CI->getArgOperand(0), CI->getArgOperand(1),
+ CI->getArgOperand(2), CI->getArgOperand(4)};
+ NewCall = Builder.CreateCall(NewFn, Args);
+ auto *MemCI = cast<MemIntrinsic>(NewCall);
+ // All mem intrinsics support dest alignment.
+ const ConstantInt *Align = cast<ConstantInt>(CI->getArgOperand(3));
+ MemCI->setDestAlignment(Align->getZExtValue());
+ // Memcpy/Memmove also support source alignment.
+ if (auto *MTI = dyn_cast<MemTransferInst>(MemCI))
+ MTI->setSourceAlignment(Align->getZExtValue());
+ break;
+ }
}
assert(NewCall && "Should have either set this variable or returned through "
"the default case");
diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp
index 027c0255bce..99795f54138 100644
--- a/llvm/lib/IR/IRBuilder.cpp
+++ b/llvm/lib/IR/IRBuilder.cpp
@@ -15,6 +15,7 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Statepoint.h"
@@ -83,13 +84,16 @@ CreateMemSet(Value *Ptr, Value *Val, Value *Size, unsigned Align,
bool isVolatile, MDNode *TBAATag, MDNode *ScopeTag,
MDNode *NoAliasTag) {
Ptr = getCastedInt8PtrValue(Ptr);
- Value *Ops[] = { Ptr, Val, Size, getInt32(Align), getInt1(isVolatile) };
+ Value *Ops[] = {Ptr, Val, Size, getInt1(isVolatile)};
Type *Tys[] = { Ptr->getType(), Size->getType() };
Module *M = BB->getParent()->getParent();
Value *TheFn = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys);
CallInst *CI = createCallHelper(TheFn, Ops, this);
-
+
+ if (Align > 0)
+ cast<MemSetInst>(CI)->setDestAlignment(Align);
+
// Set the TBAA info if present.
if (TBAATag)
CI->setMetadata(LLVMContext::MD_tbaa, TBAATag);
@@ -99,7 +103,7 @@ CreateMemSet(Value *Ptr, Value *Val, Value *Size, unsigned Align,
if (NoAliasTag)
CI->setMetadata(LLVMContext::MD_noalias, NoAliasTag);
-
+
return CI;
}
@@ -107,16 +111,20 @@ CallInst *IRBuilderBase::
CreateMemCpy(Value *Dst, Value *Src, Value *Size, unsigned Align,
bool isVolatile, MDNode *TBAATag, MDNode *TBAAStructTag,
MDNode *ScopeTag, MDNode *NoAliasTag) {
+ assert((Align == 0 || isPowerOf2_32(Align)) && "Must be 0 or a power of 2");
Dst = getCastedInt8PtrValue(Dst);
Src = getCastedInt8PtrValue(Src);
- Value *Ops[] = { Dst, Src, Size, getInt32(Align), getInt1(isVolatile) };
+ Value *Ops[] = {Dst, Src, Size, getInt1(isVolatile)};
Type *Tys[] = { Dst->getType(), Src->getType(), Size->getType() };
Module *M = BB->getParent()->getParent();
Value *TheFn = Intrinsic::getDeclaration(M, Intrinsic::memcpy, Tys);
CallInst *CI = createCallHelper(TheFn, Ops, this);
-
+
+ if (Align > 0)
+ cast<MemCpyInst>(CI)->setAlignment(Align);
+
// Set the TBAA info if present.
if (TBAATag)
CI->setMetadata(LLVMContext::MD_tbaa, TBAATag);
@@ -130,7 +138,7 @@ CreateMemCpy(Value *Dst, Value *Src, Value *Size, unsigned Align,
if (NoAliasTag)
CI->setMetadata(LLVMContext::MD_noalias, NoAliasTag);
-
+
return CI;
}
@@ -154,8 +162,9 @@ CallInst *IRBuilderBase::CreateElementUnorderedAtomicMemCpy(
CallInst *CI = createCallHelper(TheFn, Ops, this);
// Set the alignment of the pointer args.
- CI->addParamAttr(0, Attribute::getWithAlignment(CI->getContext(), DstAlign));
- CI->addParamAttr(1, Attribute::getWithAlignment(CI->getContext(), SrcAlign));
+ auto *AMCI = cast<AtomicMemCpyInst>(CI);
+ AMCI->setDestAlignment(DstAlign);
+ AMCI->setSourceAlignment(SrcAlign);
// Set the TBAA info if present.
if (TBAATag)
@@ -178,16 +187,21 @@ CallInst *IRBuilderBase::
CreateMemMove(Value *Dst, Value *Src, Value *Size, unsigned Align,
bool isVolatile, MDNode *TBAATag, MDNode *ScopeTag,
MDNode *NoAliasTag) {
+ assert((Align == 0 || isPowerOf2_32(Align)) && "Must be 0 or a power of 2");
Dst = getCastedInt8PtrValue(Dst);
Src = getCastedInt8PtrValue(Src);
-
- Value *Ops[] = { Dst, Src, Size, getInt32(Align), getInt1(isVolatile) };
+
+ Value *Ops[] = {Dst, Src, Size, getInt1(isVolatile)};
Type *Tys[] = { Dst->getType(), Src->getType(), Size->getType() };
Module *M = BB->getParent()->getParent();
Value *TheFn = Intrinsic::getDeclaration(M, Intrinsic::memmove, Tys);
CallInst *CI = createCallHelper(TheFn, Ops, this);
-
+
+ auto *MMI = cast<MemMoveInst>(CI);
+ if (Align > 0)
+ MMI->setAlignment(Align);
+
// Set the TBAA info if present.
if (TBAATag)
CI->setMetadata(LLVMContext::MD_tbaa, TBAATag);
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index f7775be6961..b73f9dfe4d6 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -4048,18 +4048,23 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) {
case Intrinsic::memcpy:
case Intrinsic::memmove:
case Intrinsic::memset: {
- ConstantInt *AlignCI = dyn_cast<ConstantInt>(CS.getArgOperand(3));
- Assert(AlignCI,
- "alignment argument of memory intrinsics must be a constant int",
- CS);
const auto *MI = cast<MemIntrinsic>(CS.getInstruction());
auto IsValidAlignment = [&](unsigned Alignment) -> bool {
return Alignment == 0 || isPowerOf2_32(Alignment);
};
- Assert(IsValidAlignment(MI->getAlignment()),
- "alignment argument of memory intrinsics must be 0 or a power of 2",
+ Assert(IsValidAlignment(MI->getDestAlignment()),
+ "alignment of arg 0 of memory intrinsic must be 0 or a power of 2",
CS);
- Assert(isa<ConstantInt>(CS.getArgOperand(4)),
+ if (const auto *MTI = dyn_cast<MemTransferInst>(MI)) {
+ Assert(IsValidAlignment(MTI->getSourceAlignment()),
+ "alignment of arg 1 of memory intrinsic must be 0 or a power of 2",
+ CS);
+ // TODO: Remove this assert when we enhance IRBuilder API to create
+ // memcpy/memmove with separate source & dest alignments.
+ Assert(MTI->getSourceAlignment() == MTI->getDestAlignment(),
+ "TEMPORARY: source and dest alignments must be the same");
+ }
+ Assert(isa<ConstantInt>(CS.getArgOperand(3)),
"isvolatile argument of memory intrinsics must be a constant int",
CS);
break;
OpenPOWER on IntegriCloud