From 2bb1e45ea3cd218cd0fdc73e0a057a8e5b4d9da9 Mon Sep 17 00:00:00 2001 From: Cameron Zwarich Date: Wed, 16 Mar 2011 22:20:18 +0000 Subject: [PATCH] The x86-64 ABI says that a bool is only guaranteed to be sign-extended to a byte rather than an int. Thankfully, this only causes LLVM to miss optimizations, not generate incorrect code. This just fixes the zext at the return. We still insert an i32 ZextAssert when reading a function's arguments, but it is followed by a truncate and another i8 ZextAssert so it is not optimized. llvm-svn: 127766 --- docs/LangRef.html | 5 +++-- include/llvm/Target/TargetLowering.h | 11 +++++++++++ .../SelectionDAG/SelectionDAGBuilder.cpp | 7 ++----- lib/Target/X86/X86ISelLowering.cpp | 9 +++++++++ lib/Target/X86/X86ISelLowering.h | 3 +++ test/CodeGen/X86/bool-zext.ll | 18 +++++++++++++++--- 6 files changed, 43 insertions(+), 10 deletions(-) diff --git a/docs/LangRef.html b/docs/LangRef.html index 893876620a4..ab9f1caae69 100644 --- a/docs/LangRef.html +++ b/docs/LangRef.html @@ -1017,8 +1017,9 @@ declare signext i8 @returns_signed_char()
zeroext
This indicates to the code generator that the parameter or return value - should be zero-extended to a 32-bit value by the caller (for a parameter) - or the callee (for a return value).
+ should be zero-extended to the extent required by the target's ABI (which + is usually 32-bits, but is 8-bits for a i1 on x86-64) by the caller (for a + parameter) or the callee (for a return value).
signext
This indicates to the code generator that the parameter or return value diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 618ed548947..f257b035b8f 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -1287,6 +1287,17 @@ public: return false; } + /// getTypeForExtendedInteger - Return the type that should be used to zero or + /// sign extend a zeroext/signext integer argument or return value. + /// FIXME: Most C calling convention requires the return type to be promoted, + /// but this is not true all the time, e.g. i1 on x86-64. It is also not + /// necessary for non-C calling conventions. The frontend should handle this + /// and include all of the necessary information. + virtual MVT + getTypeForExtendedInteger(EVT VT, ISD::NodeType ExtendKind) const { + return MVT::i32; + } + /// LowerOperationWrapper - This callback is invoked by the type legalizer /// to legalize nodes with an illegal operand type but legal result types. /// It replaces the LowerOperation callback in the type Legalizer. diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index aa7009ac395..55483188355 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1128,12 +1128,9 @@ void SelectionDAGBuilder::visitRet(const ReturnInst &I) { else if (F->paramHasAttr(0, Attribute::ZExt)) ExtendKind = ISD::ZERO_EXTEND; - // FIXME: C calling convention requires the return type to be promoted - // to at least 32-bit. But this is not necessary for non-C calling - // conventions. The frontend should mark functions whose return values - // require promoting with signext or zeroext attributes. if (ExtendKind != ISD::ANY_EXTEND && VT.isInteger()) { - EVT MinVT = TLI.getRegisterType(*DAG.getContext(), MVT::i32); + MVT ReturnMVT = TLI.getTypeForExtendedInteger(VT, ExtendKind); + EVT MinVT = TLI.getRegisterType(*DAG.getContext(), ReturnMVT); if (VT.bitsLT(MinVT)) VT = MinVT; } diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 910ed2abd1f..c1aa7200bef 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -1448,6 +1448,15 @@ bool X86TargetLowering::isUsedByReturnOnly(SDNode *N) const { return HasRet; } +MVT +X86TargetLowering::getTypeForExtendedInteger(EVT VT, + ISD::NodeType ExtendKind) const { + // TODO: Is this also valid on 32-bit? + if (Subtarget->is64Bit() && VT == MVT::i1 && ExtendKind == ISD::ZERO_EXTEND) + return MVT::i8; + return MVT::i32; +} + /// LowerCallResult - Lower the result values of a call into the /// appropriate copies out of appropriate physical registers. /// diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 551884b18e4..0857c594b4f 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -843,6 +843,9 @@ namespace llvm { virtual bool isUsedByReturnOnly(SDNode *N) const; + virtual MVT + getTypeForExtendedInteger(EVT VT, ISD::NodeType ExtendKind) const; + virtual bool CanLowerReturn(CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl &Outs, diff --git a/test/CodeGen/X86/bool-zext.ll b/test/CodeGen/X86/bool-zext.ll index 67168d4bf04..d2c30c64f23 100644 --- a/test/CodeGen/X86/bool-zext.ll +++ b/test/CodeGen/X86/bool-zext.ll @@ -6,7 +6,7 @@ define void @bar1(i1 zeroext %v1) nounwind ssp { entry: %conv = zext i1 %v1 to i32 - %call = tail call i32 (...)* @foo(i32 %conv) nounwind + %call = tail call i32 (...)* @foo1(i32 %conv) nounwind ret void } @@ -16,8 +16,20 @@ entry: define void @bar2(i8 zeroext %v1) nounwind ssp { entry: %conv = zext i8 %v1 to i32 - %call = tail call i32 (...)* @foo(i32 %conv) nounwind + %call = tail call i32 (...)* @foo1(i32 %conv) nounwind ret void } -declare i32 @foo(...) +; CHECK: @bar3 +; CHECK: callq +; CHECK-NOT: movzbl +; CHECK-NOT: and +; CHECK: ret +define zeroext i1 @bar3() nounwind ssp { +entry: + %call = call i1 @foo2() nounwind + ret i1 %call +} + +declare i32 @foo1(...) +declare zeroext i1 @foo2()