OSDN Git Service

Add load and store instructions to Subzero bitcode reader.
authorKarl Schimpf <kschimpf@google.com>
Wed, 10 Sep 2014 21:36:07 +0000 (14:36 -0700)
committerKarl Schimpf <kschimpf@google.com>
Wed, 10 Sep 2014 21:36:07 +0000 (14:36 -0700)
BUG= https://code.google.com/p/nativeclient/issues/detail?id=3892
R=jvoung@chromium.org, stichnot@chromium.org

Review URL: https://codereview.chromium.org/561883002

src/IceInst.h
src/IceTypes.cpp
src/IceTypes.def
src/IceTypes.h
src/PNaClTranslator.cpp
tests_lit/reader_tests/load.ll [new file with mode: 0644]
tests_lit/reader_tests/store.ll [new file with mode: 0644]

index fd01e92..484e10f 100644 (file)
@@ -481,7 +481,10 @@ private:
 // Load instruction.  The source address is captured in getSrc(0).
 class InstLoad : public Inst {
 public:
-  static InstLoad *create(Cfg *Func, Variable *Dest, Operand *SourceAddr) {
+  static InstLoad *create(Cfg *Func, Variable *Dest, Operand *SourceAddr,
+                          uint32_t align = 1) {
+    // TODO(kschimpf) Stop ignoring alignment specification.
+    (void)align;
     return new (Func->allocateInst<InstLoad>())
         InstLoad(Func, Dest, SourceAddr);
   }
@@ -577,7 +580,10 @@ private:
 // data operand to be stored into the address.
 class InstStore : public Inst {
 public:
-  static InstStore *create(Cfg *Func, Operand *Data, Operand *Addr) {
+  static InstStore *create(Cfg *Func, Operand *Data, Operand *Addr,
+                           uint32_t align = 1) {
+    // TODO(kschimpf) Stop ignoring alignment specification.
+    (void)align;
     return new (Func->allocateInst<InstStore>()) InstStore(Func, Data, Addr);
   }
   Operand *getAddr() const { return getSrc(1); }
index 3a5b80a..a3e19ae 100644 (file)
@@ -33,8 +33,8 @@ void __attribute__((unused)) xIceTypeMacroIntegrityCheck() {
   };
   // Define a temporary set of enum values based on ICETYPE_PROPS_TABLE
   enum {
-#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, CompareResult)               \
-    _props_table_tag_##tag,
+#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, IsLoadStore, CompareResult)  \
+  _props_table_tag_##tag,
     ICETYPE_PROPS_TABLE
 #undef X
         _enum_props_table_tag_Names
@@ -45,9 +45,9 @@ void __attribute__((unused)) xIceTypeMacroIntegrityCheck() {
   ICETYPE_TABLE;
 #undef X
 // Assert that tags in ICETYPE_PROPS_TABLE is in ICETYPE_TABLE.
-#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, CompareResult)               \
+#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, IsLoadStore, CompareResult)  \
   STATIC_ASSERT((unsigned)_table_tag_##tag == (unsigned)_props_table_tag_##tag);
-  ICETYPE_PROPS_TABLE;
+  ICETYPE_PROPS_TABLE
 #undef X
 
   // Show vector definitions match in ICETYPE_TABLE and
@@ -62,13 +62,13 @@ void __attribute__((unused)) xIceTypeMacroIntegrityCheck() {
   };
   // Define constants for boolean flag if vector in ICETYPE_PROPS_TABLE.
   enum {
-#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, CompareResult)               \
-    _props_table_IsVec_##tag = IsVec,
+#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, IsLoadStore, CompareResult)  \
+  _props_table_IsVec_##tag = IsVec,
     ICETYPE_PROPS_TABLE
 #undef X
   };
 // Verify that the number of vector elements is consistent with IsVec.
-#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, CompareResult)               \
+#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, IsLoadStore, CompareResult)  \
   STATIC_ASSERT((_table_elts_##tag > 1) == _props_table_IsVec_##tag);
   ICETYPE_PROPS_TABLE;
 #undef X
@@ -99,14 +99,15 @@ struct TypePropertyFields {
   bool TypeIsFloatingType;
   bool TypeIsScalarFloatingType;
   bool TypeIsVectorFloatingType;
+  bool TypeIsLoadStoreType;
   Type CompareResultType;
 };
 
 const TypePropertyFields TypePropertiesTable[] = {
-#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, CompareResult)               \
+#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, IsLoadStore, CompareResult)  \
   {                                                                            \
     IsVec, IsInt, IsInt && !IsVec, IsInt && IsVec, IsIntArith, IsFloat,        \
-    IsFloat && !IsVec, IsFloat && IsVec, CompareResult                         \
+        IsFloat && !IsVec, IsFloat && IsVec, IsLoadStore, CompareResult        \
   }                                                                            \
   ,
     ICETYPE_PROPS_TABLE
@@ -211,6 +212,14 @@ bool isVectorFloatingType(Type Ty) {
   return false;
 }
 
+bool isLoadStoreType(Type Ty) {
+  size_t Index = static_cast<size_t>(Ty);
+  if (Index < IceType_NUM)
+    return TypePropertiesTable[Index].TypeIsLoadStoreType;
+  llvm_unreachable("Invalid type for isLoadStoreType()");
+  return false;
+}
+
 Type getCompareResultType(Type Ty) {
   size_t Index = static_cast<size_t>(Ty);
   if (Index < IceType_NUM)
index 26e9216..19175f0 100644 (file)
 //   I - Is integer value (scalar or vector).
 //   F - Is floating point value (scalar or vector).
 //   IA - Is integer arithmetic type
+//   LS - true if load/store allowed on type.
 //   CR - Result type of compare instruction for argument type
 //        (IceType_void if disallowed)
 #define ICETYPE_PROPS_TABLE                                              \
-  /* Enum Value    V  I  F IA  CR */                                     \
-  X(IceType_void,  0, 0, 0, 0, IceType_void)                             \
-  X(IceType_i1,    0, 1, 0, 0, IceType_i1)                               \
-  X(IceType_i8,    0, 1, 0, 1, IceType_i1)                               \
-  X(IceType_i16,   0, 1, 0, 1, IceType_i1)                               \
-  X(IceType_i32,   0, 1, 0, 1, IceType_i1)                               \
-  X(IceType_i64,   0, 1, 0, 1, IceType_i1)                               \
-  X(IceType_f32,   0, 0, 1, 0, IceType_i1)                               \
-  X(IceType_f64,   0, 0, 1, 0, IceType_i1)                               \
-  X(IceType_v4i1,  1, 1, 0, 0, IceType_v4i1)                             \
-  X(IceType_v8i1,  1, 1, 0, 0, IceType_v8i1)                             \
-  X(IceType_v16i1, 1, 1, 0, 0, IceType_v16i1)                            \
-  X(IceType_v16i8, 1, 1, 0, 1, IceType_v16i1)                            \
-  X(IceType_v8i16, 1, 1, 0, 1, IceType_v8i1)                             \
-  X(IceType_v4i32, 1, 1, 0, 1, IceType_v4i1)                             \
-  X(IceType_v4f32, 1, 0, 1, 0, IceType_v4i1)                             \
-//#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, CompareResult)
+  /* Enum Value    V  I  F IA  LS CR */                                  \
+  X(IceType_void,  0, 0, 0, 0, 0, IceType_void)                          \
+  X(IceType_i1,    0, 1, 0, 0, 0, IceType_i1)                            \
+  X(IceType_i8,    0, 1, 0, 1, 1, IceType_i1)                            \
+  X(IceType_i16,   0, 1, 0, 1, 1, IceType_i1)                            \
+  X(IceType_i32,   0, 1, 0, 1, 1, IceType_i1)                            \
+  X(IceType_i64,   0, 1, 0, 1, 1, IceType_i1)                            \
+  X(IceType_f32,   0, 0, 1, 0, 1, IceType_i1)                            \
+  X(IceType_f64,   0, 0, 1, 0, 1, IceType_i1)                            \
+  X(IceType_v4i1,  1, 1, 0, 0, 0, IceType_v4i1)                          \
+  X(IceType_v8i1,  1, 1, 0, 0, 0, IceType_v8i1)                          \
+  X(IceType_v16i1, 1, 1, 0, 0, 0, IceType_v16i1)                         \
+  X(IceType_v16i8, 1, 1, 0, 1, 1, IceType_v16i1)                         \
+  X(IceType_v8i16, 1, 1, 0, 1, 1, IceType_v8i1)                          \
+  X(IceType_v4i32, 1, 1, 0, 1, 1, IceType_v4i1)                          \
+  X(IceType_v4f32, 1, 0, 1, 0, 1, IceType_v4i1)                          \
+//#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, IsLoadStore, CompareResult)
 
 #endif // SUBZERO_SRC_ICETYPES_DEF
index 2ce8f35..4127104 100644 (file)
@@ -58,6 +58,9 @@ bool isFloatingType(Type Ty); // scalar or vector
 bool isScalarFloatingType(Type Ty);
 bool isVectorFloatingType(Type Ty);
 
+/// Returns true if the given type can be used in a load instruction.
+bool isLoadStoreType(Type Ty);
+
 /// Returns type generated by applying the compare instructions (icmp and fcmp)
 /// to arguments of the given type. Returns IceType_void if compare is not
 /// allowed.
index bde906a..c83898d 100644 (file)
 #include "IceInst.h"
 #include "IceOperand.h"
 #include "IceTypeConverter.h"
+#include "llvm/Analysis/NaCl/PNaClABIProps.h"
 #include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h"
 #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
 #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h"
 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
 #include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Format.h"
@@ -55,9 +57,10 @@ public:
                  NaClBitcodeHeader &Header, NaClBitstreamCursor &Cursor,
                  bool &ErrorStatus)
       : NaClBitcodeParser(Cursor), Translator(Translator),
-        Mod(new Module(InputName, getGlobalContext())), Header(Header),
-        TypeConverter(getLLVMContext()), ErrorStatus(ErrorStatus), NumErrors(0),
-        NumFunctionIds(0), NumFunctionBlocks(0),
+        Mod(new Module(InputName, getGlobalContext())), DL(PNaClDataLayout),
+        Header(Header), TypeConverter(getLLVMContext()),
+        ErrorStatus(ErrorStatus), NumErrors(0), NumFunctionIds(0),
+        NumFunctionBlocks(0),
         GlobalVarPlaceHolderType(convertToLLVMType(Ice::IceType_i8)) {
     Mod->setDataLayout(PNaClDataLayout);
   }
@@ -84,6 +87,8 @@ public:
   /// Returns the LLVM module associated with the translation.
   Module *getModule() const { return Mod.get(); }
 
+  const DataLayout &getDataLayout() const { return DL; }
+
   /// Returns the number of bytes in the bitcode header.
   size_t getHeaderSize() const { return Header.getHeaderSize(); }
 
@@ -228,6 +233,8 @@ private:
   Ice::Translator &Translator;
   // The parsed module.
   OwningPtr<Module> Mod;
+  // The data layout to use.
+  DataLayout DL;
   // The bitcode header.
   NaClBitcodeHeader &Header;
   // Converter between LLVM and ICE types.
@@ -848,6 +855,24 @@ private:
   // Upper limit of alignment power allowed by LLVM
   static const uint64_t AlignPowerLimit = 29;
 
+  // Extracts the corresponding Alignment to use, given the AlignPower
+  // (i.e. 2**AlignPower, or 0 if AlignPower == 0). InstName is the
+  // name of the instruction the alignment appears in.
+  void extractAlignment(const char *InstName, uint64_t AlignPower,
+                        unsigned &Alignment) {
+    if (AlignPower <= AlignPowerLimit) {
+      Alignment = (1 << static_cast<unsigned>(AlignPower)) >> 1;
+      return;
+    }
+    std::string Buffer;
+    raw_string_ostream StrBuf(Buffer);
+    StrBuf << InstName << " alignment greater than 2**" << AlignPowerLimit
+           << ". Found: 2**" << AlignPower;
+    Error(StrBuf.str());
+    // Error recover with value that is always acceptable.
+    Alignment = 1;
+  }
+
   virtual bool ParseBlock(unsigned BlockID) LLVM_OVERRIDE;
 
   virtual void ProcessRecord() LLVM_OVERRIDE;
@@ -959,8 +984,8 @@ private:
   }
 
   // Checks if floating arithmetic Op, for type OpTy, is valid.
-  // Returns false if valid. Otherwise generates an error message and
-  // returns true.
+  // Returns true if valid. Otherwise generates an error message and
+  // returns false;
   bool isValidFloatingArithOp(Ice::InstArithmetic::OpKind Op, Ice::Type OpTy) {
     if (Ice::isFloatingType(OpTy))
       return true;
@@ -968,6 +993,52 @@ private:
     return false;
   }
 
+  // Checks if the type of operand Op is the valid pointer type, for
+  // the given InstructionName. Returns true if valid. Otherwise
+  // generates an error message and returns false.
+  bool isValidPointerType(Ice::Operand *Op, const char *InstructionName) {
+    Ice::Type PtrType = Context->getIcePointerType();
+    if (Op->getType() == PtrType)
+      return true;
+    std::string Buffer;
+    raw_string_ostream StrBuf(Buffer);
+    StrBuf << InstructionName << " address not " << PtrType
+           << ". Found: " << Op;
+    Error(StrBuf.str());
+    return false;
+  }
+
+  // Checks if loading/storing a value of type Ty is allowed.
+  // Returns true if Valid. Otherwise generates an error message and
+  // returns false.
+  bool isValidLoadStoreType(Ice::Type Ty, const char *InstructionName) {
+    if (isLoadStoreType(Ty))
+      return true;
+    std::string Buffer;
+    raw_string_ostream StrBuf(Buffer);
+    StrBuf << InstructionName << " type not allowed: " << Ty << "*";
+    Error(StrBuf.str());
+    return false;
+  }
+
+  // Checks if loading/storing a value of type Ty is allowed for
+  // the given Alignment. Otherwise generates an error message and
+  // returns false.
+  bool isValidLoadStoreAlignment(unsigned Alignment, Ice::Type Ty,
+                                 const char *InstructionName) {
+    if (!isValidLoadStoreType(Ty, InstructionName))
+      return false;
+    if (PNaClABIProps::isAllowedAlignment(&Context->getDataLayout(), Alignment,
+                                          Context->convertToLLVMType(Ty)))
+      return true;
+    std::string Buffer;
+    raw_string_ostream StrBuf(Buffer);
+    StrBuf << InstructionName << " " << Ty << "*: not allowed for alignment "
+           << Alignment;
+    Error(StrBuf.str());
+    return false;
+  }
+
   // Reports that the given binary Opcode, for the given type Ty,
   // is not understood.
   void ReportInvalidBinopOpcode(unsigned Opcode, Ice::Type Ty);
@@ -1529,22 +1600,46 @@ void FunctionParser::ProcessRecord() {
       Error(StrBuf.str());
       return;
     }
-    uint64_t AlignPower = Values[1];
-    unsigned Alignment = 1;
-    if (AlignPower <= AlignPowerLimit) {
-      Alignment = (1 << static_cast<unsigned>(AlignPower)) >> 1;
-    } else {
-      std::string Buffer;
-      raw_string_ostream StrBuf(Buffer);
-      StrBuf << "Alloca on alignment greater than 2**" << AlignPowerLimit
-             << ". Found: 2**" << AlignPower;
-      Error(StrBuf.str());
-      // TODO(kschimpf) Remove error recovery once implementation complete.
-    }
+    unsigned Alignment;
+    extractAlignment("Alloca", Values[1], Alignment);
     Ice::Variable *Dest = NextInstVar(Context->getIcePointerType());
     Inst = Ice::InstAlloca::create(Func, ByteCount, Alignment, Dest);
     break;
   }
+  case naclbitc::FUNC_CODE_INST_LOAD: {
+    // LOAD: [address, align, ty]
+    if (!isValidRecordSize(3, "function block load"))
+      return;
+    Ice::Operand *Address = getRelativeOperand(Values[0]);
+    if (!isValidPointerType(Address, "Load"))
+      return;
+    unsigned Alignment;
+    extractAlignment("Load", Values[1], Alignment);
+    Ice::Type Ty = Context->convertToIceType(Context->getTypeByID(Values[2]));
+    if (!isValidLoadStoreAlignment(Alignment, Ty, "Load"))
+      return;
+    Ice::Variable *Dest = NextInstVar(Ty);
+    Inst = Ice::InstLoad::create(Func, Dest, Address, Alignment);
+    break;
+  }
+  case naclbitc::FUNC_CODE_INST_STORE: {
+    // STORE: [address, value, align]
+    if (!isValidRecordSize(3, "function block store"))
+      return;
+    Ice::Operand *Address = getRelativeOperand(Values[0]);
+    if (!isValidPointerType(Address, "Store"))
+      return;
+    Ice::Operand *Value = getRelativeOperand(Values[1]);
+    unsigned Alignment;
+    if (!extractAlignment("Store", Values[2], Alignment)) {
+      // TODO(kschimpf) Remove error recovery once implementation complete.
+      Alignment = 1;
+    }
+    if (!isValidLoadStoreAlignment(Alignment, Value->getType(), "Store"))
+      return;
+    Inst = Ice::InstStore::create(Func, Value, Address, Alignment);
+    break;
+  }
   default:
     // Generate error message!
     BlockParserBaseClass::ProcessRecord();
diff --git a/tests_lit/reader_tests/load.ll b/tests_lit/reader_tests/load.ll
new file mode 100644 (file)
index 0000000..117dbbf
--- /dev/null
@@ -0,0 +1,149 @@
+; Test if we can read load instructions.
+
+; RUN: llvm-as < %s | pnacl-freeze \
+; RUN:              | %llvm2ice -notranslate -verbose=inst -build-on-read \
+; RUN:                -allow-pnacl-reader-error-recovery \
+; RUN:              | FileCheck %s
+
+define i32 @load_i8(i32 %addr) {
+entry:
+  %addr_i8 = inttoptr i32 %addr to i8*
+  %v = load i8* %addr_i8, align 1
+  %r = sext i8 %v to i32
+  ret i32 %r
+
+; CHECK:      __0:
+; CHECK-NEXT:   %__1 = load i8* %__0, align 1
+; CHECK-NEXT:   %__2 = sext i8 %__1 to i32
+; CHECK-NEXT:   ret i32 %__2
+}
+
+define i32 @load_i16(i32 %addr) {
+entry:
+  %addr_i16 = inttoptr i32 %addr to i16*
+  %v = load i16* %addr_i16, align 1
+  %r = sext i16 %v to i32
+  ret i32 %r
+
+; CHECK:      __0:
+; CHECK-NEXT:   %__1 = load i16* %__0, align 1
+; CHECK-NEXT:   %__2 = sext i16 %__1 to i32
+; CHECK-NEXT:   ret i32 %__2
+}
+
+define i32 @load_i32(i32 %addr) {
+entry:
+  %addr_i32 = inttoptr i32 %addr to i32*
+  %v = load i32* %addr_i32, align 1
+  ret i32 %v
+
+; CHECK:      __0:
+; CHECK-NEXT:   %__1 = load i32* %__0, align 1
+; CHECK-NEXT:   ret i32 %__1
+}
+
+define i64 @load_i64(i32 %addr) {
+entry:
+  %addr_i64 = inttoptr i32 %addr to i64*
+  %v = load i64* %addr_i64, align 1
+  ret i64 %v
+
+; CHECK:      __0:
+; CHECK-NEXT:   %__1 = load i64* %__0, align 1
+; CHECK-NEXT:   ret i64 %__1
+}
+
+define float @load_float_a1(i32 %addr) {
+entry:
+  %addr_float = inttoptr i32 %addr to float*
+  %v = load float* %addr_float, align 1
+  ret float %v
+
+; TODO(kschimpf) Fix load alignment in ICE to allow non-default.
+
+; CHECK:      __0:
+; CHECK-NEXT:   %__1 = load float* %__0, align 4
+; CHECK-NEXT:   ret float %__1
+}
+
+
+define float @load_float_a4(i32 %addr) {
+entry:
+  %addr_float = inttoptr i32 %addr to float*
+  %v = load float* %addr_float, align 4
+  ret float %v
+
+; CHECK:       __0:
+; CHECK-NEXT:   %__1 = load float* %__0, align 4
+; CHECK-NEXT:   ret float %__1
+}
+
+define double @load_double_a1(i32 %addr) {
+entry:
+  %addr_double = inttoptr i32 %addr to double*
+  %v = load double* %addr_double, align 1
+  ret double %v
+
+; TODO(kschimpf) Fix load alignment in ICE to allow non-default.
+
+; CHECK:      __0:
+; CHECK-NEXT:   %__1 = load double* %__0, align 8
+; CHECK-NEXT:   ret double %__1
+}
+
+
+define double @load_double_a8(i32 %addr) {
+entry:
+  %addr_double = inttoptr i32 %addr to double*
+  %v = load double* %addr_double, align 8
+  ret double %v
+
+; CHECK:      __0:
+; CHECK-NEXT:   %__1 = load double* %__0, align 8
+; CHECK-NEXT:   ret double %__1
+}
+
+define <16 x i8> @load_v16xI8(i32 %addr) {
+entry:
+  %addr_v16xI8 = inttoptr i32 %addr to <16 x i8>*
+  %v = load <16 x i8>* %addr_v16xI8, align 1
+  ret <16 x i8> %v
+
+; CHECK:      __0:
+; CHECK-NEXT:   %__1 = load <16 x i8>* %__0, align 1
+; CHECK-NEXT:   ret <16 x i8> %__1
+}
+
+define <8 x i16> @load_v8xI16(i32 %addr) {
+entry:
+  %addr_v8xI16 = inttoptr i32 %addr to <8 x i16>*
+  %v = load <8 x i16>* %addr_v8xI16, align 2
+  ret <8 x i16> %v
+
+; CHECK:      __0:
+; CHECK-NEXT:   %__1 = load <8 x i16>* %__0, align 2
+; CHECK-NEXT:   ret <8 x i16> %__1
+}
+
+define <4 x i32> @load_v4xI32(i32 %addr) {
+entry:
+  %addr_v4xI32 = inttoptr i32 %addr to <4 x i32>*
+  %v = load <4 x i32>* %addr_v4xI32, align 4
+  ret <4 x i32> %v
+
+; CHECK:      __0:
+; CHECK-NEXT:   %__1 = load <4 x i32>* %__0, align 4
+; CHECK-NEXT:   ret <4 x i32> %__1
+}
+
+define <4 x float> @load_v4xFloat(i32 %addr) {
+entry:
+  %addr_v4xFloat = inttoptr i32 %addr to <4 x float>*
+  %v = load <4 x float>* %addr_v4xFloat, align 4
+  ret <4 x float> %v
+
+; CHECK:      __0:
+; CHECK-NEXT:   %__1 = load <4 x float>* %__0, align 4
+; CHECK-NEXT:   ret <4 x float> %__1
+}
+
diff --git a/tests_lit/reader_tests/store.ll b/tests_lit/reader_tests/store.ll
new file mode 100644 (file)
index 0000000..ac1f711
--- /dev/null
@@ -0,0 +1,138 @@
+; Test if we can read store instructions.
+
+; RUN: llvm-as < %s | pnacl-freeze \
+; RUN:              | %llvm2ice -notranslate -verbose=inst -build-on-read \
+; RUN:                -allow-pnacl-reader-error-recovery \
+; RUN:              | FileCheck %s
+
+define void @store_i8(i32 %addr) {
+entry:
+  %addr_i8 = inttoptr i32 %addr to i8*
+  store i8 3, i8* %addr_i8, align 1
+  ret void
+
+; CHECK:      __0:
+; CHECK-NEXT:   store i8 3, i8* %__0, align 1
+; CHECK-NEXT:   ret void
+}
+
+define void @store_i16(i32 %addr) {
+entry:
+  %addr_i16 = inttoptr i32 %addr to i16*
+  store i16 5, i16* %addr_i16, align 1
+  ret void
+
+; CHECK:      __0:
+; CHECK-NEXT:   store i16 5, i16* %__0, align 1
+; CHECK-NEXT:   ret void
+}
+
+define void @store_i32(i32 %addr, i32 %v) {
+entry:
+  %addr_i32 = inttoptr i32 %addr to i32*
+  store i32 %v, i32* %addr_i32, align 1
+  ret void
+
+; CHECK:      __0:
+; CHECK-NEXT:   store i32 %__1, i32* %__0, align 1
+; CHECK-NEXT:   ret void
+}
+
+define void @store_i64(i32 %addr, i64 %v) {
+entry:
+  %addr_i64 = inttoptr i32 %addr to i64*
+  store i64 %v, i64* %addr_i64, align 1
+  ret void
+
+; CHECK:      __0:
+; CHECK-NEXT:   store i64 %__1, i64* %__0, align 1
+; CHECK-NEXT:   ret void
+}
+
+define void @store_float_a1(i32 %addr, float %v) {
+entry:
+  %addr_float = inttoptr i32 %addr to float*
+  store float %v, float* %addr_float, align 1
+  ret void
+
+; TODO(kschimpf) Fix store alignment in ICE to allow non-default.
+
+; CHECK:      __0:
+; CHECK-NEXT:   store float %__1, float* %__0, align 4
+; CHECK-NEXT:   ret void
+}
+
+define void @store_float_a4(i32 %addr, float %v) {
+entry:
+  %addr_float = inttoptr i32 %addr to float*
+  store float %v, float* %addr_float, align 4
+  ret void
+
+; CHECK:       __0:
+; CHECK-NEXT:   store float %__1, float* %__0, align 4
+; CHECK-NEXT:   ret void
+}
+
+define void @store_double_a1(i32 %addr, double %v) {
+entry:
+  %addr_double = inttoptr i32 %addr to double*
+  store double %v, double* %addr_double, align 1
+  ret void
+
+; TODO(kschimpf) Fix store alignment in ICE to allow non-default.
+
+; CHECK:      __0:
+; CHECK-NEXT:   store double %__1, double* %__0, align 8
+; CHECK-NEXT:   ret void
+}
+
+define void @store_double_a8(i32 %addr, double %v) {
+entry:
+  %addr_double = inttoptr i32 %addr to double*
+  store double %v, double* %addr_double, align 8
+  ret void
+
+; CHECK:      __0:
+; CHECK-NEXT:   store double %__1, double* %__0, align 8
+; CHECK-NEXT:   ret void
+}
+
+define void @store_v16xI8(i32 %addr, <16 x i8> %v) {
+  %addr_v16xI8 = inttoptr i32 %addr to <16 x i8>*
+  store <16 x i8> %v, <16 x i8>* %addr_v16xI8, align 1
+  ret void
+
+; CHECK:      __0:
+; CHECK-NEXT:   store <16 x i8> %__1, <16 x i8>* %__0, align 1
+; CHECK-NEXT:   ret void
+}
+
+define void @store_v8xI16(i32 %addr, <8 x i16> %v) {
+  %addr_v8xI16 = inttoptr i32 %addr to <8 x i16>*
+  store <8 x i16> %v, <8 x i16>* %addr_v8xI16, align 2
+  ret void
+
+; CHECK:      __0:
+; CHECK-NEXT:   store <8 x i16> %__1, <8 x i16>* %__0, align 2
+; CHECK-NEXT:   ret void
+}
+
+define void @store_v4xI32(i32 %addr, <4 x i32> %v) {
+  %addr_v4xI32 = inttoptr i32 %addr to <4 x i32>*
+  store <4 x i32> %v, <4 x i32>* %addr_v4xI32, align 4
+  ret void
+
+; CHECK:      __0:
+; CHECK-NEXT:   store <4 x i32> %__1, <4 x i32>* %__0, align 4
+; CHECK-NEXT:   ret void
+}
+
+define void @store_v4xFloat(i32 %addr, <4 x float> %v) {
+  %addr_v4xFloat = inttoptr i32 %addr to <4 x float>*
+  store <4 x float> %v, <4 x float>* %addr_v4xFloat, align 4
+  ret void
+
+; CHECK:      __0:
+; CHECK-NEXT:   store <4 x float> %__1, <4 x float>* %__0, align 4
+; CHECK-NEXT:   ret void
+}