mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
Add fast-isel support for byval calls on x86.
llvm-svn: 131764
This commit is contained in:
parent
989cc73ef3
commit
dfd96ebe52
@ -133,6 +133,8 @@ private:
|
|||||||
|
|
||||||
bool isTypeLegal(const Type *Ty, MVT &VT, bool AllowI1 = false);
|
bool isTypeLegal(const Type *Ty, MVT &VT, bool AllowI1 = false);
|
||||||
|
|
||||||
|
bool IsMemcpySmall(uint64_t Len);
|
||||||
|
|
||||||
bool TryEmitSmallMemcpy(X86AddressMode DestAM,
|
bool TryEmitSmallMemcpy(X86AddressMode DestAM,
|
||||||
X86AddressMode SrcAM, uint64_t Len);
|
X86AddressMode SrcAM, uint64_t Len);
|
||||||
};
|
};
|
||||||
@ -1264,11 +1266,18 @@ bool X86FastISel::X86SelectTrunc(const Instruction *I) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool X86FastISel::IsMemcpySmall(uint64_t Len) {
|
||||||
|
return Len <= (Subtarget->is64Bit() ? 32 : 16);
|
||||||
|
}
|
||||||
|
|
||||||
bool X86FastISel::TryEmitSmallMemcpy(X86AddressMode DestAM,
|
bool X86FastISel::TryEmitSmallMemcpy(X86AddressMode DestAM,
|
||||||
X86AddressMode SrcAM, uint64_t Len) {
|
X86AddressMode SrcAM, uint64_t Len) {
|
||||||
|
|
||||||
// Make sure we don't bloat code by inlining very large memcpy's.
|
// Make sure we don't bloat code by inlining very large memcpy's.
|
||||||
bool i64Legal = TLI.isTypeLegal(MVT::i64);
|
if (!IsMemcpySmall(Len))
|
||||||
if (Len > (i64Legal ? 32 : 16)) return false;
|
return false;
|
||||||
|
|
||||||
|
bool i64Legal = Subtarget->is64Bit();
|
||||||
|
|
||||||
// We don't care about alignment here since we just emit integer accesses.
|
// We don't care about alignment here since we just emit integer accesses.
|
||||||
while (Len) {
|
while (Len) {
|
||||||
@ -1477,6 +1486,25 @@ bool X86FastISel::X86SelectCall(const Instruction *I) {
|
|||||||
if (CS.paramHasAttr(AttrInd, Attribute::ZExt))
|
if (CS.paramHasAttr(AttrInd, Attribute::ZExt))
|
||||||
Flags.setZExt();
|
Flags.setZExt();
|
||||||
|
|
||||||
|
if (CS.paramHasAttr(AttrInd, Attribute::ByVal)) {
|
||||||
|
const PointerType *Ty = cast<PointerType>(ArgVal->getType());
|
||||||
|
const Type *ElementTy = Ty->getElementType();
|
||||||
|
unsigned FrameSize = TD.getTypeAllocSize(ElementTy);
|
||||||
|
unsigned FrameAlign = CS.getParamAlignment(AttrInd);
|
||||||
|
if (!FrameAlign)
|
||||||
|
FrameAlign = TLI.getByValTypeAlignment(ElementTy);
|
||||||
|
Flags.setByVal();
|
||||||
|
Flags.setByValSize(FrameSize);
|
||||||
|
Flags.setByValAlign(FrameAlign);
|
||||||
|
if (!IsMemcpySmall(FrameSize))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CS.paramHasAttr(AttrInd, Attribute::InReg))
|
||||||
|
Flags.setInReg();
|
||||||
|
if (CS.paramHasAttr(AttrInd, Attribute::Nest))
|
||||||
|
Flags.setNest();
|
||||||
|
|
||||||
// If this is an i1/i8/i16 argument, promote to i32 to avoid an extra
|
// If this is an i1/i8/i16 argument, promote to i32 to avoid an extra
|
||||||
// instruction. This is safe because it is common to all fastisel supported
|
// instruction. This is safe because it is common to all fastisel supported
|
||||||
// calling conventions on x86.
|
// calling conventions on x86.
|
||||||
@ -1512,16 +1540,12 @@ bool X86FastISel::X86SelectCall(const Instruction *I) {
|
|||||||
|
|
||||||
if (ArgReg == 0) return false;
|
if (ArgReg == 0) return false;
|
||||||
|
|
||||||
// FIXME: Only handle *easy* calls for now.
|
|
||||||
if (CS.paramHasAttr(AttrInd, Attribute::InReg) ||
|
|
||||||
CS.paramHasAttr(AttrInd, Attribute::Nest) ||
|
|
||||||
CS.paramHasAttr(AttrInd, Attribute::ByVal))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const Type *ArgTy = ArgVal->getType();
|
const Type *ArgTy = ArgVal->getType();
|
||||||
MVT ArgVT;
|
MVT ArgVT;
|
||||||
if (!isTypeLegal(ArgTy, ArgVT))
|
if (!isTypeLegal(ArgTy, ArgVT))
|
||||||
return false;
|
return false;
|
||||||
|
if (ArgVT == MVT::x86mmx)
|
||||||
|
return false;
|
||||||
unsigned OriginalAlignment = TD.getABITypeAlignment(ArgTy);
|
unsigned OriginalAlignment = TD.getABITypeAlignment(ArgTy);
|
||||||
Flags.setOrigAlign(OriginalAlignment);
|
Flags.setOrigAlign(OriginalAlignment);
|
||||||
|
|
||||||
@ -1562,6 +1586,8 @@ bool X86FastISel::X86SelectCall(const Instruction *I) {
|
|||||||
default: llvm_unreachable("Unknown loc info!");
|
default: llvm_unreachable("Unknown loc info!");
|
||||||
case CCValAssign::Full: break;
|
case CCValAssign::Full: break;
|
||||||
case CCValAssign::SExt: {
|
case CCValAssign::SExt: {
|
||||||
|
assert(VA.getLocVT().isInteger() && !VA.getLocVT().isVector() &&
|
||||||
|
"Unexpected extend");
|
||||||
bool Emitted = X86FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(),
|
bool Emitted = X86FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(),
|
||||||
Arg, ArgVT, Arg);
|
Arg, ArgVT, Arg);
|
||||||
assert(Emitted && "Failed to emit a sext!"); (void)Emitted;
|
assert(Emitted && "Failed to emit a sext!"); (void)Emitted;
|
||||||
@ -1569,6 +1595,8 @@ bool X86FastISel::X86SelectCall(const Instruction *I) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CCValAssign::ZExt: {
|
case CCValAssign::ZExt: {
|
||||||
|
assert(VA.getLocVT().isInteger() && !VA.getLocVT().isVector() &&
|
||||||
|
"Unexpected extend");
|
||||||
bool Emitted = X86FastEmitExtend(ISD::ZERO_EXTEND, VA.getLocVT(),
|
bool Emitted = X86FastEmitExtend(ISD::ZERO_EXTEND, VA.getLocVT(),
|
||||||
Arg, ArgVT, Arg);
|
Arg, ArgVT, Arg);
|
||||||
assert(Emitted && "Failed to emit a zext!"); (void)Emitted;
|
assert(Emitted && "Failed to emit a zext!"); (void)Emitted;
|
||||||
@ -1576,9 +1604,8 @@ bool X86FastISel::X86SelectCall(const Instruction *I) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CCValAssign::AExt: {
|
case CCValAssign::AExt: {
|
||||||
// We don't handle MMX parameters yet.
|
assert(VA.getLocVT().isInteger() && !VA.getLocVT().isVector() &&
|
||||||
if (VA.getLocVT().isVector() && VA.getLocVT().getSizeInBits() == 128)
|
"Unexpected extend");
|
||||||
return false;
|
|
||||||
bool Emitted = X86FastEmitExtend(ISD::ANY_EXTEND, VA.getLocVT(),
|
bool Emitted = X86FastEmitExtend(ISD::ANY_EXTEND, VA.getLocVT(),
|
||||||
Arg, ArgVT, Arg);
|
Arg, ArgVT, Arg);
|
||||||
if (!Emitted)
|
if (!Emitted)
|
||||||
@ -1612,14 +1639,21 @@ bool X86FastISel::X86SelectCall(const Instruction *I) {
|
|||||||
AM.Base.Reg = StackPtr;
|
AM.Base.Reg = StackPtr;
|
||||||
AM.Disp = LocMemOffset;
|
AM.Disp = LocMemOffset;
|
||||||
const Value *ArgVal = ArgVals[VA.getValNo()];
|
const Value *ArgVal = ArgVals[VA.getValNo()];
|
||||||
|
ISD::ArgFlagsTy Flags = ArgFlags[VA.getValNo()];
|
||||||
|
|
||||||
// If this is a really simple value, emit this with the Value* version of
|
if (Flags.isByVal()) {
|
||||||
// X86FastEmitStore. If it isn't simple, we don't want to do this, as it
|
X86AddressMode SrcAM;
|
||||||
// can cause us to reevaluate the argument.
|
SrcAM.Base.Reg = Arg;
|
||||||
if (isa<ConstantInt>(ArgVal) || isa<ConstantPointerNull>(ArgVal))
|
bool Res = TryEmitSmallMemcpy(AM, SrcAM, Flags.getByValSize());
|
||||||
|
assert(Res && "memcpy length already checked!"); (void)Res;
|
||||||
|
} else if (isa<ConstantInt>(ArgVal) || isa<ConstantPointerNull>(ArgVal)) {
|
||||||
|
// If this is a really simple value, emit this with the Value* version
|
||||||
|
//of X86FastEmitStore. If it isn't simple, we don't want to do this,
|
||||||
|
// as it can cause us to reevaluate the argument.
|
||||||
X86FastEmitStore(ArgVT, ArgVal, AM);
|
X86FastEmitStore(ArgVT, ArgVal, AM);
|
||||||
else
|
} else {
|
||||||
X86FastEmitStore(ArgVT, Arg, AM);
|
X86FastEmitStore(ArgVT, Arg, AM);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
; RUN: llc < %s -fast-isel -march=x86 | FileCheck %s
|
; RUN: llc < %s -O0 -fast-isel-abort -march=x86 | FileCheck %s
|
||||||
|
|
||||||
define i32 @t() nounwind {
|
%struct.s = type {i32, i32, i32}
|
||||||
|
|
||||||
|
define i32 @test1() nounwind {
|
||||||
tak:
|
tak:
|
||||||
%tmp = call i1 @foo()
|
%tmp = call i1 @foo()
|
||||||
br i1 %tmp, label %BB1, label %BB2
|
br i1 %tmp, label %BB1, label %BB2
|
||||||
@ -8,8 +10,22 @@ BB1:
|
|||||||
ret i32 1
|
ret i32 1
|
||||||
BB2:
|
BB2:
|
||||||
ret i32 0
|
ret i32 0
|
||||||
|
; CHECK: test1:
|
||||||
; CHECK: calll
|
; CHECK: calll
|
||||||
; CHECK-NEXT: testb $1
|
; CHECK-NEXT: testb $1
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i1 @foo() zeroext nounwind
|
declare i1 @foo() zeroext nounwind
|
||||||
|
|
||||||
|
declare void @foo2(%struct.s* byval)
|
||||||
|
|
||||||
|
define void @test2(%struct.s* %d) nounwind {
|
||||||
|
call void @foo2(%struct.s* %d byval)
|
||||||
|
ret void
|
||||||
|
; CHECK: test2:
|
||||||
|
; CHECK: movl (%eax)
|
||||||
|
; CHECK: movl {{.*}}, (%esp)
|
||||||
|
; CHECK: movl 4(%eax)
|
||||||
|
; CHECK: movl {{.*}}, 4(%esp)
|
||||||
|
; CHECK: movl 8(%eax)
|
||||||
|
; CHECK: movl {{.*}}, 8(%esp)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user