Commit 41689df2 by Karl Schimpf

Add load and store instructions to Subzero bitcode reader.

parent e5a5be75
...@@ -481,7 +481,10 @@ private: ...@@ -481,7 +481,10 @@ private:
// Load instruction. The source address is captured in getSrc(0). // Load instruction. The source address is captured in getSrc(0).
class InstLoad : public Inst { class InstLoad : public Inst {
public: 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>()) return new (Func->allocateInst<InstLoad>())
InstLoad(Func, Dest, SourceAddr); InstLoad(Func, Dest, SourceAddr);
} }
...@@ -577,7 +580,10 @@ private: ...@@ -577,7 +580,10 @@ private:
// data operand to be stored into the address. // data operand to be stored into the address.
class InstStore : public Inst { class InstStore : public Inst {
public: 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); return new (Func->allocateInst<InstStore>()) InstStore(Func, Data, Addr);
} }
Operand *getAddr() const { return getSrc(1); } Operand *getAddr() const { return getSrc(1); }
......
...@@ -33,7 +33,7 @@ void __attribute__((unused)) xIceTypeMacroIntegrityCheck() { ...@@ -33,7 +33,7 @@ void __attribute__((unused)) xIceTypeMacroIntegrityCheck() {
}; };
// Define a temporary set of enum values based on ICETYPE_PROPS_TABLE // Define a temporary set of enum values based on ICETYPE_PROPS_TABLE
enum { enum {
#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, CompareResult) \ #define X(tag, IsVec, IsInt, IsFloat, IsIntArith, IsLoadStore, CompareResult) \
_props_table_tag_##tag, _props_table_tag_##tag,
ICETYPE_PROPS_TABLE ICETYPE_PROPS_TABLE
#undef X #undef X
...@@ -45,9 +45,9 @@ void __attribute__((unused)) xIceTypeMacroIntegrityCheck() { ...@@ -45,9 +45,9 @@ void __attribute__((unused)) xIceTypeMacroIntegrityCheck() {
ICETYPE_TABLE; ICETYPE_TABLE;
#undef X #undef X
// Assert that tags in ICETYPE_PROPS_TABLE is in ICETYPE_TABLE. // 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); STATIC_ASSERT((unsigned)_table_tag_##tag == (unsigned)_props_table_tag_##tag);
ICETYPE_PROPS_TABLE; ICETYPE_PROPS_TABLE
#undef X #undef X
// Show vector definitions match in ICETYPE_TABLE and // Show vector definitions match in ICETYPE_TABLE and
...@@ -62,13 +62,13 @@ void __attribute__((unused)) xIceTypeMacroIntegrityCheck() { ...@@ -62,13 +62,13 @@ void __attribute__((unused)) xIceTypeMacroIntegrityCheck() {
}; };
// Define constants for boolean flag if vector in ICETYPE_PROPS_TABLE. // Define constants for boolean flag if vector in ICETYPE_PROPS_TABLE.
enum { enum {
#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, CompareResult) \ #define X(tag, IsVec, IsInt, IsFloat, IsIntArith, IsLoadStore, CompareResult) \
_props_table_IsVec_##tag = IsVec, _props_table_IsVec_##tag = IsVec,
ICETYPE_PROPS_TABLE ICETYPE_PROPS_TABLE
#undef X #undef X
}; };
// Verify that the number of vector elements is consistent with IsVec. // 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); STATIC_ASSERT((_table_elts_##tag > 1) == _props_table_IsVec_##tag);
ICETYPE_PROPS_TABLE; ICETYPE_PROPS_TABLE;
#undef X #undef X
...@@ -99,14 +99,15 @@ struct TypePropertyFields { ...@@ -99,14 +99,15 @@ struct TypePropertyFields {
bool TypeIsFloatingType; bool TypeIsFloatingType;
bool TypeIsScalarFloatingType; bool TypeIsScalarFloatingType;
bool TypeIsVectorFloatingType; bool TypeIsVectorFloatingType;
bool TypeIsLoadStoreType;
Type CompareResultType; Type CompareResultType;
}; };
const TypePropertyFields TypePropertiesTable[] = { 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, \ IsVec, IsInt, IsInt && !IsVec, IsInt && IsVec, IsIntArith, IsFloat, \
IsFloat && !IsVec, IsFloat && IsVec, CompareResult \ IsFloat && !IsVec, IsFloat && IsVec, IsLoadStore, CompareResult \
} \ } \
, ,
ICETYPE_PROPS_TABLE ICETYPE_PROPS_TABLE
...@@ -211,6 +212,14 @@ bool isVectorFloatingType(Type Ty) { ...@@ -211,6 +212,14 @@ bool isVectorFloatingType(Type Ty) {
return false; 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) { Type getCompareResultType(Type Ty) {
size_t Index = static_cast<size_t>(Ty); size_t Index = static_cast<size_t>(Ty);
if (Index < IceType_NUM) if (Index < IceType_NUM)
......
...@@ -40,25 +40,26 @@ ...@@ -40,25 +40,26 @@
// I - Is integer value (scalar or vector). // I - Is integer value (scalar or vector).
// F - Is floating point value (scalar or vector). // F - Is floating point value (scalar or vector).
// IA - Is integer arithmetic type // IA - Is integer arithmetic type
// LS - true if load/store allowed on type.
// CR - Result type of compare instruction for argument type // CR - Result type of compare instruction for argument type
// (IceType_void if disallowed) // (IceType_void if disallowed)
#define ICETYPE_PROPS_TABLE \ #define ICETYPE_PROPS_TABLE \
/* Enum Value V I F IA CR */ \ /* Enum Value V I F IA LS CR */ \
X(IceType_void, 0, 0, 0, 0, IceType_void) \ X(IceType_void, 0, 0, 0, 0, 0, IceType_void) \
X(IceType_i1, 0, 1, 0, 0, IceType_i1) \ X(IceType_i1, 0, 1, 0, 0, 0, IceType_i1) \
X(IceType_i8, 0, 1, 0, 1, IceType_i1) \ X(IceType_i8, 0, 1, 0, 1, 1, IceType_i1) \
X(IceType_i16, 0, 1, 0, 1, IceType_i1) \ X(IceType_i16, 0, 1, 0, 1, 1, IceType_i1) \
X(IceType_i32, 0, 1, 0, 1, IceType_i1) \ X(IceType_i32, 0, 1, 0, 1, 1, IceType_i1) \
X(IceType_i64, 0, 1, 0, 1, IceType_i1) \ X(IceType_i64, 0, 1, 0, 1, 1, IceType_i1) \
X(IceType_f32, 0, 0, 1, 0, IceType_i1) \ X(IceType_f32, 0, 0, 1, 0, 1, IceType_i1) \
X(IceType_f64, 0, 0, 1, 0, IceType_i1) \ X(IceType_f64, 0, 0, 1, 0, 1, IceType_i1) \
X(IceType_v4i1, 1, 1, 0, 0, IceType_v4i1) \ X(IceType_v4i1, 1, 1, 0, 0, 0, IceType_v4i1) \
X(IceType_v8i1, 1, 1, 0, 0, IceType_v8i1) \ X(IceType_v8i1, 1, 1, 0, 0, 0, IceType_v8i1) \
X(IceType_v16i1, 1, 1, 0, 0, IceType_v16i1) \ X(IceType_v16i1, 1, 1, 0, 0, 0, IceType_v16i1) \
X(IceType_v16i8, 1, 1, 0, 1, IceType_v16i1) \ X(IceType_v16i8, 1, 1, 0, 1, 1, IceType_v16i1) \
X(IceType_v8i16, 1, 1, 0, 1, IceType_v8i1) \ X(IceType_v8i16, 1, 1, 0, 1, 1, IceType_v8i1) \
X(IceType_v4i32, 1, 1, 0, 1, IceType_v4i1) \ X(IceType_v4i32, 1, 1, 0, 1, 1, IceType_v4i1) \
X(IceType_v4f32, 1, 0, 1, 0, IceType_v4i1) \ X(IceType_v4f32, 1, 0, 1, 0, 1, IceType_v4i1) \
//#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, CompareResult) //#define X(tag, IsVec, IsInt, IsFloat, IsIntArith, IsLoadStore, CompareResult)
#endif // SUBZERO_SRC_ICETYPES_DEF #endif // SUBZERO_SRC_ICETYPES_DEF
...@@ -58,6 +58,9 @@ bool isFloatingType(Type Ty); // scalar or vector ...@@ -58,6 +58,9 @@ bool isFloatingType(Type Ty); // scalar or vector
bool isScalarFloatingType(Type Ty); bool isScalarFloatingType(Type Ty);
bool isVectorFloatingType(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) /// Returns type generated by applying the compare instructions (icmp and fcmp)
/// to arguments of the given type. Returns IceType_void if compare is not /// to arguments of the given type. Returns IceType_void if compare is not
/// allowed. /// allowed.
......
...@@ -20,11 +20,13 @@ ...@@ -20,11 +20,13 @@
#include "IceInst.h" #include "IceInst.h"
#include "IceOperand.h" #include "IceOperand.h"
#include "IceTypeConverter.h" #include "IceTypeConverter.h"
#include "llvm/Analysis/NaCl/PNaClABIProps.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h" #include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeParser.h" #include "llvm/Bitcode/NaCl/NaClBitcodeParser.h"
#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" #include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
#include "llvm/IR/Constants.h" #include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/Support/Format.h" #include "llvm/Support/Format.h"
...@@ -55,9 +57,10 @@ public: ...@@ -55,9 +57,10 @@ public:
NaClBitcodeHeader &Header, NaClBitstreamCursor &Cursor, NaClBitcodeHeader &Header, NaClBitstreamCursor &Cursor,
bool &ErrorStatus) bool &ErrorStatus)
: NaClBitcodeParser(Cursor), Translator(Translator), : NaClBitcodeParser(Cursor), Translator(Translator),
Mod(new Module(InputName, getGlobalContext())), Header(Header), Mod(new Module(InputName, getGlobalContext())), DL(PNaClDataLayout),
TypeConverter(getLLVMContext()), ErrorStatus(ErrorStatus), NumErrors(0), Header(Header), TypeConverter(getLLVMContext()),
NumFunctionIds(0), NumFunctionBlocks(0), ErrorStatus(ErrorStatus), NumErrors(0), NumFunctionIds(0),
NumFunctionBlocks(0),
GlobalVarPlaceHolderType(convertToLLVMType(Ice::IceType_i8)) { GlobalVarPlaceHolderType(convertToLLVMType(Ice::IceType_i8)) {
Mod->setDataLayout(PNaClDataLayout); Mod->setDataLayout(PNaClDataLayout);
} }
...@@ -84,6 +87,8 @@ public: ...@@ -84,6 +87,8 @@ public:
/// Returns the LLVM module associated with the translation. /// Returns the LLVM module associated with the translation.
Module *getModule() const { return Mod.get(); } Module *getModule() const { return Mod.get(); }
const DataLayout &getDataLayout() const { return DL; }
/// Returns the number of bytes in the bitcode header. /// Returns the number of bytes in the bitcode header.
size_t getHeaderSize() const { return Header.getHeaderSize(); } size_t getHeaderSize() const { return Header.getHeaderSize(); }
...@@ -228,6 +233,8 @@ private: ...@@ -228,6 +233,8 @@ private:
Ice::Translator &Translator; Ice::Translator &Translator;
// The parsed module. // The parsed module.
OwningPtr<Module> Mod; OwningPtr<Module> Mod;
// The data layout to use.
DataLayout DL;
// The bitcode header. // The bitcode header.
NaClBitcodeHeader &Header; NaClBitcodeHeader &Header;
// Converter between LLVM and ICE types. // Converter between LLVM and ICE types.
...@@ -848,6 +855,24 @@ private: ...@@ -848,6 +855,24 @@ private:
// Upper limit of alignment power allowed by LLVM // Upper limit of alignment power allowed by LLVM
static const uint64_t AlignPowerLimit = 29; 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 bool ParseBlock(unsigned BlockID) LLVM_OVERRIDE;
virtual void ProcessRecord() LLVM_OVERRIDE; virtual void ProcessRecord() LLVM_OVERRIDE;
...@@ -959,8 +984,8 @@ private: ...@@ -959,8 +984,8 @@ private:
} }
// Checks if floating arithmetic Op, for type OpTy, is valid. // Checks if floating arithmetic Op, for type OpTy, is valid.
// Returns false if valid. Otherwise generates an error message and // Returns true if valid. Otherwise generates an error message and
// returns true. // returns false;
bool isValidFloatingArithOp(Ice::InstArithmetic::OpKind Op, Ice::Type OpTy) { bool isValidFloatingArithOp(Ice::InstArithmetic::OpKind Op, Ice::Type OpTy) {
if (Ice::isFloatingType(OpTy)) if (Ice::isFloatingType(OpTy))
return true; return true;
...@@ -968,6 +993,52 @@ private: ...@@ -968,6 +993,52 @@ private:
return false; 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, // Reports that the given binary Opcode, for the given type Ty,
// is not understood. // is not understood.
void ReportInvalidBinopOpcode(unsigned Opcode, Ice::Type Ty); void ReportInvalidBinopOpcode(unsigned Opcode, Ice::Type Ty);
...@@ -1529,22 +1600,46 @@ void FunctionParser::ProcessRecord() { ...@@ -1529,22 +1600,46 @@ void FunctionParser::ProcessRecord() {
Error(StrBuf.str()); Error(StrBuf.str());
return; return;
} }
uint64_t AlignPower = Values[1]; unsigned Alignment;
unsigned Alignment = 1; extractAlignment("Alloca", Values[1], Alignment);
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.
}
Ice::Variable *Dest = NextInstVar(Context->getIcePointerType()); Ice::Variable *Dest = NextInstVar(Context->getIcePointerType());
Inst = Ice::InstAlloca::create(Func, ByteCount, Alignment, Dest); Inst = Ice::InstAlloca::create(Func, ByteCount, Alignment, Dest);
break; 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: default:
// Generate error message! // Generate error message!
BlockParserBaseClass::ProcessRecord(); BlockParserBaseClass::ProcessRecord();
......
; 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
}
; 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
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment