Add load and store instructions to Subzero bitcode reader.
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
diff --git a/src/IceInst.h b/src/IceInst.h
index fd01e92..484e10f 100644
--- a/src/IceInst.h
+++ b/src/IceInst.h
@@ -481,7 +481,10 @@
// 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 @@
// 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); }
diff --git a/src/IceTypes.cpp b/src/IceTypes.cpp
index 3a5b80a..a3e19ae 100644
--- a/src/IceTypes.cpp
+++ b/src/IceTypes.cpp
@@ -33,8 +33,8 @@
};
// 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 @@
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 @@
};
// 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 @@
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 @@
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)
diff --git a/src/IceTypes.def b/src/IceTypes.def
index 26e9216..19175f0 100644
--- a/src/IceTypes.def
+++ b/src/IceTypes.def
@@ -40,25 +40,26 @@
// 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
diff --git a/src/IceTypes.h b/src/IceTypes.h
index 2ce8f35..4127104 100644
--- a/src/IceTypes.h
+++ b/src/IceTypes.h
@@ -58,6 +58,9 @@
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.
diff --git a/src/PNaClTranslator.cpp b/src/PNaClTranslator.cpp
index bde906a..c83898d 100644
--- a/src/PNaClTranslator.cpp
+++ b/src/PNaClTranslator.cpp
@@ -20,11 +20,13 @@
#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 @@
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 @@
/// 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 @@
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 @@
// 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 @@
}
// 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 @@
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 @@
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
index 0000000..117dbbf
--- /dev/null
+++ b/tests_lit/reader_tests/load.ll
@@ -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
index 0000000..ac1f711
--- /dev/null
+++ b/tests_lit/reader_tests/store.ll
@@ -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
+}