[X86] Check that attribute parameters match for tail calls (PR26590)

In the code below on 32-bit targets, x would previously get forwarded to g()
without sign-extension to 32 bits as required by the parameter attribute.

  void g(signed short);
  void f(unsigned short x) {
    g(x);
  }

llvm-svn: 262352
This commit is contained in:
Hans Wennborg 2016-03-01 17:45:23 +00:00
parent 2ca144f14c
commit e64cf9dddb
3 changed files with 95 additions and 4 deletions

View File

@ -122,11 +122,17 @@ class MachineFrameInfo {
// arguments have ABI-prescribed offsets). // arguments have ABI-prescribed offsets).
bool isAliased; bool isAliased;
/// If true, the object has been zero-extended.
bool isZExt;
/// If true, the object has been zero-extended.
bool isSExt;
StackObject(uint64_t Sz, unsigned Al, int64_t SP, bool IM, StackObject(uint64_t Sz, unsigned Al, int64_t SP, bool IM,
bool isSS, const AllocaInst *Val, bool A) bool isSS, const AllocaInst *Val, bool A)
: SPOffset(SP), Size(Sz), Alignment(Al), isImmutable(IM), : SPOffset(SP), Size(Sz), Alignment(Al), isImmutable(IM),
isSpillSlot(isSS), isStatepointSpillSlot(false), Alloca(Val), isSpillSlot(isSS), isStatepointSpillSlot(false), Alloca(Val),
PreAllocated(false), isAliased(A) {} PreAllocated(false), isAliased(A), isZExt(false), isSExt(false) {}
}; };
/// The alignment of the stack. /// The alignment of the stack.
@ -450,6 +456,30 @@ public:
return Objects[ObjectIdx+NumFixedObjects].SPOffset; return Objects[ObjectIdx+NumFixedObjects].SPOffset;
} }
bool isObjectZExt(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isZExt;
}
void setObjectZExt(int ObjectIdx, bool IsZExt) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].isZExt = IsZExt;
}
bool isObjectSExt(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isSExt;
}
void setObjectSExt(int ObjectIdx, bool IsSExt) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].isSExt = IsSExt;
}
/// Set the stack frame offset of the specified object. The /// Set the stack frame offset of the specified object. The
/// offset is relative to the stack pointer on entry to the function. /// offset is relative to the stack pointer on entry to the function.
void setObjectOffset(int ObjectIdx, int64_t SPOffset) { void setObjectOffset(int ObjectIdx, int64_t SPOffset) {

View File

@ -2601,6 +2601,14 @@ X86TargetLowering::LowerMemArgument(SDValue Chain,
} else { } else {
int FI = MFI->CreateFixedObject(ValVT.getSizeInBits()/8, int FI = MFI->CreateFixedObject(ValVT.getSizeInBits()/8,
VA.getLocMemOffset(), isImmutable); VA.getLocMemOffset(), isImmutable);
// Set SExt or ZExt flag.
if (VA.getLocInfo() == CCValAssign::ZExt) {
MFI->setObjectZExt(FI, true);
} else if (VA.getLocInfo() == CCValAssign::SExt) {
MFI->setObjectSExt(FI, true);
}
// Adjust SP offset of interrupt parameter. // Adjust SP offset of interrupt parameter.
if (CallConv == CallingConv::X86_INTR) { if (CallConv == CallingConv::X86_INTR) {
MFI->setObjectOffset(FI, Offset); MFI->setObjectOffset(FI, Offset);
@ -3635,7 +3643,7 @@ X86TargetLowering::GetAlignedArgumentStackSize(unsigned StackSize,
static static
bool MatchingStackOffset(SDValue Arg, unsigned Offset, ISD::ArgFlagsTy Flags, bool MatchingStackOffset(SDValue Arg, unsigned Offset, ISD::ArgFlagsTy Flags,
MachineFrameInfo *MFI, const MachineRegisterInfo *MRI, MachineFrameInfo *MFI, const MachineRegisterInfo *MRI,
const X86InstrInfo *TII) { const X86InstrInfo *TII, const CCValAssign &VA) {
unsigned Bytes = Arg.getValueType().getSizeInBits() / 8; unsigned Bytes = Arg.getValueType().getSizeInBits() / 8;
int FI = INT_MAX; int FI = INT_MAX;
if (Arg.getOpcode() == ISD::CopyFromReg) { if (Arg.getOpcode() == ISD::CopyFromReg) {
@ -3681,7 +3689,20 @@ bool MatchingStackOffset(SDValue Arg, unsigned Offset, ISD::ArgFlagsTy Flags,
assert(FI != INT_MAX); assert(FI != INT_MAX);
if (!MFI->isFixedObjectIndex(FI)) if (!MFI->isFixedObjectIndex(FI))
return false; return false;
return Offset == MFI->getObjectOffset(FI) && Bytes == MFI->getObjectSize(FI);
if (Offset != MFI->getObjectOffset(FI))
return false;
if (VA.getLocVT().getSizeInBits() > Arg.getValueType().getSizeInBits()) {
// If the argument location is wider than the argument type, check that any
// extension flags match.
if (Flags.isZExt() != MFI->isObjectZExt(FI) ||
Flags.isSExt() != MFI->isObjectSExt(FI)) {
return false;
}
}
return Bytes == MFI->getObjectSize(FI);
} }
/// Check whether the call is eligible for tail call optimization. Targets /// Check whether the call is eligible for tail call optimization. Targets
@ -3838,7 +3859,7 @@ bool X86TargetLowering::IsEligibleForTailCallOptimization(
return false; return false;
if (!VA.isRegLoc()) { if (!VA.isRegLoc()) {
if (!MatchingStackOffset(Arg, VA.getLocMemOffset(), Flags, if (!MatchingStackOffset(Arg, VA.getLocMemOffset(), Flags,
MFI, MRI, TII)) MFI, MRI, TII, VA))
return false; return false;
} }
} }

View File

@ -0,0 +1,40 @@
; RUN: llc -mtriple=i686-unknown-linux-gnu -o - %s | FileCheck %s
declare void @f(i16 signext)
declare void @g(i32 signext)
define void @flags_match(i16 signext %x) {
entry:
tail call void @f(i16 signext %x)
ret void
; The parameter flags match; do the tail call.
; CHECK-LABEL: flags_match:
; CHECK: jmp f
}
define void @flags_mismatch(i16 zeroext %x) {
entry:
tail call void @f(i16 signext %x)
ret void
; The parameter flags mismatch. %x has not been sign-extended,
; so tail call is not possible.
; CHECK-LABEL: flags_mismatch:
; CHECK: movswl
; CHECK: calll f
}
define void @mismatch_doesnt_matter(i32 zeroext %x) {
entry:
tail call void @g(i32 signext %x)
ret void
; The parameter flags mismatch, but the type is wide enough that
; no extension takes place in practice, so do the tail call.
; CHECK-LABEL: mismatch_doesnt_matter:
; CHECK: jmp g
}