From 8b9023ba35a86838789e2c9034a6128728c547aa Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Fri, 13 Jul 2007 03:05:23 +0000 Subject: [PATCH] Implement codegen for + and - with pointers. Patch contributed by Keith Bauer. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@39793 91177308-0d34-0410-b5e6-96231b3b80d8 --- AST/ASTContext.cpp | 8 ++++ AST/Type.cpp | 78 ++++++++++++++++++++----------- CodeGen/CGExpr.cpp | 85 ++++++++++++++++++++++++++++++---- CodeGen/CodeGenFunction.h | 4 ++ CodeGen/CodeGenTypes.cpp | 2 +- Sema/SemaDecl.cpp | 4 +- Sema/SemaExpr.cpp | 5 +- include/clang/AST/ASTContext.h | 4 ++ include/clang/AST/Type.h | 12 ++--- 9 files changed, 155 insertions(+), 47 deletions(-) diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp index b1c20c98e5..17b18d52f4 100644 --- a/AST/ASTContext.cpp +++ b/AST/ASTContext.cpp @@ -397,6 +397,14 @@ QualType ASTContext::getSizeType() const { return UnsignedLongTy; } +/// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?) +/// defined in . Pointer - pointer requires this (C99 6.5.6p9). +QualType ASTContext::getPointerDiffType() const { + // On Darwin, ptrdiff_t is defined as a "int". This seems like a bug... + // FIXME: should derive from "Target". + return IntTy; +} + /// getIntegerBitwidth - Return the bitwidth of the specified integer type /// according to the target. 'Loc' specifies the source location that /// requires evaluation of this property. diff --git a/AST/Type.cpp b/AST/Type.cpp index 1a20c1184d..07bdd3e124 100644 --- a/AST/Type.cpp +++ b/AST/Type.cpp @@ -22,6 +22,52 @@ using namespace clang; Type::~Type() {} +/// getSize - the number of bits to represent the type. +unsigned Type::getSize() const +{ + switch (CanonicalType->getTypeClass()) { + case Builtin: { + // FIXME: need to use TargetInfo to derive the target specific sizes. This + // implementation will suffice for play with vector support. + switch (cast(this)->getKind()) { + case BuiltinType::Void: return 0; + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: return sizeof(char) * 8; + case BuiltinType::SChar: return sizeof(signed char) * 8; + case BuiltinType::Short: return sizeof(short) * 8; + case BuiltinType::Int: return sizeof(int) * 8; + case BuiltinType::Long: return sizeof(long) * 8; + case BuiltinType::LongLong: return sizeof(long long) * 8; + case BuiltinType::UChar: return sizeof(unsigned char) * 8; + case BuiltinType::UShort: return sizeof(unsigned short) * 8; + case BuiltinType::UInt: return sizeof(unsigned int) * 8; + case BuiltinType::ULong: return sizeof(unsigned long) * 8; + case BuiltinType::ULongLong: return sizeof(unsigned long long) * 8; + case BuiltinType::Float: return sizeof(float) * 8; + case BuiltinType::Double: return sizeof(double) * 8; + case BuiltinType::LongDouble: return sizeof(long double) * 8; + } + assert(0 && "Can't get here"); + } + case Pointer: + // FIXME: need to use TargetInfo again + return sizeof(void *) * 8; + case Reference: + // seems that sizeof(T&) == sizeof(T) -- spec reference? + return (cast(this)->getReferenceeType()->getSize()); + case Complex: + case Array: + case Vector: + case FunctionNoProto: + case FunctionProto: + case TypeName: + case Tagged: + assert(0 && "Type sizes are not yet known, in general"); + } + assert(0 && "Can't get here"); +} + /// isVoidType - Helper method to determine if this is the 'void' type. bool Type::isVoidType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) @@ -330,8 +376,9 @@ bool Type::isAggregateType() const { // the structure is still constant size (C99 6.7.2.1p16). bool Type::isConstantSizeType(SourceLocation *loc) const { if (const ArrayType *Ary = dyn_cast(CanonicalType)) { - assert(Ary->getSize() && "Incomplete types don't have a size at all!"); - return Ary->getSize()->isIntegerConstantExpr(loc); // Variable Length Array? + assert(Ary->getSizeExpr() && "Incomplete types don't have a size at all!"); + // Variable Length Array? + return Ary->getSizeExpr()->isIntegerConstantExpr(loc); } return true; } @@ -352,7 +399,7 @@ bool Type::isIncompleteType() const { return !cast(CanonicalType)->getDecl()->isDefinition(); case Array: // An array of unknown size is an incomplete type (C99 6.2.5p22). - return cast(CanonicalType)->getSize() == 0; + return cast(CanonicalType)->getSizeExpr() == 0; } } @@ -396,31 +443,6 @@ const char *BuiltinType::getName() const { } } -// FIXME: need to use TargetInfo to derive the target specific sizes. This -// implementation will suffice for play with vector support. -unsigned BuiltinType::getSize() const { - switch (getKind()) { - default: assert(0 && "Unknown builtin type!"); - case Void: return 0; - case Bool: - case Char_S: - case Char_U: return sizeof(char) * 8; - case SChar: return sizeof(signed char) * 8; - case Short: return sizeof(short) * 8; - case Int: return sizeof(int) * 8; - case Long: return sizeof(long) * 8; - case LongLong: return sizeof(long long) * 8; - case UChar: return sizeof(unsigned char) * 8; - case UShort: return sizeof(unsigned short) * 8; - case UInt: return sizeof(unsigned int) * 8; - case ULong: return sizeof(unsigned long) * 8; - case ULongLong: return sizeof(unsigned long long) * 8; - case Float: return sizeof(float) * 8; - case Double: return sizeof(double) * 8; - case LongDouble: return sizeof(long double) * 8; - } -} - void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID, QualType Result, QualType* ArgTys, unsigned NumArgs, bool isVariadic) { diff --git a/CodeGen/CGExpr.cpp b/CodeGen/CGExpr.cpp index 0250ab42db..51ad770dca 100644 --- a/CodeGen/CGExpr.cpp +++ b/CodeGen/CGExpr.cpp @@ -906,14 +906,36 @@ RValue CodeGenFunction::EmitBinaryOperator(const BinaryOperator *E) { case BinaryOperator::Rem: EmitUsualArithmeticConversions(E, LHS, RHS); return EmitRem(LHS, RHS, E->getType()); - case BinaryOperator::Add: - // FIXME: This doesn't handle ptr+int etc yet. - EmitUsualArithmeticConversions(E, LHS, RHS); - return EmitAdd(LHS, RHS, E->getType()); - case BinaryOperator::Sub: - // FIXME: This doesn't handle ptr-int etc yet. - EmitUsualArithmeticConversions(E, LHS, RHS); - return EmitSub(LHS, RHS, E->getType()); + case BinaryOperator::Add: { + QualType ExprTy = E->getType(); + if (ExprTy->isPointerType()) { + Expr *LHSExpr = E->getLHS(); + QualType LHSTy; + LHS = EmitExprWithUsualUnaryConversions(LHSExpr, LHSTy); + Expr *RHSExpr = E->getRHS(); + QualType RHSTy; + RHS = EmitExprWithUsualUnaryConversions(RHSExpr, RHSTy); + return EmitPointerAdd(LHS, LHSTy, RHS, RHSTy, ExprTy); + } else { + EmitUsualArithmeticConversions(E, LHS, RHS); + return EmitAdd(LHS, RHS, ExprTy); + } + } + case BinaryOperator::Sub: { + QualType ExprTy = E->getType(); + Expr *LHSExpr = E->getLHS(); + if (LHSExpr->getType()->isPointerType()) { + QualType LHSTy; + LHS = EmitExprWithUsualUnaryConversions(LHSExpr, LHSTy); + Expr *RHSExpr = E->getRHS(); + QualType RHSTy; + RHS = EmitExprWithUsualUnaryConversions(RHSExpr, RHSTy); + return EmitPointerSub(LHS, LHSTy, RHS, RHSTy, ExprTy); + } else { + EmitUsualArithmeticConversions(E, LHS, RHS); + return EmitSub(LHS, RHS, ExprTy); + } + } case BinaryOperator::Shl: EmitShiftOperands(E, LHS, RHS); return EmitShl(LHS, RHS, E->getType()); @@ -1085,6 +1107,20 @@ RValue CodeGenFunction::EmitAdd(RValue LHS, RValue RHS, QualType ResTy) { return RValue::getAggregate(Res); } +RValue CodeGenFunction::EmitPointerAdd(RValue LHS, QualType LHSTy, + RValue RHS, QualType RHSTy, + QualType ResTy) { + llvm::Value *LHSValue = LHS.getVal(); + llvm::Value *RHSValue = RHS.getVal(); + if (LHSTy->isPointerType()) { + // pointer + int + return RValue::get(Builder.CreateGEP(LHSValue, RHSValue, "add.ptr")); + } else { + // int + pointer + return RValue::get(Builder.CreateGEP(RHSValue, LHSValue, "add.ptr")); + } +} + RValue CodeGenFunction::EmitSub(RValue LHS, RValue RHS, QualType ResTy) { if (LHS.isScalar()) return RValue::get(Builder.CreateSub(LHS.getVal(), RHS.getVal(), "sub")); @@ -1092,6 +1128,39 @@ RValue CodeGenFunction::EmitSub(RValue LHS, RValue RHS, QualType ResTy) { assert(0 && "FIXME: This doesn't handle complex operands yet"); } +RValue CodeGenFunction::EmitPointerSub(RValue LHS, QualType LHSTy, + RValue RHS, QualType RHSTy, + QualType ResTy) { + llvm::Value *LHSValue = LHS.getVal(); + llvm::Value *RHSValue = RHS.getVal(); + if (const PointerType *RHSPtrType = + dyn_cast(RHSTy.getTypePtr())) { + // pointer - pointer + const PointerType *LHSPtrType = cast(LHSTy.getTypePtr()); + QualType LHSElementType = LHSPtrType->getPointeeType(); + assert(LHSElementType == RHSPtrType->getPointeeType() && + "can't subtract pointers with differing element types"); + unsigned ElementSize = LHSElementType->getSize() / 8; + const llvm::Type *ResultType = ConvertType(ResTy); + llvm::Value *CastLHS = Builder.CreatePtrToInt(LHSValue, ResultType, + "sub.ptr.lhs.cast"); + llvm::Value *CastRHS = Builder.CreatePtrToInt(RHSValue, ResultType, + "sub.ptr.rhs.cast"); + llvm::Value *BytesBetween = Builder.CreateSub(CastLHS, CastRHS, + "sub.ptr.sub"); + llvm::Value *BytesPerElement = llvm::ConstantInt::get(ResultType, + ElementSize); + llvm::Value *ElementsBetween = Builder.CreateSDiv(BytesBetween, + BytesPerElement, + "sub.ptr.div"); + return RValue::get(ElementsBetween); + } else { + // pointer - int + llvm::Value *NegatedRHS = Builder.CreateNeg(RHSValue, "sub.ptr.neg"); + return RValue::get(Builder.CreateGEP(LHSValue, NegatedRHS, "sub.ptr")); + } +} + void CodeGenFunction::EmitShiftOperands(const BinaryOperator *E, RValue &LHS, RValue &RHS) { // For shifts, integer promotions are performed, but the usual arithmetic diff --git a/CodeGen/CodeGenFunction.h b/CodeGen/CodeGenFunction.h index fe570feb93..268a70276a 100644 --- a/CodeGen/CodeGenFunction.h +++ b/CodeGen/CodeGenFunction.h @@ -334,7 +334,11 @@ public: RValue EmitDiv(RValue LHS, RValue RHS, QualType EltTy); RValue EmitRem(RValue LHS, RValue RHS, QualType EltTy); RValue EmitAdd(RValue LHS, RValue RHS, QualType EltTy); + RValue EmitPointerAdd(RValue LHS, QualType LHSTy, + RValue RHS, QualType RHSTy, QualType EltTy); RValue EmitSub(RValue LHS, RValue RHS, QualType EltTy); + RValue EmitPointerSub(RValue LHS, QualType LHSTy, + RValue RHS, QualType RHSTy, QualType EltTy); RValue EmitShl(RValue LHS, RValue RHS, QualType ResTy); RValue EmitShr(RValue LHS, RValue RHS, QualType ResTy); RValue EmitBinaryCompare(const BinaryOperator *E, unsigned UICmpOpc, diff --git a/CodeGen/CodeGenTypes.cpp b/CodeGen/CodeGenTypes.cpp index f0b77908be..a75ac4ce75 100644 --- a/CodeGen/CodeGenTypes.cpp +++ b/CodeGen/CodeGenTypes.cpp @@ -88,7 +88,7 @@ const llvm::Type *CodeGenTypes::ConvertType(QualType T) { "FIXME: We only handle trivial array types so far!"); llvm::APSInt Size(32); - if (A.getSize() && A.getSize()->isIntegerConstantExpr(Size)) { + if (A.getSizeExpr() && A.getSizeExpr()->isIntegerConstantExpr(Size)) { const llvm::Type *EltTy = ConvertType(A.getElementType()); return llvm::ArrayType::get(EltTy, Size.getZExtValue()); } else { diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 34bee52f6d..5913c6bed7 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -29,7 +29,7 @@ using namespace clang; // a constant expression of type int with a value greater than zero. bool Sema::VerifyConstantArrayType(const ArrayType *Array, SourceLocation DeclLoc) { - const Expr *Size = Array->getSize(); + const Expr *Size = Array->getSizeExpr(); if (Size == 0) return false; // incomplete type. if (!Size->getType()->isIntegerType()) { @@ -450,7 +450,7 @@ Sema::ParseParamDeclarator(DeclaratorChunk &FTI, unsigned ArgNo, // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. // Can this happen for params? We already checked that they don't conflict // among each other. Here they can only shadow globals, which is ok. - if (Decl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary, + if (/*Decl *PrevDecl = */LookupScopedDecl(II, Decl::IDNS_Ordinary, PI.IdentLoc, FnScope)) { } diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 72e2c44a81..c598e7cdb6 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -816,9 +816,10 @@ inline QualType Sema::CheckSubtractionOperands( // C99 6.5.6 // handle the common case first (both operands are arithmetic). if (resType->isArithmeticType()) return resType; - if ((lhsType->isPointerType() && rhsType->isIntegerType()) || - (lhsType->isPointerType() && rhsType->isPointerType())) + if (lhsType->isPointerType() && rhsType->isIntegerType()) return resType; + if (lhsType->isPointerType() && rhsType->isPointerType()) + return Context.getPointerDiffType(); InvalidOperands(loc, lex, rex); return QualType(); } diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 759940dfdd..984b6f99be 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -98,6 +98,10 @@ public: /// in . The sizeof operator requires this (C99 6.5.3.4p4). QualType getSizeType() const; + /// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?) + /// defined in . Pointer - pointer requires this (C99 6.5.6p9). + QualType getPointerDiffType() const; + /// getIntegerBitwidth - Return the bitwidth of the specified integer type /// according to the target. 'Loc' specifies the source location that /// requires evaluation of this property. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 93969b2684..e23a7bd7b7 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -195,7 +195,10 @@ protected: : CanonicalType(Canonical.isNull() ? QualType(this,0) : Canonical), TC(tc){} virtual ~Type(); friend class ASTContext; -public: +public: + /// getSize - the number of bits to represent the type. + unsigned getSize() const; + TypeClass getTypeClass() const { return TC; } bool isCanonical() const { return CanonicalType.getTypePtr() == this; } @@ -307,9 +310,6 @@ public: Kind getKind() const { return TypeKind; } const char *getName() const; - // the number of bits to represent the builtin type. - unsigned getSize() const; - virtual void getAsStringInternal(std::string &InnerString) const; static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } @@ -428,13 +428,13 @@ public: QualType getElementType() const { return ElementType; } ArraySizeModifier getSizeModifier() const { return SizeModifier; } unsigned getIndexTypeQualifier() const { return IndexTypeQuals; } - Expr *getSize() const { return SizeExpr; } + Expr *getSizeExpr() const { return SizeExpr; } virtual void getAsStringInternal(std::string &InnerString) const; void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getSizeModifier(), getIndexTypeQualifier(), getElementType(), - getSize()); + getSizeExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, ArraySizeModifier SizeModifier, -- 2.40.0