Commit d6064a1a by Karl Schimpf

Start processing function blocks.

Handle binops and returns. BUG= https://code.google.com/p/nativeclient/issues/detail?id=3894 R=jvoung@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/395193005
parent 89d7956d
......@@ -61,6 +61,7 @@ SRCS= \
IceTargetLowering.cpp \
IceTargetLoweringX8632.cpp \
IceTranslator.cpp \
IceTypeConverter.cpp \
IceTypes.cpp \
llvm2ice.cpp \
PNaClTranslator.cpp
......
......@@ -22,6 +22,7 @@
#include "IceOperand.h"
#include "IceTargetLowering.h"
#include "IceTypes.h"
#include "IceTypeConverter.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
......@@ -54,12 +55,8 @@ template <typename T> static std::string LLVMObjectAsString(const T *O) {
//
class LLVM2ICEConverter {
public:
LLVM2ICEConverter(Ice::GlobalContext *Ctx)
: Ctx(Ctx), Func(NULL), CurrentNode(NULL) {
// All PNaCl pointer widths are 32 bits because of the sandbox
// model.
SubzeroPointerType = Ice::IceType_i32;
}
LLVM2ICEConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
: Ctx(Ctx), Func(NULL), CurrentNode(NULL), TypeConverter(LLVMContext) {}
// Caller is expected to delete the returned Ice::Cfg object.
Ice::Cfg *convertFunction(const Function *F) {
......@@ -67,7 +64,7 @@ public:
NodeMap.clear();
Func = new Ice::Cfg(Ctx);
Func->setFunctionName(F->getName());
Func->setReturnType(convertType(F->getReturnType()));
Func->setReturnType(convertToIceType(F->getReturnType()));
Func->setInternal(F->hasInternalLinkage());
// The initial definition/use of each arg is the entry node.
......@@ -102,12 +99,13 @@ public:
// global initializers.
Ice::Constant *convertConstant(const Constant *Const) {
if (const GlobalValue *GV = dyn_cast<GlobalValue>(Const)) {
return Ctx->getConstantSym(convertType(GV->getType()), 0, GV->getName());
return Ctx->getConstantSym(convertToIceType(GV->getType()), 0,
GV->getName());
} else if (const ConstantInt *CI = dyn_cast<ConstantInt>(Const)) {
return Ctx->getConstantInt(convertIntegerType(CI->getType()),
return Ctx->getConstantInt(convertToIceType(CI->getType()),
CI->getZExtValue());
} else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(Const)) {
Ice::Type Type = convertType(CFP->getType());
Ice::Type Type = convertToIceType(CFP->getType());
if (Type == Ice::IceType_f32)
return Ctx->getConstantFloat(CFP->getValueAPF().convertToFloat());
else if (Type == Ice::IceType_f64)
......@@ -115,7 +113,7 @@ public:
llvm_unreachable("Unexpected floating point type");
return NULL;
} else if (const UndefValue *CU = dyn_cast<UndefValue>(Const)) {
return Ctx->getConstantUndef(convertType(CU->getType()));
return Ctx->getConstantUndef(convertToIceType(CU->getType()));
} else {
llvm_unreachable("Unhandled constant type");
return NULL;
......@@ -125,7 +123,7 @@ public:
private:
// LLVM values (instructions, etc.) are mapped directly to ICE variables.
// mapValueToIceVar has a version that forces an ICE type on the variable,
// and a version that just uses convertType on V.
// and a version that just uses convertToIceType on V.
Ice::Variable *mapValueToIceVar(const Value *V, Ice::Type IceTy) {
if (IceTy == Ice::IceType_void)
return NULL;
......@@ -137,7 +135,7 @@ private:
}
Ice::Variable *mapValueToIceVar(const Value *V) {
return mapValueToIceVar(V, convertType(V->getType()));
return mapValueToIceVar(V, convertToIceType(V->getType()));
}
Ice::CfgNode *mapBasicBlockToNode(const BasicBlock *BB) {
......@@ -147,85 +145,12 @@ private:
return NodeMap[BB];
}
Ice::Type convertIntegerType(const IntegerType *IntTy) const {
switch (IntTy->getBitWidth()) {
case 1:
return Ice::IceType_i1;
case 8:
return Ice::IceType_i8;
case 16:
return Ice::IceType_i16;
case 32:
return Ice::IceType_i32;
case 64:
return Ice::IceType_i64;
default:
report_fatal_error(std::string("Invalid PNaCl int type: ") +
LLVMObjectAsString(IntTy));
return Ice::IceType_void;
}
}
Ice::Type convertVectorType(const VectorType *VecTy) const {
unsigned NumElements = VecTy->getNumElements();
const Type *ElementType = VecTy->getElementType();
if (ElementType->isFloatTy()) {
if (NumElements == 4)
return Ice::IceType_v4f32;
} else if (ElementType->isIntegerTy()) {
switch (cast<IntegerType>(ElementType)->getBitWidth()) {
case 1:
if (NumElements == 4)
return Ice::IceType_v4i1;
if (NumElements == 8)
return Ice::IceType_v8i1;
if (NumElements == 16)
return Ice::IceType_v16i1;
break;
case 8:
if (NumElements == 16)
return Ice::IceType_v16i8;
break;
case 16:
if (NumElements == 8)
return Ice::IceType_v8i16;
break;
case 32:
if (NumElements == 4)
return Ice::IceType_v4i32;
break;
}
}
report_fatal_error(std::string("Unhandled vector type: ") +
LLVMObjectAsString(VecTy));
return Ice::IceType_void;
}
Ice::Type convertType(const Type *Ty) const {
switch (Ty->getTypeID()) {
case Type::VoidTyID:
return Ice::IceType_void;
case Type::IntegerTyID:
return convertIntegerType(cast<IntegerType>(Ty));
case Type::FloatTyID:
return Ice::IceType_f32;
case Type::DoubleTyID:
return Ice::IceType_f64;
case Type::PointerTyID:
return SubzeroPointerType;
case Type::FunctionTyID:
return SubzeroPointerType;
case Type::VectorTyID:
return convertVectorType(cast<VectorType>(Ty));
default:
report_fatal_error(std::string("Invalid PNaCl type: ") +
LLVMObjectAsString(Ty));
}
llvm_unreachable("convertType");
return Ice::IceType_void;
Ice::Type convertToIceType(Type *LLVMTy) const {
Ice::Type IceTy = TypeConverter.convertToIceType(LLVMTy);
if (IceTy == Ice::IceType_NUM)
llvm::report_fatal_error(std::string("Invalid PNaCl type ") +
LLVMObjectAsString(LLVMTy));
return IceTy;
}
// Given an LLVM instruction and an operand number, produce the
......@@ -404,7 +329,8 @@ private:
Ice::Inst *convertIntToPtrInstruction(const IntToPtrInst *Inst) {
Ice::Operand *Src = convertOperand(Inst, 0);
Ice::Variable *Dest = mapValueToIceVar(Inst, SubzeroPointerType);
Ice::Variable *Dest =
mapValueToIceVar(Inst, TypeConverter.getIcePointerType());
return Ice::InstAssign::create(Func, Dest, Src);
}
......@@ -622,7 +548,8 @@ private:
// PNaCl bitcode only contains allocas of byte-granular objects.
Ice::Operand *ByteCount = convertValue(Inst->getArraySize());
uint32_t Align = Inst->getAlignment();
Ice::Variable *Dest = mapValueToIceVar(Inst, SubzeroPointerType);
Ice::Variable *Dest =
mapValueToIceVar(Inst, TypeConverter.getIcePointerType());
return Ice::InstAlloca::create(Func, ByteCount, Align, Dest);
}
......@@ -671,22 +598,22 @@ private:
Ice::GlobalContext *Ctx;
Ice::Cfg *Func;
Ice::CfgNode *CurrentNode;
Ice::Type SubzeroPointerType;
std::map<const Value *, Ice::Variable *> VarMap;
std::map<const BasicBlock *, Ice::CfgNode *> NodeMap;
Ice::TypeConverter TypeConverter;
};
} // end of anonymous namespace
namespace Ice {
void Converter::convertToIce(Module *Mod) {
void Converter::convertToIce() {
if (!Ctx->getFlags().DisableGlobals)
convertGlobals(Mod);
convertFunctions(Mod);
convertGlobals();
convertFunctions();
}
void Converter::convertGlobals(Module *Mod) {
void Converter::convertGlobals() {
OwningPtr<TargetGlobalInitLowering> GlobalLowering(
TargetGlobalInitLowering::createLowering(Ctx->getTargetArch(), Ctx));
for (Module::const_global_iterator I = Mod->global_begin(),
......@@ -729,11 +656,11 @@ void Converter::convertGlobals(Module *Mod) {
GlobalLowering.reset();
}
void Converter::convertFunctions(Module *Mod) {
void Converter::convertFunctions() {
for (Module::const_iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) {
if (I->empty())
continue;
LLVM2ICEConverter FunctionConverter(Ctx);
LLVM2ICEConverter FunctionConverter(Ctx, Mod->getContext());
Timer TConvert;
Cfg *Fcn = FunctionConverter.convertFunction(I);
......
......@@ -24,16 +24,18 @@ namespace Ice {
class Converter : public Translator {
public:
Converter(GlobalContext *Ctx) : Translator(Ctx) {}
Converter(llvm::Module *Mod, GlobalContext *Ctx, const Ice::ClFlags &Flags)
: Translator(Ctx, Flags), Mod(Mod) {}
/// Converts the LLVM Module to ICE. Sets exit status to false if successful,
/// true otherwise.
void convertToIce(llvm::Module *Mod);
void convertToIce();
private:
llvm::Module *Mod;
// Converts globals to ICE, and then machine code.
void convertGlobals(llvm::Module *Mod);
void convertGlobals();
// Converts functions to ICE, and then machine code.
void convertFunctions(llvm::Module *Mod);
void convertFunctions();
Converter(const Converter &) LLVM_DELETED_FUNCTION;
Converter &operator=(const Converter &) LLVM_DELETED_FUNCTION;
};
......
......@@ -33,8 +33,6 @@ const struct InstArithmeticAttributes_ {
ICEINSTARITHMETIC_TABLE
#undef X
};
const size_t InstArithmeticAttributesSize =
llvm::array_lengthof(InstArithmeticAttributes);
// Using non-anonymous struct so that array_lengthof works.
const struct InstCastAttributes_ {
......@@ -46,7 +44,6 @@ const struct InstCastAttributes_ {
ICEINSTCAST_TABLE
#undef X
};
const size_t InstCastAttributesSize = llvm::array_lengthof(InstCastAttributes);
// Using non-anonymous struct so that array_lengthof works.
const struct InstFcmpAttributes_ {
......@@ -58,7 +55,6 @@ const struct InstFcmpAttributes_ {
ICEINSTFCMP_TABLE
#undef X
};
const size_t InstFcmpAttributesSize = llvm::array_lengthof(InstFcmpAttributes);
// Using non-anonymous struct so that array_lengthof works.
const struct InstIcmpAttributes_ {
......@@ -70,7 +66,6 @@ const struct InstIcmpAttributes_ {
ICEINSTICMP_TABLE
#undef X
};
const size_t InstIcmpAttributesSize = llvm::array_lengthof(InstIcmpAttributes);
} // end of anonymous namespace
......@@ -228,6 +223,13 @@ InstArithmetic::InstArithmetic(Cfg *Func, OpKind Op, Variable *Dest,
addSource(Source2);
}
const char *InstArithmetic::getOpName(OpKind Op) {
size_t OpIndex = static_cast<size_t>(Op);
return OpIndex < InstArithmetic::_num
? InstArithmeticAttributes[OpIndex].DisplayString
: "???";
}
bool InstArithmetic::isCommutative() const {
return InstArithmeticAttributes[getOp()].IsCommutative;
}
......
......@@ -203,6 +203,7 @@ public:
InstArithmetic(Func, Op, Dest, Source1, Source2);
}
OpKind getOp() const { return Op; }
static const char *getOpName(OpKind Op);
bool isCommutative() const;
virtual void dump(const Cfg *Func) const;
static bool classof(const Inst *Inst) {
......
......@@ -29,13 +29,27 @@ class GlobalContext;
// machine instructions.
class Translator {
public:
Translator(GlobalContext *Ctx) : Ctx(Ctx), ErrorStatus(0) {}
Translator(GlobalContext *Ctx, const ClFlags &Flags)
: Ctx(Ctx), Flags(Flags), ErrorStatus(0) {}
~Translator();
bool getErrorStatus() const { return ErrorStatus; }
GlobalContext *getContext() const { return Ctx; }
const ClFlags &getFlags() const { return Flags; }
/// Translates the constructed ICE function Fcn to machine code.
/// Takes ownership of Fcn. Note: As a side effect, Field Func is
/// set to Fcn.
void translateFcn(Cfg *Fcn);
/// Emits the constant pool.
void emitConstants();
protected:
GlobalContext *Ctx;
const ClFlags &Flags;
// The exit status of the translation. False is successful. True
// otherwise.
bool ErrorStatus;
......@@ -49,13 +63,6 @@ protected:
// that.
llvm::OwningPtr<Cfg> Func;
/// Translates the constructed ICE function Fcn to machine code.
/// Note: As a side effect, Field Func is set to Fcn.
void translateFcn(Cfg *Fcn);
/// Emits the constant pool.
void emitConstants();
private:
Translator(const Translator &) LLVM_DELETED_FUNCTION;
Translator &operator=(const Translator &) LLVM_DELETED_FUNCTION;
......
//===- subzero/src/IceTypeConverter.cpp - Convert ICE/LLVM Types ----------===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements how to convert LLVM types to ICE types, and ICE types
// to LLVM types.
//
//===----------------------------------------------------------------------===//
#include "IceTypeConverter.h"
#include "llvm/Support/raw_ostream.h"
namespace Ice {
TypeConverter::TypeConverter(llvm::LLVMContext &Context) : Context(Context) {
AddLLVMType(IceType_void, llvm::Type::getVoidTy(Context));
AddLLVMType(IceType_i1, llvm::IntegerType::get(Context, 1));
AddLLVMType(IceType_i8, llvm::IntegerType::get(Context, 8));
AddLLVMType(IceType_i16, llvm::IntegerType::get(Context, 16));
AddLLVMType(IceType_i32, llvm::IntegerType::get(Context, 32));
AddLLVMType(IceType_i64, llvm::IntegerType::get(Context, 64));
AddLLVMType(IceType_f32, llvm::Type::getFloatTy(Context));
AddLLVMType(IceType_f64, llvm::Type::getDoubleTy(Context));
AddLLVMType(IceType_v4i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 4));
AddLLVMType(IceType_v8i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 8));
AddLLVMType(IceType_v16i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 16));
AddLLVMType(IceType_v16i8, llvm::VectorType::get(LLVMTypes[IceType_i8], 16));
AddLLVMType(IceType_v8i16, llvm::VectorType::get(LLVMTypes[IceType_i16], 8));
AddLLVMType(IceType_v4i32, llvm::VectorType::get(LLVMTypes[IceType_i32], 4));
AddLLVMType(IceType_v4f32, llvm::VectorType::get(LLVMTypes[IceType_f32], 4));
assert(LLVMTypes.size() == static_cast<size_t>(IceType_NUM));
}
void TypeConverter::AddLLVMType(Type Ty, llvm::Type *LLVMTy) {
assert(static_cast<size_t>(Ty) == LLVMTypes.size());
LLVMTypes.push_back(LLVMTy);
LLVM2IceMap[LLVMTy] = Ty;
}
Type TypeConverter::convertToIceTypeOther(llvm::Type *LLVMTy) const {
switch (LLVMTy->getTypeID()) {
case llvm::Type::PointerTyID:
case llvm::Type::FunctionTyID:
return getIcePointerType();
default:
return Ice::IceType_NUM;
}
}
llvm::Type *TypeConverter::getLLVMIntegerType(unsigned NumBits) const {
switch (NumBits) {
case 1:
return LLVMTypes[IceType_i1];
case 8:
return LLVMTypes[IceType_i8];
case 16:
return LLVMTypes[IceType_i16];
case 32:
return LLVMTypes[IceType_i32];
case 64:
return LLVMTypes[IceType_i64];
default:
return NULL;
}
}
llvm::Type *TypeConverter::getLLVMVectorType(unsigned Size, Type Ty) const {
switch (Ty) {
case IceType_i1:
switch (Size) {
case 4:
return convertToLLVMType(IceType_v4i1);
case 8:
return convertToLLVMType(IceType_v8i1);
case 16:
return convertToLLVMType(IceType_v16i1);
default:
break;
}
break;
case IceType_i8:
if (Size == 16)
return convertToLLVMType(IceType_v16i8);
break;
case IceType_i16:
if (Size == 8)
return convertToLLVMType(IceType_v8i16);
break;
case IceType_i32:
if (Size == 4)
return convertToLLVMType(IceType_v4i32);
break;
case IceType_f32:
if (Size == 4)
return convertToLLVMType(IceType_v4f32);
break;
default:
break;
}
return NULL;
}
} // end of Ice namespace.
//===- subzero/src/IceTypeConverter.h - Convert ICE/LLVM Types --*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines how to convert LLVM types to ICE types, and ICE types
// to LLVM types.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICETYPECONVERTER_H
#define SUBZERO_SRC_ICETYPECONVERTER_H
#include "IceDefs.h"
#include "IceTypes.h"
#include "llvm/IR/DerivedTypes.h"
namespace llvm {
class LLVMContext;
} // end of llvm namespace.
namespace Ice {
/// Converts LLVM types to ICE types, and ICE types to LLVM types.
class TypeConverter {
TypeConverter(const TypeConverter &) LLVM_DELETED_FUNCTION;
TypeConverter &operator=(const TypeConverter &) LLVM_DELETED_FUNCTION;
public:
/// Context is the context to use to build llvm types.
TypeConverter(llvm::LLVMContext &Context);
/// Returns the LLVM type for the corresponding ICE type Ty.
llvm::Type *convertToLLVMType(Type Ty) const {
// Note: We use "at" here in case Ty wasn't registered.
return LLVMTypes.at(Ty);
}
/// Converts LLVM type LLVMTy to an ICE type. Returns
/// Ice::IceType_NUM if unable to convert.
Type convertToIceType(llvm::Type *LLVMTy) const {
std::map<llvm::Type *, Type>::const_iterator Pos = LLVM2IceMap.find(LLVMTy);
if (Pos == LLVM2IceMap.end())
return convertToIceTypeOther(LLVMTy);
return Pos->second;
}
/// Returns ICE model of pointer type.
Type getIcePointerType() const { return IceType_i32; }
/// Returns LLVM integer type with specified number of bits. Returns
/// NULL if not a valid PNaCl integer type.
llvm::Type *getLLVMIntegerType(unsigned NumBits) const;
/// Returns the LLVM vector type for Size and Ty arguments. Returns
/// NULL if not a valid PNaCl vector type.
llvm::Type *getLLVMVectorType(unsigned Size, Type Ty) const;
private:
// The LLVM context to use to build LLVM types.
llvm::LLVMContext &Context;
// The list of allowable LLVM types. Indexed by ICE type.
std::vector<llvm::Type *> LLVMTypes;
// The inverse mapping of LLVMTypes.
std::map<llvm::Type *, Type> LLVM2IceMap;
// Add LLVM/ICE pair to internal tables.
void AddLLVMType(Type Ty, llvm::Type *LLVMTy);
// Converts types not in LLVM2IceMap.
Type convertToIceTypeOther(llvm::Type *LLVMTy) const;
};
} // end of Ice namespace.
#endif // SUBZERO_SRC_ICETYPECONVERTER_H
......@@ -18,74 +18,203 @@ namespace Ice {
namespace {
const struct {
// Dummy function to make sure the two type tables have the same
// enumerated types.
void __attribute__((unused)) xIceTypeMacroIntegrityCheck() {
// Show tags match between ICETYPE_TABLE and ICETYPE_PROPS_TABLE.
// Define a temporary set of enum values based on ICETYPE_TABLE
enum {
#define X(tag, size, align, elts, elty, str) _table_tag_##tag,
ICETYPE_TABLE
#undef X
_enum_table_tag_Names
};
// Define a temporary set of enum values based on ICETYPE_PROPS_TABLE
enum {
#define X(tag, IsVec, IsInt, IsFloat, IsIntArith) _props_table_tag_##tag,
ICETYPE_PROPS_TABLE
#undef X
_enum_props_table_tag_Names
};
// Assert that tags in ICETYPE_TABLE are also in ICETYPE_PROPS_TABLE.
#define X(tag, size, align, elts, elty, str) \
STATIC_ASSERT((unsigned)_table_tag_##tag == (unsigned)_props_table_tag_##tag);
ICETYPE_TABLE;
#undef X
// Assert that tags in ICETYPE_PROPS_TABLE is in ICETYPE_TABLE.
#define X(tag, IsVec, IsInt, IsFloat, IsIntArith) \
STATIC_ASSERT((unsigned)_table_tag_##tag == (unsigned)_props_table_tag_##tag);
ICETYPE_PROPS_TABLE;
#undef X
// Show vector definitions match in ICETYPE_TABLE and
// ICETYPE_PROPS_TABLE.
// Define constants for each element size in ICETYPE_TABLE.
enum {
#define X(tag, size, align, elts, elty, str) _table_elts_##tag = elts,
ICETYPE_TABLE
#undef X
_enum_table_elts_Elements = 0
};
// Define constants for boolean flag if vector in ICETYPE_PROPS_TABLE.
enum {
#define X(tag, IsVec, IsInt, IsFloat, IsIntArith) \
_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) \
STATIC_ASSERT((_table_elts_##tag > 1) == _props_table_IsVec_##tag);
ICETYPE_PROPS_TABLE;
#undef X
}
struct TypeAttributeFields {
size_t TypeWidthInBytes;
size_t TypeAlignInBytes;
size_t TypeNumElements;
Type TypeElementType;
const char *DisplayString;
} TypeAttributes[] = {
};
const struct TypeAttributeFields TypeAttributes[] = {
#define X(tag, size, align, elts, elty, str) \
{ size, align, elts, elty, str } \
,
ICETYPE_TABLE
#undef X
};
};
const size_t TypeAttributesSize =
sizeof(TypeAttributes) / sizeof(*TypeAttributes);
struct TypePropertyFields {
bool TypeIsVectorType;
bool TypeIsIntegerType;
bool TypeIsScalarIntegerType;
bool TypeIsVectorIntegerType;
bool TypeIsIntegerArithmeticType;
bool TypeIsFloatingType;
bool TypeIsScalarFloatingType;
bool TypeIsVectorFloatingType;
};
const TypePropertyFields TypePropertiesTable[] = {
#define X(tag, IsVec, IsInt, IsFloat, IsIntArith) \
{ \
IsVec, IsInt, IsInt && !IsVec, IsInt && IsVec, IsIntArith, IsFloat, \
IsFloat && !IsVec, IsFloat && IsVec \
} \
,
ICETYPE_PROPS_TABLE
#undef X
};
} // end anonymous namespace
size_t typeWidthInBytes(Type Ty) {
size_t Width = 0;
size_t Index = static_cast<size_t>(Ty);
if (Index < TypeAttributesSize) {
Width = TypeAttributes[Index].TypeWidthInBytes;
} else {
llvm_unreachable("Invalid type for typeWidthInBytes()");
}
return Width;
if (Index < IceType_NUM)
return TypeAttributes[Index].TypeWidthInBytes;
llvm_unreachable("Invalid type for typeWidthInBytes()");
return 0;
}
size_t typeAlignInBytes(Type Ty) {
size_t Align = 0;
size_t Index = static_cast<size_t>(Ty);
if (Index < TypeAttributesSize) {
Align = TypeAttributes[Index].TypeAlignInBytes;
} else {
llvm_unreachable("Invalid type for typeAlignInBytes()");
}
return Align;
if (Index < IceType_NUM)
return TypeAttributes[Index].TypeAlignInBytes;
llvm_unreachable("Invalid type for typeAlignInBytes()");
return 1;
}
size_t typeNumElements(Type Ty) {
size_t NumElements = 0;
size_t Index = static_cast<size_t>(Ty);
if (Index < TypeAttributesSize) {
NumElements = TypeAttributes[Index].TypeNumElements;
} else {
llvm_unreachable("Invalid type for typeNumElements()");
}
return NumElements;
if (Index < IceType_NUM)
return TypeAttributes[Index].TypeNumElements;
llvm_unreachable("Invalid type for typeNumElements()");
return 1;
}
Type typeElementType(Type Ty) {
Type ElementType = IceType_void;
size_t Index = static_cast<size_t>(Ty);
if (Index < TypeAttributesSize) {
ElementType = TypeAttributes[Index].TypeElementType;
} else {
llvm_unreachable("Invalid type for typeElementType()");
}
return ElementType;
if (Index < IceType_NUM)
return TypeAttributes[Index].TypeElementType;
llvm_unreachable("Invalid type for typeElementType()");
return IceType_void;
}
bool isVectorType(Type Ty) {
size_t Index = static_cast<size_t>(Ty);
if (Index < IceType_NUM)
return TypePropertiesTable[Index].TypeIsVectorType;
llvm_unreachable("Invalid type for isVectorType()");
return false;
}
bool isIntegerType(Type Ty) {
size_t Index = static_cast<size_t>(Ty);
if (Index < IceType_NUM)
return TypePropertiesTable[Index].TypeIsIntegerType;
llvm_unreachable("Invalid type for isIntegerType()");
return false;
}
bool isScalarIntegerType(Type Ty) {
size_t Index = static_cast<size_t>(Ty);
if (Index < IceType_NUM)
return TypePropertiesTable[Index].TypeIsScalarIntegerType;
llvm_unreachable("Invalid type for isScalIntegerType()");
return false;
}
bool isVectorIntegerType(Type Ty) {
size_t Index = static_cast<size_t>(Ty);
if (Index < IceType_NUM)
return TypePropertiesTable[Index].TypeIsVectorIntegerType;
llvm_unreachable("Invalid type for isVectorIntegerType()");
return false;
}
bool isIntegerArithmeticType(Type Ty) {
size_t Index = static_cast<size_t>(Ty);
if (Index < IceType_NUM)
return TypePropertiesTable[Index].TypeIsIntegerArithmeticType;
llvm_unreachable("Invalid type for isIntegerArithmeticType()");
return false;
}
bool isFloatingType(Type Ty) {
size_t Index = static_cast<size_t>(Ty);
if (Index < IceType_NUM)
return TypePropertiesTable[Index].TypeIsFloatingType;
llvm_unreachable("Invalid type for isFloatingType()");
return false;
}
bool isScalarFloatingType(Type Ty) {
size_t Index = static_cast<size_t>(Ty);
if (Index < IceType_NUM)
return TypePropertiesTable[Index].TypeIsScalarFloatingType;
llvm_unreachable("Invalid type for isScalarFloatingType()");
return false;
}
bool isVectorFloatingType(Type Ty) {
size_t Index = static_cast<size_t>(Ty);
if (Index < IceType_NUM)
return TypePropertiesTable[Index].TypeIsVectorFloatingType;
llvm_unreachable("Invalid type for isVectorFloatingType()");
return false;
}
// ======================== Dump routines ======================== //
const char *typeString(Type Ty) {
size_t Index = static_cast<size_t>(Ty);
if (Index < TypeAttributesSize) {
if (Index < IceType_NUM)
return TypeAttributes[Index].DisplayString;
}
llvm_unreachable("Invalid type for typeString");
return "???";
}
......
......@@ -35,4 +35,28 @@
X(IceType_v4f32, 16, 4, 4, IceType_f32, "<4 x float>") \
//#define X(tag, size, align, elts, elty, str)
// Dictionary:
// V - Is vector type.
// I - Is integer value (scalar or vector).
// F - Is floating point value (scalar or vector).
// IA - Is integer arithmetic type
#define ICETYPE_PROPS_TABLE \
/* Enum Value V I F IA */ \
X(IceType_void, 0, 0, 0, 0) \
X(IceType_i1, 0, 1, 0, 0) \
X(IceType_i8, 0, 1, 0, 1) \
X(IceType_i16, 0, 1, 0, 1) \
X(IceType_i32, 0, 1, 0, 1) \
X(IceType_i64, 0, 1, 0, 1) \
X(IceType_f32, 0, 0, 1, 0) \
X(IceType_f64, 0, 0, 1, 0) \
X(IceType_v4i1, 1, 1, 0, 0) \
X(IceType_v8i1, 1, 1, 0, 0) \
X(IceType_v16i1, 1, 1, 0, 0) \
X(IceType_v16i8, 1, 1, 0, 1) \
X(IceType_v8i16, 1, 1, 0, 1) \
X(IceType_v4i32, 1, 1, 0, 1) \
X(IceType_v4f32, 1, 0, 1, 0) \
//#define X(tag, IsVec, IsInt, IsFloat, IsIntArith)
#endif // SUBZERO_SRC_ICETYPES_DEF
......@@ -47,7 +47,16 @@ size_t typeNumElements(Type Ty);
Type typeElementType(Type Ty);
const char *typeString(Type Ty);
inline bool isVectorType(Type Ty) { return typeNumElements(Ty) > 1; }
bool isVectorType(Type Ty);
bool isIntegerType(Type Ty); // scalar or vector
bool isScalarIntegerType(Type Ty);
bool isVectorIntegerType(Type Ty);
bool isIntegerArithmeticType(Type Ty);
bool isFloatingType(Type Ty); // scalar or vector
bool isScalarFloatingType(Type Ty);
bool isVectorFloatingType(Type Ty);
template <typename StreamType>
inline StreamType &operator<<(StreamType &Str, const Type &Ty) {
......
......@@ -14,6 +14,12 @@
#include "PNaClTranslator.h"
#include "IceCfg.h"
#include "IceCfgNode.h"
#include "IceClFlags.h"
#include "IceDefs.h"
#include "IceInst.h"
#include "IceOperand.h"
#include "IceTypeConverter.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeParser.h"
......@@ -33,28 +39,42 @@ using namespace llvm;
namespace {
// TODO(kschimpf) Remove error recovery once implementation complete.
static cl::opt<bool> AllowErrorRecovery(
"allow-pnacl-reader-error-recovery",
cl::desc("Allow error recovery when reading PNaCl bitcode."),
cl::init(false));
// Top-level class to read PNaCl bitcode files, and translate to ICE.
class TopLevelParser : public NaClBitcodeParser {
TopLevelParser(const TopLevelParser &) LLVM_DELETED_FUNCTION;
TopLevelParser &operator=(const TopLevelParser &) LLVM_DELETED_FUNCTION;
public:
TopLevelParser(const std::string &InputName, NaClBitcodeHeader &Header,
NaClBitstreamCursor &Cursor, bool &ErrorStatus)
: NaClBitcodeParser(Cursor),
TopLevelParser(Ice::Translator &Translator, const std::string &InputName,
NaClBitcodeHeader &Header, NaClBitstreamCursor &Cursor,
bool &ErrorStatus)
: NaClBitcodeParser(Cursor), Translator(Translator),
Mod(new Module(InputName, getGlobalContext())), Header(Header),
ErrorStatus(ErrorStatus), NumErrors(0), NumFunctionIds(0),
GlobalVarPlaceHolderType(Type::getInt8Ty(getLLVMContext())) {
TypeConverter(getLLVMContext()), ErrorStatus(ErrorStatus), NumErrors(0),
NumFunctionIds(0), NumFunctionBlocks(0),
GlobalVarPlaceHolderType(convertToLLVMType(Ice::IceType_i8)) {
Mod->setDataLayout(PNaClDataLayout);
}
virtual ~TopLevelParser() {}
LLVM_OVERRIDE;
Ice::Translator &getTranslator() { return Translator; }
// Generates error with given Message. Always returns true.
virtual bool Error(const std::string &Message) LLVM_OVERRIDE {
ErrorStatus = true;
++NumErrors;
return NaClBitcodeParser::Error(Message);
NaClBitcodeParser::Error(Message);
if (!AllowErrorRecovery)
report_fatal_error("Unable to continue");
return true;
}
/// Returns the number of errors found while parsing the bitcode
......@@ -104,10 +124,20 @@ public:
DefiningFunctionsList.push_back(ValueIDValues.size());
}
/// Returns the value id that should be associated with the the
/// current function block. Increments internal counters during call
/// so that it will be in correct position for next function block.
unsigned getNextFunctionBlockValueID() {
if (NumFunctionBlocks >= DefiningFunctionsList.size())
report_fatal_error(
"More function blocks than defined function addresses");
return DefiningFunctionsList[NumFunctionBlocks++];
}
/// Returns the LLVM IR value associatd with the global value ID.
Value *getGlobalValueByID(unsigned ID) const {
if (ID >= ValueIDValues.size())
return 0;
return NULL;
return ValueIDValues[ID];
}
......@@ -131,7 +161,7 @@ public:
/// later.
Constant *getOrCreateGlobalVarRef(unsigned ID) {
if (ID >= ValueIDValues.size())
return 0;
return NULL;
if (Value *C = ValueIDValues[ID])
return dyn_cast<Constant>(C);
Constant *C = new GlobalVariable(*Mod, GlobalVarPlaceHolderType, false,
......@@ -147,7 +177,7 @@ public:
if (ID < NumFunctionIds || ID >= ValueIDValues.size())
return false;
WeakVH &OldV = ValueIDValues[ID];
if (OldV == 0) {
if (OldV == NULL) {
ValueIDValues[ID] = GV;
return true;
}
......@@ -162,11 +192,46 @@ public:
return true;
}
/// Returns the corresponding ICE type for LLVMTy.
Ice::Type convertToIceType(Type *LLVMTy) {
Ice::Type IceTy = TypeConverter.convertToIceType(LLVMTy);
if (IceTy >= Ice::IceType_NUM) {
return convertToIceTypeError(LLVMTy);
}
return IceTy;
}
/// Returns the corresponding LLVM type for IceTy.
Type *convertToLLVMType(Ice::Type IceTy) const {
return TypeConverter.convertToLLVMType(IceTy);
}
/// Returns the LLVM integer type with the given number of Bits. If
/// Bits is not a valid PNaCl type, returns NULL.
Type *getLLVMIntegerType(unsigned Bits) const {
return TypeConverter.getLLVMIntegerType(Bits);
}
/// Returns the LLVM vector with the given Size and Ty. If not a
/// valid PNaCl vector type, returns NULL.
Type *getLLVMVectorType(unsigned Size, Ice::Type Ty) const {
return TypeConverter.getLLVMVectorType(Size, Ty);
}
/// Returns the model for pointer types in ICE.
Ice::Type getIcePointerType() const {
return TypeConverter.getIcePointerType();
}
private:
// The translator associated with the parser.
Ice::Translator &Translator;
// The parsed module.
OwningPtr<Module> Mod;
// The bitcode header.
NaClBitcodeHeader &Header;
// Converter between LLVM and ICE types.
Ice::TypeConverter TypeConverter;
// The exit status that should be set to true if an error occurs.
bool &ErrorStatus;
// The number of errors reported.
......@@ -177,6 +242,8 @@ private:
std::vector<WeakVH> ValueIDValues;
// The number of function IDs.
unsigned NumFunctionIds;
// The number of function blocks (processed so far).
unsigned NumFunctionBlocks;
// The list of value IDs (in the order found) of defining function
// addresses.
std::vector<unsigned> DefiningFunctionsList;
......@@ -192,6 +259,10 @@ private:
/// Reports error about bad call to setTypeID.
void reportBadSetTypeID(unsigned ID, Type *Ty);
// Reports that there is no corresponding ICE type for LLVMTy, and
// returns ICE::IceType_void.
Ice::Type convertToIceTypeError(Type *LLVMTy);
};
Type *TopLevelParser::reportTypeIDAsUndefined(unsigned ID) {
......@@ -199,7 +270,8 @@ Type *TopLevelParser::reportTypeIDAsUndefined(unsigned ID) {
raw_string_ostream StrBuf(Buffer);
StrBuf << "Can't find type for type id: " << ID;
Error(StrBuf.str());
Type *Ty = Type::getVoidTy(getLLVMContext());
// TODO(kschimpf) Remove error recovery once implementation complete.
Type *Ty = TypeConverter.convertToLLVMType(Ice::IceType_void);
// To reduce error messages, update type list if possible.
if (ID < TypeIDValues.size())
TypeIDValues[ID] = Ty;
......@@ -219,6 +291,14 @@ void TopLevelParser::reportBadSetTypeID(unsigned ID, Type *Ty) {
Error(StrBuf.str());
}
Ice::Type TopLevelParser::convertToIceTypeError(Type *LLVMTy) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Invalid LLVM type: " << *LLVMTy;
Error(StrBuf.str());
return Ice::IceType_void;
}
// Base class for parsing blocks within the bitcode file. Note:
// Because this is the base class of block parsers, we generate error
// messages if ParseBlock or ParseRecord is not overridden in derived
......@@ -240,6 +320,9 @@ protected:
: NaClBitcodeParser(BlockID, EnclosingParser),
Context(EnclosingParser->Context) {}
// Gets the translator associated with the bitcode parser.
Ice::Translator &getTranslator() { return Context->getTranslator(); }
// Generates an error Message with the bit address prefixed to it.
virtual bool Error(const std::string &Message) LLVM_OVERRIDE {
uint64_t Bit = Record.GetStartBit() + Context->getHeaderSize() * 8;
......@@ -258,66 +341,72 @@ protected:
// understood.
virtual void ProcessRecord() LLVM_OVERRIDE;
/// Checks if the size of the record is Size. If not, an error is
/// produced using the given RecordName. Return true if error was
/// reported. Otherwise false.
bool checkRecordSize(unsigned Size, const char *RecordName) {
// Checks if the size of the record is Size. Return true if valid.
// Otherwise generates an error and returns false.
bool isValidRecordSize(unsigned Size, const char *RecordName) {
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
if (Values.size() != Size) {
return RecordSizeError(Size, RecordName, 0);
}
if (Values.size() == Size)
return true;
ReportRecordSizeError(Size, RecordName, NULL);
return false;
}
/// Checks if the size of the record is at least as large as the
/// LowerLimit.
bool checkRecordSizeAtLeast(unsigned LowerLimit, const char *RecordName) {
// Checks if the size of the record is at least as large as the
// LowerLimit. Returns true if valid. Otherwise generates an error
// and returns false.
bool isValidRecordSizeAtLeast(unsigned LowerLimit, const char *RecordName) {
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
if (Values.size() < LowerLimit) {
return RecordSizeError(LowerLimit, RecordName, "at least");
}
if (Values.size() >= LowerLimit)
return true;
ReportRecordSizeError(LowerLimit, RecordName, "at least");
return false;
}
/// Checks if the size of the record is no larger than the
/// UpperLimit.
bool checkRecordSizeNoMoreThan(unsigned UpperLimit, const char *RecordName) {
// Checks if the size of the record is no larger than the
// UpperLimit. Returns true if valid. Otherwise generates an error
// and returns false.
bool isValidRecordSizeAtMost(unsigned UpperLimit, const char *RecordName) {
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
if (Values.size() > UpperLimit) {
return RecordSizeError(UpperLimit, RecordName, "no more than");
}
if (Values.size() <= UpperLimit)
return true;
ReportRecordSizeError(UpperLimit, RecordName, "no more than");
return false;
}
/// Checks if the size of the record is at least as large as the
/// LowerLimit, and no larger than the UpperLimit.
bool checkRecordSizeInRange(unsigned LowerLimit, unsigned UpperLimit,
const char *RecordName) {
return checkRecordSizeAtLeast(LowerLimit, RecordName) ||
checkRecordSizeNoMoreThan(UpperLimit, RecordName);
// Checks if the size of the record is at least as large as the
// LowerLimit, and no larger than the UpperLimit. Returns true if
// valid. Otherwise generates an error and returns false.
bool isValidRecordSizeInRange(unsigned LowerLimit, unsigned UpperLimit,
const char *RecordName) {
return isValidRecordSizeAtLeast(LowerLimit, RecordName) ||
isValidRecordSizeAtMost(UpperLimit, RecordName);
}
private:
/// Generates a record size error. ExpectedSize is the number
/// of elements expected. RecordName is the name of the kind of
/// record that has incorrect size. ContextMessage (if not 0)
/// record that has incorrect size. ContextMessage (if not NULL)
/// is appended to "record expects" to describe how ExpectedSize
/// should be interpreted.
bool RecordSizeError(unsigned ExpectedSize, const char *RecordName,
const char *ContextMessage) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << RecordName << " record expects";
if (ContextMessage)
StrBuf << " " << ContextMessage;
StrBuf << " " << ExpectedSize << " argument";
if (ExpectedSize > 1)
StrBuf << "s";
StrBuf << ". Found: " << Record.GetValues().size();
return Error(StrBuf.str());
}
void ReportRecordSizeError(unsigned ExpectedSize, const char *RecordName,
const char *ContextMessage);
};
void BlockParserBaseClass::ReportRecordSizeError(unsigned ExpectedSize,
const char *RecordName,
const char *ContextMessage) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << RecordName << " record expects";
if (ContextMessage)
StrBuf << " " << ContextMessage;
StrBuf << " " << ExpectedSize << " argument";
if (ExpectedSize > 1)
StrBuf << "s";
StrBuf << ". Found: " << Record.GetValues().size();
Error(StrBuf.str());
}
bool BlockParserBaseClass::ParseBlock(unsigned BlockID) {
// If called, derived class doesn't know how to handle block.
// Report error and skip.
......@@ -325,6 +414,7 @@ bool BlockParserBaseClass::ParseBlock(unsigned BlockID) {
raw_string_ostream StrBuf(Buffer);
StrBuf << "Don't know how to parse block id: " << BlockID;
Error(StrBuf.str());
// TODO(kschimpf) Remove error recovery once implementation complete.
SkipBlock();
return false;
}
......@@ -359,45 +449,64 @@ void TypesParser::ProcessRecord() {
switch (Record.GetCode()) {
case naclbitc::TYPE_CODE_NUMENTRY:
// NUMENTRY: [numentries]
if (checkRecordSize(1, "Type count"))
if (!isValidRecordSize(1, "Type count"))
return;
Context->resizeTypeIDValues(Values[0]);
return;
case naclbitc::TYPE_CODE_VOID:
// VOID
if (checkRecordSize(0, "Type void"))
break;
Ty = Type::getVoidTy(Context->getLLVMContext());
if (!isValidRecordSize(0, "Type void"))
return;
Ty = Context->convertToLLVMType(Ice::IceType_void);
break;
case naclbitc::TYPE_CODE_FLOAT:
// FLOAT
if (checkRecordSize(0, "Type float"))
break;
Ty = Type::getFloatTy(Context->getLLVMContext());
if (!isValidRecordSize(0, "Type float"))
return;
Ty = Context->convertToLLVMType(Ice::IceType_f32);
break;
case naclbitc::TYPE_CODE_DOUBLE:
// DOUBLE
if (checkRecordSize(0, "Type double"))
break;
Ty = Type::getDoubleTy(Context->getLLVMContext());
if (!isValidRecordSize(0, "Type double"))
return;
Ty = Context->convertToLLVMType(Ice::IceType_f64);
break;
case naclbitc::TYPE_CODE_INTEGER:
// INTEGER: [width]
if (checkRecordSize(1, "Type integer"))
break;
Ty = IntegerType::get(Context->getLLVMContext(), Values[0]);
// TODO(kschimpf) Check if size is legal.
if (!isValidRecordSize(1, "Type integer"))
return;
Ty = Context->getLLVMIntegerType(Values[0]);
if (Ty == NULL) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Type integer record with invalid bitsize: " << Values[0];
Error(StrBuf.str());
// TODO(kschimpf) Remove error recovery once implementation complete.
// Fix type so that we can continue.
Ty = Context->convertToLLVMType(Ice::IceType_i32);
}
break;
case naclbitc::TYPE_CODE_VECTOR:
case naclbitc::TYPE_CODE_VECTOR: {
// VECTOR: [numelts, eltty]
if (checkRecordSize(2, "Type vector"))
break;
Ty = VectorType::get(Context->getTypeByID(Values[1]), Values[0]);
if (!isValidRecordSize(2, "Type vector"))
return;
Type *BaseTy = Context->getTypeByID(Values[1]);
Ty = Context->getLLVMVectorType(Values[0],
Context->convertToIceType(BaseTy));
if (Ty == NULL) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Invalid type vector record: <" << Values[0] << " x " << *BaseTy
<< ">";
Error(StrBuf.str());
Ty = Context->convertToLLVMType(Ice::IceType_void);
}
break;
}
case naclbitc::TYPE_CODE_FUNCTION: {
// FUNCTION: [vararg, retty, paramty x N]
if (checkRecordSizeAtLeast(2, "Type signature"))
break;
if (!isValidRecordSizeAtLeast(2, "Type signature"))
return;
SmallVector<Type *, 8> ArgTys;
for (unsigned i = 2, e = Values.size(); i != e; ++i) {
ArgTys.push_back(Context->getTypeByID(Values[i]));
......@@ -407,11 +516,11 @@ void TypesParser::ProcessRecord() {
}
default:
BlockParserBaseClass::ProcessRecord();
break;
return;
}
// If Ty not defined, assume error. Use void as filler.
if (Ty == NULL)
Ty = Type::getVoidTy(Context->getLLVMContext());
Ty = Context->convertToLLVMType(Ice::IceType_void);
Context->setTypeID(NextTypeId++, Ty);
}
......@@ -474,6 +583,7 @@ private:
StrBuf << "s";
StrBuf << ". Found: " << Initializers.size();
Error(StrBuf.str());
// TODO(kschimpf) Remove error recovery once implementation complete.
// Fix up state so that we can continue.
InitializersNeeded = Initializers.size();
installGlobalVar();
......@@ -530,7 +640,7 @@ void GlobalsParser::ProcessRecord() {
switch (Record.GetCode()) {
case naclbitc::GLOBALVAR_COUNT:
// COUNT: [n]
if (checkRecordSize(1, "Globals count"))
if (!isValidRecordSize(1, "Globals count"))
return;
if (NextGlobalID != Context->getNumFunctionIDs()) {
Error("Globals count record not first in block.");
......@@ -541,7 +651,7 @@ void GlobalsParser::ProcessRecord() {
return;
case naclbitc::GLOBALVAR_VAR: {
// VAR: [align, isconst]
if (checkRecordSize(2, "Globals variable"))
if (!isValidRecordSize(2, "Globals variable"))
return;
verifyNoMissingInitializers();
InitializersNeeded = 1;
......@@ -552,7 +662,7 @@ void GlobalsParser::ProcessRecord() {
}
case naclbitc::GLOBALVAR_COMPOUND:
// COMPOUND: [size]
if (checkRecordSize(1, "globals compound"))
if (!isValidRecordSize(1, "globals compound"))
return;
if (Initializers.size() > 0 || InitializersNeeded != 1) {
Error("Globals compound record not first initializer");
......@@ -569,18 +679,18 @@ void GlobalsParser::ProcessRecord() {
return;
case naclbitc::GLOBALVAR_ZEROFILL: {
// ZEROFILL: [size]
if (checkRecordSize(1, "Globals zerofill"))
if (!isValidRecordSize(1, "Globals zerofill"))
return;
reserveInitializer("Globals zerofill");
Type *Ty =
ArrayType::get(Type::getInt8Ty(Context->getLLVMContext()), Values[0]);
ArrayType::get(Context->convertToLLVMType(Ice::IceType_i8), Values[0]);
Constant *Zero = ConstantAggregateZero::get(Ty);
Initializers.push_back(Zero);
break;
}
case naclbitc::GLOBALVAR_DATA: {
// DATA: [b0, b1, ...]
if (checkRecordSizeAtLeast(1, "Globals data"))
if (!isValidRecordSizeAtLeast(1, "Globals data"))
return;
reserveInitializer("Globals data");
unsigned Size = Values.size();
......@@ -594,17 +704,17 @@ void GlobalsParser::ProcessRecord() {
}
case naclbitc::GLOBALVAR_RELOC: {
// RELOC: [val, [addend]]
if (checkRecordSizeInRange(1, 2, "Globals reloc"))
if (!isValidRecordSizeInRange(1, 2, "Globals reloc"))
return;
Constant *BaseVal = Context->getOrCreateGlobalVarRef(Values[0]);
if (BaseVal == 0) {
if (BaseVal == NULL) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Can't find global relocation value: " << Values[0];
Error(StrBuf.str());
return;
}
Type *IntPtrType = IntegerType::get(Context->getLLVMContext(), 32);
Type *IntPtrType = Context->convertToLLVMType(Context->getIcePointerType());
Constant *Val = ConstantExpr::getPtrToInt(BaseVal, IntPtrType);
if (Values.size() == 2) {
Val = ConstantExpr::getAdd(Val, ConstantInt::get(IntPtrType, Values[1]));
......@@ -654,11 +764,11 @@ void ValuesymtabParser::ProcessRecord() {
switch (Record.GetCode()) {
case naclbitc::VST_CODE_ENTRY: {
// VST_ENTRY: [ValueId, namechar x N]
if (checkRecordSizeAtLeast(2, "Valuesymtab value entry"))
if (!isValidRecordSizeAtLeast(2, "Valuesymtab value entry"))
return;
ConvertToString(ConvertedName);
Value *V = Context->getGlobalValueByID(Values[0]);
if (V == 0) {
if (V == NULL) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Invalid global address ID in valuesymtab: " << Values[0];
......@@ -685,6 +795,354 @@ void ValuesymtabParser::ProcessRecord() {
return;
}
/// Parses function blocks in the bitcode file.
class FunctionParser : public BlockParserBaseClass {
FunctionParser(const FunctionParser &) LLVM_DELETED_FUNCTION;
FunctionParser &operator=(const FunctionParser &) LLVM_DELETED_FUNCTION;
public:
FunctionParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser)
: BlockParserBaseClass(BlockID, EnclosingParser),
Func(new Ice::Cfg(getTranslator().getContext())), CurrentBbIndex(0),
FcnId(Context->getNextFunctionBlockValueID()),
LLVMFunc(cast<Function>(Context->getGlobalValueByID(FcnId))),
CachedNumGlobalValueIDs(Context->getNumGlobalValueIDs()),
InstIsTerminating(false) {
Func->setFunctionName(LLVMFunc->getName());
Func->setReturnType(Context->convertToIceType(LLVMFunc->getReturnType()));
Func->setInternal(LLVMFunc->hasInternalLinkage());
CurrentNode = InstallNextBasicBlock();
for (Function::const_arg_iterator ArgI = LLVMFunc->arg_begin(),
ArgE = LLVMFunc->arg_end();
ArgI != ArgE; ++ArgI) {
Func->addArg(NextInstVar(Context->convertToIceType(ArgI->getType())));
}
}
~FunctionParser() LLVM_OVERRIDE;
private:
// Timer for reading function bitcode and converting to ICE.
Ice::Timer TConvert;
// The corresponding ICE function defined by the function block.
Ice::Cfg *Func;
// The index to the current basic block being built.
uint32_t CurrentBbIndex;
// The basic block being built.
Ice::CfgNode *CurrentNode;
// The ID for the function.
unsigned FcnId;
// The corresponding LLVM function.
Function *LLVMFunc;
// Holds operands local to the function block, based on indices
// defined in the bitcode file.
std::vector<Ice::Operand *> LocalOperands;
// Holds the dividing point between local and global absolute value indices.
uint32_t CachedNumGlobalValueIDs;
// True if the last processed instruction was a terminating
// instruction.
bool InstIsTerminating;
virtual void ProcessRecord() LLVM_OVERRIDE;
virtual void ExitBlock() LLVM_OVERRIDE;
// Creates and appends a new basic block to the list of basic blocks.
Ice::CfgNode *InstallNextBasicBlock() { return Func->makeNode(); }
// Returns the Index-th basic block in the list of basic blocks.
Ice::CfgNode *GetBasicBlock(uint32_t Index) {
const Ice::NodeList &Nodes = Func->getNodes();
if (Index >= Nodes.size()) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Reference to basic block " << Index
<< " not found. Must be less than " << Nodes.size();
Error(StrBuf.str());
// TODO(kschimpf) Remove error recovery once implementation complete.
Index = 0;
}
return Nodes[Index];
}
// Generates the next available local variable using the given
// type. Note: if Ty is void, this function returns NULL.
Ice::Variable *NextInstVar(Ice::Type Ty) {
if (Ty == Ice::IceType_void)
return NULL;
Ice::Variable *Var = Func->makeVariable(Ty, CurrentNode);
LocalOperands.push_back(Var);
return Var;
}
// Converts a relative index (to the next instruction to be read) to
// an absolute value index.
uint32_t convertRelativeToAbsIndex(int32_t Id) {
int32_t AbsNextId = CachedNumGlobalValueIDs + LocalOperands.size();
if (Id > 0 && AbsNextId < static_cast<uint32_t>(Id)) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Invalid relative value id: " << Id
<< " (must be <= " << AbsNextId << ")";
Error(StrBuf.str());
// TODO(kschimpf) Remove error recovery once implementation complete.
return 0;
}
return AbsNextId - Id;
}
// Returns the value referenced by the given value Index.
Ice::Operand *getOperand(uint32_t Index) {
if (Index < CachedNumGlobalValueIDs) {
// TODO(kschimpf): Define implementation.
report_fatal_error("getOperand of global addresses not implemented");
}
uint32_t LocalIndex = Index - CachedNumGlobalValueIDs;
if (LocalIndex >= LocalOperands.size()) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Value index " << Index << " out of range. Must be less than "
<< (LocalOperands.size() + CachedNumGlobalValueIDs);
Error(StrBuf.str());
report_fatal_error("Unable to continue");
}
return LocalOperands[LocalIndex];
}
// Generates type error message for binary operator Op
// operating on Type OpTy.
void ReportInvalidBinaryOp(Ice::InstArithmetic::OpKind Op, Ice::Type OpTy);
// Validates if integer logical Op, for type OpTy, is valid.
// Returns true if valid. Otherwise generates error message and
// returns false.
bool isValidIntegerLogicalOp(Ice::InstArithmetic::OpKind Op, Ice::Type OpTy) {
if (Ice::isIntegerType(OpTy))
return true;
ReportInvalidBinaryOp(Op, OpTy);
return false;
}
// Validates if integer (or vector of integers) arithmetic Op, for type
// OpTy, is valid. Returns true if valid. Otherwise generates
// error message and returns false.
bool isValidIntegerArithOp(Ice::InstArithmetic::OpKind Op, Ice::Type OpTy) {
if (Ice::isIntegerArithmeticType(OpTy))
return true;
ReportInvalidBinaryOp(Op, OpTy);
return false;
}
// Checks if floating arithmetic Op, for type OpTy, is valid.
// Returns false if valid. Otherwise generates an error message and
// returns true.
bool isValidFloatingArithOp(Ice::InstArithmetic::OpKind Op, Ice::Type OpTy) {
if (Ice::isFloatingType(OpTy))
return true;
ReportInvalidBinaryOp(Op, OpTy);
return false;
}
// Reports that the given binary Opcode, for the given type Ty,
// is not understood.
void ReportInvalidBinopOpcode(unsigned Opcode, Ice::Type Ty);
// Takes the PNaCl bitcode binary operator Opcode, and the opcode
// type Ty, and sets Op to the corresponding ICE binary
// opcode. Returns true if able to convert, false otherwise.
bool convertBinopOpcode(unsigned Opcode, Ice::Type Ty,
Ice::InstArithmetic::OpKind &Op) {
Instruction::BinaryOps LLVMOpcode;
if (!naclbitc::DecodeBinaryOpcode(Opcode, Context->convertToLLVMType(Ty),
LLVMOpcode)) {
ReportInvalidBinopOpcode(Opcode, Ty);
// TODO(kschimpf) Remove error recovery once implementation complete.
Op = Ice::InstArithmetic::Add;
return false;
}
switch (LLVMOpcode) {
default: {
ReportInvalidBinopOpcode(Opcode, Ty);
// TODO(kschimpf) Remove error recovery once implementation complete.
Op = Ice::InstArithmetic::Add;
return false;
}
case Instruction::Add:
Op = Ice::InstArithmetic::Add;
return isValidIntegerArithOp(Op, Ty);
case Instruction::FAdd:
Op = Ice::InstArithmetic::Fadd;
return isValidFloatingArithOp(Op, Ty);
case Instruction::Sub:
Op = Ice::InstArithmetic::Sub;
return isValidIntegerArithOp(Op, Ty);
case Instruction::FSub:
Op = Ice::InstArithmetic::Fsub;
return isValidFloatingArithOp(Op, Ty);
case Instruction::Mul:
Op = Ice::InstArithmetic::Mul;
return isValidIntegerArithOp(Op, Ty);
case Instruction::FMul:
Op = Ice::InstArithmetic::Fmul;
return isValidFloatingArithOp(Op, Ty);
case Instruction::UDiv:
Op = Ice::InstArithmetic::Udiv;
return isValidIntegerArithOp(Op, Ty);
case Instruction::SDiv:
Op = Ice::InstArithmetic::Sdiv;
return isValidIntegerArithOp(Op, Ty);
case Instruction::FDiv:
Op = Ice::InstArithmetic::Fdiv;
return isValidFloatingArithOp(Op, Ty);
case Instruction::URem:
Op = Ice::InstArithmetic::Urem;
return isValidIntegerArithOp(Op, Ty);
case Instruction::SRem:
Op = Ice::InstArithmetic::Srem;
return isValidIntegerArithOp(Op, Ty);
case Instruction::FRem:
Op = Ice::InstArithmetic::Frem;
return isValidFloatingArithOp(Op, Ty);
case Instruction::Shl:
Op = Ice::InstArithmetic::Shl;
return isValidIntegerArithOp(Op, Ty);
case Instruction::LShr:
Op = Ice::InstArithmetic::Lshr;
return isValidIntegerArithOp(Op, Ty);
case Instruction::AShr:
Op = Ice::InstArithmetic::Ashr;
return isValidIntegerArithOp(Op, Ty);
case Instruction::And:
Op = Ice::InstArithmetic::And;
return isValidIntegerLogicalOp(Op, Ty);
case Instruction::Or:
Op = Ice::InstArithmetic::Or;
return isValidIntegerLogicalOp(Op, Ty);
case Instruction::Xor:
Op = Ice::InstArithmetic::Xor;
return isValidIntegerLogicalOp(Op, Ty);
}
}
};
FunctionParser::~FunctionParser() {
if (getTranslator().getFlags().SubzeroTimingEnabled) {
errs() << "[Subzero timing] Convert function " << Func->getFunctionName()
<< ": " << TConvert.getElapsedSec() << " sec\n";
}
}
void FunctionParser::ReportInvalidBinopOpcode(unsigned Opcode, Ice::Type Ty) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Binary opcode " << Opcode << "not understood for type " << Ty;
Error(StrBuf.str());
}
void FunctionParser::ExitBlock() {
// Before translating, check for blocks without instructions, and
// insert unreachable. This shouldn't happen, but be safe.
unsigned Index = 0;
const Ice::NodeList &Nodes = Func->getNodes();
for (std::vector<Ice::CfgNode *>::const_iterator Iter = Nodes.begin(),
IterEnd = Nodes.end();
Iter != IterEnd; ++Iter, ++Index) {
Ice::CfgNode *Node = *Iter;
if (Node->getInsts().size() == 0) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Basic block " << Index << " contains no instructions";
Error(StrBuf.str());
// TODO(kschimpf) Remove error recovery once implementation complete.
Node->appendInst(Ice::InstUnreachable::create(Func));
}
}
getTranslator().translateFcn(Func);
}
void FunctionParser::ReportInvalidBinaryOp(Ice::InstArithmetic::OpKind Op,
Ice::Type OpTy) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Invalid operator type for " << Ice::InstArithmetic::getOpName(Op)
<< ". Found " << OpTy;
Error(StrBuf.str());
}
void FunctionParser::ProcessRecord() {
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
if (InstIsTerminating) {
InstIsTerminating = false;
CurrentNode = GetBasicBlock(++CurrentBbIndex);
}
Ice::Inst *Inst = NULL;
switch (Record.GetCode()) {
case naclbitc::FUNC_CODE_DECLAREBLOCKS: {
// DECLAREBLOCKS: [n]
if (!isValidRecordSize(1, "function block count"))
break;
if (Func->getNodes().size() != 1) {
Error("Duplicate function block count record");
return;
}
uint32_t NumBbs = Values[0];
if (NumBbs == 0) {
Error("Functions must contain at least one basic block.");
// TODO(kschimpf) Remove error recovery once implementation complete.
NumBbs = 1;
}
// Install the basic blocks, skipping bb0 which was created in the
// constructor.
for (size_t i = 1; i < NumBbs; ++i)
InstallNextBasicBlock();
break;
}
case naclbitc::FUNC_CODE_INST_BINOP: {
// BINOP: [opval, opval, opcode]
if (!isValidRecordSize(3, "function block binop"))
break;
Ice::Operand *Op1 = getOperand(convertRelativeToAbsIndex(Values[0]));
Ice::Operand *Op2 = getOperand(convertRelativeToAbsIndex(Values[1]));
Ice::Type Type1 = Op1->getType();
Ice::Type Type2 = Op2->getType();
if (Type1 != Type2) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Binop argument types differ: " << Type1 << " and " << Type2;
Error(StrBuf.str());
// TODO(kschimpf) Remove error recovery once implementation complete.
Op2 = Op1;
}
Ice::InstArithmetic::OpKind Opcode;
if (!convertBinopOpcode(Values[2], Type1, Opcode))
break;
Ice::Variable *Dest = NextInstVar(Type1);
Inst = Ice::InstArithmetic::create(Func, Opcode, Dest, Op1, Op2);
break;
}
case naclbitc::FUNC_CODE_INST_RET: {
// RET: [opval?]
InstIsTerminating = true;
if (!isValidRecordSizeInRange(0, 1, "function block ret"))
break;
if (Values.size() == 0) {
Inst = Ice::InstRet::create(Func);
} else {
Inst = Ice::InstRet::create(
Func, getOperand(convertRelativeToAbsIndex(Values[0])));
}
break;
}
default:
// Generate error message!
BlockParserBaseClass::ProcessRecord();
break;
}
if (Inst)
CurrentNode->appendInst(Inst);
}
/// Parses the module block in the bitcode file.
class ModuleParser : public BlockParserBaseClass {
public:
......@@ -716,9 +1174,8 @@ bool ModuleParser::ParseBlock(unsigned BlockID) LLVM_OVERRIDE {
return Parser.ParseThisBlock();
}
case naclbitc::FUNCTION_BLOCK_ID: {
Error("Function block parser not yet implemented, skipping");
SkipBlock();
return false;
FunctionParser Parser(BlockID, this);
return Parser.ParseThisBlock();
}
default:
return BlockParserBaseClass::ParseBlock(BlockID);
......@@ -730,7 +1187,7 @@ void ModuleParser::ProcessRecord() {
switch (Record.GetCode()) {
case naclbitc::MODULE_CODE_VERSION: {
// VERSION: [version#]
if (checkRecordSize(1, "Module version"))
if (!isValidRecordSize(1, "Module version"))
return;
unsigned Version = Values[0];
if (Version != 1) {
......@@ -743,11 +1200,11 @@ void ModuleParser::ProcessRecord() {
}
case naclbitc::MODULE_CODE_FUNCTION: {
// FUNCTION: [type, callingconv, isproto, linkage]
if (checkRecordSize(4, "Function heading"))
if (!isValidRecordSize(4, "Function heading"))
return;
Type *Ty = Context->getTypeByID(Values[0]);
FunctionType *FTy = dyn_cast<FunctionType>(Ty);
if (FTy == 0) {
if (FTy == NULL) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Function heading expects function type. Found: " << Ty;
......@@ -788,13 +1245,7 @@ void ModuleParser::ProcessRecord() {
bool TopLevelParser::ParseBlock(unsigned BlockID) {
if (BlockID == naclbitc::MODULE_BLOCK_ID) {
ModuleParser Parser(BlockID, this);
bool ReturnValue = Parser.ParseThisBlock();
// TODO(kschimpf): Remove once translating function blocks.
errs() << "Global addresses:\n";
for (size_t i = 0; i < ValueIDValues.size(); ++i) {
errs() << "[" << i << "]: " << *ValueIDValues[i] << "\n";
}
return ReturnValue;
return Parser.ParseThisBlock();
}
// Generate error message by using default block implementation.
BlockParserBaseClass Parser(BlockID, this);
......@@ -836,8 +1287,8 @@ void PNaClTranslator::translate(const std::string &IRFilename) {
NaClBitstreamReader InputStreamFile(BufPtr, EndBufPtr);
NaClBitstreamCursor InputStream(InputStreamFile);
TopLevelParser Parser(MemBuf->getBufferIdentifier(), Header, InputStream,
ErrorStatus);
TopLevelParser Parser(*this, MemBuf->getBufferIdentifier(), Header,
InputStream, ErrorStatus);
int TopLevelBlocks = 0;
while (!InputStream.AtEndOfStream()) {
if (Parser.Parse()) {
......
......@@ -22,7 +22,8 @@ namespace Ice {
class PNaClTranslator : public Translator {
public:
PNaClTranslator(GlobalContext *Ctx) : Translator(Ctx) {}
PNaClTranslator(GlobalContext *Ctx, const ClFlags &Flags)
: Translator(Ctx, Flags) {}
// Reads the PNaCl bitcode file and translates to ICE, which is then
// converted to machine code. Sets ErrorStatus to true if any
// errors occurred.
......
......@@ -143,7 +143,7 @@ int main(int argc, char **argv) {
Flags);
if (BuildOnRead) {
Ice::PNaClTranslator Translator(&Ctx);
Ice::PNaClTranslator Translator(&Ctx, Flags);
Translator.translate(IRFilename);
return Translator.getErrorStatus();
} else {
......@@ -163,8 +163,8 @@ int main(int argc, char **argv) {
return 1;
}
Ice::Converter Converter(&Ctx);
Converter.convertToIce(Mod);
Ice::Converter Converter(Mod, &Ctx, Flags);
Converter.convertToIce();
return Converter.getErrorStatus();
}
}
; Tests if we can read binary operators.
; RUN: llvm-as < %s | pnacl-freeze \
; RUN: | %llvm2ice -notranslate -verbose=inst -build-on-read \
; RUN: -allow-pnacl-reader-error-recovery \
; RUN: | FileCheck %s
; TODO(kschimpf): add i8/i16. Needs bitcasts.
define i32 @AddI32(i32 %a, i32 %b) {
%add = add i32 %b, %a
ret i32 %add
}
; CHECK: define i32 @AddI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = add i32 %__1, %__0
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @AddI64(i64 %a, i64 %b) {
%add = add i64 %b, %a
ret i64 %add
}
; CHECK-NEXT: define i64 @AddI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = add i64 %__1, %__0
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @AddV16I8(<16 x i8> %a, <16 x i8> %b) {
%add = add <16 x i8> %b, %a
ret <16 x i8> %add
}
; CHECK-NEXT: define <16 x i8> @AddV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = add <16 x i8> %__1, %__0
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define <8 x i16> @AddV8I16(<8 x i16> %a, <8 x i16> %b) {
%add = add <8 x i16> %b, %a
ret <8 x i16> %add
}
; CHECK-NEXT: define <8 x i16> @AddV8I16(<8 x i16> %__0, <8 x i16> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = add <8 x i16> %__1, %__0
; CHECK-NEXT: ret <8 x i16> %__2
; CHECK-NEXT: }
define <4 x i32> @AddV4I32(<4 x i32> %a, <4 x i32> %b) {
%add = add <4 x i32> %b, %a
ret <4 x i32> %add
}
; CHECK-NEXT: define <4 x i32> @AddV4I32(<4 x i32> %__0, <4 x i32> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = add <4 x i32> %__1, %__0
; CHECK-NEXT: ret <4 x i32> %__2
; CHECK-NEXT: }
define float @AddFloat(float %a, float %b) {
%add = fadd float %b, %a
ret float %add
}
; CHECK-NEXT: define float @AddFloat(float %__0, float %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = fadd float %__1, %__0
; CHECK-NEXT: ret float %__2
; CHECK-NEXT: }
define double @AddDouble(double %a, double %b) {
%add = fadd double %b, %a
ret double %add
}
; CHECK-NEXT: define double @AddDouble(double %__0, double %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = fadd double %__1, %__0
; CHECK-NEXT: ret double %__2
; CHECK-NEXT: }
define <4 x float> @AddV4Float(<4 x float> %a, <4 x float> %b) {
%add = fadd <4 x float> %b, %a
ret <4 x float> %add
}
; CHECK-NEXT: define <4 x float> @AddV4Float(<4 x float> %__0, <4 x float> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = fadd <4 x float> %__1, %__0
; CHECK-NEXT: ret <4 x float> %__2
; CHECK-NEXT: }
; TODO(kschimpf): sub i8/i16. Needs bitcasts.
define i32 @SubI32(i32 %a, i32 %b) {
%sub = sub i32 %a, %b
ret i32 %sub
}
; CHECK-NEXT: define i32 @SubI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = sub i32 %__0, %__1
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @SubI64(i64 %a, i64 %b) {
%sub = sub i64 %a, %b
ret i64 %sub
}
; CHECK-NEXT: define i64 @SubI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = sub i64 %__0, %__1
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @SubV16I8(<16 x i8> %a, <16 x i8> %b) {
%sub = sub <16 x i8> %a, %b
ret <16 x i8> %sub
}
; CHECK-NEXT: define <16 x i8> @SubV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = sub <16 x i8> %__0, %__1
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define <8 x i16> @SubV8I16(<8 x i16> %a, <8 x i16> %b) {
%sub = sub <8 x i16> %a, %b
ret <8 x i16> %sub
}
; CHECK-NEXT: define <8 x i16> @SubV8I16(<8 x i16> %__0, <8 x i16> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = sub <8 x i16> %__0, %__1
; CHECK-NEXT: ret <8 x i16> %__2
; CHECK-NEXT: }
define <4 x i32> @SubV4I32(<4 x i32> %a, <4 x i32> %b) {
%sub = sub <4 x i32> %a, %b
ret <4 x i32> %sub
}
; CHECK-NEXT: define <4 x i32> @SubV4I32(<4 x i32> %__0, <4 x i32> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = sub <4 x i32> %__0, %__1
; CHECK-NEXT: ret <4 x i32> %__2
; CHECK-NEXT: }
define float @SubFloat(float %a, float %b) {
%sub = fsub float %a, %b
ret float %sub
}
; CHECK-NEXT: define float @SubFloat(float %__0, float %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = fsub float %__0, %__1
; CHECK-NEXT: ret float %__2
; CHECK-NEXT: }
define double @SubDouble(double %a, double %b) {
%sub = fsub double %a, %b
ret double %sub
}
; CHECK-NEXT: define double @SubDouble(double %__0, double %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = fsub double %__0, %__1
; CHECK-NEXT: ret double %__2
; CHECK-NEXT: }
define <4 x float> @SubV4Float(<4 x float> %a, <4 x float> %b) {
%sub = fsub <4 x float> %a, %b
ret <4 x float> %sub
}
; CHECK-NEXT: define <4 x float> @SubV4Float(<4 x float> %__0, <4 x float> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = fsub <4 x float> %__0, %__1
; CHECK-NEXT: ret <4 x float> %__2
; CHECK-NEXT: }
; TODO(kschimpf): mul i8/i16. Needs bitcasts.
define i32 @MulI32(i32 %a, i32 %b) {
%mul = mul i32 %b, %a
ret i32 %mul
}
; CHECK-NEXT: define i32 @MulI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = mul i32 %__1, %__0
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @MulI64(i64 %a, i64 %b) {
%mul = mul i64 %b, %a
ret i64 %mul
}
; CHECK-NEXT: define i64 @MulI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = mul i64 %__1, %__0
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @MulV16I8(<16 x i8> %a, <16 x i8> %b) {
%mul = mul <16 x i8> %b, %a
ret <16 x i8> %mul
}
; CHECK-NEXT: define <16 x i8> @MulV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = mul <16 x i8> %__1, %__0
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define float @MulFloat(float %a, float %b) {
%mul = fmul float %b, %a
ret float %mul
}
; CHECK-NEXT: define float @MulFloat(float %__0, float %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = fmul float %__1, %__0
; CHECK-NEXT: ret float %__2
; CHECK-NEXT: }
define double @MulDouble(double %a, double %b) {
%mul = fmul double %b, %a
ret double %mul
}
; CHECK-NEXT: define double @MulDouble(double %__0, double %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = fmul double %__1, %__0
; CHECK-NEXT: ret double %__2
; CHECK-NEXT: }
define <4 x float> @MulV4Float(<4 x float> %a, <4 x float> %b) {
%mul = fmul <4 x float> %b, %a
ret <4 x float> %mul
}
; CHECK-NEXT: define <4 x float> @MulV4Float(<4 x float> %__0, <4 x float> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = fmul <4 x float> %__1, %__0
; CHECK-NEXT: ret <4 x float> %__2
; CHECK-NEXT: }
; TODO(kschimpf): sdiv i8/i16. Needs bitcasts.
define i32 @SdivI32(i32 %a, i32 %b) {
%div = sdiv i32 %a, %b
ret i32 %div
}
; CHECK-NEXT: define i32 @SdivI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = sdiv i32 %__0, %__1
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @SdivI64(i64 %a, i64 %b) {
%div = sdiv i64 %a, %b
ret i64 %div
}
; CHECK-NEXT: define i64 @SdivI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = sdiv i64 %__0, %__1
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @SdivV16I8(<16 x i8> %a, <16 x i8> %b) {
%div = sdiv <16 x i8> %a, %b
ret <16 x i8> %div
}
; CHECK-NEXT: define <16 x i8> @SdivV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = sdiv <16 x i8> %__0, %__1
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define <8 x i16> @SdivV8I16(<8 x i16> %a, <8 x i16> %b) {
%div = sdiv <8 x i16> %a, %b
ret <8 x i16> %div
}
; CHECK-NEXT: define <8 x i16> @SdivV8I16(<8 x i16> %__0, <8 x i16> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = sdiv <8 x i16> %__0, %__1
; CHECK-NEXT: ret <8 x i16> %__2
; CHECK-NEXT: }
define <4 x i32> @SdivV4I32(<4 x i32> %a, <4 x i32> %b) {
%div = sdiv <4 x i32> %a, %b
ret <4 x i32> %div
}
; CHECK-NEXT: define <4 x i32> @SdivV4I32(<4 x i32> %__0, <4 x i32> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = sdiv <4 x i32> %__0, %__1
; CHECK-NEXT: ret <4 x i32> %__2
; CHECK-NEXT: }
; TODO(kschimpf): srem i8/i16. Needs bitcasts.
define i32 @SremI32(i32 %a, i32 %b) {
%rem = srem i32 %a, %b
ret i32 %rem
}
; CHECK-NEXT: define i32 @SremI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = srem i32 %__0, %__1
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @SremI64(i64 %a, i64 %b) {
%rem = srem i64 %a, %b
ret i64 %rem
}
; CHECK-NEXT: define i64 @SremI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = srem i64 %__0, %__1
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @SremV16I8(<16 x i8> %a, <16 x i8> %b) {
%rem = srem <16 x i8> %a, %b
ret <16 x i8> %rem
}
; CHECK-NEXT: define <16 x i8> @SremV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = srem <16 x i8> %__0, %__1
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define <8 x i16> @SremV8I16(<8 x i16> %a, <8 x i16> %b) {
%rem = srem <8 x i16> %a, %b
ret <8 x i16> %rem
}
; CHECK-NEXT: define <8 x i16> @SremV8I16(<8 x i16> %__0, <8 x i16> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = srem <8 x i16> %__0, %__1
; CHECK-NEXT: ret <8 x i16> %__2
; CHECK-NEXT: }
define <4 x i32> @SremV4I32(<4 x i32> %a, <4 x i32> %b) {
%rem = srem <4 x i32> %a, %b
ret <4 x i32> %rem
}
; CHECK-NEXT: define <4 x i32> @SremV4I32(<4 x i32> %__0, <4 x i32> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = srem <4 x i32> %__0, %__1
; CHECK-NEXT: ret <4 x i32> %__2
; CHECK-NEXT: }
; TODO(kschimpf): udiv i8/i16. Needs bitcasts.
define i32 @UdivI32(i32 %a, i32 %b) {
%div = udiv i32 %a, %b
ret i32 %div
}
; CHECK-NEXT: define i32 @UdivI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = udiv i32 %__0, %__1
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @UdivI64(i64 %a, i64 %b) {
%div = udiv i64 %a, %b
ret i64 %div
}
; CHECK-NEXT: define i64 @UdivI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = udiv i64 %__0, %__1
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @UdivV16I8(<16 x i8> %a, <16 x i8> %b) {
%div = udiv <16 x i8> %a, %b
ret <16 x i8> %div
}
; CHECK-NEXT: define <16 x i8> @UdivV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = udiv <16 x i8> %__0, %__1
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define <8 x i16> @UdivV8I16(<8 x i16> %a, <8 x i16> %b) {
%div = udiv <8 x i16> %a, %b
ret <8 x i16> %div
}
; CHECK-NEXT: define <8 x i16> @UdivV8I16(<8 x i16> %__0, <8 x i16> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = udiv <8 x i16> %__0, %__1
; CHECK-NEXT: ret <8 x i16> %__2
; CHECK-NEXT: }
define <4 x i32> @UdivV4I32(<4 x i32> %a, <4 x i32> %b) {
%div = udiv <4 x i32> %a, %b
ret <4 x i32> %div
}
; CHECK-NEXT: define <4 x i32> @UdivV4I32(<4 x i32> %__0, <4 x i32> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = udiv <4 x i32> %__0, %__1
; CHECK-NEXT: ret <4 x i32> %__2
; CHECK-NEXT: }
; TODO(kschimpf): urem i8/i16. Needs bitcasts.
define i32 @UremI32(i32 %a, i32 %b) {
%rem = urem i32 %a, %b
ret i32 %rem
}
; CHECK-NEXT: define i32 @UremI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = urem i32 %__0, %__1
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @UremI64(i64 %a, i64 %b) {
%rem = urem i64 %a, %b
ret i64 %rem
}
; CHECK-NEXT: define i64 @UremI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = urem i64 %__0, %__1
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @UremV16I8(<16 x i8> %a, <16 x i8> %b) {
%rem = urem <16 x i8> %a, %b
ret <16 x i8> %rem
}
; CHECK-NEXT: define <16 x i8> @UremV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = urem <16 x i8> %__0, %__1
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define <8 x i16> @UremV8I16(<8 x i16> %a, <8 x i16> %b) {
%rem = urem <8 x i16> %a, %b
ret <8 x i16> %rem
}
; CHECK-NEXT: define <8 x i16> @UremV8I16(<8 x i16> %__0, <8 x i16> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = urem <8 x i16> %__0, %__1
; CHECK-NEXT: ret <8 x i16> %__2
; CHECK-NEXT: }
define <4 x i32> @UremV4I32(<4 x i32> %a, <4 x i32> %b) {
%rem = urem <4 x i32> %a, %b
ret <4 x i32> %rem
}
; CHECK-NEXT: define <4 x i32> @UremV4I32(<4 x i32> %__0, <4 x i32> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = urem <4 x i32> %__0, %__1
; CHECK-NEXT: ret <4 x i32> %__2
; CHECK-NEXT: }
define float @fdivFloat(float %a, float %b) {
%div = fdiv float %a, %b
ret float %div
}
; CHECK-NEXT: define float @fdivFloat(float %__0, float %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = fdiv float %__0, %__1
; CHECK-NEXT: ret float %__2
; CHECK-NEXT: }
define double @fdivDouble(double %a, double %b) {
%div = fdiv double %a, %b
ret double %div
}
; CHECK-NEXT: define double @fdivDouble(double %__0, double %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = fdiv double %__0, %__1
; CHECK-NEXT: ret double %__2
; CHECK-NEXT: }
define <4 x float> @fdivV4Float(<4 x float> %a, <4 x float> %b) {
%div = fdiv <4 x float> %a, %b
ret <4 x float> %div
}
; CHECK-NEXT: define <4 x float> @fdivV4Float(<4 x float> %__0, <4 x float> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = fdiv <4 x float> %__0, %__1
; CHECK-NEXT: ret <4 x float> %__2
; CHECK-NEXT: }
define float @fremFloat(float %a, float %b) {
%rem = frem float %a, %b
ret float %rem
}
; CHECK-NEXT: define float @fremFloat(float %__0, float %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = frem float %__0, %__1
; CHECK-NEXT: ret float %__2
; CHECK-NEXT: }
define double @fremDouble(double %a, double %b) {
%rem = frem double %a, %b
ret double %rem
}
; CHECK-NEXT: define double @fremDouble(double %__0, double %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = frem double %__0, %__1
; CHECK-NEXT: ret double %__2
; CHECK-NEXT: }
define <4 x float> @fremV4Float(<4 x float> %a, <4 x float> %b) {
%rem = frem <4 x float> %a, %b
ret <4 x float> %rem
}
; CHECK-NEXT: define <4 x float> @fremV4Float(<4 x float> %__0, <4 x float> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = frem <4 x float> %__0, %__1
; CHECK-NEXT: ret <4 x float> %__2
; CHECK-NEXT: }
; TODO(kschimpf): and i1/i8/i16. Needs bitcasts.
define i32 @AndI32(i32 %a, i32 %b) {
%and = and i32 %b, %a
ret i32 %and
}
; CHECK-NEXT: define i32 @AndI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = and i32 %__1, %__0
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @AndI64(i64 %a, i64 %b) {
%and = and i64 %b, %a
ret i64 %and
}
; CHECK-NEXT: define i64 @AndI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = and i64 %__1, %__0
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @AndV16I8(<16 x i8> %a, <16 x i8> %b) {
%and = and <16 x i8> %b, %a
ret <16 x i8> %and
}
; CHECK-NEXT: define <16 x i8> @AndV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = and <16 x i8> %__1, %__0
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define <8 x i16> @AndV8I16(<8 x i16> %a, <8 x i16> %b) {
%and = and <8 x i16> %b, %a
ret <8 x i16> %and
}
; CHECK-NEXT: define <8 x i16> @AndV8I16(<8 x i16> %__0, <8 x i16> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = and <8 x i16> %__1, %__0
; CHECK-NEXT: ret <8 x i16> %__2
; CHECK-NEXT: }
define <4 x i32> @AndV4I32(<4 x i32> %a, <4 x i32> %b) {
%and = and <4 x i32> %b, %a
ret <4 x i32> %and
}
; CHECK-NEXT: define <4 x i32> @AndV4I32(<4 x i32> %__0, <4 x i32> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = and <4 x i32> %__1, %__0
; CHECK-NEXT: ret <4 x i32> %__2
; CHECK-NEXT: }
; TODO(kschimpf): or i1/i8/i16. Needs bitcasts.
define i32 @OrI32(i32 %a, i32 %b) {
%or = or i32 %b, %a
ret i32 %or
}
; CHECK-NEXT: define i32 @OrI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = or i32 %__1, %__0
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @OrI64(i64 %a, i64 %b) {
%or = or i64 %b, %a
ret i64 %or
}
; CHECK-NEXT: define i64 @OrI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = or i64 %__1, %__0
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @OrV16I8(<16 x i8> %a, <16 x i8> %b) {
%or = or <16 x i8> %b, %a
ret <16 x i8> %or
}
; CHECK-NEXT: define <16 x i8> @OrV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = or <16 x i8> %__1, %__0
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define <8 x i16> @OrV8I16(<8 x i16> %a, <8 x i16> %b) {
%or = or <8 x i16> %b, %a
ret <8 x i16> %or
}
; CHECK-NEXT: define <8 x i16> @OrV8I16(<8 x i16> %__0, <8 x i16> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = or <8 x i16> %__1, %__0
; CHECK-NEXT: ret <8 x i16> %__2
; CHECK-NEXT: }
define <4 x i32> @OrV4I32(<4 x i32> %a, <4 x i32> %b) {
%or = or <4 x i32> %b, %a
ret <4 x i32> %or
}
; CHECK-NEXT: define <4 x i32> @OrV4I32(<4 x i32> %__0, <4 x i32> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = or <4 x i32> %__1, %__0
; CHECK-NEXT: ret <4 x i32> %__2
; CHECK-NEXT: }
; TODO(kschimpf): xor i1/i8/i16. Needs bitcasts.
define i32 @XorI32(i32 %a, i32 %b) {
%xor = xor i32 %b, %a
ret i32 %xor
}
; CHECK-NEXT: define i32 @XorI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = xor i32 %__1, %__0
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @XorI64(i64 %a, i64 %b) {
%xor = xor i64 %b, %a
ret i64 %xor
}
; CHECK-NEXT: define i64 @XorI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = xor i64 %__1, %__0
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @XorV16I8(<16 x i8> %a, <16 x i8> %b) {
%xor = xor <16 x i8> %b, %a
ret <16 x i8> %xor
}
; CHECK-NEXT: define <16 x i8> @XorV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = xor <16 x i8> %__1, %__0
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define <8 x i16> @XorV8I16(<8 x i16> %a, <8 x i16> %b) {
%xor = xor <8 x i16> %b, %a
ret <8 x i16> %xor
}
; CHECK-NEXT: define <8 x i16> @XorV8I16(<8 x i16> %__0, <8 x i16> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = xor <8 x i16> %__1, %__0
; CHECK-NEXT: ret <8 x i16> %__2
; CHECK-NEXT: }
define <4 x i32> @XorV4I32(<4 x i32> %a, <4 x i32> %b) {
%xor = xor <4 x i32> %b, %a
ret <4 x i32> %xor
}
; CHECK-NEXT: define <4 x i32> @XorV4I32(<4 x i32> %__0, <4 x i32> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = xor <4 x i32> %__1, %__0
; CHECK-NEXT: ret <4 x i32> %__2
; CHECK-NEXT: }
; TODO(kschimpf): shl i8/i16. Needs bitcasts.
define i32 @ShlI32(i32 %a, i32 %b) {
%shl = shl i32 %b, %a
ret i32 %shl
}
; CHECK-NEXT: define i32 @ShlI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = shl i32 %__1, %__0
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @ShlI64(i64 %a, i64 %b) {
%shl = shl i64 %b, %a
ret i64 %shl
}
; CHECK-NEXT: define i64 @ShlI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = shl i64 %__1, %__0
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @ShlV16I8(<16 x i8> %a, <16 x i8> %b) {
%shl = shl <16 x i8> %b, %a
ret <16 x i8> %shl
}
; CHECK-NEXT: define <16 x i8> @ShlV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = shl <16 x i8> %__1, %__0
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define <8 x i16> @ShlV8I16(<8 x i16> %a, <8 x i16> %b) {
%shl = shl <8 x i16> %b, %a
ret <8 x i16> %shl
}
; CHECK-NEXT: define <8 x i16> @ShlV8I16(<8 x i16> %__0, <8 x i16> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = shl <8 x i16> %__1, %__0
; CHECK-NEXT: ret <8 x i16> %__2
; CHECK-NEXT: }
define <4 x i32> @ShlV4I32(<4 x i32> %a, <4 x i32> %b) {
%shl = shl <4 x i32> %b, %a
ret <4 x i32> %shl
}
; CHECK-NEXT: define <4 x i32> @ShlV4I32(<4 x i32> %__0, <4 x i32> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = shl <4 x i32> %__1, %__0
; CHECK-NEXT: ret <4 x i32> %__2
; CHECK-NEXT: }
; TODO(kschimpf): ashr i8/i16. Needs bitcasts.
define i32 @ashrI32(i32 %a, i32 %b) {
%ashr = ashr i32 %b, %a
ret i32 %ashr
}
; CHECK-NEXT: define i32 @ashrI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = ashr i32 %__1, %__0
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @AshrI64(i64 %a, i64 %b) {
%ashr = ashr i64 %b, %a
ret i64 %ashr
}
; CHECK-NEXT: define i64 @AshrI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = ashr i64 %__1, %__0
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @AshrV16I8(<16 x i8> %a, <16 x i8> %b) {
%ashr = ashr <16 x i8> %b, %a
ret <16 x i8> %ashr
}
; CHECK-NEXT: define <16 x i8> @AshrV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = ashr <16 x i8> %__1, %__0
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define <8 x i16> @AshrV8I16(<8 x i16> %a, <8 x i16> %b) {
%ashr = ashr <8 x i16> %b, %a
ret <8 x i16> %ashr
}
; CHECK-NEXT: define <8 x i16> @AshrV8I16(<8 x i16> %__0, <8 x i16> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = ashr <8 x i16> %__1, %__0
; CHECK-NEXT: ret <8 x i16> %__2
; CHECK-NEXT: }
define <4 x i32> @AshrV4I32(<4 x i32> %a, <4 x i32> %b) {
%ashr = ashr <4 x i32> %b, %a
ret <4 x i32> %ashr
}
; CHECK-NEXT: define <4 x i32> @AshrV4I32(<4 x i32> %__0, <4 x i32> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = ashr <4 x i32> %__1, %__0
; CHECK-NEXT: ret <4 x i32> %__2
; CHECK-NEXT: }
; TODO(kschimpf): lshr i8/i16. Needs bitcasts.
define i32 @lshrI32(i32 %a, i32 %b) {
%lshr = lshr i32 %b, %a
ret i32 %lshr
}
; CHECK-NEXT: define i32 @lshrI32(i32 %__0, i32 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = lshr i32 %__1, %__0
; CHECK-NEXT: ret i32 %__2
; CHECK-NEXT: }
define i64 @LshrI64(i64 %a, i64 %b) {
%lshr = lshr i64 %b, %a
ret i64 %lshr
}
; CHECK-NEXT: define i64 @LshrI64(i64 %__0, i64 %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = lshr i64 %__1, %__0
; CHECK-NEXT: ret i64 %__2
; CHECK-NEXT: }
define <16 x i8> @LshrV16I8(<16 x i8> %a, <16 x i8> %b) {
%lshr = lshr <16 x i8> %b, %a
ret <16 x i8> %lshr
}
; CHECK-NEXT: define <16 x i8> @LshrV16I8(<16 x i8> %__0, <16 x i8> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = lshr <16 x i8> %__1, %__0
; CHECK-NEXT: ret <16 x i8> %__2
; CHECK-NEXT: }
define <8 x i16> @LshrV8I16(<8 x i16> %a, <8 x i16> %b) {
%lshr = lshr <8 x i16> %b, %a
ret <8 x i16> %lshr
}
; CHECK-NEXT: define <8 x i16> @LshrV8I16(<8 x i16> %__0, <8 x i16> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = lshr <8 x i16> %__1, %__0
; CHECK-NEXT: ret <8 x i16> %__2
; CHECK-NEXT: }
define <4 x i32> @LshrV4I32(<4 x i32> %a, <4 x i32> %b) {
%lshr = lshr <4 x i32> %b, %a
ret <4 x i32> %lshr
}
; CHECK-NEXT: define <4 x i32> @LshrV4I32(<4 x i32> %__0, <4 x i32> %__1) {
; CHECK-NEXT: __0:
; CHECK-NEXT: %__2 = lshr <4 x i32> %__1, %__0
; CHECK-NEXT: ret <4 x i32> %__2
; CHECK-NEXT: }
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