Allow memory intrinsics to be tail calls

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@234764 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Krzysztof Parzyszek 2015-04-13 17:16:45 +00:00
parent 12a7039644
commit fcc330abfe
19 changed files with 222 additions and 30 deletions

View File

@ -685,16 +685,16 @@ public:
SDValue getMemcpy(SDValue Chain, SDLoc dl, SDValue Dst, SDValue Src, SDValue getMemcpy(SDValue Chain, SDLoc dl, SDValue Dst, SDValue Src,
SDValue Size, unsigned Align, bool isVol, bool AlwaysInline, SDValue Size, unsigned Align, bool isVol, bool AlwaysInline,
MachinePointerInfo DstPtrInfo, bool isTailCall, MachinePointerInfo DstPtrInfo,
MachinePointerInfo SrcPtrInfo); MachinePointerInfo SrcPtrInfo);
SDValue getMemmove(SDValue Chain, SDLoc dl, SDValue Dst, SDValue Src, SDValue getMemmove(SDValue Chain, SDLoc dl, SDValue Dst, SDValue Src,
SDValue Size, unsigned Align, bool isVol, SDValue Size, unsigned Align, bool isVol, bool isTailCall,
MachinePointerInfo DstPtrInfo, MachinePointerInfo DstPtrInfo,
MachinePointerInfo SrcPtrInfo); MachinePointerInfo SrcPtrInfo);
SDValue getMemset(SDValue Chain, SDLoc dl, SDValue Dst, SDValue Src, SDValue getMemset(SDValue Chain, SDLoc dl, SDValue Dst, SDValue Src,
SDValue Size, unsigned Align, bool isVol, SDValue Size, unsigned Align, bool isVol, bool isTailCall,
MachinePointerInfo DstPtrInfo); MachinePointerInfo DstPtrInfo);
/// Helper function to make it easier to build SetCC's if you just /// Helper function to make it easier to build SetCC's if you just

View File

@ -4294,7 +4294,7 @@ static SDValue getMemsetStores(SelectionDAG &DAG, SDLoc dl,
SDValue SelectionDAG::getMemcpy(SDValue Chain, SDLoc dl, SDValue Dst, SDValue SelectionDAG::getMemcpy(SDValue Chain, SDLoc dl, SDValue Dst,
SDValue Src, SDValue Size, SDValue Src, SDValue Size,
unsigned Align, bool isVol, bool AlwaysInline, unsigned Align, bool isVol, bool AlwaysInline,
MachinePointerInfo DstPtrInfo, bool isTailCall, MachinePointerInfo DstPtrInfo,
MachinePointerInfo SrcPtrInfo) { MachinePointerInfo SrcPtrInfo) {
assert(Align && "The SDAG layer expects explicit alignment and reserves 0"); assert(Align && "The SDAG layer expects explicit alignment and reserves 0");
@ -4352,15 +4352,16 @@ SDValue SelectionDAG::getMemcpy(SDValue Chain, SDLoc dl, SDValue Dst,
Type::getVoidTy(*getContext()), Type::getVoidTy(*getContext()),
getExternalSymbol(TLI->getLibcallName(RTLIB::MEMCPY), getExternalSymbol(TLI->getLibcallName(RTLIB::MEMCPY),
TLI->getPointerTy()), std::move(Args), 0) TLI->getPointerTy()), std::move(Args), 0)
.setDiscardResult(); .setDiscardResult()
std::pair<SDValue,SDValue> CallResult = TLI->LowerCallTo(CLI); .setTailCall(isTailCall);
std::pair<SDValue,SDValue> CallResult = TLI->LowerCallTo(CLI);
return CallResult.second; return CallResult.second;
} }
SDValue SelectionDAG::getMemmove(SDValue Chain, SDLoc dl, SDValue Dst, SDValue SelectionDAG::getMemmove(SDValue Chain, SDLoc dl, SDValue Dst,
SDValue Src, SDValue Size, SDValue Src, SDValue Size,
unsigned Align, bool isVol, unsigned Align, bool isVol, bool isTailCall,
MachinePointerInfo DstPtrInfo, MachinePointerInfo DstPtrInfo,
MachinePointerInfo SrcPtrInfo) { MachinePointerInfo SrcPtrInfo) {
assert(Align && "The SDAG layer expects explicit alignment and reserves 0"); assert(Align && "The SDAG layer expects explicit alignment and reserves 0");
@ -4407,15 +4408,16 @@ SDValue SelectionDAG::getMemmove(SDValue Chain, SDLoc dl, SDValue Dst,
Type::getVoidTy(*getContext()), Type::getVoidTy(*getContext()),
getExternalSymbol(TLI->getLibcallName(RTLIB::MEMMOVE), getExternalSymbol(TLI->getLibcallName(RTLIB::MEMMOVE),
TLI->getPointerTy()), std::move(Args), 0) TLI->getPointerTy()), std::move(Args), 0)
.setDiscardResult(); .setDiscardResult()
std::pair<SDValue,SDValue> CallResult = TLI->LowerCallTo(CLI); .setTailCall(isTailCall);
std::pair<SDValue,SDValue> CallResult = TLI->LowerCallTo(CLI);
return CallResult.second; return CallResult.second;
} }
SDValue SelectionDAG::getMemset(SDValue Chain, SDLoc dl, SDValue Dst, SDValue SelectionDAG::getMemset(SDValue Chain, SDLoc dl, SDValue Dst,
SDValue Src, SDValue Size, SDValue Src, SDValue Size,
unsigned Align, bool isVol, unsigned Align, bool isVol, bool isTailCall,
MachinePointerInfo DstPtrInfo) { MachinePointerInfo DstPtrInfo) {
assert(Align && "The SDAG layer expects explicit alignment and reserves 0"); assert(Align && "The SDAG layer expects explicit alignment and reserves 0");
@ -4464,7 +4466,8 @@ SDValue SelectionDAG::getMemset(SDValue Chain, SDLoc dl, SDValue Dst,
Type::getVoidTy(*getContext()), Type::getVoidTy(*getContext()),
getExternalSymbol(TLI->getLibcallName(RTLIB::MEMSET), getExternalSymbol(TLI->getLibcallName(RTLIB::MEMSET),
TLI->getPointerTy()), std::move(Args), 0) TLI->getPointerTy()), std::move(Args), 0)
.setDiscardResult(); .setDiscardResult()
.setTailCall(isTailCall);
std::pair<SDValue,SDValue> CallResult = TLI->LowerCallTo(CLI); std::pair<SDValue,SDValue> CallResult = TLI->LowerCallTo(CLI);
return CallResult.second; return CallResult.second;

View File

@ -4592,9 +4592,12 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
if (!Align) if (!Align)
Align = 1; // @llvm.memcpy defines 0 and 1 to both mean no alignment. Align = 1; // @llvm.memcpy defines 0 and 1 to both mean no alignment.
bool isVol = cast<ConstantInt>(I.getArgOperand(4))->getZExtValue(); bool isVol = cast<ConstantInt>(I.getArgOperand(4))->getZExtValue();
DAG.setRoot(DAG.getMemcpy(getRoot(), sdl, Op1, Op2, Op3, Align, isVol, false, bool isTC = I.isTailCall() && isInTailCallPosition(&I, DAG.getTarget());
MachinePointerInfo(I.getArgOperand(0)), SDValue MC = DAG.getMemcpy(getRoot(), sdl, Op1, Op2, Op3, Align, isVol,
MachinePointerInfo(I.getArgOperand(1)))); false, isTC,
MachinePointerInfo(I.getArgOperand(0)),
MachinePointerInfo(I.getArgOperand(1)));
updateDAGForMaybeTailCall(MC);
return nullptr; return nullptr;
} }
case Intrinsic::memset: { case Intrinsic::memset: {
@ -4611,8 +4614,10 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
if (!Align) if (!Align)
Align = 1; // @llvm.memset defines 0 and 1 to both mean no alignment. Align = 1; // @llvm.memset defines 0 and 1 to both mean no alignment.
bool isVol = cast<ConstantInt>(I.getArgOperand(4))->getZExtValue(); bool isVol = cast<ConstantInt>(I.getArgOperand(4))->getZExtValue();
DAG.setRoot(DAG.getMemset(getRoot(), sdl, Op1, Op2, Op3, Align, isVol, bool isTC = I.isTailCall() && isInTailCallPosition(&I, DAG.getTarget());
MachinePointerInfo(I.getArgOperand(0)))); SDValue MS = DAG.getMemset(getRoot(), sdl, Op1, Op2, Op3, Align, isVol,
isTC, MachinePointerInfo(I.getArgOperand(0)));
updateDAGForMaybeTailCall(MS);
return nullptr; return nullptr;
} }
case Intrinsic::memmove: { case Intrinsic::memmove: {
@ -4631,9 +4636,11 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
if (!Align) if (!Align)
Align = 1; // @llvm.memmove defines 0 and 1 to both mean no alignment. Align = 1; // @llvm.memmove defines 0 and 1 to both mean no alignment.
bool isVol = cast<ConstantInt>(I.getArgOperand(4))->getZExtValue(); bool isVol = cast<ConstantInt>(I.getArgOperand(4))->getZExtValue();
DAG.setRoot(DAG.getMemmove(getRoot(), sdl, Op1, Op2, Op3, Align, isVol, bool isTC = I.isTailCall() && isInTailCallPosition(&I, DAG.getTarget());
MachinePointerInfo(I.getArgOperand(0)), SDValue MM = DAG.getMemmove(getRoot(), sdl, Op1, Op2, Op3, Align, isVol,
MachinePointerInfo(I.getArgOperand(1)))); isTC, MachinePointerInfo(I.getArgOperand(0)),
MachinePointerInfo(I.getArgOperand(1)));
updateDAGForMaybeTailCall(MM);
return nullptr; return nullptr;
} }
case Intrinsic::dbg_declare: { case Intrinsic::dbg_declare: {
@ -7794,3 +7801,17 @@ MachineBasicBlock *SelectionDAGBuilder::NextBlock(MachineBasicBlock *MBB) {
return nullptr; return nullptr;
return I; return I;
} }
/// During lowering new call nodes can be created (such as memset, etc.).
/// Those will become new roots of the current DAG, but complications arise
/// when they are tail calls. In such cases, the call lowering will update
/// the root, but the builder still needs to know that a tail call has been
/// lowered in order to avoid generating an additional return.
void SelectionDAGBuilder::updateDAGForMaybeTailCall(SDValue MaybeTC) {
// If the node is null, we do have a tail call.
if (MaybeTC.getNode() != nullptr)
DAG.setRoot(MaybeTC);
else
HasTailCall = true;
}

View File

@ -829,6 +829,10 @@ private:
/// Return the next block after MBB, or nullptr if there is none. /// Return the next block after MBB, or nullptr if there is none.
MachineBasicBlock *NextBlock(MachineBasicBlock *MBB); MachineBasicBlock *NextBlock(MachineBasicBlock *MBB);
/// Update the DAG and DAG builder with the relevant information after
/// a new root node has been created which could be a tail call.
void updateDAGForMaybeTailCall(SDValue MaybeTC);
}; };
} // end namespace llvm } // end namespace llvm

View File

@ -2744,8 +2744,9 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo &CLI,
DAG.getConstant(Outs[i].Flags.getByValSize(), MVT::i64); DAG.getConstant(Outs[i].Flags.getByValSize(), MVT::i64);
SDValue Cpy = DAG.getMemcpy( SDValue Cpy = DAG.getMemcpy(
Chain, DL, DstAddr, Arg, SizeNode, Outs[i].Flags.getByValAlign(), Chain, DL, DstAddr, Arg, SizeNode, Outs[i].Flags.getByValAlign(),
/*isVol = */ false, /*isVol = */ false, /*AlwaysInline = */ false,
/*AlwaysInline = */ false, DstInfo, MachinePointerInfo()); /*isTailCall = */ false,
DstInfo, MachinePointerInfo());
MemOpChains.push_back(Cpy); MemOpChains.push_back(Cpy);
} else { } else {
@ -3976,7 +3977,7 @@ SDValue AArch64TargetLowering::LowerVACOPY(SDValue Op,
return DAG.getMemcpy(Op.getOperand(0), SDLoc(Op), Op.getOperand(1), return DAG.getMemcpy(Op.getOperand(0), SDLoc(Op), Op.getOperand(1),
Op.getOperand(2), DAG.getConstant(VaListSize, MVT::i32), Op.getOperand(2), DAG.getConstant(VaListSize, MVT::i32),
8, false, false, MachinePointerInfo(DestSV), 8, false, false, false, MachinePointerInfo(DestSV),
MachinePointerInfo(SrcSV)); MachinePointerInfo(SrcSV));
} }

View File

@ -316,6 +316,7 @@ CreateCopyOfByValArgument(SDValue Src, SDValue Dst, SDValue Chain,
SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), MVT::i32); SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), MVT::i32);
return DAG.getMemcpy(Chain, dl, Dst, Src, SizeNode, Flags.getByValAlign(), return DAG.getMemcpy(Chain, dl, Dst, Src, SizeNode, Flags.getByValAlign(),
/*isVolatile=*/false, /*AlwaysInline=*/false, /*isVolatile=*/false, /*AlwaysInline=*/false,
/*isTailCall=*/false,
MachinePointerInfo(), MachinePointerInfo()); MachinePointerInfo(), MachinePointerInfo());
} }

View File

@ -645,6 +645,7 @@ MSP430TargetLowering::LowerCCCCallTo(SDValue Chain, SDValue Callee,
Flags.getByValAlign(), Flags.getByValAlign(),
/*isVolatile*/false, /*isVolatile*/false,
/*AlwaysInline=*/true, /*AlwaysInline=*/true,
/*isTailCall=*/false,
MachinePointerInfo(), MachinePointerInfo(),
MachinePointerInfo()); MachinePointerInfo());
} else { } else {

View File

@ -3682,6 +3682,7 @@ void MipsTargetLowering::passByValArg(
DAG.getIntPtrConstant(VA.getLocMemOffset())); DAG.getIntPtrConstant(VA.getLocMemOffset()));
Chain = DAG.getMemcpy(Chain, DL, Dst, Src, DAG.getConstant(MemCpySize, PtrTy), Chain = DAG.getMemcpy(Chain, DL, Dst, Src, DAG.getConstant(MemCpySize, PtrTy),
Alignment, /*isVolatile=*/false, /*AlwaysInline=*/false, Alignment, /*isVolatile=*/false, /*AlwaysInline=*/false,
/*isTailCall=*/false,
MachinePointerInfo(), MachinePointerInfo()); MachinePointerInfo(), MachinePointerInfo());
MemOpChains.push_back(Chain); MemOpChains.push_back(Chain);
} }

View File

@ -2221,7 +2221,7 @@ SDValue PPCTargetLowering::LowerVACOPY(SDValue Op, SelectionDAG &DAG,
// 2*sizeof(char) + 2 Byte alignment + 2*sizeof(char*) = 12 Byte // 2*sizeof(char) + 2 Byte alignment + 2*sizeof(char*) = 12 Byte
return DAG.getMemcpy(Op.getOperand(0), Op, return DAG.getMemcpy(Op.getOperand(0), Op,
Op.getOperand(1), Op.getOperand(2), Op.getOperand(1), Op.getOperand(2),
DAG.getConstant(12, MVT::i32), 8, false, true, DAG.getConstant(12, MVT::i32), 8, false, true, false,
MachinePointerInfo(), MachinePointerInfo()); MachinePointerInfo(), MachinePointerInfo());
} }
@ -3808,7 +3808,7 @@ CreateCopyOfByValArgument(SDValue Src, SDValue Dst, SDValue Chain,
SDLoc dl) { SDLoc dl) {
SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), MVT::i32); SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), MVT::i32);
return DAG.getMemcpy(Chain, dl, Dst, Src, SizeNode, Flags.getByValAlign(), return DAG.getMemcpy(Chain, dl, Dst, Src, SizeNode, Flags.getByValAlign(),
false, false, MachinePointerInfo(), false, false, false, MachinePointerInfo(),
MachinePointerInfo()); MachinePointerInfo());
} }

View File

@ -727,7 +727,8 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
Chain = DAG.getMemcpy(Chain, dl, FIPtr, Arg, SizeNode, Align, Chain = DAG.getMemcpy(Chain, dl, FIPtr, Arg, SizeNode, Align,
false, // isVolatile, false, // isVolatile,
(Size <= 32), // AlwaysInline if size <= 32 (Size <= 32), // AlwaysInline if size <= 32,
false, // isTailCall
MachinePointerInfo(), MachinePointerInfo()); MachinePointerInfo(), MachinePointerInfo());
ByValArgs.push_back(FIPtr); ByValArgs.push_back(FIPtr);
} }

View File

@ -2222,6 +2222,7 @@ SDValue SystemZTargetLowering::lowerVACOPY(SDValue Op,
return DAG.getMemcpy(Chain, DL, DstPtr, SrcPtr, DAG.getIntPtrConstant(32), return DAG.getMemcpy(Chain, DL, DstPtr, SrcPtr, DAG.getIntPtrConstant(32),
/*Align*/8, /*isVolatile*/false, /*AlwaysInline*/false, /*Align*/8, /*isVolatile*/false, /*AlwaysInline*/false,
/*isTailCall*/false,
MachinePointerInfo(DstSV), MachinePointerInfo(SrcSV)); MachinePointerInfo(DstSV), MachinePointerInfo(SrcSV));
} }

View File

@ -2143,6 +2143,7 @@ CreateCopyOfByValArgument(SDValue Src, SDValue Dst, SDValue Chain,
return DAG.getMemcpy(Chain, dl, Dst, Src, SizeNode, Flags.getByValAlign(), return DAG.getMemcpy(Chain, dl, Dst, Src, SizeNode, Flags.getByValAlign(),
/*isVolatile*/false, /*AlwaysInline=*/true, /*isVolatile*/false, /*AlwaysInline=*/true,
/*isTailCall*/false,
MachinePointerInfo(), MachinePointerInfo()); MachinePointerInfo(), MachinePointerInfo());
} }
@ -14494,7 +14495,7 @@ static SDValue LowerVACOPY(SDValue Op, const X86Subtarget *Subtarget,
return DAG.getMemcpy(Chain, DL, DstPtr, SrcPtr, return DAG.getMemcpy(Chain, DL, DstPtr, SrcPtr,
DAG.getIntPtrConstant(24), 8, /*isVolatile*/false, DAG.getIntPtrConstant(24), 8, /*isVolatile*/false,
false, false, false,
MachinePointerInfo(DstSV), MachinePointerInfo(SrcSV)); MachinePointerInfo(DstSV), MachinePointerInfo(SrcSV));
} }

View File

@ -193,7 +193,8 @@ X86SelectionDAGInfo::EmitTargetCodeForMemset(SelectionDAG &DAG, SDLoc dl,
DAG.getConstant(Offset, AddrVT)), DAG.getConstant(Offset, AddrVT)),
Src, Src,
DAG.getConstant(BytesLeft, SizeVT), DAG.getConstant(BytesLeft, SizeVT),
Align, isVolatile, DstPtrInfo.getWithOffset(Offset)); Align, isVolatile, false,
DstPtrInfo.getWithOffset(Offset));
} }
// TODO: Use a Tokenfactor, as in memcpy, instead of a single chain. // TODO: Use a Tokenfactor, as in memcpy, instead of a single chain.
@ -282,7 +283,7 @@ SDValue X86SelectionDAGInfo::EmitTargetCodeForMemcpy(
DAG.getNode(ISD::ADD, dl, SrcVT, Src, DAG.getNode(ISD::ADD, dl, SrcVT, Src,
DAG.getConstant(Offset, SrcVT)), DAG.getConstant(Offset, SrcVT)),
DAG.getConstant(BytesLeft, SizeVT), DAG.getConstant(BytesLeft, SizeVT),
Align, isVolatile, AlwaysInline, Align, isVolatile, AlwaysInline, false,
DstPtrInfo.getWithOffset(Offset), DstPtrInfo.getWithOffset(Offset),
SrcPtrInfo.getWithOffset(Offset))); SrcPtrInfo.getWithOffset(Offset)));
} }

View File

@ -1423,7 +1423,7 @@ XCoreTargetLowering::LowerCCCArguments(SDValue Chain,
InVals.push_back(FIN); InVals.push_back(FIN);
MemOps.push_back(DAG.getMemcpy(Chain, dl, FIN, ArgDI->SDV, MemOps.push_back(DAG.getMemcpy(Chain, dl, FIN, ArgDI->SDV,
DAG.getConstant(Size, MVT::i32), DAG.getConstant(Size, MVT::i32),
Align, false, false, Align, false, false, false,
MachinePointerInfo(), MachinePointerInfo(),
MachinePointerInfo())); MachinePointerInfo()));
} else { } else {
@ -1834,10 +1834,11 @@ SDValue XCoreTargetLowering::PerformDAGCombine(SDNode *N,
LD->getAlignment() == Alignment && LD->getAlignment() == Alignment &&
!LD->isVolatile() && !LD->isIndexed() && !LD->isVolatile() && !LD->isIndexed() &&
Chain.reachesChainWithoutSideEffects(SDValue(LD, 1))) { Chain.reachesChainWithoutSideEffects(SDValue(LD, 1))) {
bool isTail = isInTailCallPosition(DAG, ST, Chain);
return DAG.getMemmove(Chain, dl, ST->getBasePtr(), return DAG.getMemmove(Chain, dl, ST->getBasePtr(),
LD->getBasePtr(), LD->getBasePtr(),
DAG.getConstant(StoreBits/8, MVT::i32), DAG.getConstant(StoreBits/8, MVT::i32),
Alignment, false, ST->getPointerInfo(), Alignment, false, isTail, ST->getPointerInfo(),
LD->getPointerInfo()); LD->getPointerInfo());
} }
} }

View File

@ -0,0 +1,31 @@
; RUN: llc -march=aarch64 < %s | FileCheck %s
; CHECK-LABEL: tail_memcpy:
; CHECK: b memcpy
define void @tail_memcpy(i8* nocapture %p, i8* nocapture readonly %q, i32 %n) #0 {
entry:
tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i32 1, i1 false)
ret void
}
; CHECK-LABEL: tail_memmove:
; CHECK: b memmove
define void @tail_memmove(i8* nocapture %p, i8* nocapture readonly %q, i32 %n) #0 {
entry:
tail call void @llvm.memmove.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i32 1, i1 false)
ret void
}
; CHECK-LABEL: tail_memset:
; CHECK: b memset
define void @tail_memset(i8* nocapture %p, i8 %c, i32 %n) #0 {
entry:
tail call void @llvm.memset.p0i8.i32(i8* %p, i8 %c, i32 %n, i32 1, i1 false)
ret void
}
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0
declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0
declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) #0
attributes #0 = { nounwind }

View File

@ -0,0 +1,31 @@
; RUN: llc -march=arm < %s | FileCheck %s
; CHECK-LABEL: tail_memcpy:
; CHECK: b memcpy
define void @tail_memcpy(i8* nocapture %p, i8* nocapture readonly %q, i32 %n) #0 {
entry:
tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i32 1, i1 false)
ret void
}
; CHECK-LABEL: tail_memmove:
; CHECK: b memmove
define void @tail_memmove(i8* nocapture %p, i8* nocapture readonly %q, i32 %n) #0 {
entry:
tail call void @llvm.memmove.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i32 1, i1 false)
ret void
}
; CHECK-LABEL: tail_memset:
; CHECK: b memset
define void @tail_memset(i8* nocapture %p, i8 %c, i32 %n) #0 {
entry:
tail call void @llvm.memset.p0i8.i32(i8* %p, i8 %c, i32 %n, i32 1, i1 false)
ret void
}
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0
declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0
declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) #0
attributes #0 = { nounwind }

View File

@ -0,0 +1,31 @@
; RUN: llc -march=hexagon < %s | FileCheck %s
; CHECK-LABEL: tail_memcpy:
; CHECK: jump memcpy
define void @tail_memcpy(i8* nocapture %p, i8* nocapture readonly %q, i32 %n) #0 {
entry:
tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i32 1, i1 false)
ret void
}
; CHECK-LABEL: tail_memmove:
; CHECK: jump memmove
define void @tail_memmove(i8* nocapture %p, i8* nocapture readonly %q, i32 %n) #0 {
entry:
tail call void @llvm.memmove.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i32 1, i1 false)
ret void
}
; CHECK-LABEL: tail_memset:
; CHECK: jump memset
define void @tail_memset(i8* nocapture %p, i8 %c, i32 %n) #0 {
entry:
tail call void @llvm.memset.p0i8.i32(i8* %p, i8 %c, i32 %n, i32 1, i1 false)
ret void
}
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0
declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0
declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) #0
attributes #0 = { nounwind }

View File

@ -0,0 +1,31 @@
; RUN: llc -march=systemz < %s | FileCheck %s
; CHECK-LABEL: tail_memcpy:
; CHECK: jg memcpy
define void @tail_memcpy(i8* nocapture %p, i8* nocapture readonly %q, i32 %n) #0 {
entry:
tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i32 1, i1 false)
ret void
}
; CHECK-LABEL: tail_memmove:
; CHECK: jg memmove
define void @tail_memmove(i8* nocapture %p, i8* nocapture readonly %q, i32 %n) #0 {
entry:
tail call void @llvm.memmove.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i32 1, i1 false)
ret void
}
; CHECK-LABEL: tail_memset:
; CHECK: jg memset
define void @tail_memset(i8* nocapture %p, i8 %c, i32 %n) #0 {
entry:
tail call void @llvm.memset.p0i8.i32(i8* %p, i8 %c, i32 %n, i32 1, i1 false)
ret void
}
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0
declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0
declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) #0
attributes #0 = { nounwind }

View File

@ -0,0 +1,31 @@
; RUN: llc -march=x86 < %s | FileCheck %s
; CHECK-LABEL: tail_memcpy
; CHECK: jmp memcpy
define void @tail_memcpy(i8* nocapture %p, i8* nocapture readonly %q, i32 %n) #0 {
entry:
tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i32 1, i1 false)
ret void
}
; CHECK-LABEL: tail_memset
; CHECK; jmp memmove
define void @tail_memmove(i8* nocapture %p, i8* nocapture readonly %q, i32 %n) #0 {
entry:
tail call void @llvm.memmove.p0i8.p0i8.i32(i8* %p, i8* %q, i32 %n, i32 1, i1 false)
ret void
}
; CHECK-LABEL: tail_memset
; CHECK: jmp memset
define void @tail_memset(i8* nocapture %p, i8 %c, i32 %n) #0 {
entry:
tail call void @llvm.memset.p0i8.i32(i8* %p, i8 %c, i32 %n, i32 1, i1 false)
ret void
}
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0
declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1) #0
declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) #0
attributes #0 = { nounwind }