From 94bb1a06fbb58f5eafce3785d229b0e61a25df54 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 8 Sep 2017 23:41:17 +0000 Subject: [PATCH] CodeGen: correct arguments for NSFastEnumeration When performing a NSFastEnumeration, the compiler synthesizes a call to `countByEnumeratingWithState:objects:count:` where the `count` parameter is of type `NSUInteger` and the return type is a `NSUInteger`. We would previously always use a `UnsignedLongTy` for the `NSUInteger` type. On 32-bit targets, `long` is 32-bits which is the same as `unsigned int`. Most 64-bit targets are LP64, where `long` is 64-bits. However, on LLP64 targets, such as Windows, `long` is 32-bits. Introduce new `getNSUIntegerType` and `getNSIntegerType` helpers to allow us to determine the correct type for the `NSUInteger` type. Wire those through into the generation of the message dispatch to the selector. llvm-svn: 312835 --- clang/include/clang/AST/ASTContext.h | 20 ++++++++++++++- clang/lib/CodeGen/CGObjC.cpp | 30 ++++++++++------------ clang/test/CodeGenObjC/NSFastEnumeration.m | 16 ++++++++++++ 3 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 clang/test/CodeGenObjC/NSFastEnumeration.m diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index acb0f657df01..371809806b89 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -39,6 +39,7 @@ #include "clang/Basic/SanitizerBlacklist.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Basic/XRayLists.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" @@ -89,7 +90,6 @@ class DiagnosticsEngine; class Expr; class MangleNumberingContext; class MaterializeTemporaryExpr; -class TargetInfo; // Decls class MangleContext; class ObjCIvarDecl; @@ -1582,6 +1582,24 @@ public: return NSCopyingName; } + CanQualType getNSUIntegerType() const { + assert(Target && "Expected target to be initialized"); + const llvm::Triple &T = Target->getTriple(); + // Windows is LLP64 rather than LP64 + if (T.isOSWindows() && T.isArch64Bit()) + return UnsignedLongLongTy; + return UnsignedLongTy; + } + + CanQualType getNSIntegerType() const { + assert(Target && "Expected target to be initialized"); + const llvm::Triple &T = Target->getTriple(); + // Windows is LLP64 rather than LP64 + if (T.isOSWindows() && T.isArch64Bit()) + return LongLongTy; + return LongTy; + } + /// Retrieve the identifier 'bool'. IdentifierInfo *getBoolName() const { if (!BoolName) diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 90fcad261415..42ed944e5e8b 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -1546,16 +1546,15 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ getContext().getPointerType(ItemsTy)); // The third argument is the capacity of that temporary array. - llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy); - llvm::Constant *Count = llvm::ConstantInt::get(UnsignedLongLTy, NumItems); - Args.add(RValue::get(Count), getContext().UnsignedLongTy); + llvm::Type *NSUIntegerTy = ConvertType(getContext().getNSUIntegerType()); + llvm::Constant *Count = llvm::ConstantInt::get(NSUIntegerTy, NumItems); + Args.add(RValue::get(Count), getContext().getNSUIntegerType()); // Start the enumeration. RValue CountRV = - CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), - getContext().UnsignedLongTy, - FastEnumSel, - Collection, Args); + CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), + getContext().getNSUIntegerType(), + FastEnumSel, Collection, Args); // The initial number of objects that were returned in the buffer. llvm::Value *initialBufferLimit = CountRV.getScalarVal(); @@ -1563,7 +1562,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ llvm::BasicBlock *EmptyBB = createBasicBlock("forcoll.empty"); llvm::BasicBlock *LoopInitBB = createBasicBlock("forcoll.loopinit"); - llvm::Value *zero = llvm::Constant::getNullValue(UnsignedLongLTy); + llvm::Value *zero = llvm::Constant::getNullValue(NSUIntegerTy); // If the limit pointer was zero to begin with, the collection is // empty; skip all this. Set the branch weight assuming this has the same @@ -1595,11 +1594,11 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ EmitBlock(LoopBodyBB); // The current index into the buffer. - llvm::PHINode *index = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.index"); + llvm::PHINode *index = Builder.CreatePHI(NSUIntegerTy, 3, "forcoll.index"); index->addIncoming(zero, LoopInitBB); // The current buffer size. - llvm::PHINode *count = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.count"); + llvm::PHINode *count = Builder.CreatePHI(NSUIntegerTy, 3, "forcoll.count"); count->addIncoming(initialBufferLimit, LoopInitBB); incrementProfileCounter(&S); @@ -1709,8 +1708,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ llvm::BasicBlock *FetchMoreBB = createBasicBlock("forcoll.refetch"); // First we check in the local buffer. - llvm::Value *indexPlusOne - = Builder.CreateAdd(index, llvm::ConstantInt::get(UnsignedLongLTy, 1)); + llvm::Value *indexPlusOne = + Builder.CreateAdd(index, llvm::ConstantInt::get(NSUIntegerTy, 1)); // If we haven't overrun the buffer yet, we can continue. // Set the branch weights based on the simplifying assumption that this is @@ -1727,10 +1726,9 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ EmitBlock(FetchMoreBB); CountRV = - CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), - getContext().UnsignedLongTy, - FastEnumSel, - Collection, Args); + CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), + getContext().getNSUIntegerType(), + FastEnumSel, Collection, Args); // If we got a zero count, we're done. llvm::Value *refetchCount = CountRV.getScalarVal(); diff --git a/clang/test/CodeGenObjC/NSFastEnumeration.m b/clang/test/CodeGenObjC/NSFastEnumeration.m new file mode 100644 index 000000000000..ba131fc4c7ca --- /dev/null +++ b/clang/test/CodeGenObjC/NSFastEnumeration.m @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple i686-apple-ios10.3 -fobjc-runtime=ios-6.0 -Os -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK32 +// RUN: %clang_cc1 -triple i686--windows-msvc -fobjc-runtime=ios-6.0 -Os -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK32 +// RUN: %clang_cc1 -triple x86_64-apple-ios10.3 -fobjc-runtime=ios-6.0 -Os -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK64 +// RUN: %clang_cc1 -triple x86_64--windows-msvc -fobjc-runtime=ios-6.0 -Os -emit-llvm -o - %s | FileCheck %s -check-prefix CHECK64 + +void f(id a) { + for (id i in a) + (void)i; +} + +// CHECK32: call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*, %struct.__objcFastEnumerationState*, [16 x i8*]*, i32)*) +// CHECK32: call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*, %struct.__objcFastEnumerationState*, [16 x i8*]*, i32)*) + +// CHECK64: call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*, %struct.__objcFastEnumerationState*, [16 x i8*]*, i64)*) +// CHECK64: call i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (i8*, i8*, %struct.__objcFastEnumerationState*, [16 x i8*]*, i64)*) +