From c7b5154d6de53e57bf2a04bf098dc555233f8ca5 Mon Sep 17 00:00:00 2001
From: YakoYakoYokuYoku <gc1000ll@gmail.com>
Date: Thu, 11 Jul 2019 09:24:24 -0300
Subject: [PATCH 1/2] recovering from nightly crash

---
 src/librustc_codegen_llvm/abi.rs           |  20 +--
 src/librustc_codegen_llvm/builder.rs       |  88 ++++++++--
 src/librustc_codegen_llvm/common.rs        |  43 ++++-
 src/librustc_codegen_llvm/consts.rs        |  65 ++++++--
 src/librustc_codegen_llvm/context.rs       | 154 ++++++++++++++++-
 src/librustc_codegen_llvm/debuginfo/gdb.rs |   3 +-
 src/librustc_codegen_llvm/declare.rs       |  19 ++-
 src/librustc_codegen_llvm/intrinsic.rs     |   8 +-
 src/librustc_codegen_llvm/llvm/ffi.rs      |  13 +-
 src/librustc_codegen_llvm/mono_item.rs     |   8 +-
 src/librustc_codegen_llvm/type_.rs         |  56 ++++++-
 src/librustc_codegen_llvm/type_of.rs       |   4 +-
 src/librustc_codegen_ssa/back/link.rs      |   2 +
 src/librustc_codegen_ssa/back/linker.rs    | 129 +++++++++++++++
 src/librustc_codegen_ssa/meth.rs           |   2 +-
 src/librustc_codegen_ssa/mir/block.rs      |  22 ++-
 src/librustc_codegen_ssa/mir/mod.rs        |   7 +-
 src/librustc_codegen_ssa/mir/place.rs      |  14 +-
 src/librustc_codegen_ssa/mir/rvalue.rs     |  43 ++++-
 src/librustc_codegen_ssa/traits/builder.rs |  12 +-
 src/librustc_codegen_ssa/traits/consts.rs  |  10 +-
 src/librustc_codegen_ssa/traits/declare.rs |  10 +-
 src/librustc_codegen_ssa/traits/misc.rs    |   8 +
 src/librustc_codegen_ssa/traits/mod.rs     |  13 ++
 src/librustc_codegen_ssa/traits/type_.rs   |  80 ++++++++-
 src/librustc_target/abi/mod.rs             | 163 ++++++++++++++++--
 src/librustc_target/spec/mod.rs            | 184 ++++++++++++++++++++-
 src/rustllvm/RustWrapper.cpp               |  26 ++-
 28 files changed, 1084 insertions(+), 122 deletions(-)

diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index ff87afe0c444b..e51bd34f50a45 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -11,7 +11,7 @@ use rustc_target::abi::call::ArgType;
 
 use rustc_codegen_ssa::traits::*;
 
-use rustc_target::abi::{HasDataLayout, LayoutOf};
+use rustc_target::abi::LayoutOf;
 use rustc::ty::{Ty};
 use rustc::ty::layout::{self};
 
@@ -302,7 +302,7 @@ impl ArgTypeMethods<'tcx> for Builder<'a, 'll, 'tcx> {
 
 pub trait FnTypeLlvmExt<'tcx> {
     fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
-    fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
+    // fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn llvm_cconv(&self) -> llvm::CallConv;
     fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value);
     fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
@@ -323,11 +323,11 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
             PassMode::Ignore(IgnoreMode::CVarArgs) =>
                 bug!("`va_list` should never be a return type"),
             PassMode::Direct(_) | PassMode::Pair(..) => {
-                self.ret.layout.immediate_llvm_type(cx)
+                self.ret.layout.immediate_llvm_type(cx).copy_addr_space(cx.flat_addr_space())
             }
             PassMode::Cast(cast) => cast.llvm_type(cx),
             PassMode::Indirect(..) => {
-                llargument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
+                llargument_tys.push(cx.type_ptr_to_alloca(self.ret.memory_ty(cx)));
                 cx.type_void()
             }
         };
@@ -340,7 +340,8 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
 
             let llarg_ty = match arg.mode {
                 PassMode::Ignore(_) => continue,
-                PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx),
+                PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx)
+                    .copy_addr_space(cx.flat_addr_space()),
                 PassMode::Pair(..) => {
                     llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true));
                     llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
@@ -354,7 +355,7 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
                     continue;
                 }
                 PassMode::Cast(cast) => cast.llvm_type(cx),
-                PassMode::Indirect(_, None) => cx.type_ptr_to(arg.memory_ty(cx)),
+                PassMode::Indirect(_, None) => cx.type_ptr_to_alloca(arg.memory_ty(cx)),
             };
             llargument_tys.push(llarg_ty);
         }
@@ -366,13 +367,6 @@ impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
         }
     }
 
-    fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
-        unsafe {
-            llvm::LLVMPointerType(self.llvm_type(cx),
-                                  cx.data_layout().instruction_address_space as c_uint)
-        }
-    }
-
     fn llvm_cconv(&self) -> llvm::CallConv {
         match self.conv {
             Conv::C => llvm::CCallConv,
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 5ac1cf8c36f93..a343f6271c355 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -1,6 +1,6 @@
 use crate::llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope};
 use crate::llvm::{self, False, BasicBlock};
-use crate::common::Funclet;
+use crate::common::{Funclet, val_addr_space, val_addr_space_opt};
 use crate::context::CodegenCx;
 use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
@@ -18,7 +18,7 @@ use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::base::to_immediate;
 use rustc_codegen_ssa::mir::operand::{OperandValue, OperandRef};
 use rustc_codegen_ssa::mir::place::PlaceRef;
-use rustc_target::spec::{HasTargetSpec, Target};
+use rustc_target::spec::{HasTargetSpec, Target, AddrSpaceIdx};
 use std::borrow::Cow;
 use std::ffi::CStr;
 use std::ops::{Deref, Range};
@@ -215,7 +215,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         funclet: Option<&Funclet<'ll>>,
     ) -> &'ll Value {
 
-        debug!("invoke {:?} with args ({:?})",
+        debug!("Invoke {:?} with args ({:?})",
                llfn,
                args);
 
@@ -548,6 +548,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         let count = self.const_usize(count);
         let start = dest.project_index(&mut self, zero).llval;
         let end = dest.project_index(&mut self, count).llval;
+        let start = self.flat_addr_cast(start);
+        let end = self.flat_addr_cast(end);
 
         let mut header_bx = self.build_sibling_block("repeat_loop_header");
         let mut body_bx = self.build_sibling_block("repeat_loop_body");
@@ -724,23 +726,56 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn ptrtoint(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
+        let val = self.flat_addr_cast(val);
         unsafe {
             llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty, UNNAMED)
         }
     }
 
     fn inttoptr(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
+        let dest_ty = dest_ty.copy_addr_space(self.cx().flat_addr_space());
         unsafe {
             llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty, UNNAMED)
         }
     }
 
     fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
+        let dest_ty = dest_ty.copy_addr_space(val_addr_space(val));
         unsafe {
             llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED)
         }
     }
 
+    fn as_ptr_cast(
+        &mut self, val: &'ll Value,
+        addr_space: AddrSpaceIdx, dest_ty: &'ll Type
+    ) -> &'ll Value {
+        let val = self.addrspace_cast(val, addr_space);
+        self.pointercast(val, dest_ty.copy_addr_space(addr_space))
+    }
+
+    fn flat_as_ptr_cast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
+        self.as_ptr_cast(val, self.cx().flat_addr_space(), dest_ty)
+    }
+
+    fn addrspace_cast(&mut self, val: &'ll Value, dest: AddrSpaceIdx) -> &'ll Value {
+        let src_ty = self.cx().val_ty(val);
+
+        if src_ty.is_ptr() && src_ty.address_space() != dest {
+            let dest_ty = src_ty.copy_addr_space(dest);
+            self.cx().check_addr_space_cast(val, dest_ty);
+            unsafe {
+                llvm::LLVMBuildAddrSpaceCast(self.llbuilder, val,
+                                             dest_ty, UNNAMED)
+            }
+        } else {
+            val
+        }
+    }
+
+    fn flat_addr_cast(&mut self, val: &'ll Value) -> &'ll Value {
+        self.addrspace_cast(val, self.cx().flat_addr_space())
+    }
 
     fn intcast(&mut self, val: &'ll Value, dest_ty: &'ll Type, is_signed: bool) -> &'ll Value {
         unsafe {
@@ -749,6 +784,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn pointercast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
+        let dest_ty = dest_ty.copy_addr_space(val_addr_space(val));
         unsafe {
             llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty, UNNAMED)
         }
@@ -757,6 +793,16 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     /* Comparisons */
     fn icmp(&mut self, op: IntPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
         let op = llvm::IntPredicate::from_generic(op);
+
+        match (val_addr_space_opt(lhs), val_addr_space_opt(rhs)) {
+            (Some(l), Some(r)) if l == r => {},
+            (Some(l), Some(r)) if l != r => {
+                bug!("Tried to compare pointers of different address spaces: lhs {:?} rhs {:?}",
+                     lhs, rhs);
+            },
+            _ => {},
+        }
+
         unsafe {
             llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, UNNAMED)
         }
@@ -818,7 +864,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         flags: MemFlags,
     ) {
         let ptr_width = &self.sess().target.target.target_pointer_width;
-        let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width);
+        let addr_space = self.val_ty(ptr).address_space();
+        let intrinsic_key = format!("llvm.memset.p{}i8.i{}", addr_space, ptr_width);
         let llintrinsicfn = self.get_intrinsic(&intrinsic_key);
         let ptr = self.pointercast(ptr, self.type_i8p());
         let align = self.const_u32(align.bytes() as u32);
@@ -1035,7 +1082,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         funclet: Option<&Funclet<'ll>>,
     ) -> &'ll Value {
 
-        debug!("call {:?} with args ({:?})",
+        debug!("Call {:?} with args ({:?})",
                llfn,
                args);
 
@@ -1231,14 +1278,15 @@ impl Builder<'a, 'll, 'tcx> {
     fn check_store(&mut self, val: &'ll Value, ptr: &'ll Value) -> &'ll Value {
         let dest_ptr_ty = self.cx.val_ty(ptr);
         let stored_ty = self.cx.val_ty(val);
-        let stored_ptr_ty = self.cx.type_ptr_to(stored_ty);
+        let stored_ptr_ty = self.cx.type_as_ptr_to(stored_ty,
+                                                   dest_ptr_ty.address_space());
 
         assert_eq!(self.cx.type_kind(dest_ptr_ty), TypeKind::Pointer);
 
         if dest_ptr_ty == stored_ptr_ty {
             ptr
         } else {
-            debug!("type mismatch in store. \
+            debug!("Type mismatch in store. \
                     Expected {:?}, got {:?}; inserting bitcast",
                    dest_ptr_ty, stored_ptr_ty);
             self.bitcast(ptr, stored_ptr_ty)
@@ -1274,10 +1322,21 @@ impl Builder<'a, 'll, 'tcx> {
             .map(|(i, (expected_ty, &actual_val))| {
                 let actual_ty = self.val_ty(actual_val);
                 if expected_ty != actual_ty {
-                    debug!("type mismatch in function call of {:?}. \
+                    debug!("Type mismatch in function call of {:?}. \
                             Expected {:?} for param {}, got {:?}; injecting bitcast",
                            llfn, expected_ty, i, actual_ty);
-                    self.bitcast(actual_val, expected_ty)
+                    if expected_ty.is_ptr() && actual_ty.is_ptr() {
+                        let actual_val = self.addrspace_cast(actual_val,
+                                                             expected_ty.address_space());
+                        self.pointercast(actual_val, expected_ty)
+                    } else {
+                        let actual_val = if actual_ty.is_ptr() {
+                            self.flat_addr_cast(actual_val)
+                        } else {
+                            actual_val
+                        };
+                        self.bitcast(actual_val, expected_ty)
+                    }
                 } else {
                     actual_val
                 }
@@ -1303,7 +1362,16 @@ impl Builder<'a, 'll, 'tcx> {
             return;
         }
 
-        let lifetime_intrinsic = self.cx.get_intrinsic(intrinsic);
+        let addr_space = self.cx.val_ty(ptr).address_space();
+        // Old LLVMs don't have the address space specific intrinsics.
+        // So as a semi-crude workaround, don't specialize if in the
+        // default address space.
+        let lifetime_intrinsic = if let AddrSpaceIdx(0) = addr_space {
+            self.cx.get_intrinsic(intrinsic)
+        } else {
+            let intrinsic = format!("{}.p{}i8", intrinsic, addr_space);
+            self.cx.get_intrinsic(&intrinsic)
+        };
 
         let ptr = self.pointercast(ptr, self.cx.type_i8p());
         self.call(lifetime_intrinsic, &[self.cx.const_u64(size), ptr], None);
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index e9f25e6344b06..9a6de7f2bb36f 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -13,7 +13,9 @@ use rustc_codegen_ssa::traits::*;
 use crate::consts::const_alloc_to_llvm;
 use rustc::ty::layout::{HasDataLayout, LayoutOf, self, TyLayout, Size, Align};
 use rustc::mir::interpret::{Scalar, GlobalAlloc, Allocation};
+use rustc_codegen_ssa::common::TypeKind;
 use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_target::spec::AddrSpaceIdx;
 
 use libc::{c_uint, c_char};
 
@@ -135,9 +137,9 @@ impl CodegenCx<'ll, 'tcx> {
                                                     s.len() as c_uint,
                                                     !null_terminated as Bool);
             let sym = self.generate_local_symbol_name("str");
-            let g = self.define_global(&sym[..], self.val_ty(sc)).unwrap_or_else(||{
-                bug!("symbol `{}` is already defined", sym);
-            });
+            let addr_space = self.const_addr_space();
+            let g = self.define_global(&sym[..], self.val_ty(sc), addr_space)
+                .unwrap_or_else(||bug!("symbol `{}` is already defined", sym) );
             llvm::LLVMSetInitializer(g, sc);
             llvm::LLVMSetGlobalConstant(g, True);
             llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
@@ -290,6 +292,10 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         }
     }
 
+    fn const_as_cast(&self, val: &'ll Value, addr_space: AddrSpaceIdx) -> &'ll Value {
+        self.const_addrcast(val, addr_space)
+    }
+
     fn scalar_to_backend(
         &self,
         cv: Scalar,
@@ -305,10 +311,16 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             Scalar::Raw { data, size } => {
                 assert_eq!(size as u64, layout.value.size(self).bytes());
                 let llval = self.const_uint_big(self.type_ix(bitsize), data);
-                if layout.value == layout::Pointer {
-                    unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
+                let flat_llty = llty.copy_addr_space(self.flat_addr_space());
+                let llval = if layout.value == layout::Pointer {
+                    unsafe { llvm::LLVMConstIntToPtr(llval, flat_llty) }
                 } else {
-                    self.const_bitcast(llval, llty)
+                    self.const_bitcast(llval, flat_llty)
+                };
+                if llty.is_ptr() {
+                    self.const_as_cast(llval, llty.address_space())
+                } else {
+                    llval
                 }
             },
             Scalar::Ptr(ptr) => {
@@ -317,7 +329,8 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                     Some(GlobalAlloc::Memory(alloc)) => {
                         let init = const_alloc_to_llvm(self, alloc);
                         if alloc.mutability == Mutability::Mutable {
-                            self.static_addr_of_mut(init, alloc.align, None)
+                            self.static_addr_of_mut(init, alloc.align, None,
+                                                    self.mutable_addr_space())
                         } else {
                             self.static_addr_of(init, alloc.align, None)
                         }
@@ -331,11 +344,12 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                     }
                     None => bug!("missing allocation {:?}", ptr.alloc_id),
                 };
-                let llval = unsafe { llvm::LLVMConstInBoundsGEP(
+                let llval_ref = unsafe { llvm::LLVMConstInBoundsGEP(
                     self.const_bitcast(base_addr, self.type_i8p()),
                     &self.const_usize(ptr.offset.bytes()),
                     1,
                 ) };
+                let llval = self.const_flat_as_cast(llval_ref);
                 if layout.value != layout::Pointer {
                     unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
                 } else {
@@ -375,6 +389,19 @@ pub fn val_ty(v: &'ll Value) -> &'ll Type {
     }
 }
 
+pub fn val_addr_space_opt(v: &'ll Value) -> Option<AddrSpaceIdx> {
+    let ty = val_ty(v);
+    if ty.kind() == TypeKind::Pointer {
+        Some(ty.address_space())
+    } else {
+        None
+    }
+}
+
+pub fn val_addr_space(v: &'ll Value) -> AddrSpaceIdx {
+    val_addr_space_opt(v).unwrap_or_default()
+}
+
 pub fn bytes_in_context(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value {
     unsafe {
         let ptr = bytes.as_ptr() as *const c_char;
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index e02d14a151e62..a62b8514cef8c 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -1,6 +1,6 @@
 use crate::llvm::{self, SetUnnamedAddr, True};
 use crate::debuginfo;
-use crate::common::CodegenCx;
+use crate::common::{CodegenCx, val_addr_space, val_addr_space_opt};
 use crate::base;
 use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
@@ -12,7 +12,7 @@ use rustc::mir::interpret::{ConstValue, Allocation, read_target_uint,
 use rustc::mir::mono::MonoItem;
 use rustc::hir::Node;
 use syntax_pos::Span;
-use rustc_target::abi::HasDataLayout;
+use rustc_target::{abi::HasDataLayout, spec::AddrSpaceIdx};
 use syntax::symbol::sym;
 use syntax_pos::symbol::LocalInternedString;
 use rustc::ty::{self, Ty, Instance};
@@ -124,7 +124,7 @@ fn check_and_apply_linkage(
         };
         unsafe {
             // Declare a symbol `foo` with the desired linkage.
-            let g1 = cx.declare_global(&sym, llty2);
+            let g1 = cx.declare_global(&sym, llty2, cx.flat_addr_space());
             llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
 
             // Declare an internal global `extern_with_linkage_foo` which
@@ -135,9 +135,10 @@ fn check_and_apply_linkage(
             // zero.
             let mut real_name = "_rust_extern_with_linkage_".to_string();
             real_name.push_str(&sym);
-            let g2 = cx.define_global(&real_name, llty).unwrap_or_else(||{
-                cx.sess().span_fatal(span, &format!("symbol `{}` is already defined", &sym))
-            });
+            let g2 = cx.define_global(&real_name, llty, cx.flat_addr_space())
+                .unwrap_or_else(||{
+                    cx.sess().span_fatal(span, &format!("symbol `{}` is already defined", &sym))
+                });
             llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
             llvm::LLVMSetInitializer(g2, g1);
             g2
@@ -145,11 +146,12 @@ fn check_and_apply_linkage(
     } else {
         // Generate an external declaration.
         // FIXME(nagisa): investigate whether it can be changed into define_global
-        cx.declare_global(&sym, llty)
+        cx.declare_global(&sym, llty, cx.flat_addr_space())
     }
 }
 
 pub fn ptrcast(val: &'ll Value, ty: &'ll Type) -> &'ll Value {
+    let ty = ty.copy_addr_space(val_addr_space(val));
     unsafe {
         llvm::LLVMConstPointerCast(val, ty)
     }
@@ -157,29 +159,48 @@ pub fn ptrcast(val: &'ll Value, ty: &'ll Type) -> &'ll Value {
 
 impl CodegenCx<'ll, 'tcx> {
     crate fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
+        let ty = if let Some(addr_space) = val_addr_space_opt(val) {
+            ty.copy_addr_space(addr_space)
+        } else {
+            ty
+        };
         unsafe {
             llvm::LLVMConstBitCast(val, ty)
         }
     }
 
+    crate fn const_addrcast(&self, val: &'ll Value, addr_space: AddrSpaceIdx) -> &'ll Value {
+        let src_ty = self.val_ty(val);
+        if src_ty.is_ptr() && src_ty.address_space() != addr_space {
+            let dest_ty = src_ty.copy_addr_space(addr_space);
+            self.check_addr_space_cast(val, dest_ty);
+            unsafe {
+                llvm::LLVMConstAddrSpaceCast(val, dest_ty)
+            }
+        } else {
+            val
+        }
+    }
+
     crate fn static_addr_of_mut(
         &self,
         cv: &'ll Value,
         align: Align,
         kind: Option<&str>,
+        addr_space: AddrSpaceIdx,
     ) -> &'ll Value {
         unsafe {
             let gv = match kind {
                 Some(kind) if !self.tcx.sess.fewer_names() => {
                     let name = self.generate_local_symbol_name(kind);
                     let gv = self.define_global(&name[..],
-                        self.val_ty(cv)).unwrap_or_else(||{
+                        self.val_ty(cv), addr_space).unwrap_or_else(||{
                             bug!("symbol `{}` is already defined", name);
                     });
                     llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage);
                     gv
                 },
-                _ => self.define_private_global(self.val_ty(cv)),
+                _ => self.define_private_global(self.val_ty(cv), addr_space),
             };
             llvm::LLVMSetInitializer(gv, cv);
             set_global_alignment(&self, gv, align);
@@ -212,13 +233,18 @@ impl CodegenCx<'ll, 'tcx> {
             let llty = self.layout_of(ty).llvm_type(self);
             let (g, attrs) = match self.tcx.hir().get(id) {
                 Node::Item(&hir::Item {
-                    ref attrs, span, node: hir::ItemKind::Static(..), ..
+                    ref attrs, span, node: hir::ItemKind::Static(_, m, _), ..
                 }) => {
                     if self.get_declared_value(&sym[..]).is_some() {
                         span_bug!(span, "Conflicting symbol names for static?");
                     }
+                    let addr_space = if m == hir::MutMutable {
+                        self.mutable_addr_space()
+                    } else {
+                        self.const_addr_space()
+                    };
 
-                    let g = self.define_global(&sym[..], llty).unwrap();
+                    let g = self.define_global(&sym[..], llty, addr_space).unwrap();
 
                     if !self.tcx.is_reachable_non_generic(def_id) {
                         unsafe {
@@ -329,7 +355,8 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
             }
             return gv;
         }
-        let gv = self.static_addr_of_mut(cv, align, kind);
+        let gv = self.static_addr_of_mut(cv, align, kind,
+                                         self.const_addr_space());
         unsafe {
             llvm::LLVMSetGlobalConstant(gv, True);
         }
@@ -365,6 +392,9 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
 
             let instance = Instance::mono(self.tcx, def_id);
             let ty = instance.ty(self.tcx);
+
+            let llvm_mutable = is_mutable || !self.type_is_freeze(ty);
+
             let llty = self.layout_of(ty).llvm_type(self);
             let g = if val_llty == llty {
                 g
@@ -379,8 +409,15 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
                 let linkage = llvm::LLVMRustGetLinkage(g);
                 let visibility = llvm::LLVMRustGetVisibility(g);
 
+                let addr_space = if llvm_mutable {
+                    self.mutable_addr_space()
+                } else {
+                    self.const_addr_space()
+                };
+
                 let new_g = llvm::LLVMRustGetOrInsertGlobal(
-                    self.llmod, name_string.as_ptr(), val_llty);
+                    self.llmod, name_string.as_ptr(), val_llty,
+                    addr_space.0);
 
                 llvm::LLVMRustSetLinkage(new_g, linkage);
                 llvm::LLVMRustSetVisibility(new_g, visibility);
@@ -396,7 +433,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
 
             // As an optimization, all shared statics which do not have interior
             // mutability are placed into read-only memory.
-            if !is_mutable {
+            if !llvm_mutable {
                 if self.type_is_freeze(ty) {
                     llvm::LLVMSetGlobalConstant(g, llvm::True);
                 }
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 2b68eb53a4ab9..82eed46ccebb7 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -6,7 +6,7 @@ use crate::value::Value;
 use rustc::dep_graph::DepGraphSafe;
 use rustc::hir;
 
-use crate::type_::Type;
+use crate::type_::{Type, AddrSpaceIdx, AddrSpaceKind};
 use rustc_codegen_ssa::traits::*;
 
 use rustc_data_structures::base_n;
@@ -19,7 +19,8 @@ use rustc::ty::layout::{
 };
 use rustc::ty::{self, Ty, TyCtxt, Instance};
 use rustc::util::nodemap::FxHashMap;
-use rustc_target::spec::{HasTargetSpec, Target};
+use rustc_target::abi::HasDataLayout;
+use rustc_target::spec::{HasTargetSpec, Target, AddrSpaceProps};
 use rustc_codegen_ssa::callee::resolve_and_get_fn;
 use rustc_codegen_ssa::base::wants_msvc_seh;
 use crate::callee::get_fn;
@@ -31,6 +32,7 @@ use std::str;
 use std::sync::Arc;
 use syntax::symbol::LocalInternedString;
 use crate::abi::Abi;
+use std::u32;
 
 /// There is one `CodegenCx` per compilation unit. Each one has its own LLVM
 /// `llvm::Context` so that several compilation units may be optimized in parallel.
@@ -81,13 +83,19 @@ pub struct CodegenCx<'ll, 'tcx> {
     pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
     pub isize_ty: &'ll Type,
 
+    alloca_addr_space: AddrSpaceIdx,
+    const_addr_space: AddrSpaceIdx,
+    mutable_addr_space: AddrSpaceIdx,
+    flat_addr_space: AddrSpaceIdx,
+    instruction_addr_space: AddrSpaceIdx,
+
     pub dbg_cx: Option<debuginfo::CrateDebugContext<'ll, 'tcx>>,
 
     eh_personality: Cell<Option<&'ll Value>>,
     eh_unwind_resume: Cell<Option<&'ll Value>>,
     pub rust_try_fn: Cell<Option<&'ll Value>>,
 
-    intrinsics: RefCell<FxHashMap<&'static str, &'ll Value>>,
+    intrinsics: RefCell<FxHashMap<String, &'ll Value>>,
 
     /// A counter that is used for generating local symbol names
     local_gen_sym_counter: Cell<usize>,
@@ -286,6 +294,28 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
 
         let isize_ty = Type::ix_llcx(llcx, tcx.data_layout.pointer_size.bits());
 
+        let alloca_addr_space = tcx.data_layout().alloca_address_space;
+        let mutable_addr_space =
+            tcx.sess.target.target.options.addr_spaces
+              .get(&AddrSpaceKind::ReadWrite)
+              .map(|v| v.index )
+              .unwrap_or_default();
+        let const_addr_space =
+            tcx.sess.target.target.options.addr_spaces
+              .get(&AddrSpaceKind::ReadOnly)
+              .map(|v| v.index )
+              .unwrap_or(mutable_addr_space);
+        let flat_addr_space =
+            tcx.sess.target.target.options.addr_spaces
+              .get(&AddrSpaceKind::Flat)
+              .map(|v| v.index )
+              .unwrap_or_default();
+        let instruction_addr_space =
+            tcx.sess.target.target.options.addr_spaces
+              .get(&AddrSpaceKind::Instruction)
+              .map(|v| v.index )
+              .unwrap_or_default();
+
         CodegenCx {
             tcx,
             check_overflow,
@@ -305,6 +335,13 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             scalar_lltypes: Default::default(),
             pointee_infos: Default::default(),
             isize_ty,
+
+            alloca_addr_space,
+            const_addr_space,
+            mutable_addr_space,
+            flat_addr_space,
+            instruction_addr_space,
+
             dbg_cx,
             eh_personality: Cell::new(None),
             eh_unwind_resume: Cell::new(None),
@@ -449,6 +486,36 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             llvm::LLVMSetSection(g, section.as_ptr());
         }
     }
+
+    fn can_cast_addr_space(&self, from: AddrSpaceIdx, to: AddrSpaceIdx) -> bool {
+        if from == to { return true; }
+
+        let bug = || {
+            bug!("no address space kind for {}", from);
+        };
+
+        let (to_kind, _) = self.addr_space_props_from_idx(to)
+          .unwrap_or_else(&bug);
+        let (_, from_props) = self.addr_space_props_from_idx(from)
+          .unwrap_or_else(&bug);
+
+        from_props.shared_with.contains(&to_kind)
+    }
+    fn inst_addr_space(&self) -> AddrSpaceIdx {
+        self.instruction_addr_space
+    }
+    fn alloca_addr_space(&self) -> AddrSpaceIdx {
+        self.alloca_addr_space
+    }
+    fn const_addr_space(&self) -> AddrSpaceIdx {
+        self.const_addr_space
+    }
+    fn mutable_addr_space(&self) -> AddrSpaceIdx {
+        self.mutable_addr_space
+    }
+    fn flat_addr_space(&self) -> AddrSpaceIdx {
+        self.flat_addr_space
+    }
 }
 
 impl CodegenCx<'b, 'tcx> {
@@ -470,7 +537,7 @@ impl CodegenCx<'b, 'tcx> {
         };
         let f = self.declare_cfn(name, fn_ty);
         llvm::SetUnnamedAddr(f, false);
-        self.intrinsics.borrow_mut().insert(name, f);
+        self.intrinsics.borrow_mut().insert(name.to_string(), f);
         f
     }
 
@@ -529,9 +596,57 @@ impl CodegenCx<'b, 'tcx> {
             t_v8f64: t_f64, 8;
         }
 
-        ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void);
-        ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
-        ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void);
+        // ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void);
+        // ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
+        // ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void);
+
+        fn parse_addr_space(s: &str) -> AddrSpaceIdx {
+            assert!(s.starts_with("p"));
+            assert!(s.ends_with("i8"));
+            let s = &s[1..];
+            let s = &s[..s.len() - 2];
+            AddrSpaceIdx(u32::from_str_radix(s, 10).unwrap())
+        }
+
+        if key.starts_with("llvm.memcpy") || key.starts_with("llvm.memmove") ||
+          key.starts_with("llvm.memset") {
+
+            let mut split = key.split('.');
+            assert_eq!(Some("llvm"), split.next());
+            let flavor = split.next();
+            let flavor = flavor.unwrap();
+
+            let dst_ptr_str = split.next();
+            assert!(dst_ptr_str.is_some());
+            let dst_ptr_str = dst_ptr_str.unwrap();
+            let dst_asp = parse_addr_space(dst_ptr_str);
+            let dst_ty = self.type_i8p_as(dst_asp);
+
+            let src_ty = if flavor != "memset" {
+                let src_ptr_str = split.next();
+                assert!(src_ptr_str.is_some());
+                let src_ptr_str = src_ptr_str.unwrap();
+                let src_asp = parse_addr_space(src_ptr_str);
+                self.type_i8p_as(src_asp)
+            } else {
+                t_i8
+            };
+
+            let len_ty = match split.next() {
+                Some("i16") => t_i16,
+                Some("i32") => t_i32,
+                Some("i64") => t_i64,
+                Some("i128") => t_i128,
+                l => {
+                    bug!("unknown llvm.{} intrinsic sig (len ty): {}, {:?}", flavor, key, l);
+                },
+            };
+            let fty = self.type_func(&[dst_ty, src_ty, len_ty, t_i32, i1], &void);
+            let f = self.declare_cfn(key, fty);
+            llvm::SetUnnamedAddr(f, false);
+            self.intrinsics.borrow_mut().insert(key.to_string(), f.clone());
+            return Some(f);
+        }
 
         ifn!("llvm.trap", fn() -> void);
         ifn!("llvm.debugtrap", fn() -> void);
@@ -799,6 +914,24 @@ impl CodegenCx<'b, 'tcx> {
         ifn!("llvm.lifetime.start", fn(t_i64,i8p) -> void);
         ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void);
 
+        if key.starts_with("llvm.lifetime") {
+            let mut split = key.split('.');
+            split.next(); split.next();
+
+            let _variant = split.next();
+
+            let addr_space = match split.next() {
+                Some(addr_space) => parse_addr_space(addr_space),
+                None => unreachable!(),
+            };
+
+            let fty = self.type_func(&[t_i64, self.type_i8p_as(addr_space)], &void);
+            let f = self.declare_cfn(key, fty);
+            llvm::SetUnnamedAddr(f, false);
+            self.intrinsics.borrow_mut().insert(key.to_string(), f.clone());
+            return Some(f);
+        }
+
         ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
         ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32);
         ifn!("llvm.localescape", fn(...) -> void);
@@ -835,6 +968,13 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
         base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name);
         name
     }
+
+    pub fn addr_space_props_from_idx(&self, idx: AddrSpaceIdx)
+        -> Option<(&AddrSpaceKind, &AddrSpaceProps)>
+    {
+        self.tcx.sess.target.target.options.addr_spaces.iter()
+          .find(|&(_, ref props)| props.index == idx )
+    }
 }
 
 impl ty::layout::HasDataLayout for CodegenCx<'ll, 'tcx> {
diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs
index 04c9e93c7a527..2c40f0961c23d 100644
--- a/src/librustc_codegen_llvm/debuginfo/gdb.rs
+++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs
@@ -48,8 +48,9 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>)
             let llvm_type = cx.type_array(cx.type_i8(),
                                         section_contents.len() as u64);
 
+            let addr_space = cx.flat_addr_space();
             let section_var = cx.define_global(section_var_name,
-                                                     llvm_type).unwrap_or_else(||{
+                                                     llvm_type, addr_space).unwrap_or_else(||{
                 bug!("symbol `{}` is already defined", section_var_name)
             });
             llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _);
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index 62eab0f3d4e69..aeaf866f579bf 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -18,11 +18,13 @@ use crate::attributes;
 use crate::context::CodegenCx;
 use crate::type_::Type;
 use crate::value::Value;
+use crate::common::val_ty;
 use rustc::ty::{self, PolyFnSig};
 use rustc::ty::layout::{FnTypeExt, LayoutOf};
 use rustc::session::config::Sanitizer;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_codegen_ssa::traits::*;
+use rustc_target::spec::AddrSpaceIdx;
 
 /// Declare a function.
 ///
@@ -39,6 +41,7 @@ fn declare_raw_fn(
     let llfn = unsafe {
         llvm::LLVMRustGetOrInsertFunction(cx.llmod, namebuf.as_ptr(), ty)
     };
+    assert_eq!(val_ty(llfn).address_space(), cx.inst_addr_space());
 
     llvm::SetFunctionCallConv(llfn, callconv);
     // Function addresses in Rust are never significant, allowing functions to
@@ -74,12 +77,15 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 
     fn declare_global(
         &self,
-        name: &str, ty: &'ll Type
+        name: &str,
+        ty: &'ll Type,
+        addr_space: AddrSpaceIdx,
     ) -> &'ll Value {
         debug!("declare_global(name={:?})", name);
         let namebuf = SmallCStr::new(name);
         unsafe {
-            llvm::LLVMRustGetOrInsertGlobal(self.llmod, namebuf.as_ptr(), ty)
+            llvm::LLVMRustGetOrInsertGlobal(self.llmod, namebuf.as_ptr(), ty,
+                                            addr_space.0)
         }
     }
 
@@ -115,18 +121,19 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     fn define_global(
         &self,
         name: &str,
-        ty: &'ll Type
+        ty: &'ll Type,
+        addr_space: AddrSpaceIdx
     ) -> Option<&'ll Value> {
         if self.get_defined_value(name).is_some() {
             None
         } else {
-            Some(self.declare_global(name, ty))
+            Some(self.declare_global(name, ty, addr_space))
         }
     }
 
-    fn define_private_global(&self, ty: &'ll Type) -> &'ll Value {
+    fn define_private_global(&self, ty: &'ll Type, addr_space: AddrSpaceIdx) -> &'ll Value {
         unsafe {
-            llvm::LLVMRustInsertPrivateGlobal(self.llmod, ty)
+            llvm::LLVMRustInsertPrivateGlobal(self.llmod, ty, addr_space.0)
         }
     }
 
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index dd6cfd7e29e4e..990490d3257d6 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -798,7 +798,9 @@ fn try_intrinsic(
     if bx.sess().no_landing_pads() {
         bx.call(func, &[data], None);
         let ptr_align = bx.tcx().data_layout.pointer_align.abi;
-        bx.store(bx.const_null(bx.type_i8p()), dest, ptr_align);
+        let addr_space = bx.type_addr_space(bx.val_ty(dest)).unwrap();
+        bx.store(bx.const_null(bx.type_i8p_as(addr_space)),
+                 dest, ptr_align);
     } else if wants_msvc_seh(bx.sess()) {
         codegen_msvc_try(bx, func, data, local_ptr, dest);
     } else {
@@ -962,10 +964,10 @@ fn codegen_gnu_try(
         // rust_try ignores the selector.
         let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false);
         let vals = catch.landing_pad(lpad_ty, bx.eh_personality(), 1);
-        catch.add_clause(vals, bx.const_null(bx.type_i8p()));
+        catch.add_clause(vals, bx.const_null(bx.type_flat_i8p()));
         let ptr = catch.extract_value(vals, 0);
         let ptr_align = bx.tcx().data_layout.pointer_align.abi;
-        let bitcast = catch.bitcast(local_ptr, bx.type_ptr_to(bx.type_i8p()));
+        let bitcast = catch.bitcast(local_ptr, bx.type_ptr_to(bx.type_flat_i8p()));
         catch.store(ptr, bitcast, ptr_align);
         catch.ret(bx.const_i32(1));
     });
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 2b22925f44969..c14b572a88256 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -690,6 +690,7 @@ extern "C" {
 
     pub fn LLVMGetElementType(Ty: &Type) -> &Type;
     pub fn LLVMGetVectorSize(VectorTy: &Type) -> c_uint;
+    pub fn LLVMGetPointerAddressSpace(Ty: &Type) -> c_uint;
 
     // Operations on other types
     pub fn LLVMVoidTypeInContext(C: &Context) -> &Type;
@@ -751,6 +752,7 @@ extern "C" {
     pub fn LLVMConstIntToPtr(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
     pub fn LLVMConstBitCast(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
     pub fn LLVMConstPointerCast(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
+    pub fn LLVMConstAddrSpaceCast(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
     pub fn LLVMConstExtractValue(AggConstant: &Value,
                                  IdxList: *const c_uint,
                                  NumIdx: c_uint)
@@ -772,8 +774,10 @@ extern "C" {
     pub fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>;
     pub fn LLVMAddGlobal(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value;
     pub fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>;
-    pub fn LLVMRustGetOrInsertGlobal(M: &'a Module, Name: *const c_char, T: &'a Type) -> &'a Value;
-    pub fn LLVMRustInsertPrivateGlobal(M: &'a Module, T: &'a Type) -> &'a Value;
+    pub fn LLVMRustGetOrInsertGlobal(M: &'a Module, Name: *const c_char, T: &'a Type,
+                                     AS: c_uint) -> &'a Value;
+    pub fn LLVMRustInsertPrivateGlobal(M: &'a Module, T: &'a Type,
+                                       AS: c_uint) -> &'a Value;
     pub fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>;
     pub fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>;
     pub fn LLVMDeleteGlobal(GlobalVar: &Value);
@@ -1150,6 +1154,11 @@ extern "C" {
                                 DestTy: &'a Type,
                                 Name: *const c_char)
                                 -> &'a Value;
+    pub fn LLVMBuildAddrSpaceCast(B: &Builder<'a>,
+                                  Val: &'a Value,
+                                  DestTy: &'a Type,
+                                  Name: *const c_char)
+                                  -> &'a Value;
     pub fn LLVMRustBuildIntCast(B: &Builder<'a>,
                                 Val: &'a Value,
                                 DestTy: &'a Type,
diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs
index c1703ffd0c753..ea663877d3dc0 100644
--- a/src/librustc_codegen_llvm/mono_item.rs
+++ b/src/librustc_codegen_llvm/mono_item.rs
@@ -3,6 +3,7 @@ use crate::base;
 use crate::context::CodegenCx;
 use crate::llvm;
 use crate::type_of::LayoutLlvmExt;
+use rustc::hir::def::DefKind;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::mir::mono::{Linkage, Visibility};
 use rustc::ty::{TypeFoldable, Instance};
@@ -21,7 +22,12 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         let ty = instance.ty(self.tcx);
         let llty = self.layout_of(ty).llvm_type(self);
 
-        let g = self.define_global(symbol_name, llty).unwrap_or_else(|| {
+        let addr_space = match self.tcx.def_kind(def_id) {
+          Some(DefKind::Static) => self.mutable_addr_space(),
+          _ => self.const_addr_space(),
+        };
+
+        let g = self.define_global(symbol_name, llty, addr_space).unwrap_or_else(|| {
             self.sess().span_fatal(self.tcx.def_span(def_id),
                 &format!("symbol `{}` is already defined", symbol_name))
         });
diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs
index 2c167256ad56c..5e67a7872c920 100644
--- a/src/librustc_codegen_llvm/type_.rs
+++ b/src/librustc_codegen_llvm/type_.rs
@@ -23,6 +23,8 @@ use std::ptr;
 
 use libc::c_uint;
 
+pub use rustc_target::spec::{AddrSpaceKind, AddrSpaceIdx};
+
 impl PartialEq for Type {
     fn eq(&self, other: &Self) -> bool {
         ptr::eq(self, other)
@@ -243,10 +245,8 @@ impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         }
     }
 
-    fn type_ptr_to(&self, ty: &'ll Type) -> &'ll Type {
-        assert_ne!(self.type_kind(ty), TypeKind::Function,
-                   "don't call ptr_to on function types, use ptr_to_llvm_type on FnType instead");
-        ty.ptr_to()
+    fn type_as_ptr_to(&self, ty: &'ll Type, addr_space: AddrSpaceIdx) -> &'ll Type {
+        ty.ptr_to(addr_space)
     }
 
     fn element_type(&self, ty: &'ll Type) -> &'ll Type {
@@ -280,6 +280,14 @@ impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     fn val_ty(&self, v: &'ll Value) -> &'ll Type {
         common::val_ty(v)
     }
+
+    fn type_addr_space(&self, ty: &'ll Type) -> Option<AddrSpaceIdx> {
+        if self.type_kind(ty) == TypeKind::Pointer {
+            Some(ty.address_space())
+        } else {
+            None
+        }
+    }
 }
 
 impl Type {
@@ -300,12 +308,43 @@ impl Type {
     }
 
     pub fn i8p_llcx(llcx: &'ll llvm::Context) -> &'ll Type {
-        Type::i8_llcx(llcx).ptr_to()
+        Type::i8_llcx(llcx).ptr_to(Default::default())
+    }
+
+    pub fn kind(&self) -> TypeKind {
+        unsafe {
+            llvm::LLVMRustGetTypeKind(self).to_generic()
+        }
+    }
+    pub fn is_ptr(&self) -> bool {
+        self.kind() == TypeKind::Pointer
     }
 
-    fn ptr_to(&self) -> &Type {
+    // fn ptr_to(&self) -> &Type {
+    fn element_type(&self) -> &Type {
         unsafe {
-            llvm::LLVMPointerType(&self, 0)
+            llvm::LLVMGetElementType(self)
+        }
+    }
+
+    fn ptr_to(&self, addr_space: AddrSpaceIdx) -> &Type {
+        unsafe {
+            llvm::LLVMPointerType(&self,
+                                  addr_space.0)
+        }
+    }
+    pub fn address_space(&self) -> AddrSpaceIdx {
+        AddrSpaceIdx(unsafe {
+            llvm::LLVMGetPointerAddressSpace(self)
+        })
+    }
+    pub fn copy_addr_space(&self, addr_space: AddrSpaceIdx) -> &Type {
+        if !self.is_ptr() { return self; }
+
+        if addr_space != self.address_space() {
+            self.element_type().ptr_to(addr_space)
+        } else {
+            self
         }
     }
 }
@@ -339,7 +378,8 @@ impl LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         ty.llvm_type(self)
     }
     fn fn_ptr_backend_type(&self, ty: &FnType<'tcx, Ty<'tcx>>) -> &'ll Type {
-        ty.ptr_to_llvm_type(self)
+        // ty.ptr_to_llvm_type(self)
+        self.type_as_ptr_to(ty.llvm_type(self), self.inst_addr_space())
     }
     fn reg_backend_type(&self, ty: &Reg) -> &'ll Type {
         ty.llvm_type(self)
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index 36a9ff0a2d2e5..21e7f41dce64e 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -229,10 +229,10 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
             let llty = match self.ty.sty {
                 ty::Ref(_, ty, _) |
                 ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
-                    cx.type_ptr_to(cx.layout_of(ty).llvm_type(cx))
+                    cx.type_ptr_to_flat(cx.layout_of(ty).llvm_type(cx))
                 }
                 ty::Adt(def, _) if def.is_box() => {
-                    cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx))
+                    cx.type_ptr_to_flat(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx))
                 }
                 ty::FnPtr(sig) => {
                     let sig = cx.tcx.normalize_erasing_late_bound_regions(
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 707b7cae16ce7..89f81b3413803 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -721,6 +721,8 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
                 LinkerFlavor::Ld => "ld",
                 LinkerFlavor::Msvc => "link.exe",
                 LinkerFlavor::Lld(_) => "lld",
+                // FIXME: Waiting till ready
+                // LinkerFlavor::AmdGpuLinker => "lld",
                 LinkerFlavor::PtxLinker => "rust-ptx-linker",
             }), flavor)),
             (Some(linker), None) => {
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index 32696d46cd577..053e76d8ac114 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -84,6 +84,11 @@ impl LinkerInfo {
                 Box::new(WasmLd::new(cmd, sess, self)) as Box<dyn Linker>
             }
 
+            // FIXME: Waiting till ready
+            // LinkerFlavor::AmdGpuLinker => {
+                // Box::new(AmdGpuLinker { cmd, sess }) as Box<dyn Linker>
+            // }
+
             LinkerFlavor::PtxLinker => {
                 Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>
             }
@@ -1163,3 +1168,127 @@ impl<'a> Linker for PtxLinker<'a> {
     fn linker_plugin_lto(&mut self) {
     }
 }
+
+pub struct AmdGpuLinker<'a> {
+    cmd: Command,
+    sess: &'a Session,
+}
+
+impl<'a> Linker for AmdGpuLinker<'a> {
+    fn link_rlib(&mut self, path: &Path) {
+        self.cmd.arg("--rlib").arg(path);
+    }
+
+    fn link_whole_rlib(&mut self, path: &Path) {
+        self.cmd.arg("--rlib").arg(path);
+    }
+
+    fn include_path(&mut self, path: &Path) {
+        self.cmd.arg("-L").arg(path);
+    }
+
+    fn debuginfo(&mut self) {
+        self.cmd.arg("--debug");
+    }
+
+    fn add_object(&mut self, path: &Path) {
+        self.cmd.arg("--bitcode").arg(path);
+    }
+
+    fn args(&mut self, args: &[String]) {
+        self.cmd.args(args);
+    }
+
+    fn optimize(&mut self) {
+        match self.sess.lto() {
+            Lto::Thin | Lto::Fat | Lto::ThinLocal => {
+                self.cmd.arg("-Olto");
+            },
+
+            Lto::No => { },
+        };
+    }
+
+    fn output_filename(&mut self, path: &Path) {
+        self.cmd.arg("-o").arg(path);
+    }
+
+    fn finalize(&mut self) -> Command {
+        // Provide the linker with fallback to internal `target-cpu`.
+        self.cmd.arg("--fallback-arch").arg(match self.sess.opts.cg.target_cpu {
+            Some(ref s) => s,
+            None => &self.sess.target.target.options.cpu
+        });
+
+        ::std::mem::replace(&mut self.cmd, Command::new(""))
+    }
+
+    fn link_dylib(&mut self, _lib: &str) {
+        panic!("external dylibs not supported")
+    }
+
+    fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) {
+        panic!("external dylibs not supported")
+    }
+
+    fn link_staticlib(&mut self, _lib: &str) {
+        panic!("staticlibs not supported")
+    }
+
+    fn link_whole_staticlib(&mut self, _lib: &str, _search_path: &[PathBuf]) {
+        panic!("staticlibs not supported")
+    }
+
+    fn framework_path(&mut self, _path: &Path) {
+        panic!("frameworks not supported")
+    }
+
+    fn link_framework(&mut self, _framework: &str) {
+        panic!("frameworks not supported")
+    }
+
+    fn position_independent_executable(&mut self) {
+    }
+
+    fn full_relro(&mut self) {
+    }
+
+    fn partial_relro(&mut self) {
+    }
+
+    fn no_relro(&mut self) {
+    }
+
+    fn build_static_executable(&mut self) {
+    }
+
+    fn gc_sections(&mut self, _keep_metadata: bool) {
+    }
+
+    fn pgo_gen(&mut self) {
+    }
+
+    fn no_default_libraries(&mut self) {
+    }
+
+    fn build_dylib(&mut self, _out_filename: &Path) {
+    }
+
+    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {
+    }
+
+    fn subsystem(&mut self, _subsystem: &str) {
+    }
+
+    fn no_position_independent_executable(&mut self) {
+    }
+
+    fn group_start(&mut self) {
+    }
+
+    fn group_end(&mut self) {
+    }
+
+    fn linker_plugin_lto(&mut self) {
+    }
+}
diff --git a/src/librustc_codegen_ssa/meth.rs b/src/librustc_codegen_ssa/meth.rs
index 7fe9f5f25130a..0797fc61c6914 100644
--- a/src/librustc_codegen_ssa/meth.rs
+++ b/src/librustc_codegen_ssa/meth.rs
@@ -80,7 +80,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
     }
 
     // Not in the cache. Build it.
-    let nullptr = cx.const_null(cx.type_i8p());
+    let nullptr = cx.const_null(cx.type_inst_i8p());
 
     let methods_root;
     let methods = if let Some(trait_ref) = trait_ref {
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 941166ccfab09..290c3446a0bb2 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -276,7 +276,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let llslot = match op.val {
                     Immediate(_) | Pair(..) => {
                         let scratch =
-                            PlaceRef::alloca(&mut bx, self.fn_ty.ret.layout, "ret");
+                            PlaceRef::alloca_addr_space(&mut bx, self.fn_ty.ret.layout,
+                                                        "ret");
                         op.val.store(&mut bx, scratch);
                         scratch.llval
                     }
@@ -292,6 +293,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 bx.load(addr, self.fn_ty.ret.layout.align.abi)
             }
         };
+        let llval = bx.flat_addr_cast(llval);
         bx.ret(llval);
     }
 
@@ -414,6 +416,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     col,
                     "panic_bounds_check_loc",
                 );
+                let file_line_col = bx.cx().const_flat_as_cast(file_line_col);
                 (lang_items::PanicBoundsCheckFnLangItem,
                     vec![file_line_col, index, len])
             }
@@ -427,6 +430,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     col,
                     "panic_loc",
                 );
+                let msg_file_line_col = bx.cx().const_flat_as_cast(msg_file_line_col);
                 (lang_items::PanicFnLangItem,
                     vec![msg_file_line_col])
             }
@@ -920,7 +924,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             Immediate(_) | Pair(..) => {
                 match arg.mode {
                     PassMode::Indirect(..) | PassMode::Cast(_) => {
-                        let scratch = PlaceRef::alloca(bx, arg.layout, "arg");
+                        let scratch = PlaceRef::alloca_addr_space(bx, arg.layout, "arg");
                         op.val.store(bx, scratch);
                         (scratch.llval, scratch.align, true)
                     }
@@ -935,12 +939,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't
                     // have scary latent bugs around.
 
-                    let scratch = PlaceRef::alloca(bx, arg.layout, "arg");
+                    let scratch = PlaceRef::alloca_addr_space(bx, arg.layout, "arg");
                     base::memcpy_ty(bx, scratch.llval, scratch.align, llval, align,
                                     op.layout, MemFlags::empty());
                     (scratch.llval, scratch.align, true)
                 } else {
-                    (llval, align, true)
+                    (bx.flat_addr_cast(llval), align, true)
                 }
             }
         };
@@ -1012,7 +1016,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 cx.tcx().mk_mut_ptr(cx.tcx().types.u8),
                 cx.tcx().types.i32
             ]));
-            let slot = PlaceRef::alloca(bx, layout, "personalityslot");
+            let slot = PlaceRef::alloca_addr_space(bx, layout, "personalityslot");
             self.personality_slot = Some(slot);
             slot
         }
@@ -1108,7 +1112,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     return if fn_ret.is_indirect() {
                         // Odd, but possible, case, we have an operand temporary,
                         // but the calling convention has an indirect return.
-                        let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret");
+                        let tmp = PlaceRef::alloca_addr_space(bx, fn_ret.layout, "tmp_ret");
                         tmp.storage_live(bx);
                         llargs.push(tmp.llval);
                         ReturnDest::IndirectOperand(tmp, index)
@@ -1116,7 +1120,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         // Currently, intrinsics always need a location to store
                         // the result, so we create a temporary `alloca` for the
                         // result.
-                        let tmp = PlaceRef::alloca(bx, fn_ret.layout, "tmp_ret");
+                        let tmp = PlaceRef::alloca_addr_space(bx, fn_ret.layout, "tmp_ret");
                         tmp.storage_live(bx);
                         ReturnDest::IndirectOperand(tmp, index)
                     } else {
@@ -1160,7 +1164,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 LocalRef::Operand(None) => {
                     let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst));
                     assert!(!dst_layout.ty.has_erasable_regions());
-                    let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp");
+                    let place = PlaceRef::alloca_addr_space(bx, dst_layout, "transmute_temp");
                     place.storage_live(bx);
                     self.codegen_transmute_into(bx, src, place);
                     let op = bx.load_operand(place);
@@ -1213,7 +1217,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             DirectOperand(index) => {
                 // If there is a cast, we have to store and reload.
                 let op = if let PassMode::Cast(_) = ret_ty.mode {
-                    let tmp = PlaceRef::alloca(bx, ret_ty.layout, "tmp_ret");
+                    let tmp = PlaceRef::alloca_addr_space(bx, ret_ty.layout, "tmp_ret");
                     tmp.storage_live(bx);
                     bx.store_arg_ty(&ret_ty, llval, tmp);
                     let op = bx.load_operand(tmp);
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index e7517d6999195..27eb2a4b0a729 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -272,7 +272,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                     // FIXME: add an appropriate debuginfo
                     LocalRef::UnsizedPlace(indirect_place)
                 } else {
-                    let place = PlaceRef::alloca(&mut bx, layout, &name.as_str());
+                    let place = PlaceRef::alloca_addr_space(&mut bx, layout, &name.as_str());
                     if dbg {
                         let (scope, span) = fx.debug_loc(mir::SourceInfo {
                             span: decl.source_info.span,
@@ -300,7 +300,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                         );
                         LocalRef::UnsizedPlace(indirect_place)
                     } else {
-                        LocalRef::Place(PlaceRef::alloca(&mut bx, layout, &format!("{:?}", local)))
+                        LocalRef::Place(PlaceRef::alloca_addr_space(&mut bx, layout,
+                                                                    &format!("{:?}", local)))
                     }
                 } else {
                     // If this is an immediate local, we do not create an
@@ -470,7 +471,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 _ => bug!("spread argument isn't a tuple?!")
             };
 
-            let place = PlaceRef::alloca(bx, bx.layout_of(arg_ty), &name);
+            let place = PlaceRef::alloca_addr_space(bx, bx.layout_of(arg_ty), &name);
             for i in 0..tupled_arg_tys.len() {
                 let arg = &fx.fn_ty.args[idx];
                 idx += 1;
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index 010be3e8c7404..4323eaeabd7c3 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -67,6 +67,18 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         Self::new_sized(tmp, layout, layout.align.abi)
     }
 
+    /// An alloca, left in the alloca address space. If unsure, use `alloca` below.
+    pub fn alloca_addr_space<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
+        bx: &mut Bx,
+        layout: TyLayout<'tcx>,
+        name: &str
+    ) -> Self {
+        debug!("alloca({:?}: {:?})", name, layout);
+        assert!(!layout.is_unsized(), "tried to statically allocate unsized place");
+        let tmp = bx.alloca(bx.cx().backend_type(layout), name, layout.align.abi);
+        Self::new_sized(tmp, layout, layout.align.abi)
+    }
+
     /// Returns a place for an indirect reference to an unsized place.
     pub fn alloca_unsized_indirect<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         bx: &mut Bx,
@@ -77,7 +89,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         assert!(layout.is_unsized(), "tried to allocate indirect place for sized values");
         let ptr_ty = bx.cx().tcx().mk_mut_ptr(layout.ty);
         let ptr_layout = bx.cx().layout_of(ptr_ty);
-        Self::alloca(bx, ptr_layout, name)
+        Self::alloca_addr_space(bx, ptr_layout, name)
     }
 
     pub fn len<Cx: ConstMethods<'tcx, Value = V>>(
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index 4a1971e3e2ee0..0cb560b2c6379 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -18,6 +18,36 @@ use super::{FunctionCx, LocalRef};
 use super::operand::{OperandRef, OperandValue};
 use super::place::PlaceRef;
 
+fn codegen_binop_fixup<'a, 'tcx: 'a, Bx>(bx: &mut Bx,
+                                         lhs: Bx::Value,
+                                         rhs: Bx::Value)
+    -> (Bx::Value, Bx::Value)
+    where Bx: BuilderMethods<'a, 'tcx>,
+{
+    // In case we're in separate addr spaces.
+    // Can happen when cmp against null_mut, eg.
+    // `infer-addr-spaces` should propagate.
+    // But, empirically, `infer-addr-spaces` doesn't.
+    let fix_null_ty = |val, this_ty, other_ty| {
+        if bx.cx().const_null(this_ty) == val {
+            bx.cx().const_null(other_ty)
+        } else {
+            val
+        }
+    };
+    let lhs_ty = bx.cx().val_ty(lhs);
+    let rhs_ty = bx.cx().val_ty(rhs);
+    let lhs = fix_null_ty(lhs, lhs_ty, rhs_ty);
+    let rhs = fix_null_ty(rhs, rhs_ty, lhs_ty);
+    if bx.cx().type_addr_space(lhs_ty).is_some() {
+        assert!(bx.cx().type_addr_space(rhs_ty).is_some());
+        (bx.flat_addr_cast(lhs),
+         bx.flat_addr_cast(rhs))
+    } else {
+        (lhs, rhs)
+    }
+}
+
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn codegen_rvalue(
         &mut self,
@@ -63,7 +93,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         // index into the struct, and this case isn't
                         // important enough for it.
                         debug!("codegen_rvalue: creating ugly alloca");
-                        let scratch = PlaceRef::alloca(&mut bx, operand.layout, "__unsize_temp");
+                        let scratch = PlaceRef::alloca_addr_space(&mut bx, operand.layout,
+                                                                  "__unsize_temp");
                         scratch.storage_live(&mut bx);
                         operand.val.store(&mut bx, scratch);
                         base::coerce_unsized_into(&mut bx, scratch, dest);
@@ -331,12 +362,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             (CastTy::RPtr(_), CastTy::Ptr(_)) =>
                                 bx.pointercast(llval, ll_t_out),
                             (CastTy::Ptr(_), CastTy::Int(_)) |
-                            (CastTy::FnPtr, CastTy::Int(_)) =>
-                                bx.ptrtoint(llval, ll_t_out),
+                            (CastTy::FnPtr, CastTy::Int(_)) => {
+                                let llval = bx.flat_addr_cast(llval);
+                                bx.ptrtoint(llval, ll_t_out)
+                            },
                             (CastTy::Int(_), CastTy::Ptr(_)) => {
                                 let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed);
                                 bx.inttoptr(usize_llval, ll_t_out)
-                            }
+                            },
                             (CastTy::Int(_), CastTy::Float) =>
                                 cast_int_to_float(&mut bx, signed, llval, ll_t_in, ll_t_out),
                             (CastTy::Float, CastTy::Int(IntTy::I)) =>
@@ -588,6 +621,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     lhs, rhs
                 )
             } else {
+                let (lhs, rhs) = codegen_binop_fixup(bx, lhs, rhs);
                 bx.icmp(
                     base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed),
                     lhs, rhs
@@ -606,6 +640,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         rhs_extra: Bx::Value,
         _input_ty: Ty<'tcx>,
     ) -> Bx::Value {
+        let (lhs_addr, rhs_addr) = codegen_binop_fixup(bx, lhs_addr, rhs_addr);
         match op {
             mir::BinOp::Eq => {
                 let lhs = bx.icmp(IntPredicate::IntEQ, lhs_addr, rhs_addr);
diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs
index 3a144f0b0e0aa..3acd4242a6bf3 100644
--- a/src/librustc_codegen_ssa/traits/builder.rs
+++ b/src/librustc_codegen_ssa/traits/builder.rs
@@ -11,7 +11,7 @@ use crate::mir::place::PlaceRef;
 use crate::MemFlags;
 use rustc::ty::Ty;
 use rustc::ty::layout::{Align, Size, HasParamEnv};
-use rustc_target::spec::{HasTargetSpec};
+use rustc_target::spec::{AddrSpaceIdx, HasTargetSpec};
 use std::ops::Range;
 use std::iter::TrustedLen;
 
@@ -170,6 +170,16 @@ pub trait BuilderMethods<'a, 'tcx>:
     fn intcast(&mut self, val: Self::Value, dest_ty: Self::Type, is_signed: bool) -> Self::Value;
     fn pointercast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
 
+    fn as_ptr_cast(&mut self,
+                   val: Self::Value,
+                   addr_space: AddrSpaceIdx,
+                   dest_ty: Self::Type) -> Self::Value;
+    fn addrspace_cast(&mut self, val: Self::Value,
+                      dest: AddrSpaceIdx) -> Self::Value;
+    fn flat_addr_cast(&mut self, val: Self::Value) -> Self::Value;
+    fn flat_as_ptr_cast(&mut self, val: Self::Value,
+                        dest_ty: Self::Type) -> Self::Value;
+
     fn icmp(&mut self, op: IntPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
     fn fcmp(&mut self, op: RealPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
 
diff --git a/src/librustc_codegen_ssa/traits/consts.rs b/src/librustc_codegen_ssa/traits/consts.rs
index 248fadfaf0f27..e53829fa5ac6c 100644
--- a/src/librustc_codegen_ssa/traits/consts.rs
+++ b/src/librustc_codegen_ssa/traits/consts.rs
@@ -1,10 +1,11 @@
-use super::BackendTypes;
+use super::MiscMethods;
 use crate::mir::place::PlaceRef;
 use rustc::mir::interpret::Allocation;
 use rustc::mir::interpret::Scalar;
 use rustc::ty::layout;
+use rustc_target::spec::AddrSpaceIdx;
 
-pub trait ConstMethods<'tcx>: BackendTypes {
+pub trait ConstMethods<'tcx>: MiscMethods<'tcx> {
     // Constant constructors
     fn const_null(&self, t: Self::Type) -> Self::Value;
     fn const_undef(&self, t: Self::Type) -> Self::Value;
@@ -24,6 +25,11 @@ pub trait ConstMethods<'tcx>: BackendTypes {
     fn const_to_uint(&self, v: Self::Value) -> u64;
     fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;
 
+    fn const_as_cast(&self, v: Self::Value, space: AddrSpaceIdx) -> Self::Value;
+    fn const_flat_as_cast(&self, v: Self::Value) -> Self::Value {
+        self.const_as_cast(v, self.flat_addr_space())
+    }
+
     fn is_const_integral(&self, v: Self::Value) -> bool;
 
     fn scalar_to_backend(
diff --git a/src/librustc_codegen_ssa/traits/declare.rs b/src/librustc_codegen_ssa/traits/declare.rs
index 624a982b619ee..c4586f5eddddc 100644
--- a/src/librustc_codegen_ssa/traits/declare.rs
+++ b/src/librustc_codegen_ssa/traits/declare.rs
@@ -2,13 +2,15 @@ use super::BackendTypes;
 use rustc::hir::def_id::DefId;
 use rustc::mir::mono::{Linkage, Visibility};
 use rustc::ty::{self, Instance};
+use rustc_target::spec::AddrSpaceIdx;
 
 pub trait DeclareMethods<'tcx>: BackendTypes {
     /// Declare a global value.
     ///
     /// If there’s a value with the same name already declared, the function will
     /// return its Value instead.
-    fn declare_global(&self, name: &str, ty: Self::Type) -> Self::Value;
+    fn declare_global(&self, name: &str, ty: Self::Type,
+                      addr_space: AddrSpaceIdx) -> Self::Value;
 
     /// Declare a C ABI function.
     ///
@@ -31,12 +33,14 @@ pub trait DeclareMethods<'tcx>: BackendTypes {
     /// return `None` if the name already has a definition associated with it. In that
     /// case an error should be reported to the user, because it usually happens due
     /// to user’s fault (e.g., misuse of #[no_mangle] or #[export_name] attributes).
-    fn define_global(&self, name: &str, ty: Self::Type) -> Option<Self::Value>;
+    fn define_global(&self, name: &str, ty: Self::Type,
+                     addr_space: AddrSpaceIdx) -> Option<Self::Value>;
 
     /// Declare a private global
     ///
     /// Use this function when you intend to define a global without a name.
-    fn define_private_global(&self, ty: Self::Type) -> Self::Value;
+    fn define_private_global(&self, ty: Self::Type,
+                             addr_space: AddrSpaceIdx) -> Self::Value;
 
     /// Declare a Rust function with an intention to define it.
     ///
diff --git a/src/librustc_codegen_ssa/traits/misc.rs b/src/librustc_codegen_ssa/traits/misc.rs
index 46c88a6113ebe..a49423f346320 100644
--- a/src/librustc_codegen_ssa/traits/misc.rs
+++ b/src/librustc_codegen_ssa/traits/misc.rs
@@ -3,6 +3,7 @@ use rustc::mir::mono::CodegenUnit;
 use rustc::session::Session;
 use rustc::ty::{self, Instance, Ty};
 use rustc::util::nodemap::FxHashMap;
+use rustc_target::spec::AddrSpaceIdx;
 use std::cell::RefCell;
 use std::sync::Arc;
 
@@ -21,4 +22,11 @@ pub trait MiscMethods<'tcx>: BackendTypes {
     fn set_frame_pointer_elimination(&self, llfn: Self::Value);
     fn apply_target_cpu_attr(&self, llfn: Self::Value);
     fn create_used_variable(&self);
+
+    fn can_cast_addr_space(&self, _from: AddrSpaceIdx, _to: AddrSpaceIdx) -> bool { true }
+    fn inst_addr_space(&self) -> AddrSpaceIdx { Default::default() }
+    fn alloca_addr_space(&self) -> AddrSpaceIdx { Default::default() }
+    fn const_addr_space(&self) -> AddrSpaceIdx { Default::default() }
+    fn mutable_addr_space(&self) -> AddrSpaceIdx { Default::default() }
+    fn flat_addr_space(&self) -> AddrSpaceIdx { Default::default() }
 }
diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs
index efe4a25570104..c4fdb345e39ff 100644
--- a/src/librustc_codegen_ssa/traits/mod.rs
+++ b/src/librustc_codegen_ssa/traits/mod.rs
@@ -64,6 +64,19 @@ pub trait CodegenMethods<'tcx>:
     + HasTyCtxt<'tcx>
     + HasTargetSpec
 {
+    fn check_addr_space_cast(&self, val: Self::Value, dest: Self::Type) {
+        let src_ty = self.val_ty(val);
+
+        match (self.type_addr_space(src_ty), self.type_addr_space(dest)) {
+            (Some(left), Some(right)) if !self.can_cast_addr_space(left, right) => {
+                bug!("Target incompatible address space cast:\n\
+                      source addr space `{}`, dest addr space `{}`\n\
+                      source value: {:?}, dest ty: {:?}",
+                     left, right, val, dest);
+            },
+            _ => { },
+        }
+    }
 }
 
 impl<'tcx, T> CodegenMethods<'tcx> for T where
diff --git a/src/librustc_codegen_ssa/traits/type_.rs b/src/librustc_codegen_ssa/traits/type_.rs
index aa38d8d51848d..fa83291ea82dd 100644
--- a/src/librustc_codegen_ssa/traits/type_.rs
+++ b/src/librustc_codegen_ssa/traits/type_.rs
@@ -6,6 +6,7 @@ use crate::mir::place::PlaceRef;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, TyLayout};
 use rustc_target::abi::call::{ArgType, CastTarget, FnType, Reg};
+use rustc_target::spec::AddrSpaceIdx;
 use syntax_pos::DUMMY_SP;
 
 // This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use
@@ -25,7 +26,10 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> {
     fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type;
     fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type;
     fn type_kind(&self, ty: Self::Type) -> TypeKind;
-    fn type_ptr_to(&self, ty: Self::Type) -> Self::Type;
+    fn type_ptr_to(&self, ty: Self::Type) -> Self::Type {
+        self.type_as_ptr_to(ty, Default::default())
+    }
+    fn type_as_ptr_to(&self, ty: Self::Type, addr_space: AddrSpaceIdx) -> Self::Type;
     fn element_type(&self, ty: Self::Type) -> Self::Type;
 
     /// Returns the number of elements in `self` if it is a LLVM vector type.
@@ -37,12 +41,44 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> {
     fn int_width(&self, ty: Self::Type) -> u64;
 
     fn val_ty(&self, v: Self::Value) -> Self::Type;
+    fn val_addr_space(&self, v: Self::Value) -> Option<AddrSpaceIdx> {
+        self.type_addr_space(self.val_ty(v))
+    }
+
+    fn type_addr_space(&self, ty: Self::Type) -> Option<AddrSpaceIdx>;
+    fn type_copy_addr_space(&self, ty: Self::Type, addr_space: Option<AddrSpaceIdx>) -> Self::Type {
+        match (addr_space, self.type_kind(ty)) {
+            (Some(addr_space), TypeKind::Pointer) => {
+                let elem = self.element_type(ty);
+                self.type_as_ptr_to(elem, addr_space)
+            },
+            _ => ty,
+        }
+    }
 }
 
 pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
     fn type_i8p(&self) -> Self::Type {
         self.type_ptr_to(self.type_i8())
     }
+    fn type_i8p_as(&self, addr_space: AddrSpaceIdx) -> Self::Type {
+        self.type_as_ptr_to(self.type_i8(), addr_space)
+    }
+    fn type_inst_i8p(&self) -> Self::Type {
+        self.type_i8p_as(self.inst_addr_space())
+    }
+    fn type_alloca_i8p(&self) -> Self::Type {
+        self.type_i8p_as(self.alloca_addr_space())
+    }
+    fn type_const_i8p(&self) -> Self::Type {
+        self.type_i8p_as(self.const_addr_space())
+    }
+    fn type_mut_i8p(&self) -> Self::Type {
+        self.type_i8p_as(self.mutable_addr_space())
+    }
+    fn type_flat_i8p(&self) -> Self::Type {
+        self.type_i8p_as(self.flat_addr_space())
+    }
 
     fn type_int(&self) -> Self::Type {
         match &self.sess().target.target.target_c_int_width[..] {
@@ -88,6 +124,48 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
             _ => bug!("unexpected unsized tail: {:?}", tail),
         }
     }
+    /// Enforce no address space changes are happening in a cast.
+    /// Pointers in different address spaces can have different
+    /// machine level sizes (ie on AMDGPU, allocas are 32bits,
+    /// not 64bits!). We enforce that the flat address space is the
+    /// largest (+alignment), so that address space is safe to cast to
+    /// ints/etc. Also, address space changes require computing a offset
+    /// or two, so a straight bitcast is wrong.
+    fn type_check_no_addr_space_change(&self, what: &str,
+                                       src: Self::Value,
+                                       dest_ty: Self::Type) {
+        let src_ty = self.val_ty(src);
+        match (self.type_addr_space(src_ty), self.type_addr_space(dest_ty)) {
+            (Some(src_as), Some(dest_as)) if src_as != dest_as => {
+                bug!("Invalid address space cast in `{}` cast:\n\
+                     source addr space `{}`, dest addr space `{}`\n\
+                     source value: {:?}, dest ty: {:?}", what,
+                     src_as, dest_as, src, dest_ty);
+            },
+            (Some(src_as), None) if src_as != self.flat_addr_space() => {
+                bug!("Invalid address space cast in `{}` cast:\n\
+                     source addr space `{}` is not flat\n\
+                     source value: {:?}",
+                     what, src_as, src);
+            },
+            _ => { },
+        }
+    }
+    fn type_ptr_to_inst(&self, ty: Self::Type) -> Self::Type {
+        self.type_as_ptr_to(ty, self.inst_addr_space())
+    }
+    fn type_ptr_to_alloca(&self, ty: Self::Type) -> Self::Type {
+        self.type_as_ptr_to(ty, self.alloca_addr_space())
+    }
+    fn type_ptr_to_const(&self, ty: Self::Type) -> Self::Type {
+        self.type_as_ptr_to(ty, self.const_addr_space())
+    }
+    fn type_ptr_to_mut(&self, ty: Self::Type) -> Self::Type {
+        self.type_as_ptr_to(ty, self.mutable_addr_space())
+    }
+    fn type_ptr_to_flat(&self, ty: Self::Type) -> Self::Type {
+        self.type_as_ptr_to(ty, self.flat_addr_space())
+    }
 }
 
 impl<T> DerivedTypeMethods<'tcx> for T where Self: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {}
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 55cb179144309..910c51443d20d 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -1,7 +1,7 @@
 pub use Integer::*;
 pub use Primitive::*;
 
-use crate::spec::Target;
+use crate::spec::{Target, AddrSpaceIdx};
 
 use std::fmt;
 use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive};
@@ -23,6 +23,7 @@ pub struct TargetDataLayout {
     pub i128_align: AbiAndPrefAlign,
     pub f32_align: AbiAndPrefAlign,
     pub f64_align: AbiAndPrefAlign,
+    pub pointers: Vec<Option<(Size, AbiAndPrefAlign)>>,
     pub pointer_size: Size,
     pub pointer_align: AbiAndPrefAlign,
     pub aggregate_align: AbiAndPrefAlign,
@@ -30,7 +31,8 @@ pub struct TargetDataLayout {
     /// Alignments for vector types.
     pub vector_align: Vec<(Size, AbiAndPrefAlign)>,
 
-    pub instruction_address_space: u32,
+    pub alloca_address_space: AddrSpaceIdx,
+    pub instruction_address_space: AddrSpaceIdx,
 }
 
 impl Default for TargetDataLayout {
@@ -47,28 +49,22 @@ impl Default for TargetDataLayout {
             i128_align: AbiAndPrefAlign { abi: align(32), pref: align(64) },
             f32_align: AbiAndPrefAlign::new(align(32)),
             f64_align: AbiAndPrefAlign::new(align(64)),
+            pointers: vec![],
             pointer_size: Size::from_bits(64),
             pointer_align: AbiAndPrefAlign::new(align(64)),
             aggregate_align: AbiAndPrefAlign { abi: align(0), pref: align(64) },
+            alloca_address_space: Default::default(),
             vector_align: vec![
                 (Size::from_bits(64), AbiAndPrefAlign::new(align(64))),
                 (Size::from_bits(128), AbiAndPrefAlign::new(align(128))),
             ],
-            instruction_address_space: 0,
+            instruction_address_space: Default::default(),
         }
     }
 }
 
 impl TargetDataLayout {
     pub fn parse(target: &Target) -> Result<TargetDataLayout, String> {
-        // Parse an address space index from a string.
-        let parse_address_space = |s: &str, cause: &str| {
-            s.parse::<u32>().map_err(|err| {
-                format!("invalid address space `{}` for `{}` in \"data-layout\": {}",
-                        s, cause, err)
-            })
-        };
-
         // Parse a bit count from a string.
         let parse_bits = |s: &str, kind: &str, cause: &str| {
             s.parse::<u64>().map_err(|err| {
@@ -101,22 +97,42 @@ impl TargetDataLayout {
             })
         };
 
+        fn resize_and_set<T>(vec: &mut Vec<T>, idx: usize, v: T)
+            where T: Default,
+        {
+          while idx >= vec.len() {
+            vec.push(T::default());
+          }
+
+          vec[idx] = v;
+        }
+
         let mut dl = TargetDataLayout::default();
         let mut i128_align_src = 64;
         for spec in target.data_layout.split('-') {
             match spec.split(':').collect::<Vec<_>>()[..] {
                 ["e"] => dl.endian = Endian::Little,
                 ["E"] => dl.endian = Endian::Big,
-                [p] if p.starts_with("P") => {
-                    dl.instruction_address_space = parse_address_space(&p[1..], "P")?
-                }
                 ["a", ref a..] => dl.aggregate_align = align(a, "a")?,
                 ["f32", ref a..] => dl.f32_align = align(a, "f32")?,
                 ["f64", ref a..] => dl.f64_align = align(a, "f64")?,
                 [p @ "p", s, ref a..] | [p @ "p0", s, ref a..] => {
                     dl.pointer_size = size(s, p)?;
                     dl.pointer_align = align(a, p)?;
-                }
+                    resize_and_set(&mut dl.pointers, 0, Some((dl.pointer_size,
+                                                              dl.pointer_align)));
+                },
+                [p, s, ref a..] if p.starts_with('p') => {
+                  let idx = parse_bits(&p[1..], "u32", "address space index")? as usize;
+                  let size = size(s, p)?;
+                  let align = align(a, p)?;
+                  resize_and_set(&mut dl.pointers, idx, Some((size, align)));
+                },
+                [ref p] if p.starts_with("P") => {
+                    let idx = parse_bits(&p[1..], "u32",
+                                         "instruction address space")? as u32;
+                    dl.instruction_address_space = AddrSpaceIdx(idx);
+                },
                 [s, ref a..] if s.starts_with("i") => {
                     let bits = match s[1..].parse::<u64>() {
                         Ok(bits) => bits,
@@ -140,7 +156,7 @@ impl TargetDataLayout {
                         i128_align_src = bits;
                         dl.i128_align = a;
                     }
-                }
+                },
                 [s, ref a..] if s.starts_with("v") => {
                     let v_size = size(&s[1..], "v")?;
                     let a = align(a, s)?;
@@ -150,7 +166,13 @@ impl TargetDataLayout {
                     }
                     // No existing entry, add a new one.
                     dl.vector_align.push((v_size, a));
-                }
+                },
+                [s, ..] if s.starts_with("A") => {
+                    // default alloca address space
+                    let idx = parse_bits(&s[1..], "u32",
+                                         "default alloca address space")? as u32;
+                    dl.alloca_address_space = AddrSpaceIdx(idx);
+                },
                 _ => {} // Ignore everything else.
             }
         }
@@ -172,9 +194,37 @@ impl TargetDataLayout {
                                dl.pointer_size.bits(), target.target_pointer_width));
         }
 
+        // We don't specialize pointer sizes for specific address spaces,
+        // so enforce that the default address space can hold all the bits
+        // of any other spaces. Similar for alignment.
+        {
+            let ptrs_iter = dl.pointers.iter().enumerate()
+              .filter_map(|(idx, ptrs)| {
+                  ptrs.map(|(s, a)| (idx, s, a) )
+              });
+            for (idx, size, align) in ptrs_iter {
+                if size > dl.pointer_size {
+                    return Err(format!("Address space {} pointer is bigger than the default \
+                                    pointer: {} vs {}",
+                                       idx, size.bits(), dl.pointer_size.bits()));
+                }
+                if align.abi > dl.pointer_align.abi {
+                    return Err(format!("Address space {} pointer alignment is bigger than the \
+                                    default pointer: {} vs {}",
+                                       idx, align.abi.bits(), dl.pointer_align.abi.bits()));
+                }
+            }
+        }
+
         Ok(dl)
     }
 
+    pub fn pointer_info(&self, addr_space: AddrSpaceIdx) -> (Size, AbiAndPrefAlign) {
+        self.pointers.get(addr_space.0 as usize)
+            .and_then(|&v| v )
+            .unwrap_or((self.pointer_size, self.pointer_align))
+    }
+
     /// Returns exclusive upper bound on object size.
     ///
     /// The theoretical maximum object size is defined as the maximum positive `isize` value.
@@ -995,3 +1045,82 @@ impl<'a, Ty> TyLayout<'a, Ty> {
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::spec::{Target, TargetTriple};
+
+    #[test]
+    fn pointer_size_align() {
+        // amdgcn-amd-amdhsa-amdgiz
+        const DL: &'static str = "e-p:64:64-p1:64:64-p2:64:64-p3:32:32-\
+                                  p4:32:32-p5:32:32-i64:64-v16:16-v24:32-\
+                                  v32:32-v48:64-v96:128-v192:256-v256:256-\
+                                  v512:512-v1024:1024-v2048:2048-n32:64-A5";
+
+        // Doesn't need to be real...
+        let triple = TargetTriple::TargetTriple("x86_64-unknown-linux-gnu".into());
+        let mut target = Target::search(&triple).unwrap();
+        target.data_layout = DL.into();
+
+        let dl = TargetDataLayout::parse(&target);
+        assert!(dl.is_ok());
+        let dl = dl.unwrap();
+
+        let default = (dl.pointer_size, dl.pointer_align);
+
+        let thirty_two_size = Size::from_bits(32);
+        let thirty_two_align = AbiAndPrefAlign::new(Align::from_bits(32).unwrap());
+        let thirty_two = (thirty_two_size, thirty_two_align);
+        let sixty_four_size = Size::from_bits(64);
+        let sixty_four_align = AbiAndPrefAlign::new(Align::from_bits(64).unwrap());
+        let sixty_four = (sixty_four_size, sixty_four_align);
+
+        assert_eq!(dl.pointer_info(AddrSpaceIdx(0)), default);
+        assert_eq!(dl.pointer_info(AddrSpaceIdx(0)), sixty_four);
+        assert_eq!(dl.pointer_info(AddrSpaceIdx(1)), sixty_four);
+        assert_eq!(dl.pointer_info(AddrSpaceIdx(2)), sixty_four);
+        assert_eq!(dl.pointer_info(AddrSpaceIdx(3)), thirty_two);
+        assert_eq!(dl.pointer_info(AddrSpaceIdx(4)), thirty_two);
+        assert_eq!(dl.pointer_info(AddrSpaceIdx(5)), thirty_two);
+
+        // unknown address spaces need to be the same as the default:
+        assert_eq!(dl.pointer_info(AddrSpaceIdx(7)), default);
+    }
+
+    #[test]
+    fn default_is_biggest() {
+        // Note p1 is 128 bits.
+        const DL: &'static str = "e-p:64:64-p1:128:128-p2:64:64-p3:32:32-\
+                                  p4:32:32-p5:32:32-i64:64-v16:16-v24:32-\
+                                  v32:32-v48:64-v96:128-v192:256-v256:256-\
+                                  v512:512-v1024:1024-v2048:2048-n32:64-A5";
+
+        // Doesn't need to be real...
+        let triple = TargetTriple::TargetTriple("x86_64-unknown-linux-gnu".into());
+        let mut target = Target::search(&triple).unwrap();
+        target.data_layout = DL.into();
+
+        assert!(TargetDataLayout::parse(&target).is_err());
+    }
+    #[test]
+    fn alloca_addr_space() {
+        // amdgcn-amd-amdhsa-amdgiz
+        const DL: &'static str = "e-p:64:64-p1:64:64-p2:64:64-p3:32:32-\
+                                  p4:32:32-p5:32:32-i64:64-v16:16-v24:32-\
+                                  v32:32-v48:64-v96:128-v192:256-v256:256-\
+                                  v512:512-v1024:1024-v2048:2048-n32:64-A5";
+
+        // Doesn't need to be real...
+        let triple = TargetTriple::TargetTriple("x86_64-unknown-linux-gnu".into());
+        let mut target = Target::search(&triple).unwrap();
+        target.data_layout = DL.into();
+
+        let dl = TargetDataLayout::parse(&target);
+        assert!(dl.is_ok());
+        let dl = dl.unwrap();
+
+        assert_eq!(dl.alloca_address_space, AddrSpaceIdx(5));
+    }
+}
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 3054ffabb4f1f..0e1f9b9744555 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -35,11 +35,12 @@
 //! to the list specified by the target, rather than replace.
 
 use serialize::json::{Json, ToJson};
-use std::collections::BTreeMap;
+use std::collections::{BTreeMap, BTreeSet};
 use std::default::Default;
 use std::{fmt, io};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
+use std::ops::{Deref, DerefMut};
 use crate::spec::abi::{Abi, lookup as lookup_abi};
 
 pub mod abi;
@@ -75,6 +76,8 @@ pub enum LinkerFlavor {
     Ld,
     Msvc,
     Lld(LldFlavor),
+    // FIXME: Enable when ready
+    // AmdGpuLinker,
     PtxLinker,
 }
 
@@ -144,6 +147,8 @@ flavor_mappings! {
     ((LinkerFlavor::Gcc), "gcc"),
     ((LinkerFlavor::Ld), "ld"),
     ((LinkerFlavor::Msvc), "msvc"),
+    // FIXME: Enable when ready
+    // ((LinkerFlavor::AmdGpuLinker), "amdgpu-linker"),
     ((LinkerFlavor::PtxLinker), "ptx-linker"),
     ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"),
     ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"),
@@ -267,6 +272,165 @@ pub enum LoadTargetError {
 pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<String>>;
 pub type TargetResult = Result<Target, String>;
 
+#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
+pub struct AddrSpaceIdx(pub u32);
+impl Default for AddrSpaceIdx {
+    fn default() -> Self {
+        AddrSpaceIdx(0)
+    }
+}
+impl fmt::Display for AddrSpaceIdx {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.0)
+    }
+}
+impl FromStr for AddrSpaceIdx {
+    type Err = <u32 as FromStr>::Err;
+    fn from_str(s: &str) -> Result<AddrSpaceIdx, Self::Err> {
+        Ok(AddrSpaceIdx(u32::from_str(s)?))
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub enum AddrSpaceKind {
+    Flat,
+    Alloca,
+    /// aka constant
+    ReadOnly,
+    /// aka global
+    ReadWrite,
+    /// For Harvard architectures, the program instruction's address space
+    Instruction,
+    Named(String),
+}
+
+impl FromStr for AddrSpaceKind {
+    type Err = String;
+    fn from_str(s: &str) -> Result<AddrSpaceKind, String> {
+        Ok(match s {
+            "flat" => AddrSpaceKind::Flat,
+            "alloca" => AddrSpaceKind::Alloca,
+            "readonly" => AddrSpaceKind::ReadOnly,
+            "readwrite" => AddrSpaceKind::ReadWrite,
+            "instruction" => AddrSpaceKind::Instruction,
+            named => AddrSpaceKind::Named(named.into()),
+        })
+    }
+}
+impl fmt::Display for AddrSpaceKind {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", match self {
+            &AddrSpaceKind::Flat => "flat",
+            &AddrSpaceKind::Alloca => "alloca",
+            &AddrSpaceKind::ReadOnly => "readonly",
+            &AddrSpaceKind::ReadWrite => "readwrite",
+            &AddrSpaceKind::Instruction => "instruction",
+            &AddrSpaceKind::Named(ref s) => s,
+        })
+    }
+}
+impl ToJson for AddrSpaceKind {
+    fn to_json(&self) -> Json {
+        Json::String(format!("{}", self))
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct AddrSpaceProps {
+    pub index: AddrSpaceIdx,
+    /// Indicates which addr spaces this addr space can be addrspacecast-ed to.
+    pub shared_with: BTreeSet<AddrSpaceKind>,
+}
+
+impl AddrSpaceProps {
+    pub fn from_json(json: &Json) -> Result<Self, String> {
+        let index = json.find("index").and_then(|v| v.as_u64() )
+          .ok_or_else(|| {
+              "invalid address space index, expected an unsigned integer"
+          })?;
+
+        let mut shared_with = vec![];
+        if let Some(shared) = json.find("shared-with").and_then(|v| v.as_array() ) {
+            for s in shared {
+                let s = s.as_string()
+                    .ok_or_else(|| {
+                        "expected string for address space kind"
+                    })?;
+
+                let kind = AddrSpaceKind::from_str(s)?;
+                shared_with.push(kind);
+            }
+        }
+
+        Ok(AddrSpaceProps {
+            index: AddrSpaceIdx(index as u32),
+            shared_with: shared_with.into_iter().collect(),
+        })
+    }
+}
+impl ToJson for AddrSpaceProps {
+    fn to_json(&self) -> Json {
+        let mut obj = BTreeMap::new();
+        obj.insert("index".to_string(), self.index.0.to_json());
+        let mut shared_with = vec![];
+        for sw in self.shared_with.iter() {
+            shared_with.push(sw.to_json());
+        }
+        obj.insert("shared-with".to_string(), Json::Array(shared_with));
+
+        Json::Object(obj)
+    }
+}
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct AddrSpaces(pub BTreeMap<AddrSpaceKind, AddrSpaceProps>);
+impl Deref for AddrSpaces {
+    type Target = BTreeMap<AddrSpaceKind, AddrSpaceProps>;
+    fn deref(&self) -> &Self::Target { &self.0 }
+}
+impl DerefMut for AddrSpaces {
+    fn deref_mut(&mut self) -> &mut BTreeMap<AddrSpaceKind, AddrSpaceProps> { &mut self.0 }
+}
+impl ToJson for AddrSpaces {
+    fn to_json(&self) -> Json {
+        let obj = self.iter()
+          .map(|(k, v)| {
+              (format!("{}", k), v.to_json())
+          })
+          .collect();
+        Json::Object(obj)
+    }
+}
+impl Default for AddrSpaces {
+    fn default() -> Self {
+        let mut asp = BTreeMap::new();
+
+        let kinds = vec![
+            AddrSpaceKind::ReadOnly,
+            AddrSpaceKind::ReadWrite,
+            AddrSpaceKind::Alloca,
+            AddrSpaceKind::Flat,
+            AddrSpaceKind::Instruction,
+        ];
+
+        let insert = |asp: &mut BTreeMap<_, _>, kind, idx| {
+            let props = AddrSpaceProps {
+                index: idx,
+                shared_with: kinds.clone()
+                  .into_iter()
+                  .filter(|k| *k != kind)
+                  .collect(),
+            };
+            assert!(asp.insert(kind, props).is_none());
+        };
+
+        for kind in kinds.iter() {
+            insert(&mut asp, kind.clone(), Default::default());
+        }
+
+        AddrSpaces(asp)
+    }
+}
+
 macro_rules! supported_targets {
     ( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
         $(mod $module;)+
@@ -757,6 +921,11 @@ pub struct TargetOptions {
     /// the usual logic to figure this out from the crate itself.
     pub override_export_symbols: Option<Vec<String>>,
 
+    /// Description of all address spaces and how they are shared with one another.
+    /// Defaults to a single, flat, address space. Note it is generally assumed that
+    /// the address space `0` is your flat address space.
+    pub addr_spaces: AddrSpaces,
+
     /// Determines how or whether the MergeFunctions LLVM pass should run for
     /// this target. Either "disabled", "trampolines", or "aliases".
     /// The MergeFunctions pass is generally useful, but some targets may need
@@ -850,6 +1019,7 @@ impl Default for TargetOptions {
             simd_types_indirect: true,
             limit_rdylib_exports: true,
             override_export_symbols: None,
+            addr_spaces: Default::default(),
             merge_functions: MergeFunctions::Aliases,
             target_mcount: "mcount".to_string(),
         }
@@ -1081,6 +1251,16 @@ impl Target {
                     }
                 }
             } );
+            ($key_name:ident, addr_spaces) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                if let Some(obj) = obj.find(&name[..]).and_then(|o| o.as_object() ) {
+                    for (k, v) in obj {
+                        let k = AddrSpaceKind::from_str(&k).unwrap();
+                        let props = AddrSpaceProps::from_json(v)?;
+                        base.options.$key_name.insert(k, props);
+                    }
+                }
+            } );
         }
 
         key!(is_builtin, bool);
@@ -1157,6 +1337,7 @@ impl Target {
         key!(simd_types_indirect, bool);
         key!(limit_rdylib_exports, bool);
         key!(override_export_symbols, opt_list);
+        key!(addr_spaces, addr_spaces);
         key!(merge_functions, MergeFunctions)?;
         key!(target_mcount);
 
@@ -1373,6 +1554,7 @@ impl ToJson for Target {
         target_option_val!(simd_types_indirect);
         target_option_val!(limit_rdylib_exports);
         target_option_val!(override_export_symbols);
+        target_option_val!(addr_spaces);
         target_option_val!(merge_functions);
         target_option_val!(target_mcount);
 
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 16d08ee534edc..b6771bcc3837d 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -125,17 +125,35 @@ extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M,
 }
 
 extern "C" LLVMValueRef
-LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, LLVMTypeRef Ty) {
-  return wrap(unwrap(M)->getOrInsertGlobal(Name, unwrap(Ty)));
+LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, LLVMTypeRef Ty, unsigned AS) {
+  GlobalVariable* GV = nullptr;
+  Module* MM = unwrap(M);
+  Type* ETy = unwrap(Ty);
+  if (!(GV = MM->getNamedGlobal(Name))) {
+    GV = new GlobalVariable(ETy, false, GlobalVariable::ExternalLinkage,
+                            nullptr, Name, GlobalVariable::NotThreadLocal, AS);
+    MM->getGlobalList().push_back(GV);
+  }
+  Type *GVTy = GV->getType();
+  PointerType *PTy = PointerType::get(ETy, GVTy->getPointerAddressSpace());
+  if (GVTy != PTy) {
+     return wrap(ConstantExpr::getBitCast(GV, PTy));
+  } else {
+     return wrap(GV);
+  }
 }
 
 extern "C" LLVMValueRef
-LLVMRustInsertPrivateGlobal(LLVMModuleRef M, LLVMTypeRef Ty) {
+LLVMRustInsertPrivateGlobal(LLVMModuleRef M, LLVMTypeRef Ty, unsigned AS) {
   return wrap(new GlobalVariable(*unwrap(M),
                                  unwrap(Ty),
                                  false,
                                  GlobalValue::PrivateLinkage,
-                                 nullptr));
+                                 nullptr,
+                                 "",
+                                 nullptr,
+                                 GlobalVariable::NotThreadLocal,
+                                 AS));
 }
 
 extern "C" LLVMTypeRef LLVMRustMetadataTypeInContext(LLVMContextRef C) {

From 456d0aa1cb0f52e066a9f28215f8da37f87a58fa Mon Sep 17 00:00:00 2001
From: YakoYakoYokuYoku <gc1000ll@gmail.com>
Date: Sat, 13 Jul 2019 23:43:16 -0300
Subject: [PATCH 2/2] refining and refactoring

---
 src/librustc_codegen_llvm/abi.rs        |   1 -
 src/librustc_codegen_llvm/builder.rs    |  59 ++++++-----
 src/librustc_codegen_llvm/common.rs     |  11 +--
 src/librustc_codegen_llvm/consts.rs     |   7 +-
 src/librustc_codegen_llvm/context.rs    |   6 +-
 src/librustc_codegen_ssa/back/link.rs   |   2 -
 src/librustc_codegen_ssa/back/linker.rs | 124 ------------------------
 src/librustc_codegen_ssa/mir/block.rs   |  10 +-
 src/librustc_codegen_ssa/mir/rvalue.rs  |   8 +-
 src/librustc_target/abi/mod.rs          |  79 ---------------
 src/librustc_target/spec/mod.rs         |   4 -
 11 files changed, 46 insertions(+), 265 deletions(-)

diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index e51bd34f50a45..dfc4310d1f4cb 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -302,7 +302,6 @@ impl ArgTypeMethods<'tcx> for Builder<'a, 'll, 'tcx> {
 
 pub trait FnTypeLlvmExt<'tcx> {
     fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
-    // fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn llvm_cconv(&self) -> llvm::CallConv;
     fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value);
     fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index a343f6271c355..54707f1fb8d41 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -215,7 +215,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         funclet: Option<&Funclet<'ll>>,
     ) -> &'ll Value {
 
-        debug!("Invoke {:?} with args ({:?})",
+        debug!("invoke {:?} with args ({:?})",
                llfn,
                args);
 
@@ -546,10 +546,10 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     ) -> Self {
         let zero = self.const_usize(0);
         let count = self.const_usize(count);
-        let start = dest.project_index(&mut self, zero).llval;
-        let end = dest.project_index(&mut self, count).llval;
-        let start = self.flat_addr_cast(start);
-        let end = self.flat_addr_cast(end);
+        let before_start = dest.project_index(&mut self, zero).llval;
+        let before_end = dest.project_index(&mut self, count).llval;
+        let start = self.flat_addr_cast(before_start);
+        let end = self.flat_addr_cast(before_end);
 
         let mut header_bx = self.build_sibling_block("repeat_loop_header");
         let mut body_bx = self.build_sibling_block("repeat_loop_body");
@@ -726,23 +726,23 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn ptrtoint(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
-        let val = self.flat_addr_cast(val);
+        let val_casted = self.flat_addr_cast(val);
         unsafe {
-            llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty, UNNAMED)
+            llvm::LLVMBuildPtrToInt(self.llbuilder, val_casted, dest_ty, UNNAMED)
         }
     }
 
     fn inttoptr(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
-        let dest_ty = dest_ty.copy_addr_space(self.cx().flat_addr_space());
+        let dest_ty_copied = dest_ty.copy_addr_space(self.cx().flat_addr_space());
         unsafe {
-            llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty, UNNAMED)
+            llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty_copied, UNNAMED)
         }
     }
 
     fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
-        let dest_ty = dest_ty.copy_addr_space(val_addr_space(val));
         unsafe {
-            llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED)
+            llvm::LLVMBuildBitCast(self.llbuilder, val,
+                                   dest_ty.copy_addr_space(val_addr_space(val)), UNNAMED)
         }
     }
 
@@ -750,8 +750,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         &mut self, val: &'ll Value,
         addr_space: AddrSpaceIdx, dest_ty: &'ll Type
     ) -> &'ll Value {
-        let val = self.addrspace_cast(val, addr_space);
-        self.pointercast(val, dest_ty.copy_addr_space(addr_space))
+        let val_addr = self.addrspace_cast(val, addr_space);
+        self.pointercast(val_addr, dest_ty.copy_addr_space(addr_space))
     }
 
     fn flat_as_ptr_cast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
@@ -784,16 +784,14 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn pointercast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
-        let dest_ty = dest_ty.copy_addr_space(val_addr_space(val));
         unsafe {
-            llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty, UNNAMED)
+            llvm::LLVMBuildPointerCast(self.llbuilder, val,
+                                       dest_ty.copy_addr_space(val_addr_space(val)), UNNAMED)
         }
     }
 
     /* Comparisons */
     fn icmp(&mut self, op: IntPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
-        let op = llvm::IntPredicate::from_generic(op);
-
         match (val_addr_space_opt(lhs), val_addr_space_opt(rhs)) {
             (Some(l), Some(r)) if l == r => {},
             (Some(l), Some(r)) if l != r => {
@@ -804,7 +802,9 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         }
 
         unsafe {
-            llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, UNNAMED)
+            llvm::LLVMBuildICmp(self.llbuilder,
+                                llvm::IntPredicate::from_generic(op) as c_uint,
+                                lhs, rhs, UNNAMED)
         }
     }
 
@@ -864,8 +864,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         flags: MemFlags,
     ) {
         let ptr_width = &self.sess().target.target.target_pointer_width;
-        let addr_space = self.val_ty(ptr).address_space();
-        let intrinsic_key = format!("llvm.memset.p{}i8.i{}", addr_space, ptr_width);
+        let intrinsic_key = format!("llvm.memset.p{}i8.i{}",
+                                    self.val_ty(ptr).address_space(), ptr_width);
         let llintrinsicfn = self.get_intrinsic(&intrinsic_key);
         let ptr = self.pointercast(ptr, self.type_i8p());
         let align = self.const_u32(align.bytes() as u32);
@@ -1082,7 +1082,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         funclet: Option<&Funclet<'ll>>,
     ) -> &'ll Value {
 
-        debug!("Call {:?} with args ({:?})",
+        debug!("call {:?} with args ({:?})",
                llfn,
                args);
 
@@ -1286,7 +1286,7 @@ impl Builder<'a, 'll, 'tcx> {
         if dest_ptr_ty == stored_ptr_ty {
             ptr
         } else {
-            debug!("Type mismatch in store. \
+            debug!("type mismatch in store. \
                     Expected {:?}, got {:?}; inserting bitcast",
                    dest_ptr_ty, stored_ptr_ty);
             self.bitcast(ptr, stored_ptr_ty)
@@ -1322,20 +1322,20 @@ impl Builder<'a, 'll, 'tcx> {
             .map(|(i, (expected_ty, &actual_val))| {
                 let actual_ty = self.val_ty(actual_val);
                 if expected_ty != actual_ty {
-                    debug!("Type mismatch in function call of {:?}. \
+                    debug!("type mismatch in function call of {:?}. \
                             Expected {:?} for param {}, got {:?}; injecting bitcast",
                            llfn, expected_ty, i, actual_ty);
                     if expected_ty.is_ptr() && actual_ty.is_ptr() {
-                        let actual_val = self.addrspace_cast(actual_val,
-                                                             expected_ty.address_space());
-                        self.pointercast(actual_val, expected_ty)
+                        let actual_val_addr = self.addrspace_cast(actual_val,
+                                                                  expected_ty.address_space());
+                        self.pointercast(actual_val_addr, expected_ty)
                     } else {
-                        let actual_val = if actual_ty.is_ptr() {
+                        let actual_val_addr = if actual_ty.is_ptr() {
                             self.flat_addr_cast(actual_val)
                         } else {
                             actual_val
                         };
-                        self.bitcast(actual_val, expected_ty)
+                        self.bitcast(actual_val_addr, expected_ty)
                     }
                 } else {
                     actual_val
@@ -1369,8 +1369,7 @@ impl Builder<'a, 'll, 'tcx> {
         let lifetime_intrinsic = if let AddrSpaceIdx(0) = addr_space {
             self.cx.get_intrinsic(intrinsic)
         } else {
-            let intrinsic = format!("{}.p{}i8", intrinsic, addr_space);
-            self.cx.get_intrinsic(&intrinsic)
+            self.cx.get_intrinsic(&format!("{}.p{}i8", intrinsic, addr_space))
         };
 
         let ptr = self.pointercast(ptr, self.cx.type_i8p());
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index 9a6de7f2bb36f..130c705231cc0 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -137,9 +137,8 @@ impl CodegenCx<'ll, 'tcx> {
                                                     s.len() as c_uint,
                                                     !null_terminated as Bool);
             let sym = self.generate_local_symbol_name("str");
-            let addr_space = self.const_addr_space();
-            let g = self.define_global(&sym[..], self.val_ty(sc), addr_space)
-                .unwrap_or_else(||bug!("symbol `{}` is already defined", sym) );
+            let g = self.define_global(&sym[..], self.val_ty(sc), self.const_addr_space())
+                .unwrap_or_else(||bug!("symbol `{}` is already defined", sym));
             llvm::LLVMSetInitializer(g, sc);
             llvm::LLVMSetGlobalConstant(g, True);
             llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
@@ -310,12 +309,12 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             },
             Scalar::Raw { data, size } => {
                 assert_eq!(size as u64, layout.value.size(self).bytes());
-                let llval = self.const_uint_big(self.type_ix(bitsize), data);
+                let llconstval = self.const_uint_big(self.type_ix(bitsize), data);
                 let flat_llty = llty.copy_addr_space(self.flat_addr_space());
                 let llval = if layout.value == layout::Pointer {
-                    unsafe { llvm::LLVMConstIntToPtr(llval, flat_llty) }
+                    unsafe { llvm::LLVMConstIntToPtr(llconstval, flat_llty) }
                 } else {
-                    self.const_bitcast(llval, flat_llty)
+                    self.const_bitcast(llconstval, flat_llty)
                 };
                 if llty.is_ptr() {
                     self.const_as_cast(llval, llty.address_space())
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index a62b8514cef8c..5f796e788a790 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -151,21 +151,20 @@ fn check_and_apply_linkage(
 }
 
 pub fn ptrcast(val: &'ll Value, ty: &'ll Type) -> &'ll Value {
-    let ty = ty.copy_addr_space(val_addr_space(val));
     unsafe {
-        llvm::LLVMConstPointerCast(val, ty)
+        llvm::LLVMConstPointerCast(val, ty.copy_addr_space(val_addr_space(val)))
     }
 }
 
 impl CodegenCx<'ll, 'tcx> {
     crate fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value {
-        let ty = if let Some(addr_space) = val_addr_space_opt(val) {
+        let ty_addr = if let Some(addr_space) = val_addr_space_opt(val) {
             ty.copy_addr_space(addr_space)
         } else {
             ty
         };
         unsafe {
-            llvm::LLVMConstBitCast(val, ty)
+            llvm::LLVMConstBitCast(val, ty_addr)
         }
     }
 
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 82eed46ccebb7..5ee0c336c43e0 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -596,10 +596,6 @@ impl CodegenCx<'b, 'tcx> {
             t_v8f64: t_f64, 8;
         }
 
-        // ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void);
-        // ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
-        // ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void);
-
         fn parse_addr_space(s: &str) -> AddrSpaceIdx {
             assert!(s.starts_with("p"));
             assert!(s.ends_with("i8"));
@@ -609,7 +605,7 @@ impl CodegenCx<'b, 'tcx> {
         }
 
         if key.starts_with("llvm.memcpy") || key.starts_with("llvm.memmove") ||
-          key.starts_with("llvm.memset") {
+            key.starts_with("llvm.memset") {
 
             let mut split = key.split('.');
             assert_eq!(Some("llvm"), split.next());
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 89f81b3413803..707b7cae16ce7 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -721,8 +721,6 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
                 LinkerFlavor::Ld => "ld",
                 LinkerFlavor::Msvc => "link.exe",
                 LinkerFlavor::Lld(_) => "lld",
-                // FIXME: Waiting till ready
-                // LinkerFlavor::AmdGpuLinker => "lld",
                 LinkerFlavor::PtxLinker => "rust-ptx-linker",
             }), flavor)),
             (Some(linker), None) => {
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index 053e76d8ac114..4dcee32259e2f 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -1168,127 +1168,3 @@ impl<'a> Linker for PtxLinker<'a> {
     fn linker_plugin_lto(&mut self) {
     }
 }
-
-pub struct AmdGpuLinker<'a> {
-    cmd: Command,
-    sess: &'a Session,
-}
-
-impl<'a> Linker for AmdGpuLinker<'a> {
-    fn link_rlib(&mut self, path: &Path) {
-        self.cmd.arg("--rlib").arg(path);
-    }
-
-    fn link_whole_rlib(&mut self, path: &Path) {
-        self.cmd.arg("--rlib").arg(path);
-    }
-
-    fn include_path(&mut self, path: &Path) {
-        self.cmd.arg("-L").arg(path);
-    }
-
-    fn debuginfo(&mut self) {
-        self.cmd.arg("--debug");
-    }
-
-    fn add_object(&mut self, path: &Path) {
-        self.cmd.arg("--bitcode").arg(path);
-    }
-
-    fn args(&mut self, args: &[String]) {
-        self.cmd.args(args);
-    }
-
-    fn optimize(&mut self) {
-        match self.sess.lto() {
-            Lto::Thin | Lto::Fat | Lto::ThinLocal => {
-                self.cmd.arg("-Olto");
-            },
-
-            Lto::No => { },
-        };
-    }
-
-    fn output_filename(&mut self, path: &Path) {
-        self.cmd.arg("-o").arg(path);
-    }
-
-    fn finalize(&mut self) -> Command {
-        // Provide the linker with fallback to internal `target-cpu`.
-        self.cmd.arg("--fallback-arch").arg(match self.sess.opts.cg.target_cpu {
-            Some(ref s) => s,
-            None => &self.sess.target.target.options.cpu
-        });
-
-        ::std::mem::replace(&mut self.cmd, Command::new(""))
-    }
-
-    fn link_dylib(&mut self, _lib: &str) {
-        panic!("external dylibs not supported")
-    }
-
-    fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) {
-        panic!("external dylibs not supported")
-    }
-
-    fn link_staticlib(&mut self, _lib: &str) {
-        panic!("staticlibs not supported")
-    }
-
-    fn link_whole_staticlib(&mut self, _lib: &str, _search_path: &[PathBuf]) {
-        panic!("staticlibs not supported")
-    }
-
-    fn framework_path(&mut self, _path: &Path) {
-        panic!("frameworks not supported")
-    }
-
-    fn link_framework(&mut self, _framework: &str) {
-        panic!("frameworks not supported")
-    }
-
-    fn position_independent_executable(&mut self) {
-    }
-
-    fn full_relro(&mut self) {
-    }
-
-    fn partial_relro(&mut self) {
-    }
-
-    fn no_relro(&mut self) {
-    }
-
-    fn build_static_executable(&mut self) {
-    }
-
-    fn gc_sections(&mut self, _keep_metadata: bool) {
-    }
-
-    fn pgo_gen(&mut self) {
-    }
-
-    fn no_default_libraries(&mut self) {
-    }
-
-    fn build_dylib(&mut self, _out_filename: &Path) {
-    }
-
-    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {
-    }
-
-    fn subsystem(&mut self, _subsystem: &str) {
-    }
-
-    fn no_position_independent_executable(&mut self) {
-    }
-
-    fn group_start(&mut self) {
-    }
-
-    fn group_end(&mut self) {
-    }
-
-    fn linker_plugin_lto(&mut self) {
-    }
-}
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 290c3446a0bb2..8d06882c8e6f9 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -293,8 +293,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 bx.load(addr, self.fn_ty.ret.layout.align.abi)
             }
         };
-        let llval = bx.flat_addr_cast(llval);
-        bx.ret(llval);
+        let llvalc = bx.flat_addr_cast(llval);
+        bx.ret(llvalc);
     }
 
 
@@ -416,9 +416,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     col,
                     "panic_bounds_check_loc",
                 );
-                let file_line_col = bx.cx().const_flat_as_cast(file_line_col);
                 (lang_items::PanicBoundsCheckFnLangItem,
-                    vec![file_line_col, index, len])
+                    vec![bx.cx().const_flat_as_cast(file_line_col), index, len])
             }
             _ => {
                 let str = msg.description();
@@ -430,9 +429,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     col,
                     "panic_loc",
                 );
-                let msg_file_line_col = bx.cx().const_flat_as_cast(msg_file_line_col);
                 (lang_items::PanicFnLangItem,
-                    vec![msg_file_line_col])
+                    vec![bx.cx().const_flat_as_cast(msg_file_line_col)])
             }
         };
 
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index 0cb560b2c6379..0f17aa26e5920 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -363,8 +363,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                 bx.pointercast(llval, ll_t_out),
                             (CastTy::Ptr(_), CastTy::Int(_)) |
                             (CastTy::FnPtr, CastTy::Int(_)) => {
-                                let llval = bx.flat_addr_cast(llval);
-                                bx.ptrtoint(llval, ll_t_out)
+                                let llvalc = bx.flat_addr_cast(llval);
+                                bx.ptrtoint(llvalc, ll_t_out)
                             },
                             (CastTy::Int(_), CastTy::Ptr(_)) => {
                                 let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed);
@@ -621,10 +621,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     lhs, rhs
                 )
             } else {
-                let (lhs, rhs) = codegen_binop_fixup(bx, lhs, rhs);
+                let (lhsc, rhsc) = codegen_binop_fixup(bx, lhs, rhs);
                 bx.icmp(
                     base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed),
-                    lhs, rhs
+                    lhsc, rhsc
                 )
             }
         }
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 910c51443d20d..37069279ec45d 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -1045,82 +1045,3 @@ impl<'a, Ty> TyLayout<'a, Ty> {
         }
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::spec::{Target, TargetTriple};
-
-    #[test]
-    fn pointer_size_align() {
-        // amdgcn-amd-amdhsa-amdgiz
-        const DL: &'static str = "e-p:64:64-p1:64:64-p2:64:64-p3:32:32-\
-                                  p4:32:32-p5:32:32-i64:64-v16:16-v24:32-\
-                                  v32:32-v48:64-v96:128-v192:256-v256:256-\
-                                  v512:512-v1024:1024-v2048:2048-n32:64-A5";
-
-        // Doesn't need to be real...
-        let triple = TargetTriple::TargetTriple("x86_64-unknown-linux-gnu".into());
-        let mut target = Target::search(&triple).unwrap();
-        target.data_layout = DL.into();
-
-        let dl = TargetDataLayout::parse(&target);
-        assert!(dl.is_ok());
-        let dl = dl.unwrap();
-
-        let default = (dl.pointer_size, dl.pointer_align);
-
-        let thirty_two_size = Size::from_bits(32);
-        let thirty_two_align = AbiAndPrefAlign::new(Align::from_bits(32).unwrap());
-        let thirty_two = (thirty_two_size, thirty_two_align);
-        let sixty_four_size = Size::from_bits(64);
-        let sixty_four_align = AbiAndPrefAlign::new(Align::from_bits(64).unwrap());
-        let sixty_four = (sixty_four_size, sixty_four_align);
-
-        assert_eq!(dl.pointer_info(AddrSpaceIdx(0)), default);
-        assert_eq!(dl.pointer_info(AddrSpaceIdx(0)), sixty_four);
-        assert_eq!(dl.pointer_info(AddrSpaceIdx(1)), sixty_four);
-        assert_eq!(dl.pointer_info(AddrSpaceIdx(2)), sixty_four);
-        assert_eq!(dl.pointer_info(AddrSpaceIdx(3)), thirty_two);
-        assert_eq!(dl.pointer_info(AddrSpaceIdx(4)), thirty_two);
-        assert_eq!(dl.pointer_info(AddrSpaceIdx(5)), thirty_two);
-
-        // unknown address spaces need to be the same as the default:
-        assert_eq!(dl.pointer_info(AddrSpaceIdx(7)), default);
-    }
-
-    #[test]
-    fn default_is_biggest() {
-        // Note p1 is 128 bits.
-        const DL: &'static str = "e-p:64:64-p1:128:128-p2:64:64-p3:32:32-\
-                                  p4:32:32-p5:32:32-i64:64-v16:16-v24:32-\
-                                  v32:32-v48:64-v96:128-v192:256-v256:256-\
-                                  v512:512-v1024:1024-v2048:2048-n32:64-A5";
-
-        // Doesn't need to be real...
-        let triple = TargetTriple::TargetTriple("x86_64-unknown-linux-gnu".into());
-        let mut target = Target::search(&triple).unwrap();
-        target.data_layout = DL.into();
-
-        assert!(TargetDataLayout::parse(&target).is_err());
-    }
-    #[test]
-    fn alloca_addr_space() {
-        // amdgcn-amd-amdhsa-amdgiz
-        const DL: &'static str = "e-p:64:64-p1:64:64-p2:64:64-p3:32:32-\
-                                  p4:32:32-p5:32:32-i64:64-v16:16-v24:32-\
-                                  v32:32-v48:64-v96:128-v192:256-v256:256-\
-                                  v512:512-v1024:1024-v2048:2048-n32:64-A5";
-
-        // Doesn't need to be real...
-        let triple = TargetTriple::TargetTriple("x86_64-unknown-linux-gnu".into());
-        let mut target = Target::search(&triple).unwrap();
-        target.data_layout = DL.into();
-
-        let dl = TargetDataLayout::parse(&target);
-        assert!(dl.is_ok());
-        let dl = dl.unwrap();
-
-        assert_eq!(dl.alloca_address_space, AddrSpaceIdx(5));
-    }
-}
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 0e1f9b9744555..f44bc66db600a 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -76,8 +76,6 @@ pub enum LinkerFlavor {
     Ld,
     Msvc,
     Lld(LldFlavor),
-    // FIXME: Enable when ready
-    // AmdGpuLinker,
     PtxLinker,
 }
 
@@ -147,8 +145,6 @@ flavor_mappings! {
     ((LinkerFlavor::Gcc), "gcc"),
     ((LinkerFlavor::Ld), "ld"),
     ((LinkerFlavor::Msvc), "msvc"),
-    // FIXME: Enable when ready
-    // ((LinkerFlavor::AmdGpuLinker), "amdgpu-linker"),
     ((LinkerFlavor::PtxLinker), "ptx-linker"),
     ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"),
     ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"),