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
This commit is contained in:
Saleem Abdulrasool 2017-09-08 23:41:17 +00:00
parent cde9acbb5d
commit 94bb1a06fb
3 changed files with 49 additions and 17 deletions

View File

@ -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)

View File

@ -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();

View File

@ -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)*)