From e2962be11e8894329d37985eccaa4f4a12dea402 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Thu, 29 Jul 2010 07:30:00 +0000 Subject: [PATCH] implement a todo: pass a eight-byte that consists of a small integer + padding as that small integer. On code like: struct c { double x; int y; }; void bar(struct c C) { } This means that we compile to: define void @bar(double %C.coerce0, i32 %C.coerce1) nounwind { entry: %C = alloca %struct.c, align 8 ; <%struct.c*> [#uses=2] %0 = getelementptr %struct.c* %C, i32 0, i32 0 ; [#uses=1] store double %C.coerce0, double* %0 %1 = getelementptr %struct.c* %C, i32 0, i32 1 ; [#uses=1] store i32 %C.coerce1, i32* %1 instead of: define void @bar(double %C.coerce0, i64 %C.coerce1) nounwind { entry: %C = alloca %struct.c, align 8 ; <%struct.c*> [#uses=3] %0 = bitcast %struct.c* %C to %0* ; <%0*> [#uses=2] %1 = getelementptr %0* %0, i32 0, i32 0 ; [#uses=1] store double %C.coerce0, double* %1 %2 = getelementptr %0* %0, i32 0, i32 1 ; [#uses=1] store i64 %C.coerce1, i64* %2 which gives SRoA heartburn. This implements rdar://5711709, a nice low number :) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109737 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/TargetInfo.cpp | 98 +++++++++++++++++++++++++++++++-- test/CodeGen/x86_64-arguments.c | 16 +++++- 2 files changed, 105 insertions(+), 9 deletions(-) diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 0f0dc0f888..6b262ebeda 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -1210,6 +1210,76 @@ const llvm::Type *X86_64ABIInfo::Get16ByteVectorType(QualType Ty) const { } +/// BitsContainNoUserData - Return true if the specified [start,end) bit range +/// is known to either be off the end of the specified type or being in +/// alignment padding. The user type specified is known to be at most 128 bits +/// in size, and have passed through X86_64ABIInfo::classify with a successful +/// classification that put one of the two halves in the INTEGER class. +/// +/// It is conservatively correct to return false. +static bool BitsContainNoUserData(QualType Ty, unsigned StartBit, + unsigned EndBit, ASTContext &Context) { + // If the bytes being queried are off the end of the type, there is no user + // data hiding here. This handles analysis of builtins, vectors and other + // types that don't contain interesting padding. + unsigned TySize = (unsigned)Context.getTypeSize(Ty); + if (TySize <= StartBit) + return true; + + //if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { + // TODO. + //} + + if (const RecordType *RT = Ty->getAs()) { + const RecordDecl *RD = RT->getDecl(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // If this is a C++ record, check the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { + for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(), + e = CXXRD->bases_end(); i != e; ++i) { + assert(!i->isVirtual() && !i->getType()->isDependentType() && + "Unexpected base class!"); + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + + // If the base is after the span we care about, ignore it. + unsigned BaseOffset = (unsigned)Layout.getBaseClassOffset(Base); + if (BaseOffset >= EndBit) continue; + + unsigned BaseStart = BaseOffset < StartBit ? StartBit-BaseOffset :0; + if (!BitsContainNoUserData(i->getType(), BaseStart, + EndBit-BaseOffset, Context)) + return false; + } + } + + // Verify that no field has data that overlaps the region of interest. Yes + // this could be sped up a lot by being smarter about queried fields, + // however we're only looking at structs up to 16 bytes, so we don't care + // much. + unsigned idx = 0; + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i, ++idx) { + unsigned FieldOffset = (unsigned)Layout.getFieldOffset(idx); + + // If we found a field after the region we care about, then we're done. + if (FieldOffset >= EndBit) break; + + unsigned FieldStart = FieldOffset < StartBit ? StartBit-FieldOffset :0; + if (!BitsContainNoUserData(i->getType(), FieldStart, EndBit-FieldOffset, + Context)) + return false; + } + + // If nothing in this record overlapped the area of interest, then we're + // clean. + return true; + } + + return false; +} + /// Get8ByteTypeAtOffset - The ABI specifies that a value should be passed in an /// 8-byte GPR. This means that we either have a scalar or we are talking about /// the high or low part of an up-to-16-byte struct. This routine picks the @@ -1227,12 +1297,28 @@ const llvm::Type *X86_64ABIInfo::Get16ByteVectorType(QualType Ty) const { const llvm::Type *X86_64ABIInfo:: Get8ByteTypeAtOffset(const llvm::Type *IRType, unsigned IROffset, QualType SourceTy, unsigned SourceOffset) const { - // Pointers are always 8-bytes at offset 0. - if (IROffset == 0 && isa(IRType)) - return IRType; - - // TODO: 1/2/4/8 byte integers are also interesting, but we have to know that - // the "hole" is not used in the containing struct (just undef padding). + // If we're dealing with an un-offset LLVM IR type, then it means that we're + // returning an 8-byte unit starting with it. See if we can safely use it. + if (IROffset == 0) { + // Pointers and int64's always fill the 8-byte unit. + if (isa(IRType) || IRType->isIntegerTy(64)) + return IRType; + + // If we have a 1/2/4-byte integer, we can use it only if the rest of the + // goodness in the source type is just tail padding. This is allowed to + // kick in for struct {double,int} on the int, but not on + // struct{double,int,int} because we wouldn't return the second int. We + // have to do this analysis on the source type because we can't depend on + // unions being lowered a specific way etc. + if (IRType->isIntegerTy(8) || IRType->isIntegerTy(16) || + IRType->isIntegerTy(32)) { + unsigned BitWidth = cast(IRType)->getBitWidth(); + + if (BitsContainNoUserData(SourceTy, SourceOffset*8+BitWidth, + SourceOffset*8+64, getContext())) + return IRType; + } + } if (const llvm::StructType *STy = dyn_cast(IRType)) { // If this is a struct, recurse into the field at the specified offset. diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c index 3bda8875c8..1a5db3a955 100644 --- a/test/CodeGen/x86_64-arguments.c +++ b/test/CodeGen/x86_64-arguments.c @@ -63,8 +63,8 @@ void f10(struct s10 a0) {} // CHECK: define void @f11(%struct.s19* sret %agg.result) union { long double a; float b; } f11() { while (1) {} } -// CHECK: define i64 @f12_0() -// CHECK: define void @f12_1(i64 %a0.coerce) +// CHECK: define i32 @f12_0() +// CHECK: define void @f12_1(i32 %a0.coerce) struct s12 { int a __attribute__((aligned(16))); }; struct s12 f12_0(void) { while (1) {} } void f12_1(struct s12 a0) {} @@ -183,4 +183,14 @@ struct v4f32wrapper { struct v4f32wrapper f27(struct v4f32wrapper X) { // CHECK: define <4 x float> @f27(<4 x float> %X.coerce) return X; -} \ No newline at end of file +} + +// rdar://5711709 +struct f28c { + double x; + int y; +}; +void f28(struct f28c C) { + // CHECK: define void @f28(double %C.coerce0, i32 %C.coerce1) +} + -- 2.40.0