Implement address space attribute for LLVM pointer types. Address spaces are
authorChristopher Lamb <christopher.lamb@gmail.com>
Tue, 11 Dec 2007 08:59:05 +0000 (08:59 +0000)
committerChristopher Lamb <christopher.lamb@gmail.com>
Tue, 11 Dec 2007 08:59:05 +0000 (08:59 +0000)
regions of memory that have a target specific relationship, as described in the
Embedded C Technical Report.

This also implements the 2007-12-11-AddressSpaces test,
which demonstrates how address space attributes can be used in LLVM IR.

In addition, this patch changes the bitcode signature for stores (in a backwards
compatible manner), such that the pointer type, rather than the pointee type, is
encoded. This permits type information in the pointer (e.g. address space) to be
preserved for stores.

LangRef updates are forthcoming.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@44858 91177308-0d34-0410-b5e6-96231b3b80d8

15 files changed:
include/llvm/Bitcode/LLVMBitCodes.h
include/llvm/DerivedTypes.h
include/llvm/GlobalVariable.h
include/llvm/Instructions.h
lib/AsmParser/LLLexer.cpp
lib/AsmParser/llvmAsmParser.y
lib/Bitcode/Reader/BitcodeReader.cpp
lib/Bitcode/Writer/BitcodeWriter.cpp
lib/VMCore/AsmWriter.cpp
lib/VMCore/Constants.cpp
lib/VMCore/Globals.cpp
lib/VMCore/Instructions.cpp
lib/VMCore/Type.cpp
test/Assembler/2007-12-11-AddressSpaces.ll [new file with mode: 0644]
tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp

index 32311b26d90baf3866841e71ebc82c8017f6abea..8d95c872a93069d98d3a7a84956900578c371574 100644 (file)
@@ -46,7 +46,7 @@ namespace bitc {
     MODULE_CODE_SECTIONNAME = 5,    // SECTIONNAME: [strchr x N]
     MODULE_CODE_DEPLIB      = 6,    // DEPLIB:      [strchr x N]
 
-    // GLOBALVAR: [type, isconst, initid, 
+    // GLOBALVAR: [pointer type, isconst, initid, 
     //             linkage, alignment, section, visibility, threadlocal]
     MODULE_CODE_GLOBALVAR   = 7,
 
@@ -194,9 +194,13 @@ namespace bitc {
     FUNC_CODE_INST_FREE        = 18, // FREE:       [opty, op]
     FUNC_CODE_INST_ALLOCA      = 19, // ALLOCA:     [instty, op, align]
     FUNC_CODE_INST_LOAD        = 20, // LOAD:       [opty, op, align, vol]
-    FUNC_CODE_INST_STORE       = 21, // STORE:      [ptrty,val,ptr, align, vol]
+    FUNC_CODE_INST_STORE       = 21, // STORE:      [valty,val,ptr, align, vol]
     FUNC_CODE_INST_CALL        = 22, // CALL:       [attr, fnty, fnid, args...]
-    FUNC_CODE_INST_VAARG       = 23  // VAARG:      [valistty, valist, instty]
+    FUNC_CODE_INST_VAARG       = 23, // VAARG:      [valistty, valist, instty]
+    // This store code encodes the pointer type, rather than the value type
+    // this is so information only available in the pointer type (e.g. address
+    // spaces) is retained.
+    FUNC_CODE_INST_STORE2      = 24 // STORE:      [ptrty,ptr,val, align, vol]
   };
 } // End bitc namespace
 } // End llvm namespace
index 12219c535425c1b000d2d2b392af755db681a0fa..d62cb3bcc959aa95733550fcffdfa6c755e5e6c4 100644 (file)
@@ -363,12 +363,17 @@ public:
 ///
 class PointerType : public SequentialType {
   friend class TypeMap<PointerValType, PointerType>;
+  unsigned AddressSpace;
+  
   PointerType(const PointerType &);                   // Do not implement
   const PointerType &operator=(const PointerType &);  // Do not implement
-  explicit PointerType(const Type *ElType);
+  explicit PointerType(const Type *ElType, unsigned AddrSpace);
 public:
   /// PointerType::get - This is the only way to construct a new pointer type.
-  static PointerType *get(const Type *ElementType);
+  static PointerType *get(const Type *ElementType, unsigned AddressSpace = 0);
+  
+  /// @brief Return the address space of the Pointer type.
+  inline unsigned getAddressSpace() const { return AddressSpace; }
 
   // Implement the AbstractTypeUser interface.
   virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy);
index 00d4acb66daf53d5886cc5af540a8bfa74f4f59e..7e99ae04ba6a257cf8597efc6e7dd4bb5e9c2310 100644 (file)
@@ -50,12 +50,14 @@ public:
   /// automatically inserted into the end of the specified modules global list.
   GlobalVariable(const Type *Ty, bool isConstant, LinkageTypes Linkage,
                  Constant *Initializer = 0, const std::string &Name = "",
-                 Module *Parent = 0, bool ThreadLocal = false);
+                 Module *Parent = 0, bool ThreadLocal = false, 
+                 unsigned AddressSpace = 0);
   /// GlobalVariable ctor - This creates a global and inserts it before the
   /// specified other global.
   GlobalVariable(const Type *Ty, bool isConstant, LinkageTypes Linkage,
                  Constant *Initializer, const std::string &Name,
-                 GlobalVariable *InsertBefore, bool ThreadLocal = false);
+                 GlobalVariable *InsertBefore, bool ThreadLocal = false, 
+                 unsigned AddressSpace = 0);
   
   /// isDeclaration - Is this global variable lacking an initializer?  If so, 
   /// the global variable is defined in some other translation unit, and is thus
index bc5e0b4af9c1bd155bac18876d74d37607b49924..3c8673e627aead6c4705e4de86a288107a4cf2fb 100644 (file)
@@ -455,7 +455,8 @@ public:
                     Instruction *InsertBefore =0)
       : Instruction(PointerType::get(
                       checkType(getIndexedType(Ptr->getType(),
-                                               IdxBegin, IdxEnd, true))),
+                                               IdxBegin, IdxEnd, true)),
+                      cast<PointerType>(Ptr->getType())->getAddressSpace()),
                     GetElementPtr, 0, 0, InsertBefore) {
     init(Ptr, IdxBegin, IdxEnd, Name,
          typename std::iterator_traits<InputIterator>::iterator_category());
@@ -465,7 +466,8 @@ public:
                     const std::string &Name, BasicBlock *InsertAtEnd)
       : Instruction(PointerType::get(
                       checkType(getIndexedType(Ptr->getType(),
-                                               IdxBegin, IdxEnd, true))),
+                                               IdxBegin, IdxEnd, true)),
+                      cast<PointerType>(Ptr->getType())->getAddressSpace()),
                     GetElementPtr, 0, 0, InsertAtEnd) {
     init(Ptr, IdxBegin, IdxEnd, Name,
          typename std::iterator_traits<InputIterator>::iterator_category());
index ef8d27c8a3727de73fdb592329beb31ac725c898..750529451a6a8ef5cdba644e2e5694ee71328aa3 100644 (file)
@@ -463,6 +463,7 @@ int LLLexer::LexIdentifier() {
   KEYWORD("datalayout", DATALAYOUT);
   KEYWORD("volatile", VOLATILE);
   KEYWORD("align", ALIGN);
+  KEYWORD("addrspace", ADDRSPACE);
   KEYWORD("section", SECTION);
   KEYWORD("alias", ALIAS);
   KEYWORD("module", MODULE);
index 57b6f81d8fb756b34096b3bbb4a1d09b6947b865..cd3a7edb502ef4156a38511613912652404db5d3 100644 (file)
@@ -491,7 +491,8 @@ static Value *getVal(const Type *Ty, const ValID &ID) {
    if (const FunctionType *FTy = dyn_cast<FunctionType>(ElTy))
      V = new Function(FTy, GlobalValue::ExternalLinkage);
    else
-     V = new GlobalVariable(ElTy, false, GlobalValue::ExternalLinkage);
+     V = new GlobalVariable(ElTy, false, GlobalValue::ExternalLinkage, 0, "",
+                            (Module*)0, false, PTy->getAddressSpace());
    break;
   }
   default:
@@ -722,13 +723,14 @@ ParseGlobalVariable(std::string *NameStr,
                     GlobalValue::LinkageTypes Linkage,
                     GlobalValue::VisibilityTypes Visibility,
                     bool isConstantGlobal, const Type *Ty,
-                    Constant *Initializer, bool IsThreadLocal) {
+                    Constant *Initializer, bool IsThreadLocal,
+                    unsigned AddressSpace = 0) {
   if (isa<FunctionType>(Ty)) {
     GenerateError("Cannot declare global vars of function type");
     return 0;
   }
 
-  const PointerType *PTy = PointerType::get(Ty);
+  const PointerType *PTy = PointerType::get(Ty, AddressSpace);
 
   std::string Name;
   if (NameStr) {
@@ -780,7 +782,7 @@ ParseGlobalVariable(std::string *NameStr,
   // Otherwise there is no existing GV to use, create one now.
   GlobalVariable *GV =
     new GlobalVariable(Ty, isConstantGlobal, Linkage, Initializer, Name,
-                       CurModule.CurrentModule, IsThreadLocal);
+                       CurModule.CurrentModule, IsThreadLocal, AddressSpace);
   GV->setVisibility(Visibility);
   InsertValue(GV, CurModule.Values);
   return GV;
@@ -1054,7 +1056,7 @@ Module *llvm::RunVMAsmParser(llvm::MemoryBuffer *MB) {
 %token DECLARE DEFINE GLOBAL CONSTANT SECTION ALIAS VOLATILE THREAD_LOCAL
 %token TO DOTDOTDOT NULL_TOK UNDEF INTERNAL LINKONCE WEAK APPENDING
 %token DLLIMPORT DLLEXPORT EXTERN_WEAK
-%token OPAQUE EXTERNAL TARGET TRIPLE ALIGN
+%token OPAQUE EXTERNAL TARGET TRIPLE ALIGN ADDRSPACE
 %token DEPLIBS CALL TAIL ASM_TOK MODULE SIDEEFFECT
 %token CC_TOK CCC_TOK FASTCC_TOK COLDCC_TOK X86_STDCALLCC_TOK X86_FASTCALLCC_TOK
 %token DATALAYOUT
@@ -1268,6 +1270,7 @@ OptCAlign : /*empty*/            { $$ = 0; } |
 };
 
 
+
 SectionString : SECTION STRINGCONSTANT {
   for (unsigned i = 0, e = $2->length(); i != e; ++i)
     if ((*$2)[i] == '"' || (*$2)[i] == '\\')
@@ -1320,6 +1323,13 @@ Types
     delete $1;
     CHECK_FOR_ERROR
   }
+  | Types ADDRSPACE '(' EUINT64VAL ')' '*' {             // Pointer type?
+    if (*$1 == Type::LabelTy)
+      GEN_ERROR("Cannot form a pointer to a basic block");
+    $$ = new PATypeHolder(HandleUpRefs(PointerType::get(*$1, $4)));
+    delete $1;
+    CHECK_FOR_ERROR
+  }
   | SymbolicValueRef {            // Named types are also simple types...
     const Type* tmp = getTypeVal($1);
     CHECK_FOR_ERROR
@@ -2073,6 +2083,17 @@ Definition
   } GlobalVarAttributes {
     CurGV = 0;
   }
+  | OptGlobalAssign GVVisibilityStyle ThreadLocal GlobalType ConstVal
+    ADDRSPACE '(' EUINT64VAL ')' { 
+    /* "Externally Visible" Linkage with address space qualifier */
+    if ($5 == 0) 
+      GEN_ERROR("Global value initializer is not a constant");
+    CurGV = ParseGlobalVariable($1, GlobalValue::ExternalLinkage,
+                                $2, $4, $5->getType(), $5, $3, $8);
+    CHECK_FOR_ERROR
+  } GlobalVarAttributes {
+    CurGV = 0;
+  }
   | OptGlobalAssign GVInternalLinkage GVVisibilityStyle ThreadLocal GlobalType
     ConstVal {
     if ($6 == 0) 
index fd3ec9e69855e2fb13fd9a41d3425e40efe3b10b..72756ef6cd6f5e1d9beb2d61ec6eb27a6dbea094 100644 (file)
@@ -323,11 +323,16 @@ bool BitcodeReader::ParseTypeTable() {
       
       ResultTy = IntegerType::get(Record[0]);
       break;
-    case bitc::TYPE_CODE_POINTER:   // POINTER: [pointee type]
+    case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or 
+                                    //          [pointee type, address space]
       if (Record.size() < 1)
         return Error("Invalid POINTER type record");
-      ResultTy = PointerType::get(getTypeByID(Record[0], true));
+      unsigned AddressSpace = 0;
+      if (Record.size() == 2)
+        AddressSpace = Record[1];
+      ResultTy = PointerType::get(getTypeByID(Record[0], true), AddressSpace);
       break;
+    }
     case bitc::TYPE_CODE_FUNCTION: {
       // FIXME: attrid is dead, remove it in LLVM 3.0
       // FUNCTION: [vararg, attrid, retty, paramty x N]
@@ -982,7 +987,7 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) {
       CollectorTable.push_back(S);
       break;
     }
-    // GLOBALVAR: [type, isconst, initid, 
+    // GLOBALVAR: [pointer type, isconst, initid,
     //             linkage, alignment, section, visibility, threadlocal]
     case bitc::MODULE_CODE_GLOBALVAR: {
       if (Record.size() < 6)
@@ -990,6 +995,7 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) {
       const Type *Ty = getTypeByID(Record[0]);
       if (!isa<PointerType>(Ty))
         return Error("Global not a pointer type!");
+      unsigned AddressSpace = cast<PointerType>(Ty)->getAddressSpace();
       Ty = cast<PointerType>(Ty)->getElementType();
       
       bool isConstant = Record[1];
@@ -1009,7 +1015,8 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) {
         isThreadLocal = Record[7];
 
       GlobalVariable *NewGV =
-        new GlobalVariable(Ty, isConstant, Linkage, 0, "", TheModule);
+        new GlobalVariable(Ty, isConstant, Linkage, 0, "", TheModule, 
+                           isThreadLocal, AddressSpace);
       NewGV->setAlignment(Alignment);
       if (!Section.empty())
         NewGV->setSection(Section);
@@ -1485,7 +1492,20 @@ bool BitcodeReader::ParseFunctionBody(Function *F) {
       I = new LoadInst(Op, "", Record[OpNum+1], (1 << Record[OpNum]) >> 1);
       break;
     }
+    case bitc::FUNC_CODE_INST_STORE2: { // STORE2:[ptrty, ptr, val, align, vol]
+      unsigned OpNum = 0;
+      Value *Val, *Ptr;
+      if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) ||
+          getValue(Record, OpNum, 
+                    cast<PointerType>(Ptr->getType())->getElementType(), Val) ||
+          OpNum+2 != Record.size())
+        return Error("Invalid STORE record");
+      
+      I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1);
+      break;
+    }
     case bitc::FUNC_CODE_INST_STORE: { // STORE:[val, valty, ptr, align, vol]
+      // FIXME: Legacy form of store instruction. Should be removed in LLVM 3.0.
       unsigned OpNum = 0;
       Value *Val, *Ptr;
       if (getValueTypePair(Record, OpNum, NextValueNo, Val) ||
index 612d89338b796159a1c75f3a38f261624e782eec..c58d23ada21cb6debcd0dcc2833cf8d954313204 100644 (file)
@@ -197,10 +197,14 @@ static void WriteTypeTable(const ValueEnumerator &VE, BitstreamWriter &Stream) {
       TypeVals.push_back(cast<IntegerType>(T)->getBitWidth());
       break;
     case Type::PointerTyID:
-      // POINTER: [pointee type]
+      const PointerType *PTy = cast<PointerType>(T);
+      // POINTER: [pointee type] or [pointee type, address space]
       Code = bitc::TYPE_CODE_POINTER;
-      TypeVals.push_back(VE.getTypeID(cast<PointerType>(T)->getElementType()));
-      AbbrevToUse = PtrAbbrev;
+      TypeVals.push_back(VE.getTypeID(PTy->getElementType()));
+      if (unsigned AddressSpace = PTy->getAddressSpace())
+        TypeVals.push_back(AddressSpace);
+      else
+        AbbrevToUse = PtrAbbrev;
       break;
 
     case Type::FunctionTyID: {
@@ -829,9 +833,9 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
     Vals.push_back(cast<LoadInst>(I).isVolatile());
     break;
   case Instruction::Store:
-    Code = bitc::FUNC_CODE_INST_STORE;
-    PushValueAndType(I.getOperand(0), InstID, Vals, VE);  // val.
-    Vals.push_back(VE.getValueID(I.getOperand(1)));       // ptr.
+    Code = bitc::FUNC_CODE_INST_STORE2;
+    PushValueAndType(I.getOperand(1), InstID, Vals, VE);  // ptrty + ptr
+    Vals.push_back(VE.getValueID(I.getOperand(0)));       // val.
     Vals.push_back(Log2_32(cast<StoreInst>(I).getAlignment())+1);
     Vals.push_back(cast<StoreInst>(I).isVolatile());
     break;
index 008c1daee192b91d53d246ec4eb81d146289872b..e35b14fbc1a304d79768e090a9bd44df3d0c22f6 100644 (file)
@@ -334,11 +334,15 @@ static void calcTypeName(const Type *Ty,
       Result += '>';
     break;
   }
-  case Type::PointerTyID:
-    calcTypeName(cast<PointerType>(Ty)->getElementType(),
+  case Type::PointerTyID: {
+    const PointerType *PTy = cast<PointerType>(Ty);
+    calcTypeName(PTy->getElementType(),
                           TypeStack, TypeNames, Result);
+    if (unsigned AddressSpace = PTy->getAddressSpace())
+      Result += " addrspace(" + utostr(AddressSpace) + ")";
     Result += "*";
     break;
+  }
   case Type::ArrayTyID: {
     const ArrayType *ATy = cast<ArrayType>(Ty);
     Result += "[" + utostr(ATy->getNumElements()) + " x ";
@@ -951,6 +955,9 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
     writeOperand(GV->getInitializer(), false);
   }
 
+  if (unsigned AddressSpace = GV->getType()->getAddressSpace())
+    Out << " addrspace(" << AddressSpace << ") ";
+    
   if (GV->hasSection())
     Out << ", section \"" << GV->getSection() << '"';
   if (GV->getAlignment())
index 49c27b82ccd665254cda5b85a56c680d21a83883..964d8880e87b625d3cc67a2a30a0c5ac9e375033 100644 (file)
@@ -1860,7 +1860,8 @@ Constant *ConstantExpr::getGetElementPtr(Constant *C, Value* const *Idxs,
   const Type *Ty = 
     GetElementPtrInst::getIndexedType(C->getType(), Idxs, Idxs+NumIdx, true);
   assert(Ty && "GEP indices invalid!");
-  return getGetElementPtrTy(PointerType::get(Ty), C, Idxs, NumIdx);
+  unsigned As = cast<PointerType>(C->getType())->getAddressSpace();
+  return getGetElementPtrTy(PointerType::get(Ty, As), C, Idxs, NumIdx);
 }
 
 Constant *ConstantExpr::getGetElementPtr(Constant *C, Constant* const *Idxs,
index eb0df60757be4dff071e4b50dee4b1b34e9ee7ae..0155915146a638424039b44a57cd507869066254 100644 (file)
@@ -85,8 +85,9 @@ void GlobalValue::destroyConstant() {
 
 GlobalVariable::GlobalVariable(const Type *Ty, bool constant, LinkageTypes Link,
                                Constant *InitVal, const std::string &Name,
-                               Module *ParentModule, bool ThreadLocal)
-  : GlobalValue(PointerType::get(Ty), Value::GlobalVariableVal,
+                               Module *ParentModule, bool ThreadLocal, 
+                               unsigned AddressSpace)
+  : GlobalValue(PointerType::get(Ty, AddressSpace), Value::GlobalVariableVal,
                 &Initializer, InitVal != 0, Link, Name),
     isConstantGlobal(constant), isThreadLocalSymbol(ThreadLocal) {
   if (InitVal) {
@@ -105,8 +106,9 @@ GlobalVariable::GlobalVariable(const Type *Ty, bool constant, LinkageTypes Link,
 
 GlobalVariable::GlobalVariable(const Type *Ty, bool constant, LinkageTypes Link,
                                Constant *InitVal, const std::string &Name,
-                               GlobalVariable *Before, bool ThreadLocal)
-  : GlobalValue(PointerType::get(Ty), Value::GlobalVariableVal,
+                               GlobalVariable *Before, bool ThreadLocal,
+                               unsigned AddressSpace)
+  : GlobalValue(PointerType::get(Ty, AddressSpace), Value::GlobalVariableVal,
                 &Initializer, InitVal != 0, Link, Name), 
     isConstantGlobal(constant), isThreadLocalSymbol(ThreadLocal) {
   if (InitVal) {
index 0df0466112bc797aeeacb2ef1fcad8486687d905..5207ea52f49325370b0bc340a1d82d9cb6fbf2f6 100644 (file)
@@ -937,7 +937,8 @@ void GetElementPtrInst::init(Value *Ptr, Value *Idx) {
 
 GetElementPtrInst::GetElementPtrInst(Value *Ptr, Value *Idx,
                                      const std::string &Name, Instruction *InBe)
-  : Instruction(PointerType::get(checkType(getIndexedType(Ptr->getType(),Idx))),
+  : Instruction(PointerType::get(checkType(getIndexedType(Ptr->getType(),Idx)),
+                      cast<PointerType>(Ptr->getType())->getAddressSpace()),
                 GetElementPtr, 0, 0, InBe) {
   init(Ptr, Idx);
   setName(Name);
@@ -945,7 +946,8 @@ GetElementPtrInst::GetElementPtrInst(Value *Ptr, Value *Idx,
 
 GetElementPtrInst::GetElementPtrInst(Value *Ptr, Value *Idx,
                                      const std::string &Name, BasicBlock *IAE)
-  : Instruction(PointerType::get(checkType(getIndexedType(Ptr->getType(),Idx))),
+  : Instruction(PointerType::get(checkType(getIndexedType(Ptr->getType(),Idx)),
+                      cast<PointerType>(Ptr->getType())->getAddressSpace()),
                 GetElementPtr, 0, 0, IAE) {
   init(Ptr, Idx);
   setName(Name);
index 1e584770420859da968b069976551502848cbc70..62de6f4fa57b7d021f8358f8957b27a5c4e51eaf 100644 (file)
@@ -338,7 +338,10 @@ static std::string getTypeDescription(const Type *Ty,
   }
   case Type::PointerTyID: {
     const PointerType *PTy = cast<PointerType>(Ty);
-    Result = getTypeDescription(PTy->getElementType(), TypeStack) + " *";
+    Result = getTypeDescription(PTy->getElementType(), TypeStack);
+    if (unsigned AddressSpace = PTy->getAddressSpace())
+      Result += " addrspace(" + utostr(AddressSpace) + ")";
+    Result += " *";
     break;
   }
   case Type::ArrayTyID: {
@@ -492,7 +495,9 @@ VectorType::VectorType(const Type *ElType, unsigned NumEl)
 }
 
 
-PointerType::PointerType(const Type *E) : SequentialType(PointerTyID, E) {
+PointerType::PointerType(const Type *E, unsigned AddrSpace)
+  : SequentialType(PointerTyID, E) {
+  AddressSpace = AddrSpace;
   // Calculate whether or not this type is abstract
   setAbstract(E->isAbstract());
 }
@@ -634,8 +639,9 @@ static bool TypesEqual(const Type *Ty, const Type *Ty2,
     const IntegerType *ITy2 = cast<IntegerType>(Ty2);
     return ITy->getBitWidth() == ITy2->getBitWidth();
   } else if (const PointerType *PTy = dyn_cast<PointerType>(Ty)) {
-    return TypesEqual(PTy->getElementType(),
-                      cast<PointerType>(Ty2)->getElementType(), EqTypes);
+    const PointerType *PTy2 = cast<PointerType>(Ty2);
+    return PTy->getAddressSpace() == PTy2->getAddressSpace() &&
+           TypesEqual(PTy->getElementType(), PTy2->getElementType(), EqTypes);
   } else if (const StructType *STy = dyn_cast<StructType>(Ty)) {
     const StructType *STy2 = cast<StructType>(Ty2);
     if (STy->getNumElements() != STy2->getNumElements()) return false;
@@ -756,6 +762,9 @@ static unsigned getSubElementHash(const Type *Ty) {
     case Type::StructTyID:
       HashVal ^= cast<StructType>(SubTy)->getNumElements();
       break;
+    case Type::PointerTyID:
+      HashVal ^= cast<PointerType>(SubTy)->getAddressSpace();
+      break;
     }
   }
   return HashVal ? HashVal : 1;  // Do not return zero unless opaque subty.
@@ -1251,11 +1260,12 @@ StructType *StructType::get(const std::vector<const Type*> &ETypes,
 namespace llvm {
 class PointerValType {
   const Type *ValTy;
+  unsigned AddressSpace;
 public:
-  PointerValType(const Type *val) : ValTy(val) {}
+  PointerValType(const Type *val, unsigned as) : ValTy(val), AddressSpace(as) {}
 
   static PointerValType get(const PointerType *PT) {
-    return PointerValType(PT->getElementType());
+    return PointerValType(PT->getElementType(), PT->getAddressSpace());
   }
 
   static unsigned hashTypeStructure(const PointerType *PT) {
@@ -1263,25 +1273,26 @@ public:
   }
 
   bool operator<(const PointerValType &MTV) const {
-    return ValTy < MTV.ValTy;
+    if (AddressSpace < MTV.AddressSpace) return true;
+    return AddressSpace == MTV.AddressSpace && ValTy < MTV.ValTy;
   }
 };
 }
 
 static ManagedStatic<TypeMap<PointerValType, PointerType> > PointerTypes;
 
-PointerType *PointerType::get(const Type *ValueType) {
+PointerType *PointerType::get(const Type *ValueType, unsigned AddressSpace) {
   assert(ValueType && "Can't get a pointer to <null> type!");
   assert(ValueType != Type::VoidTy &&
          "Pointer to void is not valid, use sbyte* instead!");
   assert(ValueType != Type::LabelTy && "Pointer to label is not valid!");
-  PointerValType PVT(ValueType);
+  PointerValType PVT(ValueType, AddressSpace);
 
   PointerType *PT = PointerTypes->get(PVT);
   if (PT) return PT;
 
   // Value not found.  Derive a new type!
-  PointerTypes->add(PVT, PT = new PointerType(ValueType));
+  PointerTypes->add(PVT, PT = new PointerType(ValueType, AddressSpace));
 
 #ifdef DEBUG_MERGE_TYPES
   DOUT << "Derived new type: " << *PT << "\n";
diff --git a/test/Assembler/2007-12-11-AddressSpaces.ll b/test/Assembler/2007-12-11-AddressSpaces.ll
new file mode 100644 (file)
index 0000000..91f6d93
--- /dev/null
@@ -0,0 +1,25 @@
+; RUN: llvm-as < %s | llvm-dis |& grep {addrspace(33)} | count 7
+; RUN: llvm-as < %s | llvm-dis |& grep {addrspace(42)} | count 2
+; RUN: llvm-as < %s | llvm-dis |& grep {addrspace(66)} | count 2
+; RUN: llvm-as < %s | llvm-dis |& grep {addrspace(11)} | count 6
+; RUN: llvm-as < %s | llvm-dis |& grep {addrspace(22)} | count 5
+
+       %struct.mystruct = type { i32, i32 addrspace(33)*, i32, i32 addrspace(33)* }
+@input = global %struct.mystruct zeroinitializer addrspace(42)                 ; <%struct.mystruct addrspace(42)*> [#uses=1]
+@output = global %struct.mystruct zeroinitializer addrspace(66)                ; <%struct.mystruct addrspace(66)*> [#uses=1]
+@y = global i32 addrspace(11)* addrspace(22)* null addrspace(33)               ; <i32 addrspace(11)* addrspace(22)* addrspace(33)*> [#uses=1]
+
+define void @foo() {
+entry:
+       %tmp1 = load i32 addrspace(33)* addrspace(42)* getelementptr (%struct.mystruct addrspace(42)* @input, i32 0, i32 3), align 4            ; <i32 addrspace(33)*> [#uses=1]
+       store i32 addrspace(33)* %tmp1, i32 addrspace(33)* addrspace(66)* getelementptr (%struct.mystruct addrspace(66)* @output, i32 0, i32 1), align 4
+       ret void
+}
+
+define i32 addrspace(11)* @bar(i32 addrspace(11)* addrspace(22)* addrspace(33)* %x) {
+entry:
+       %tmp1 = load i32 addrspace(11)* addrspace(22)* addrspace(33)* @y, align 4               ; <i32 addrspace(11)* addrspace(22)*> [#uses=2]
+       store i32 addrspace(11)* addrspace(22)* %tmp1, i32 addrspace(11)* addrspace(22)* addrspace(33)* %x, align 4
+       %tmp5 = load i32 addrspace(11)* addrspace(22)* %tmp1, align 4           ; <i32 addrspace(11)*> [#uses=1]
+       ret i32 addrspace(11)* %tmp5
+}
index b596fe3731004c3d3c50fa6a6a5afe9fc675966e..09156d68fd6bd44d38c8a06d1805f54f08f020f0 100644 (file)
@@ -197,6 +197,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID) {
     case bitc::FUNC_CODE_INST_STORE:       return "INST_STORE";
     case bitc::FUNC_CODE_INST_CALL:        return "INST_CALL";
     case bitc::FUNC_CODE_INST_VAARG:       return "INST_VAARG";
+    case bitc::FUNC_CODE_INST_STORE2:      return "INST_STORE2";
     }
   case bitc::TYPE_SYMTAB_BLOCK_ID:
     switch (CodeID) {