Preserve address space information through member accesses, e.g.,  
   __attribute__((address_space(1))) struct {int arr[ 3 ]; }  *p1;
   ... = p1->arr[2];  // load from address space 1


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76717 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 346b670..de44e69 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -143,7 +143,8 @@
   llvm::Type *Ty = VMContext.getPointerTypeUnqual(ConvertType(E->getType()));
   return LValue::MakeAddr(VMContext.getUndef(Ty),
                           E->getType().getCVRQualifiers(),
-                          getContext().getObjCGCAttrKind(E->getType()));
+                          getContext().getObjCGCAttrKind(E->getType()),
+                          E->getType().getAddressSpace());
 }
 
 /// EmitLValue - Emit code to compute a designator that specifies the location
@@ -676,7 +677,8 @@
       if (VD->getType()->isReferenceType())
         V = Builder.CreateLoad(V, "tmp");
       LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(),
-                            getContext().getObjCGCAttrKind(E->getType()));
+                            getContext().getObjCGCAttrKind(E->getType()),
+                            E->getType().getAddressSpace());
     }
     else {
       llvm::Value *V = LocalDeclMap[VD];
@@ -699,7 +701,8 @@
       }
       if (VD->getType()->isReferenceType())
         V = Builder.CreateLoad(V, "tmp");
-      LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(), attr);
+      LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(), attr,
+                            E->getType().getAddressSpace());
     }
     LValue::SetObjCNonGC(LV, NonGCable);
     return LV;
@@ -708,7 +711,8 @@
     if (VD->getType()->isReferenceType())
       V = Builder.CreateLoad(V, "tmp");
     LValue LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(),
-                                 getContext().getObjCGCAttrKind(E->getType()));
+                                 getContext().getObjCGCAttrKind(E->getType()),
+                                 E->getType().getAddressSpace());
     if (LV.isObjCStrong())
       LV.SetGlobalObjCRef(LV, true);
     return LV;
@@ -727,14 +731,16 @@
       }
     }
     return LValue::MakeAddr(V, E->getType().getCVRQualifiers(),
-                            getContext().getObjCGCAttrKind(E->getType()));
+                            getContext().getObjCGCAttrKind(E->getType()),
+                            E->getType().getAddressSpace());
   }
   else if (const ImplicitParamDecl *IPD =
       dyn_cast<ImplicitParamDecl>(E->getDecl())) {
     llvm::Value *V = LocalDeclMap[IPD];
     assert(V && "BlockVarDecl not entered in LocalDeclMap?");
     return LValue::MakeAddr(V, E->getType().getCVRQualifiers(),
-                            getContext().getObjCGCAttrKind(E->getType()));
+                            getContext().getObjCGCAttrKind(E->getType()),
+                            E->getType().getAddressSpace());
   }
   assert(0 && "Unimp declref");
   //an invalid LValue, but the assert will
@@ -745,7 +751,8 @@
 LValue CodeGenFunction::EmitBlockDeclRefLValue(const BlockDeclRefExpr *E) {
   return LValue::MakeAddr(GetAddrOfBlockDecl(E), 
                           E->getType().getCVRQualifiers(),
-                          getContext().getObjCGCAttrKind(E->getType()));
+                          getContext().getObjCGCAttrKind(E->getType()),
+                          E->getType().getAddressSpace());
 }
 
 LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
@@ -763,7 +770,8 @@
         
       LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()),
                                    T.getCVRQualifiers(), 
-                                   getContext().getObjCGCAttrKind(T));
+                                   getContext().getObjCGCAttrKind(T),
+                                   ExprTy.getAddressSpace());
      // We should not generate __weak write barrier on indirect reference
      // of a pointer to object; as in void foo (__weak id *param); *param = 0;
      // But, we continue to generate __strong write barrier on indirect write
@@ -780,7 +788,9 @@
     unsigned Idx = E->getOpcode() == UnaryOperator::Imag;
     return LValue::MakeAddr(Builder.CreateStructGEP(LV.getAddress(),
                                                     Idx, "idx"),
-                            ExprTy.getCVRQualifiers());
+                            ExprTy.getCVRQualifiers(),
+                            QualType::GCNone,
+                            ExprTy.getAddressSpace());
   }
 }
 
@@ -906,7 +916,8 @@
     
   LValue LV = LValue::MakeAddr(Address,
                                T.getCVRQualifiers(),
-                               getContext().getObjCGCAttrKind(T));
+                               getContext().getObjCGCAttrKind(T),
+                               E->getBase()->getType().getAddressSpace());
   if (getContext().getLangOptions().ObjC1 &&
       getContext().getLangOptions().getGCMode() != LangOptions::NonGC)
     LValue::SetObjCNonGC(LV, !E->isOBJCGCCandidate(getContext()));
@@ -936,7 +947,9 @@
   } else {
     const PointerType *PT = E->getBase()->getType()->getAsPointerType();
     llvm::Value *Ptr = EmitScalarExpr(E->getBase());
-    Base = LValue::MakeAddr(Ptr, PT->getPointeeType().getCVRQualifiers());
+    Base = LValue::MakeAddr(Ptr, PT->getPointeeType().getCVRQualifiers(),
+                            QualType::GCNone,
+                            PT->getPointeeType().getAddressSpace());
   }
 
   // Encode the element access list into a vector of unsigned indices.
@@ -1076,7 +1089,8 @@
   LValue LV =  
     LValue::MakeAddr(V, 
                      Field->getType().getCVRQualifiers()|CVRQualifiers,
-                     attr);
+                     attr,
+                     Field->getType().getAddressSpace());
   return LV;
 }
 
@@ -1085,7 +1099,9 @@
   llvm::Value *DeclPtr = CreateTempAlloca(LTy, ".compoundliteral");
 
   const Expr* InitExpr = E->getInitializer();
-  LValue Result = LValue::MakeAddr(DeclPtr, E->getType().getCVRQualifiers());
+  LValue Result = LValue::MakeAddr(DeclPtr, E->getType().getCVRQualifiers(),
+                                   QualType::GCNone,
+                                   E->getType().getAddressSpace());
 
   if (E->getType()->isComplexType()) {
     EmitComplexExprIntoAddr(InitExpr, DeclPtr, false);
@@ -1112,7 +1128,8 @@
   EmitAggExpr(E, Temp, false);
 
   return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(),
-                          getContext().getObjCGCAttrKind(E->getType()));
+                          getContext().getObjCGCAttrKind(E->getType()),
+                          E->getType().getAddressSpace());
  
 }
 
@@ -1136,7 +1153,8 @@
   EmitAnyExpr(E->getSubExpr(), Temp, false);
   
   return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(),
-                          getContext().getObjCGCAttrKind(E->getType()));
+                          getContext().getObjCGCAttrKind(E->getType()),
+                          E->getType().getAddressSpace());
 }
 
 //===--------------------------------------------------------------------===//
@@ -1187,7 +1205,8 @@
   EmitAggExpr(E, Temp, false);
   // FIXME: Are these qualifiers correct?
   return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(),
-                          getContext().getObjCGCAttrKind(E->getType()));
+                          getContext().getObjCGCAttrKind(E->getType()),
+                          E->getType().getAddressSpace());
 }
 
 LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
@@ -1199,19 +1218,22 @@
            "reference type!");
     
     return LValue::MakeAddr(RV.getScalarVal(), E->getType().getCVRQualifiers(), 
-                            getContext().getObjCGCAttrKind(E->getType()));
+                            getContext().getObjCGCAttrKind(E->getType()),
+                            E->getType().getAddressSpace());
   }
   
   return LValue::MakeAddr(RV.getAggregateAddr(),
                           E->getType().getCVRQualifiers(),
-                          getContext().getObjCGCAttrKind(E->getType()));
+                          getContext().getObjCGCAttrKind(E->getType()),
+                          E->getType().getAddressSpace());
 }
 
 LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) {
   // FIXME: This shouldn't require another copy.
   llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
   EmitAggExpr(E, Temp, false);
-  return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers());
+  return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(),
+                          QualType::GCNone, E->getType().getAddressSpace());
 }
 
 LValue
@@ -1223,7 +1245,8 @@
 LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
   llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), "tmp");
   EmitCXXConstructExpr(Temp, E);
-  return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers());
+  return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(),
+                          QualType::GCNone, E->getType().getAddressSpace());
 }
 
 LValue
@@ -1241,7 +1264,8 @@
   // FIXME: can this be volatile?
   return LValue::MakeAddr(RV.getAggregateAddr(),
                           E->getType().getCVRQualifiers(),
-                          getContext().getObjCGCAttrKind(E->getType()));
+                          getContext().getObjCGCAttrKind(E->getType()),
+                          E->getType().getAddressSpace());
 }
 
 llvm::Value *CodeGenFunction::EmitIvarOffset(const ObjCInterfaceDecl *Interface,
@@ -1304,7 +1328,8 @@
   // FIXME: can this be volatile?
   return LValue::MakeAddr(RV.getAggregateAddr(),
                           E->getType().getCVRQualifiers(),
-                          getContext().getObjCGCAttrKind(E->getType()));
+                          getContext().getObjCGCAttrKind(E->getType()),
+                          E->getType().getAddressSpace());
 }
 
 
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index e4192d6..32e5afc 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -173,7 +173,8 @@
         CGF.getContext().getPointerType(E->getSubExpr()->getType());
     llvm::Value *CastPtr = Builder.CreateBitCast(DestPtr,
                                                  CGF.ConvertType(PtrTy));
-    EmitInitializationToLValue(E->getSubExpr(), LValue::MakeAddr(CastPtr, 0));
+    EmitInitializationToLValue(E->getSubExpr(),
+                               LValue::MakeAddr(CastPtr, 0));
     return;
   }
 
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index 820e1bd..9e93708 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -163,7 +163,8 @@
   // objective-c's gc attributes
   unsigned ObjCType : 2;  
 
-  
+  // address space
+  unsigned AddressSpace;
 
 private:
   static void SetQualifiers(unsigned Qualifiers, LValue& R) {
@@ -195,7 +196,9 @@
   bool isGlobalObjCRef() const { return GlobalObjCRef; }
   bool isObjCWeak() const { return ObjCType == Weak; }
   bool isObjCStrong() const { return ObjCType == Strong; }
-  
+
+  unsigned getAddressSpace() const { return AddressSpace; }
+
   static void SetObjCIvar(LValue& R, bool iValue) {
     R.Ivar = iValue;
   }
@@ -254,11 +257,13 @@
   }
 
   static LValue MakeAddr(llvm::Value *V, unsigned Qualifiers,
-                         QualType::GCAttrTypes GCAttrs = QualType::GCNone) {
+                         QualType::GCAttrTypes GCAttrs = QualType::GCNone,
+                         unsigned AddressSpace = 0) {
     LValue R;
     R.LVType = Simple;
     R.V = V;
     SetQualifiers(Qualifiers,R);
+    R.AddressSpace = AddressSpace;
     SetObjCType(GCAttrs, R);
     return R;
   }
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 145a928..6ad2040 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -794,6 +794,7 @@
   // Build the implicit member references to the field of the
   // anonymous struct/union.
   Expr *Result = BaseObjectExpr;
+  unsigned BaseAddrSpace = BaseObjectExpr->getType().getAddressSpace();
   for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator
          FI = AnonFields.rbegin(), FIEnd = AnonFields.rend();
        FI != FIEnd; ++FI) {
@@ -803,6 +804,8 @@
         = MemberType.getCVRQualifiers() | ExtraQuals;
       MemberType = MemberType.getQualifiedType(combinedQualifiers);
     }
+    if (BaseAddrSpace != MemberType.getAddressSpace())
+      MemberType = Context.getAddrSpaceQualType(MemberType, BaseAddrSpace);
     MarkDeclarationReferenced(Loc, *FI);
     Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI,
                                       OpLoc, MemberType);
@@ -2175,16 +2178,18 @@
                                                         BaseExpr, OpLoc);
 
       // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
-      // FIXME: Handle address space modifiers
       QualType MemberType = FD->getType();
       if (const ReferenceType *Ref = MemberType->getAsReferenceType())
         MemberType = Ref->getPointeeType();
       else {
+        unsigned BaseAddrSpace = BaseType.getAddressSpace();
         unsigned combinedQualifiers =
           MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
         if (FD->isMutable())
           combinedQualifiers &= ~QualType::Const;
         MemberType = MemberType.getQualifiedType(combinedQualifiers);
+        if (BaseAddrSpace != MemberType.getAddressSpace())
+           MemberType = Context.getAddrSpaceQualType(MemberType, BaseAddrSpace);
       }
 
       MarkDeclarationReferenced(MemberLoc, FD);
diff --git a/test/CodeGen/address-space-field1.c b/test/CodeGen/address-space-field1.c
new file mode 100644
index 0000000..e7c655a
--- /dev/null
+++ b/test/CodeGen/address-space-field1.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc -emit-llvm < %s -o %t &&
+// RUN: grep addrspace\(1\) %t | count 9 &&
+// RUN: grep addrspace\(2\) %t | count 9
+
+// Check that we don't lose the address space when accessing a member
+// of a structure.
+
+#define __addr1    __attribute__((address_space(1)))
+#define __addr2    __attribute__((address_space(2)))
+
+typedef struct S {
+  int a;
+  int b;
+} S;
+
+void test_addrspace(__addr1 S* p1, __addr2 S*p2) {
+  // swap
+  p1->a = p2->b;
+  p1->b = p2->a;
+}
diff --git a/test/CodeGen/address-space-field2.c b/test/CodeGen/address-space-field2.c
new file mode 100644
index 0000000..8b09d57
--- /dev/null
+++ b/test/CodeGen/address-space-field2.c
@@ -0,0 +1,22 @@
+// RUN: clang-cc -emit-llvm < %s -o %t &&
+// RUN: grep addrspace\(1\) %t | count 8 &&
+// RUN: grep addrspace\(2\) %t | count 9
+
+// Check that we don't lose the address space when accessing an array element
+// inside a structure.
+
+#define __addr1    __attribute__((address_space(1)))
+#define __addr2    __attribute__((address_space(2)))
+
+typedef struct S {
+  int arr[ 3 ];
+} S;
+
+void test_addrspace(__addr1 S* p1, __addr2 S*p2, int* val, int n) {
+  for (int i=0; i < 3; ++i) {
+    int t = val[i];
+    p1->arr[i] = t;
+    for (int j=0; j < n; ++j)
+      p2[j].arr[i] = t;
+  }
+}
diff --git a/test/CodeGen/address-space-field3.c b/test/CodeGen/address-space-field3.c
new file mode 100644
index 0000000..f0b9dba
--- /dev/null
+++ b/test/CodeGen/address-space-field3.c
@@ -0,0 +1,20 @@
+// RUN: clang-cc -emit-llvm < %s -o %t &&
+// RUN: grep addrspace\(1\) %t | count 8 &&
+// RUN: grep addrspace\(2\) %t | count 8
+
+// Check that we don't lose the address space when accessing an array element
+// inside a structure.
+
+#define __addr1    __attribute__((address_space(1)))
+#define __addr2    __attribute__((address_space(2)))
+
+typedef struct S {
+  int arr[ 3 ];
+} S;
+
+void test_addrspace(__addr1 S* p1, __addr2 S*p2, int* val, int n) {
+  for (int i=0; i < 3; ++i) {
+    int t = val[i];
+    p1->arr[i] = p2->arr[i];
+  }
+}
diff --git a/test/CodeGen/address-space-field4.c b/test/CodeGen/address-space-field4.c
new file mode 100644
index 0000000..d258f61
--- /dev/null
+++ b/test/CodeGen/address-space-field4.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc -emit-llvm < %s -o %t &&
+// RUN: grep addrspace\(2\) %t | count 4
+// RUN: grep addrspace\(3\) %t | count 4
+
+// Check the load and store are using the correct address space to access
+// the variables.
+
+#define __addr1    __attribute__((address_space(1)))
+#define __addr2    __attribute__((address_space(2)))
+#define __addr3    __attribute__((address_space(3)))
+
+typedef struct Pair {
+  __addr2 int* a;
+  __addr3 int* b;
+} Pair;
+
+typedef struct S {
+  Pair arr[ 3 ];
+} S;
+
+void test_addrspace(__addr1 S* p1, __addr1 S* p2) {
+  *p1->arr[0].a = *p2->arr[1].b;
+}