From 025b5fb88303dec0883d3399fa208510efa192b1 Mon Sep 17 00:00:00 2001 From: Christopher Lamb Date: Mon, 4 Feb 2008 02:31:56 +0000 Subject: [PATCH] Add experimental support for address space qualified types. Address space qualifiers use the __attribute__((address_space(id))) syntax. llvm-svn: 46691 --- clang/AST/ASTContext.cpp | 32 ++++- clang/AST/Type.cpp | 115 ++++++++++++++++-- clang/AST/TypeSerialization.cpp | 19 +++ clang/CodeGen/CGDecl.cpp | 3 +- clang/CodeGen/CodeGenModule.cpp | 9 +- clang/CodeGen/CodeGenTypes.cpp | 16 ++- clang/Sema/Sema.h | 9 +- clang/Sema/SemaDecl.cpp | 41 +++++++ clang/include/clang/AST/ASTContext.h | 5 + clang/include/clang/AST/Type.h | 81 +++++++++--- clang/include/clang/Basic/DiagnosticKinds.def | 3 +- clang/test/CodeGen/address-space.c | 7 ++ 12 files changed, 299 insertions(+), 41 deletions(-) create mode 100644 clang/test/CodeGen/address-space.c diff --git a/clang/AST/ASTContext.cpp b/clang/AST/ASTContext.cpp index 96bf45db7b64..823a20bb03da 100644 --- a/clang/AST/ASTContext.cpp +++ b/clang/AST/ASTContext.cpp @@ -256,6 +256,8 @@ ASTContext::getTypeInfo(QualType T, SourceLocation L) { } break; } + case Type::ASQual: + return getTypeInfo(cast(T)->getBaseType(), L); case Type::ObjCQualifiedId: Target.getPointerInfo(Size, Align, getFullLoc(L)); break; @@ -368,6 +370,30 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D, // Type creation/memoization methods //===----------------------------------------------------------------------===// +QualType ASTContext::getASQualType(QualType T, unsigned AddressSpace) { + // Check if we've already instantiated an address space qual'd type of this type. + llvm::FoldingSetNodeID ID; + ASQualType::Profile(ID, T, AddressSpace); + void *InsertPos = 0; + if (ASQualType *ASQy = ASQualTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(ASQy, 0); + + // If the base type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!T->isCanonical()) { + Canonical = getASQualType(T.getCanonicalType(), AddressSpace); + + // Get the new insert position for the node we care about. + ASQualType *NewIP = ASQualTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + ASQualType *New = new ASQualType(T, Canonical, AddressSpace); + ASQualTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. @@ -817,7 +843,7 @@ static int getIntegerRank(QualType t) { return 4; } - const BuiltinType *BT = cast(t.getCanonicalType()); + const BuiltinType *BT = t.getCanonicalType()->getAsBuiltinType(); switch (BT->getKind()) { default: assert(0 && "getIntegerRank(): not a built-in integer"); @@ -847,10 +873,10 @@ static int getIntegerRank(QualType t) { /// This routine will assert if passed a built-in type that isn't a float. static int getFloatingRank(QualType T) { T = T.getCanonicalType(); - if (ComplexType *CT = dyn_cast(T)) + if (const ComplexType *CT = T->getAsComplexType()) return getFloatingRank(CT->getElementType()); - switch (cast(T)->getKind()) { + switch (T->getAsBuiltinType()->getKind()) { default: assert(0 && "getFloatingRank(): not a floating type"); case BuiltinType::Float: return FloatRank; case BuiltinType::Double: return DoubleRank; diff --git a/clang/AST/Type.cpp b/clang/AST/Type.cpp index 6751a236e3cf..d3eb003eab27 100644 --- a/clang/AST/Type.cpp +++ b/clang/AST/Type.cpp @@ -125,8 +125,12 @@ const BuiltinType *Type::getAsBuiltinType() const { return BTy; // If the canonical form of this type isn't a builtin type, reject it. - if (!isa(CanonicalType)) + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsBuiltinType(); return 0; + } // If this is a typedef for a builtin type, strip the typedef off without // losing all typedef information. @@ -137,10 +141,14 @@ const FunctionType *Type::getAsFunctionType() const { // If this is directly a function type, return it. if (const FunctionType *FTy = dyn_cast(this)) return FTy; - + // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsFunctionType(); return 0; + } // If this is a typedef for a function type, strip the typedef off without // losing all typedef information. @@ -153,8 +161,12 @@ const PointerType *Type::getAsPointerType() const { return PTy; // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsPointerType(); return 0; + } // If this is a typedef for a pointer type, strip the typedef off without // losing all typedef information. @@ -167,8 +179,12 @@ const ReferenceType *Type::getAsReferenceType() const { return RTy; // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsReferenceType(); return 0; + } // If this is a typedef for a reference type, strip the typedef off without // losing all typedef information. @@ -181,8 +197,12 @@ const ArrayType *Type::getAsArrayType() const { return ATy; // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsArrayType(); return 0; + } // If this is a typedef for an array type, strip the typedef off without // losing all typedef information. @@ -193,10 +213,14 @@ const ConstantArrayType *Type::getAsConstantArrayType() const { // If this is directly a constant array type, return it. if (const ConstantArrayType *ATy = dyn_cast(this)) return ATy; - + // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsConstantArrayType(); return 0; + } // If this is a typedef for a constant array type, strip the typedef off // without losing all typedef information. @@ -209,8 +233,12 @@ const VariableArrayType *Type::getAsVariableArrayType() const { return ATy; // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsVariableArrayType(); return 0; + } // If this is a typedef for a variable array type, strip the typedef off // without losing all typedef information. @@ -257,8 +285,12 @@ const RecordType *Type::getAsRecordType() const { return RTy; // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsRecordType(); return 0; + } // If this is a typedef for a record type, strip the typedef off without // losing all typedef information. @@ -281,6 +313,9 @@ const RecordType *Type::getAsStructureType() const { // losing all typedef information. return getDesugaredType()->getAsStructureType(); } + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsStructureType(); return 0; } @@ -290,6 +325,7 @@ const RecordType *Type::getAsUnionType() const { if (RT->getDecl()->getKind() == Decl::Union) return RT; } + // If the canonical form of this type isn't the right kind, reject it. if (const RecordType *RT = dyn_cast(CanonicalType)) { if (RT->getDecl()->getKind() != Decl::Union) @@ -299,6 +335,10 @@ const RecordType *Type::getAsUnionType() const { // losing all typedef information. return getDesugaredType()->getAsUnionType(); } + + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsUnionType(); return 0; } @@ -308,8 +348,12 @@ const ComplexType *Type::getAsComplexType() const { return CTy; // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsComplexType(); return 0; + } // If this is a typedef for a complex type, strip the typedef off without // losing all typedef information. @@ -322,8 +366,12 @@ const VectorType *Type::getAsVectorType() const { return VTy; // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsVectorType(); return 0; + } // If this is a typedef for a vector type, strip the typedef off without // losing all typedef information. @@ -336,8 +384,12 @@ const OCUVectorType *Type::getAsOCUVectorType() const { return VTy; // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsOCUVectorType(); return 0; + } // If this is a typedef for an ocuvector type, strip the typedef off without // losing all typedef information. @@ -353,6 +405,8 @@ bool Type::isIntegerType() const { return true; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isIntegerType(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isIntegerType(); return false; } @@ -363,18 +417,24 @@ bool Type::isIntegralType() const { if (const TagType *TT = dyn_cast(CanonicalType)) if (TT->getDecl()->getKind() == Decl::Enum) return true; + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isIntegralType(); return false; } bool Type::isEnumeralType() const { if (const TagType *TT = dyn_cast(CanonicalType)) return TT->getDecl()->getKind() == Decl::Enum; + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isEnumeralType(); return false; } bool Type::isBooleanType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Bool; + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isBooleanType(); return false; } @@ -384,6 +444,8 @@ bool Type::isCharType() const { BT->getKind() == BuiltinType::UChar || BT->getKind() == BuiltinType::Char_S || BT->getKind() == BuiltinType::SChar; + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isCharType(); return false; } @@ -403,6 +465,8 @@ bool Type::isSignedIntegerType() const { if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isSignedIntegerType(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isSignedIntegerType(); return false; } @@ -422,6 +486,8 @@ bool Type::isUnsignedIntegerType() const { if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isUnsignedIntegerType(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isUnsignedIntegerType(); return false; } @@ -433,6 +499,8 @@ bool Type::isFloatingType() const { return CT->getElementType()->isFloatingType(); if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isFloatingType(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isFloatingType(); return false; } @@ -442,6 +510,8 @@ bool Type::isRealFloatingType() const { BT->getKind() <= BuiltinType::LongDouble; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isRealFloatingType(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isRealFloatingType(); return false; } @@ -453,6 +523,8 @@ bool Type::isRealType() const { return TT->getDecl()->getKind() == Decl::Enum; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isRealType(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isRealType(); return false; } @@ -464,6 +536,8 @@ bool Type::isArithmeticType() const { // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). // If a body isn't seen by the time we get here, return false. return ED->isDefinition(); + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isArithmeticType(); return isa(CanonicalType) || isa(CanonicalType); } @@ -475,6 +549,8 @@ bool Type::isScalarType() const { return true; return false; } + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isScalarType(); return isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType); } @@ -485,6 +561,8 @@ bool Type::isAggregateType() const { return true; return false; } + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isAggregateType(); return CanonicalType->getTypeClass() == ConstantArray || CanonicalType->getTypeClass() == VariableArray; } @@ -493,6 +571,8 @@ bool Type::isAggregateType() const { /// according to the rules of C99 6.7.5p3. It is not legal to call this on /// incomplete types. bool Type::isConstantSizeType(ASTContext &Ctx) const { + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isConstantSizeType(Ctx); assert(!isIncompleteType() && "This doesn't make sense for incomplete types"); // The VAT must have a size, as it is known to be complete. return !isa(CanonicalType); @@ -504,6 +584,8 @@ bool Type::isConstantSizeType(ASTContext &Ctx) const { bool Type::isIncompleteType() const { switch (CanonicalType->getTypeClass()) { default: return false; + case ASQual: + return cast(CanonicalType)->getBaseType()->isIncompleteType(); case Builtin: // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never // be completed. @@ -519,6 +601,8 @@ bool Type::isIncompleteType() const { } bool Type::isPromotableIntegerType() const { + if (const ASQualType *ASQT = dyn_cast(CanonicalType)) + return ASQT->getBaseType()->isPromotableIntegerType(); const BuiltinType *BT = dyn_cast(CanonicalType); if (!BT) return false; switch (BT->getKind()) { @@ -685,6 +769,11 @@ void ComplexType::getAsStringInternal(std::string &S) const { S = "_Complex " + S; } +void ASQualType::getAsStringInternal(std::string &S) const { + S = "__attribute__((address_space("+llvm::utostr_32(AddressSpace)+")))" + S; + BaseType->getAsStringInternal(S); +} + void PointerType::getAsStringInternal(std::string &S) const { S = '*' + S; diff --git a/clang/AST/TypeSerialization.cpp b/clang/AST/TypeSerialization.cpp index c6dee4e5cf47..7583a0747567 100644 --- a/clang/AST/TypeSerialization.cpp +++ b/clang/AST/TypeSerialization.cpp @@ -71,6 +71,10 @@ void Type::Create(ASTContext& Context, unsigned i, Deserializer& D) { D.RegisterPtr(PtrID,Context.getTypes()[i]); break; + case Type::ASQual: + D.RegisterPtr(PtrID,ASQualType::CreateImpl(Context,D)); + break; + case Type::Complex: D.RegisterPtr(PtrID,ComplexType::CreateImpl(Context,D)); break; @@ -105,6 +109,21 @@ void Type::Create(ASTContext& Context, unsigned i, Deserializer& D) { } } +//===----------------------------------------------------------------------===// +// ASQualType +//===----------------------------------------------------------------------===// + +void ASQualType::EmitImpl(Serializer& S) const { + S.Emit(getBaseType()); + S.EmitInt(getAddressSpace()); +} + +Type* ASQualType::CreateImpl(ASTContext& Context, Deserializer& D) { + QualType BaseTy = QualType::ReadVal(D); + unsigned AddressSpace = D.ReadInt(); + return Context.getASQualType(BaseTy, AddressSpace).getTypePtr(); +} + //===----------------------------------------------------------------------===// // ComplexType //===----------------------------------------------------------------------===// diff --git a/clang/CodeGen/CGDecl.cpp b/clang/CodeGen/CGDecl.cpp index 23c707d8c448..a6c5da7c2622 100644 --- a/clang/CodeGen/CGDecl.cpp +++ b/clang/CodeGen/CGDecl.cpp @@ -84,7 +84,8 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const BlockVarDecl &D) { DMEntry = new llvm::GlobalVariable(LTy, false, llvm::GlobalValue::InternalLinkage, - Init, D.getName(), &CGM.getModule()); + Init, D.getName(), &CGM.getModule(), 0, + Ty.getAddressSpace()); } diff --git a/clang/CodeGen/CodeGenModule.cpp b/clang/CodeGen/CodeGenModule.cpp index edf3dc42831e..382f651272f8 100644 --- a/clang/CodeGen/CodeGenModule.cpp +++ b/clang/CodeGen/CodeGenModule.cpp @@ -131,7 +131,8 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, llvm::Constant *&Entry = GlobalDeclMap[D]; if (Entry) return Entry; - const llvm::Type *Ty = getTypes().ConvertTypeForMem(D->getType()); + QualType ASTTy = D->getType(); + const llvm::Type *Ty = getTypes().ConvertTypeForMem(ASTTy); // Check to see if the global already exists. llvm::GlobalVariable *GV = getModule().getGlobalVariable(D->getName(), true); @@ -140,7 +141,8 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, if (GV == 0) { return Entry = new llvm::GlobalVariable(Ty, false, llvm::GlobalValue::ExternalLinkage, - 0, D->getName(), &getModule()); + 0, D->getName(), &getModule(), 0, + ASTTy.getAddressSpace()); } // If the pointer type matches, just return it. @@ -162,7 +164,8 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, // making a new global of the correct type, RAUW, then steal the name. llvm::GlobalVariable *NewGV = new llvm::GlobalVariable(Ty, false, llvm::GlobalValue::ExternalLinkage, - 0, D->getName(), &getModule()); + 0, D->getName(), &getModule(), 0, + ASTTy.getAddressSpace()); NewGV->takeName(GV); // Replace uses of GV with the globalvalue we will endow with a body. diff --git a/clang/CodeGen/CodeGenTypes.cpp b/clang/CodeGen/CodeGenTypes.cpp index 9e8a2e0ea625..326503197fad 100644 --- a/clang/CodeGen/CodeGenTypes.cpp +++ b/clang/CodeGen/CodeGenTypes.cpp @@ -199,7 +199,8 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { } case Type::Pointer: { const PointerType &P = cast(Ty); - return llvm::PointerType::getUnqual(ConvertType(P.getPointeeType())); + QualType ETy = P.getPointeeType(); + return llvm::PointerType::get(ConvertType(ETy), ETy.getAddressSpace()); } case Type::Reference: { const ReferenceType &R = cast(Ty); @@ -245,7 +246,8 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { // Struct return passes the struct byref. if (!ResultType->isFirstClassType() && ResultType != llvm::Type::VoidTy) { - const llvm::Type *RType = llvm::PointerType::getUnqual(ResultType); + const llvm::Type *RType = llvm::PointerType::get(ResultType, + FP.getResultType().getAddressSpace()); QualType RTy = Context.getPointerType(FP.getResultType()); TypeHolderMap.insert(std::make_pair(RTy.getTypePtr(), llvm::PATypeHolder(RType))); @@ -263,6 +265,10 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { return llvm::FunctionType::get(ResultType, ArgTys, isVarArg); } + + case Type::ASQual: + return ConvertType(cast(Ty).getBaseType()); + break; case Type::ObjCInterface: assert(0 && "FIXME: add missing functionality here"); @@ -386,8 +392,10 @@ void CodeGenTypes::DecodeArgumentTypes(const FunctionTypeProto &FTP, if (Ty->isFirstClassType()) ArgTys.push_back(Ty); else { - QualType PTy = Context.getPointerType(FTP.getArgType(i)); - const llvm::Type *PtrTy = llvm::PointerType::getUnqual(Ty); + QualType ATy = FTP.getArgType(i); + QualType PTy = Context.getPointerType(ATy); + unsigned AS = ATy.getAddressSpace(); + const llvm::Type *PtrTy = llvm::PointerType::get(Ty, AS); TypeHolderMap.insert(std::make_pair(PTy.getTypePtr(), llvm::PATypeHolder(PtrTy))); diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h index a35af4341fc2..ecd5ffd2c9b5 100644 --- a/clang/Sema/Sema.h +++ b/clang/Sema/Sema.h @@ -245,7 +245,14 @@ private: void HandleDeclAttributes(Decl *New, AttributeList *declspec_prefix, AttributeList *declarator_postfix); void HandleDeclAttribute(Decl *New, AttributeList *rawAttr); - + + /// HandleAddressSpaceTypeAttribute - this attribute is only applicable to + /// objects without automatic storage duration. + /// The raw attribute contains 1 argument, the id of the address space + /// for the type. + QualType HandleAddressSpaceTypeAttribute(QualType curType, + AttributeList *rawAttr); + // HandleVectorTypeAttribute - this attribute is only applicable to // integral and float scalars, although arrays, pointers, and function // return values are allowed in conjunction with this construct. Aggregates diff --git a/clang/Sema/SemaDecl.cpp b/clang/Sema/SemaDecl.cpp index f45b33981945..f00ed7f51ebe 100644 --- a/clang/Sema/SemaDecl.cpp +++ b/clang/Sema/SemaDecl.cpp @@ -1760,6 +1760,19 @@ void Sema::HandleDeclAttribute(Decl *New, AttributeList *rawAttr) { else Diag(rawAttr->getAttributeLoc(), diag::err_typecheck_ocu_vector_not_typedef); + } else if (attrLen == 13 && !memcmp(attrName, "address_space", 13)) { + if (TypedefDecl *tDecl = dyn_cast(New)) { + QualType newType = HandleAddressSpaceTypeAttribute( + tDecl->getUnderlyingType(), + rawAttr); + if (!newType.isNull()) // install the new addr spaced type into the decl + tDecl->setUnderlyingType(newType); + } else if (ValueDecl *vDecl = dyn_cast(New)) { + QualType newType = HandleAddressSpaceTypeAttribute(vDecl->getType(), + rawAttr); + if (!newType.isNull()) // install the new addr spaced type into the decl + vDecl->setType(newType); + } } else if (attrLen == 7 && !memcmp(attrName, "aligned", 7)) { HandleAlignedAttribute(New, rawAttr); } @@ -1779,6 +1792,34 @@ void Sema::HandleDeclAttributes(Decl *New, AttributeList *declspec_prefix, } } +QualType Sema::HandleAddressSpaceTypeAttribute(QualType curType, + AttributeList *rawAttr) { + // check the attribute arugments. + if (rawAttr->getNumArgs() != 1) { + Diag(rawAttr->getAttributeLoc(), diag::err_attribute_wrong_number_arguments, + std::string("1")); + return QualType(); + } + Expr *addrSpaceExpr = static_cast(rawAttr->getArg(0)); + llvm::APSInt addrSpace(32); + if (!addrSpaceExpr->isIntegerConstantExpr(addrSpace, Context)) { + Diag(rawAttr->getAttributeLoc(), diag::err_attribute_address_space_not_int, + addrSpaceExpr->getSourceRange()); + return QualType(); + } + unsigned addressSpace = static_cast(addrSpace.getZExtValue()); + + // Zero is the default memory space, so no qualification is needed + if (addressSpace == 0) + return curType; + + // TODO: Should we convert contained types of address space + // qualified types here or or where they directly participate in conversions + // (i.e. elsewhere) + + return Context.getASQualType(curType, addressSpace); +} + void Sema::HandleOCUVectorTypeAttribute(TypedefDecl *tDecl, AttributeList *rawAttr) { QualType curType = tDecl->getUnderlyingType(); diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 1e5a255b91a2..3cb2d6589322 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -32,6 +32,7 @@ namespace clang { /// decls) that can be referred to throughout the semantic analysis of a file. class ASTContext { std::vector Types; + llvm::FoldingSet ASQualTypes; llvm::FoldingSet ComplexTypes; llvm::FoldingSet PointerTypes; llvm::FoldingSet ReferenceTypes; @@ -120,6 +121,10 @@ public: // Type Constructors //===--------------------------------------------------------------------===// + /// getAddrSpaceQualType - Return the uniqued reference to the type for an + /// address space qualified type with the specified type and address space. + QualType getASQualType(QualType T, unsigned AddressSpace); + /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType getComplexType(QualType T); diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index bdcef4a575d7..fd2ef34274d4 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -50,6 +50,7 @@ namespace clang { class FunctionType; class OCUVectorType; class BuiltinType; + class ASQualType; class ObjCQualifiedInterfaceType; class StmtIteratorBase; @@ -132,9 +133,7 @@ public: return QualType(getTypePtr(), TQs); } - QualType getUnqualifiedType() const { - return QualType(getTypePtr(), 0); - } + inline QualType getUnqualifiedType() const; /// operator==/!= - Indicate whether the specified types and qualifiers are /// identical. @@ -157,6 +156,9 @@ public: /// appropriate type qualifiers on it. inline QualType getCanonicalType() const; + /// getAddressSpace - Return the address space of this type. + inline unsigned getAddressSpace() const; + /// Emit - Serialize a QualType to Bitcode. void Emit(llvm::Serializer& S) const; @@ -218,7 +220,7 @@ public: ConstantArray, VariableArray, Vector, OCUVector, FunctionNoProto, FunctionProto, - TypeName, Tagged, + TypeName, Tagged, ASQual, ObjCInterface, ObjCQualifiedInterface, ObjCQualifiedId, TypeOfExp, TypeOfTyp // GNU typeof extension. @@ -229,7 +231,7 @@ private: /// TypeClass bitfield - Enum that specifies what subclass this belongs to. /// Note that this should stay at the end of the ivars for Type so that /// subclasses can pack their bitfields into the same word. - unsigned TC : 4; + unsigned TC : 5; protected: // silence VC++ warning C4355: 'this' : used in base member initializer list Type *this_() { return this; } @@ -268,7 +270,7 @@ public: bool isIncompleteArrayType() const; /// Helper methods to distinguish type categories. All type predicates - /// operate on the canonical type, ignoring typedefs. + /// operate on the canonical type, ignoring typedefs and qualifiers. /// isIntegerType() does *not* include complex integers (a GCC extension). /// isComplexIntegerType() can be used to test for complex integers. @@ -292,7 +294,7 @@ public: bool isAggregateType() const; // C99 6.2.5p21 (arrays, structures) // Type Predicates: Check to see if this type is structurally the specified - // type, ignoring typedefs. + // type, ignoring typedefs and qualifiers. bool isFunctionType() const; bool isPointerType() const; bool isFunctionPointerType() const; @@ -308,7 +310,7 @@ public: bool isObjCQualifiedIdType() const; // id includes conforming protocol type // Type Checking Functions: Check to see if this type is structurally the - // specified type, ignoring typedefs, and return a pointer to the best type + // specified type, ignoring typedefs and qualifiers, and return a pointer to the best type // we can. const BuiltinType *getAsBuiltinType() const; const FunctionType *getAsFunctionType() const; @@ -373,6 +375,42 @@ protected: virtual void EmitImpl(llvm::Serializer& S) const; }; +/// ASQualType - TR18037 (C embedded extensions) 6.2.5p26 +/// This supports address space qualified types. +/// +class ASQualType : public Type, public llvm::FoldingSetNode { + QualType BaseType; + /// Address Space ID - The address space ID this type is qualified with. + unsigned AddressSpace; + ASQualType(QualType Base, QualType CanonicalPtr, unsigned AddrSpace) : + Type(ASQual, CanonicalPtr), BaseType(Base), AddressSpace(AddrSpace) { + } + friend class ASTContext; // ASTContext creates these. +public: + QualType getBaseType() const { return BaseType; } + unsigned getAddressSpace() const { return AddressSpace; } + + virtual void getAsStringInternal(std::string &InnerString) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getBaseType(), AddressSpace); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Base, + unsigned AddrSpace) { + ID.AddPointer(Base.getAsOpaquePtr()); + ID.AddInteger(AddrSpace); + } + + static bool classof(const Type *T) { return T->getTypeClass() == ASQual; } + static bool classof(const ASQualType *) { return true; } + +protected: + virtual void EmitImpl(llvm::Serializer& S) const; + static Type* CreateImpl(ASTContext& Context,llvm::Deserializer& D); + friend class Type; +}; + + /// BuiltinType - This class is used for builtin types like 'int'. Builtin /// types are always canonical and have a literal name field. class BuiltinType : public Type { @@ -1036,12 +1074,25 @@ inline QualType QualType::getCanonicalType() const { getTypePtr()->getCanonicalTypeInternal().getQualifiers()); } +/// getUnqualifiedType - Return the type without any qualifiers. +inline QualType QualType::getUnqualifiedType() const { + if (const ASQualType *ASQT = dyn_cast(getTypePtr())) + return ASQT->getBaseType().getUnqualifiedType(); + return QualType(getTypePtr(), 0); +} + +/// getAddressSpace - Return the address space of this type. +inline unsigned QualType::getAddressSpace() const { + if (const ASQualType *ASQT = dyn_cast(getTypePtr())) + return ASQT->getAddressSpace(); + return 0; +} inline bool Type::isFunctionType() const { - return isa(CanonicalType); + return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isPointerType() const { - return isa(CanonicalType); + return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isFunctionPointerType() const { if (const PointerType* T = getAsPointerType()) @@ -1050,19 +1101,19 @@ inline bool Type::isFunctionPointerType() const { return false; } inline bool Type::isReferenceType() const { - return isa(CanonicalType); + return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isArrayType() const { - return isa(CanonicalType); + return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isRecordType() const { - return isa(CanonicalType); + return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isVectorType() const { - return isa(CanonicalType); + return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isOCUVectorType() const { - return isa(CanonicalType); + return isa(CanonicalType.getUnqualifiedType()); } inline bool Type::isObjCInterfaceType() const { return isa(CanonicalType) diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index c3087fbb3a11..b19c485cf258 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -575,6 +575,8 @@ DIAG(err_ocuvector_component_name_illegal, ERROR, "illegal vector component name '%0'") DIAG(err_ocuvector_component_access, ERROR, "vector component access limited to variables") +DIAG(err_attribute_address_space_not_int, ERROR, + "address space attribute requires an integer constant") // Function Parameter Semantic Analysis. DIAG(err_param_with_void_type, ERROR, @@ -953,5 +955,4 @@ DIAG(ext_return_has_expr, EXTENSION, "void function '%0' should not return a value") - #undef DIAG diff --git a/clang/test/CodeGen/address-space.c b/clang/test/CodeGen/address-space.c new file mode 100644 index 000000000000..304c13638aea --- /dev/null +++ b/clang/test/CodeGen/address-space.c @@ -0,0 +1,7 @@ +// RUN: clang -emit-llvm < %s 2>&1 | grep 'addrspace(1)' | count 5 +int foo __attribute__((address_space(1))); +int ban[10] __attribute__((address_space(1))); + +int bar() { return foo; } + +int baz(int i) { return ban[i]; } \ No newline at end of file