Commit 6fcbdddb by Karl Schimpf

Disable Subzero IR generation for performance testing.

This CL allows one to time Subzero's bitcode parsing without IR generation (other than types, function declarations, and uninitialized global variables) for performance testing. BUG=None R=jvoung@chromium.org Review URL: https://codereview.chromium.org/696383004
parent 0faec4c9
......@@ -51,10 +51,12 @@ CXX_DEFINES =
ifdef MINIMAL
OBJDIR := $(OBJDIR)+Min
CXX_DEFINES += -DALLOW_TEXT_ASM=0 -DALLOW_DUMP=0 -DALLOW_LLVM_CL=0 \
-DALLOW_LLVM_IR=0 -DALLOW_LLVM_IR_AS_INPUT=0
-DALLOW_LLVM_IR=0 -DALLOW_LLVM_IR_AS_INPUT=0 \
-DALLOW_DISABLE_IR_GEN=0
else
CXX_DEFINES += -DALLOW_TEXT_ASM=1 -DALLOW_DUMP=1 -DALLOW_LLVM_CL=1 \
-DALLOW_LLVM_IR=1 -DALLOW_LLVM_IR_AS_INPUT=1
-DALLOW_LLVM_IR=1 -DALLOW_LLVM_IR_AS_INPUT=1 \
-DALLOW_DISABLE_IR_GEN=1
endif
ifdef NOASSERT
......
......@@ -47,6 +47,7 @@ def main():
action='store_true',
help='Trace command that generates ICE instructions')
argparser.add_argument('--args', '-a', nargs=argparse.REMAINDER,
default=[],
help='Remaining arguments are passed to llvm2ice')
args = argparser.parse_args()
......@@ -78,8 +79,7 @@ def main():
cmd += ['--build-on-read=0']
else:
cmd += ['--build-on-read=1']
if args.args:
cmd += args.args
cmd += args.args
if args.llvm_source:
cmd += [llfile]
......
......@@ -31,7 +31,10 @@ Cfg::Cfg(GlobalContext *Ctx)
VMetadata(new VariablesMetadata(this)),
TargetAssembler(
TargetLowering::createAssembler(Ctx->getTargetArch(), this)),
CurrentNode(NULL) {}
CurrentNode(NULL) {
assert(!Ctx->isIRGenerationDisabled() &&
"Attempt to build cfg when IR generation disabled");
}
Cfg::~Cfg() {}
......
......@@ -26,8 +26,9 @@ public:
UseIntegratedAssembler(false), UseSandboxing(false),
PhiEdgeSplit(false), DecorateAsm(false), DumpStats(false),
AllowUninitializedGlobals(false), TimeEachFunction(false),
DefaultGlobalPrefix(""), DefaultFunctionPrefix(""), TimingFocusOn(""),
VerboseFocusOn(""), TranslateOnly("") {}
DisableIRGeneration(false), DefaultGlobalPrefix(""),
DefaultFunctionPrefix(""), TimingFocusOn(""), VerboseFocusOn(""),
TranslateOnly("") {}
bool DisableInternal;
bool SubzeroTimingEnabled;
bool DisableTranslation;
......@@ -40,6 +41,7 @@ public:
bool DumpStats;
bool AllowUninitializedGlobals;
bool TimeEachFunction;
bool DisableIRGeneration;
IceString DefaultGlobalPrefix;
IceString DefaultFunctionPrefix;
IceString TimingFocusOn;
......
......@@ -140,6 +140,10 @@ public:
const ClFlags &getFlags() const { return Flags; }
bool isIRGenerationDisabled() const {
return ALLOW_DISABLE_IR_GEN ? getFlags().DisableIRGeneration : false;
}
// Allocate data of type T using the global allocator.
template <typename T> T *allocate() { return Allocator.Allocate<T>(); }
......
......@@ -137,6 +137,8 @@ class ConstantPrimitive : public Constant {
public:
static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, T Value,
uint32_t PoolEntryID) {
assert(!Ctx->isIRGenerationDisabled() &&
"Attempt to build primitive constant when IR generation disabled");
return new (Ctx->allocate<ConstantPrimitive>())
ConstantPrimitive(Ty, Value, PoolEntryID);
}
......@@ -206,6 +208,8 @@ public:
static ConstantRelocatable *create(GlobalContext *Ctx, Type Ty,
const RelocatableTuple &Tuple,
uint32_t PoolEntryID) {
assert(!Ctx->isIRGenerationDisabled() &&
"Attempt to build relocatable constant when IR generation disabled");
return new (Ctx->allocate<ConstantRelocatable>()) ConstantRelocatable(
Ty, Tuple.Offset, Tuple.Name, Tuple.SuppressMangling, PoolEntryID);
}
......@@ -246,6 +250,8 @@ class ConstantUndef : public Constant {
public:
static ConstantUndef *create(GlobalContext *Ctx, Type Ty,
uint32_t PoolEntryID) {
assert(!Ctx->isIRGenerationDisabled() &&
"Attempt to build undefined constant when IR generation disabled");
return new (Ctx->allocate<ConstantUndef>()) ConstantUndef(Ty, PoolEntryID);
}
......
......@@ -201,6 +201,12 @@ public:
/// Changes the size of the type list to the given size.
void resizeTypeIDValues(unsigned NewSize) { TypeIDValues.resize(NewSize); }
/// Returns true if generation of Subzero IR is disabled.
bool isIRGenerationDisabled() const {
return ALLOW_DISABLE_IR_GEN ? Translator.getFlags().DisableIRGeneration
: false;
}
/// Returns the undefined type associated with type ID.
/// Note: Returns extended type ready to be defined.
ExtendedType *getTypeByIDForDefining(unsigned ID) {
......@@ -284,6 +290,11 @@ public:
if (C != nullptr)
return C;
if (isIRGenerationDisabled()) {
ValueIDConstants[ID] = nullptr;
return nullptr;
}
// If reached, no such constant exists, create one.
// TODO(kschimpf) Don't get addresses of intrinsic function declarations.
Ice::GlobalDeclaration *Decl = nullptr;
......@@ -523,6 +534,11 @@ protected:
const Ice::ClFlags &getFlags() const { return getTranslator().getFlags(); }
bool isIRGenerationDisabled() const {
return ALLOW_DISABLE_IR_GEN ? getTranslator().getFlags().DisableIRGeneration
: false;
}
// Generates an error Message with the bit address prefixed to it.
bool Error(const std::string &Message) override {
uint64_t Bit = Record.GetStartBit() + Context->getHeaderSize() * 8;
......@@ -811,6 +827,8 @@ public:
Ice::VariableDeclaration::create(getTranslator().getContext())),
CurGlobalVar(DummyGlobalVar) {}
~GlobalsParser() final {}
private:
Ice::TimerMarker Timer;
// Keeps track of how many initializers are expected for the global variable
......@@ -881,10 +899,12 @@ void GlobalsParser::ProcessRecord() {
if (!isValidRecordSize(2, "Globals variable"))
return;
verifyNoMissingInitializers();
InitializersNeeded = 1;
CurGlobalVar = Context->getGlobalVariableByID(NextGlobalID);
CurGlobalVar->setAlignment((1 << Values[0]) >> 1);
CurGlobalVar->setIsConstant(Values[1] != 0);
if (!isIRGenerationDisabled()) {
InitializersNeeded = 1;
CurGlobalVar = Context->getGlobalVariableByID(NextGlobalID);
CurGlobalVar->setAlignment((1 << Values[0]) >> 1);
CurGlobalVar->setIsConstant(Values[1] != 0);
}
++NextGlobalID;
return;
}
......@@ -903,12 +923,16 @@ void GlobalsParser::ProcessRecord() {
Error(StrBuf.str());
return;
}
if (isIRGenerationDisabled())
return;
InitializersNeeded = Values[0];
return;
case naclbitc::GLOBALVAR_ZEROFILL: {
// ZEROFILL: [size]
if (!isValidRecordSize(1, "Globals zerofill"))
return;
if (isIRGenerationDisabled())
return;
CurGlobalVar->addInitializer(
new Ice::VariableDeclaration::ZeroInitializer(Values[0]));
return;
......@@ -917,6 +941,8 @@ void GlobalsParser::ProcessRecord() {
// DATA: [b0, b1, ...]
if (!isValidRecordSizeAtLeast(1, "Globals data"))
return;
if (isIRGenerationDisabled())
return;
CurGlobalVar->addInitializer(
new Ice::VariableDeclaration::DataInitializer(Values));
return;
......@@ -925,6 +951,8 @@ void GlobalsParser::ProcessRecord() {
// RELOC: [val, [addend]]
if (!isValidRecordSizeInRange(1, 2, "Globals reloc"))
return;
if (isIRGenerationDisabled())
return;
unsigned Index = Values[0];
Ice::SizeT Offset = 0;
if (Values.size() == 2)
......@@ -1011,37 +1039,49 @@ public:
FunctionParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser)
: BlockParserBaseClass(BlockID, EnclosingParser),
Timer(Ice::TimerStack::TT_parseFunctions, getTranslator().getContext()),
Func(new Ice::Cfg(getTranslator().getContext())), CurrentBbIndex(0),
FcnId(Context->getNextFunctionBlockValueID()),
Func(isIRGenerationDisabled()
? nullptr
: new Ice::Cfg(getTranslator().getContext())),
CurrentBbIndex(0), FcnId(Context->getNextFunctionBlockValueID()),
FuncDecl(Context->getFunctionByID(FcnId)),
CachedNumGlobalValueIDs(Context->getNumGlobalIDs()),
NextLocalInstIndex(Context->getNumGlobalIDs()),
InstIsTerminating(false) {
Func->setFunctionName(FuncDecl->getName());
if (getFlags().TimeEachFunction)
getTranslator().getContext()->pushTimer(
getTranslator().getContext()->getTimerID(
Ice::GlobalContext::TSK_Funcs, Func->getFunctionName()),
Ice::GlobalContext::TSK_Funcs, FuncDecl->getName()),
Ice::GlobalContext::TSK_Funcs);
// TODO(kschimpf) Clean up API to add a function signature to
// a CFG.
const Ice::FuncSigType &Signature = FuncDecl->getSignature();
Func->setReturnType(Signature.getReturnType());
Func->setInternal(FuncDecl->getLinkage() == GlobalValue::InternalLinkage);
CurrentNode = InstallNextBasicBlock();
Func->setEntryNode(CurrentNode);
for (Ice::Type ArgType : Signature.getArgList()) {
Func->addArg(getNextInstVar(ArgType));
if (isIRGenerationDisabled()) {
CurrentNode = nullptr;
for (Ice::Type ArgType : Signature.getArgList()) {
(void)ArgType;
setNextLocalInstIndex(nullptr);
}
} else {
Func->setFunctionName(FuncDecl->getName());
Func->setReturnType(Signature.getReturnType());
Func->setInternal(FuncDecl->getLinkage() == GlobalValue::InternalLinkage);
CurrentNode = InstallNextBasicBlock();
Func->setEntryNode(CurrentNode);
for (Ice::Type ArgType : Signature.getArgList()) {
Func->addArg(getNextInstVar(ArgType));
}
}
}
~FunctionParser() override {};
~FunctionParser() final {}
// Set the next constant ID to the given constant C.
void setNextConstantID(Ice::Constant *C) {
setOperand(NextLocalInstIndex++, C);
void setNextLocalInstIndex(Ice::Operand *Op) {
setOperand(NextLocalInstIndex++, Op);
}
// Set the next constant ID to the given constant C.
void setNextConstantID(Ice::Constant *C) { setNextLocalInstIndex(C); }
private:
Ice::TimerMarker Timer;
// The corresponding ICE function defined by the function block.
......@@ -1068,6 +1108,15 @@ private:
// Upper limit of alignment power allowed by LLVM
static const uint64_t AlignPowerLimit = 29;
void popTimerIfTimingEachFunction() const {
if (getFlags().TimeEachFunction) {
getTranslator().getContext()->popTimer(
getTranslator().getContext()->getTimerID(
Ice::GlobalContext::TSK_Funcs, Func->getFunctionName()),
Ice::GlobalContext::TSK_Funcs);
}
}
// 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.
......@@ -1093,10 +1142,14 @@ private:
void ExitBlock() override;
// Creates and appends a new basic block to the list of basic blocks.
Ice::CfgNode *InstallNextBasicBlock() { return Func->makeNode(); }
Ice::CfgNode *InstallNextBasicBlock() {
assert(!isIRGenerationDisabled());
return Func->makeNode();
}
// Returns the Index-th basic block in the list of basic blocks.
Ice::CfgNode *getBasicBlock(uint32_t Index) {
assert(!isIRGenerationDisabled());
const Ice::NodeList &Nodes = Func->getNodes();
if (Index >= Nodes.size()) {
std::string Buffer;
......@@ -1115,6 +1168,7 @@ private:
// the branch references the entry block, it also generates a
// corresponding error.
Ice::CfgNode *getBranchBasicBlock(uint32_t Index) {
assert(!isIRGenerationDisabled());
if (Index == 0) {
Error("Branch to entry block not allowed");
// TODO(kschimpf) Remove error recovery once implementation complete.
......@@ -1124,6 +1178,7 @@ private:
// Generate an instruction variable with type Ty.
Ice::Variable *createInstVar(Ice::Type Ty) {
assert(!isIRGenerationDisabled());
if (Ty == Ice::IceType_void) {
Error("Can't define instruction value using type void");
// Recover since we can't throw an exception.
......@@ -1134,6 +1189,7 @@ private:
// Generates the next available local variable using the given type.
Ice::Variable *getNextInstVar(Ice::Type Ty) {
assert(!isIRGenerationDisabled());
assert(NextLocalInstIndex >= CachedNumGlobalValueIDs);
// Before creating one, see if a forwardtyperef has already defined it.
uint32_t LocalIndex = NextLocalInstIndex - CachedNumGlobalValueIDs;
......@@ -1191,6 +1247,8 @@ private:
}
Ice::Operand *Op = LocalOperands[LocalIndex];
if (Op == nullptr) {
if (isIRGenerationDisabled())
return nullptr;
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Value index " << Index << " not defined!";
......@@ -1202,7 +1260,7 @@ private:
// Sets element Index (in the local operands list) to Op.
void setOperand(uint32_t Index, Ice::Operand *Op) {
assert(Op);
assert(Op || isIRGenerationDisabled());
// Check if simple push works.
uint32_t LocalIndex = Index - CachedNumGlobalValueIDs;
if (LocalIndex == LocalOperands.size()) {
......@@ -1633,6 +1691,10 @@ void FunctionParser::ReportInvalidBinopOpcode(unsigned Opcode, Ice::Type Ty) {
}
void FunctionParser::ExitBlock() {
if (isIRGenerationDisabled()) {
popTimerIfTimingEachFunction();
return;
}
// Before translating, check for blocks without instructions, and
// insert unreachable. This shouldn't happen, but be safe.
unsigned Index = 0;
......@@ -1654,11 +1716,7 @@ void FunctionParser::ExitBlock() {
// for such parsing errors.
if (Context->getNumErrors() == 0)
getTranslator().translateFcn(Func);
if (getFlags().TimeEachFunction)
getTranslator().getContext()->popTimer(
getTranslator().getContext()->getTimerID(Ice::GlobalContext::TSK_Funcs,
Func->getFunctionName()),
Ice::GlobalContext::TSK_Funcs);
popTimerIfTimingEachFunction();
}
void FunctionParser::ReportInvalidBinaryOp(Ice::InstArithmetic::OpKind Op,
......@@ -1671,10 +1729,15 @@ void FunctionParser::ReportInvalidBinaryOp(Ice::InstArithmetic::OpKind Op,
}
void FunctionParser::ProcessRecord() {
// Note: To better separate parse/IR generation times, when IR generation
// is disabled we do the following:
// 1) Delay exiting until after we extract operands.
// 2) return before we access operands, since all operands will be a nullptr.
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
if (InstIsTerminating) {
InstIsTerminating = false;
CurrentNode = getBasicBlock(++CurrentBbIndex);
if (!isIRGenerationDisabled())
CurrentNode = getBasicBlock(++CurrentBbIndex);
}
// The base index for relative indexing.
int32_t BaseIndex = getNextInstIndex();
......@@ -1683,16 +1746,18 @@ void FunctionParser::ProcessRecord() {
// DECLAREBLOCKS: [n]
if (!isValidRecordSize(1, "function block count"))
return;
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;
}
if (isIRGenerationDisabled())
return;
if (Func->getNodes().size() != 1) {
Error("Duplicate function block count record");
return;
}
// Install the basic blocks, skipping bb0 which was created in the
// constructor.
for (size_t i = 1; i < NumBbs; ++i)
......@@ -1705,6 +1770,11 @@ void FunctionParser::ProcessRecord() {
return;
Ice::Operand *Op1 = getRelativeOperand(Values[0], BaseIndex);
Ice::Operand *Op2 = getRelativeOperand(Values[1], BaseIndex);
if (isIRGenerationDisabled()) {
assert(Op1 == nullptr && Op2 == nullptr);
setNextLocalInstIndex(nullptr);
return;
}
Ice::Type Type1 = Op1->getType();
Ice::Type Type2 = Op2->getType();
if (Type1 != Type2) {
......@@ -1740,6 +1810,11 @@ void FunctionParser::ProcessRecord() {
appendErrorInstruction(CastType);
return;
}
if (isIRGenerationDisabled()) {
assert(Src == nullptr);
setNextLocalInstIndex(nullptr);
return;
}
Ice::Type SrcType = Src->getType();
if (!CastInst::castIsValid(LLVMCastOp, Context->convertToLLVMType(SrcType),
Context->convertToLLVMType(CastType))) {
......@@ -1757,9 +1832,17 @@ void FunctionParser::ProcessRecord() {
}
case naclbitc::FUNC_CODE_INST_VSELECT: {
// VSELECT: [opval, opval, pred]
if (!isValidRecordSize(3, "function block select"))
return;
Ice::Operand *ThenVal = getRelativeOperand(Values[0], BaseIndex);
Ice::Type ThenType = ThenVal->getType();
Ice::Operand *ElseVal = getRelativeOperand(Values[1], BaseIndex);
Ice::Operand *CondVal = getRelativeOperand(Values[2], BaseIndex);
if (isIRGenerationDisabled()) {
assert(ThenVal == nullptr && ElseVal == nullptr && CondVal == nullptr);
setNextLocalInstIndex(nullptr);
return;
}
Ice::Type ThenType = ThenVal->getType();
Ice::Type ElseType = ElseVal->getType();
if (ThenType != ElseType) {
std::string Buffer;
......@@ -1770,7 +1853,6 @@ void FunctionParser::ProcessRecord() {
appendErrorInstruction(ThenType);
return;
}
Ice::Operand *CondVal = getRelativeOperand(Values[2], BaseIndex);
Ice::Type CondType = CondVal->getType();
if (isVectorType(CondType)) {
if (!isVectorType(ThenType) ||
......@@ -1802,8 +1884,13 @@ void FunctionParser::ProcessRecord() {
if (!isValidRecordSize(2, "function block extract element"))
return;
Ice::Operand *Vec = getRelativeOperand(Values[0], BaseIndex);
Ice::Type VecType = Vec->getType();
Ice::Operand *Index = getRelativeOperand(Values[1], BaseIndex);
if (isIRGenerationDisabled()) {
assert(Vec == nullptr && Index == nullptr);
setNextLocalInstIndex(nullptr);
return;
}
Ice::Type VecType = Vec->getType();
VectorIndexCheckValue IndexCheckValue = validateVectorIndex(Vec, Index);
if (IndexCheckValue != VectorIndexValid) {
std::string Buffer;
......@@ -1824,9 +1911,14 @@ void FunctionParser::ProcessRecord() {
if (!isValidRecordSize(3, "function block insert element"))
return;
Ice::Operand *Vec = getRelativeOperand(Values[0], BaseIndex);
Ice::Type VecType = Vec->getType();
Ice::Operand *Elt = getRelativeOperand(Values[1], BaseIndex);
Ice::Operand *Index = getRelativeOperand(Values[2], BaseIndex);
if (isIRGenerationDisabled()) {
assert(Vec == nullptr && Elt == nullptr && Index == nullptr);
setNextLocalInstIndex(nullptr);
return;
}
Ice::Type VecType = Vec->getType();
VectorIndexCheckValue IndexCheckValue = validateVectorIndex(Vec, Index);
if (IndexCheckValue != VectorIndexValid) {
std::string Buffer;
......@@ -1849,6 +1941,11 @@ void FunctionParser::ProcessRecord() {
return;
Ice::Operand *Op1 = getRelativeOperand(Values[0], BaseIndex);
Ice::Operand *Op2 = getRelativeOperand(Values[1], BaseIndex);
if (isIRGenerationDisabled()) {
assert(Op1 == nullptr && Op2 == nullptr);
setNextLocalInstIndex(nullptr);
return;
}
Ice::Type Op1Type = Op1->getType();
Ice::Type Op2Type = Op2->getType();
Ice::Type DestType = getCompareResultType(Op1Type);
......@@ -1909,10 +2006,16 @@ void FunctionParser::ProcessRecord() {
if (!isValidRecordSizeInRange(0, 1, "function block ret"))
return;
if (Values.empty()) {
if (isIRGenerationDisabled())
return;
CurrentNode->appendInst(Ice::InstRet::create(Func));
} else {
CurrentNode->appendInst(
Ice::InstRet::create(Func, getRelativeOperand(Values[0], BaseIndex)));
Ice::Operand *RetVal = getRelativeOperand(Values[0], BaseIndex);
if (isIRGenerationDisabled()) {
assert(RetVal == nullptr);
return;
}
CurrentNode->appendInst(Ice::InstRet::create(Func, RetVal));
}
InstIsTerminating = true;
return;
......@@ -1920,6 +2023,8 @@ void FunctionParser::ProcessRecord() {
case naclbitc::FUNC_CODE_INST_BR: {
if (Values.size() == 1) {
// BR: [bb#]
if (isIRGenerationDisabled())
return;
Ice::CfgNode *Block = getBranchBasicBlock(Values[0]);
if (Block == nullptr)
return;
......@@ -1929,6 +2034,10 @@ void FunctionParser::ProcessRecord() {
if (!isValidRecordSize(3, "function block branch"))
return;
Ice::Operand *Cond = getRelativeOperand(Values[2], BaseIndex);
if (isIRGenerationDisabled()) {
assert(Cond == nullptr);
return;
}
if (Cond->getType() != Ice::IceType_i1) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
......@@ -1958,6 +2067,7 @@ void FunctionParser::ProcessRecord() {
// already frozen when the problem was noticed.
if (!isValidRecordSizeAtLeast(4, "function block switch"))
return;
Ice::Type CondTy = Context->getSimpleTypeByID(Values[0]);
if (!Ice::isScalarIntegerType(CondTy)) {
std::string Buffer;
......@@ -1968,7 +2078,11 @@ void FunctionParser::ProcessRecord() {
}
Ice::SizeT BitWidth = Ice::getScalarIntBitWidth(CondTy);
Ice::Operand *Cond = getRelativeOperand(Values[1], BaseIndex);
if (CondTy != Cond->getType()) {
const bool isIRGenDisabled = isIRGenerationDisabled();
if (isIRGenDisabled) {
assert(Cond == nullptr);
} else if (CondTy != Cond->getType()) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Case condition expects type " << CondTy
......@@ -1976,14 +2090,16 @@ void FunctionParser::ProcessRecord() {
Error(StrBuf.str());
return;
}
Ice::CfgNode *DefaultLabel = getBranchBasicBlock(Values[2]);
Ice::CfgNode *DefaultLabel =
isIRGenDisabled ? nullptr : getBranchBasicBlock(Values[2]);
unsigned NumCases = Values[3];
// Now recognize each of the cases.
if (!isValidRecordSize(4 + NumCases * 4, "Function block switch"))
return;
Ice::InstSwitch *Switch =
Ice::InstSwitch::create(Func, NumCases, Cond, DefaultLabel);
isIRGenDisabled ? nullptr : Ice::InstSwitch::create(Func, NumCases,
Cond, DefaultLabel);
unsigned ValCaseIndex = 4; // index to beginning of case entry.
for (unsigned CaseIndex = 0; CaseIndex < NumCases;
++CaseIndex, ValCaseIndex += 4) {
......@@ -1998,9 +2114,13 @@ void FunctionParser::ProcessRecord() {
APInt Value(BitWidth,
NaClDecodeSignRotatedValue(Values[ValCaseIndex + 2]),
true);
if (isIRGenDisabled)
continue;
Ice::CfgNode *Label = getBranchBasicBlock(Values[ValCaseIndex + 3]);
Switch->addBranch(CaseIndex, Value.getSExtValue(), Label);
}
if (isIRGenDisabled)
return;
CurrentNode->appendInst(Switch);
InstIsTerminating = true;
return;
......@@ -2009,6 +2129,8 @@ void FunctionParser::ProcessRecord() {
// UNREACHABLE: []
if (!isValidRecordSize(0, "function block unreachable"))
return;
if (isIRGenerationDisabled())
return;
CurrentNode->appendInst(
Ice::InstUnreachable::create(Func));
InstIsTerminating = true;
......@@ -2032,6 +2154,15 @@ void FunctionParser::ProcessRecord() {
Error("Phi record using type void not allowed");
return;
}
if (isIRGenerationDisabled()) {
// Verify arguments are defined before quitting.
for (unsigned i = 1; i < Values.size(); i += 2) {
assert(getRelativeOperand(NaClDecodeSignRotatedValue(Values[i]),
BaseIndex) == nullptr);
}
setNextLocalInstIndex(nullptr);
return;
}
Ice::Variable *Dest = getNextInstVar(Ty);
Ice::InstPhi *Phi = Ice::InstPhi::create(Func, Values.size() >> 1, Dest);
for (unsigned i = 1; i < Values.size(); i += 2) {
......@@ -2056,6 +2187,13 @@ void FunctionParser::ProcessRecord() {
if (!isValidRecordSize(2, "function block alloca"))
return;
Ice::Operand *ByteCount = getRelativeOperand(Values[0], BaseIndex);
unsigned Alignment;
extractAlignment("Alloca", Values[1], Alignment);
if (isIRGenerationDisabled()) {
assert(ByteCount == nullptr);
setNextLocalInstIndex(nullptr);
return;
}
Ice::Type PtrTy = Context->getIcePointerType();
if (ByteCount->getType() != Ice::IceType_i32) {
std::string Buffer;
......@@ -2065,8 +2203,6 @@ void FunctionParser::ProcessRecord() {
appendErrorInstruction(PtrTy);
return;
}
unsigned Alignment;
extractAlignment("Alloca", Values[1], Alignment);
CurrentNode->appendInst(Ice::InstAlloca::create(Func, ByteCount, Alignment,
getNextInstVar(PtrTy)));
return;
......@@ -2077,12 +2213,17 @@ void FunctionParser::ProcessRecord() {
return;
Ice::Operand *Address = getRelativeOperand(Values[0], BaseIndex);
Ice::Type Ty = Context->getSimpleTypeByID(Values[2]);
unsigned Alignment;
extractAlignment("Load", Values[1], Alignment);
if (isIRGenerationDisabled()) {
assert(Address == nullptr);
setNextLocalInstIndex(nullptr);
return;
}
if (!isValidPointerType(Address, "Load")) {
appendErrorInstruction(Ty);
return;
}
unsigned Alignment;
extractAlignment("Load", Values[1], Alignment);
if (!isValidLoadStoreAlignment(Alignment, Ty, "Load")) {
appendErrorInstruction(Ty);
return;
......@@ -2096,11 +2237,15 @@ void FunctionParser::ProcessRecord() {
if (!isValidRecordSize(3, "function block store"))
return;
Ice::Operand *Address = getRelativeOperand(Values[0], BaseIndex);
if (!isValidPointerType(Address, "Store"))
return;
Ice::Operand *Value = getRelativeOperand(Values[1], BaseIndex);
unsigned Alignment;
extractAlignment("Store", Values[2], Alignment);
if (isIRGenerationDisabled()) {
assert(Address == nullptr && Value == nullptr);
return;
}
if (!isValidPointerType(Address, "Store"))
return;
if (!isValidLoadStoreAlignment(Alignment, Value->getType(), "Store"))
return;
CurrentNode->appendInst(
......@@ -2172,12 +2317,25 @@ void FunctionParser::ProcessRecord() {
return;
}
bool IsTailCall = static_cast<bool>(CCInfo & 1);
Ice::SizeT NumParams = Values.size() - ParamsStartIndex;
if (isIRGenerationDisabled()) {
assert(Callee == nullptr);
// Check that parameters are defined.
for (Ice::SizeT ParamIndex = 0; ParamIndex < NumParams; ++ParamIndex) {
assert(getRelativeOperand(Values[ParamsStartIndex + ParamIndex],
BaseIndex) == nullptr);
}
// Define value slot only if value returned.
if (ReturnType != Ice::IceType_void)
setNextLocalInstIndex(nullptr);
return;
}
// Create the call instruction.
Ice::Variable *Dest = (ReturnType == Ice::IceType_void)
? nullptr
: getNextInstVar(ReturnType);
Ice::SizeT NumParams = Values.size() - ParamsStartIndex;
Ice::InstCall *Inst = nullptr;
if (IntrinsicInfo) {
Inst =
......@@ -2242,7 +2400,9 @@ void FunctionParser::ProcessRecord() {
// FORWARDTYPEREF: [opval, ty]
if (!isValidRecordSize(2, "function block forward type ref"))
return;
setOperand(Values[0], createInstVar(Context->getSimpleTypeByID(Values[1])));
Ice::Type OpType = Context->getSimpleTypeByID(Values[1]);
setOperand(Values[0],
isIRGenerationDisabled() ? nullptr : createInstVar(OpType));
return;
}
default:
......@@ -2304,6 +2464,10 @@ void ConstantsParser::ProcessRecord() {
return;
if (!isValidNextConstantType())
return;
if (isIRGenerationDisabled()) {
FuncParser->setNextConstantID(nullptr);
return;
}
FuncParser->setNextConstantID(
getContext()->getConstantUndef(NextConstantType));
return;
......@@ -2314,6 +2478,10 @@ void ConstantsParser::ProcessRecord() {
return;
if (!isValidNextConstantType())
return;
if (isIRGenerationDisabled()) {
FuncParser->setNextConstantID(nullptr);
return;
}
if (IntegerType *IType = dyn_cast<IntegerType>(
Context->convertToLLVMType(NextConstantType))) {
APInt Value(IType->getBitWidth(), NaClDecodeSignRotatedValue(Values[0]));
......@@ -2338,6 +2506,10 @@ void ConstantsParser::ProcessRecord() {
return;
if (!isValidNextConstantType())
return;
if (isIRGenerationDisabled()) {
FuncParser->setNextConstantID(nullptr);
return;
}
switch (NextConstantType) {
case Ice::IceType_f32: {
APFloat Value(APFloat::IEEEsingle,
......@@ -2410,6 +2582,8 @@ void FunctionValuesymtabParser::setValueName(uint64_t Index, StringType &Name) {
// TODO(kschimpf) Remove error recovery once implementation complete.
return;
}
if (isIRGenerationDisabled())
return;
Ice::Operand *Op = getFunctionParser()->getOperand(Index);
if (Ice::Variable *V = dyn_cast<Ice::Variable>(Op)) {
std::string Nm(Name.data(), Name.size());
......@@ -2420,6 +2594,8 @@ void FunctionValuesymtabParser::setValueName(uint64_t Index, StringType &Name) {
}
void FunctionValuesymtabParser::setBbName(uint64_t Index, StringType &Name) {
if (isIRGenerationDisabled())
return;
if (Index >= getFunctionParser()->Func->getNumNodes()) {
reportUnableToAssign("block", Index, Name);
return;
......
......@@ -94,6 +94,10 @@ DisableInternal("externalize",
cl::desc("Externalize all symbols"));
static cl::opt<bool>
DisableTranslation("notranslate", cl::desc("Disable Subzero translation"));
// Note: Modifiable only if ALLOW_DISABLE_IR_GEN.
static cl::opt<bool>
DisableIRGeneration("no-ir-gen",
cl::desc("Disable generating Subzero IR."));
static cl::opt<std::string>
TranslateOnly("translate-only", cl::desc("Translate only the given function"),
cl::init(""));
......@@ -188,12 +192,12 @@ static int GetReturnValue(int Val) {
static struct {
const char *FlagName;
int FlagValue;
} ConditionalBuildAttributes[] = { { "text_asm", ALLOW_TEXT_ASM },
{ "dump", ALLOW_DUMP },
{ "llvm_cl", ALLOW_LLVM_CL },
{ "llvm_ir", ALLOW_LLVM_IR },
{ "llvm_ir_as_input",
ALLOW_LLVM_IR_AS_INPUT } };
} ConditionalBuildAttributes[] = {{"text_asm", ALLOW_TEXT_ASM},
{"dump", ALLOW_DUMP},
{"llvm_cl", ALLOW_LLVM_CL},
{"llvm_ir", ALLOW_LLVM_IR},
{"llvm_ir_as_input", ALLOW_LLVM_IR_AS_INPUT},
{"disable_ir_gen", ALLOW_DISABLE_IR_GEN}};
// Validates values of build attributes. Prints them to Stream if
// Stream is non-null.
......@@ -228,6 +232,9 @@ int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
if (DisableIRGeneration)
DisableTranslation = true;
Ice::VerboseMask VMask = Ice::IceV_None;
for (unsigned i = 0; i != VerboseList.size(); ++i)
VMask |= VerboseList[i];
......@@ -251,6 +258,12 @@ int main(int argc, char **argv) {
raw_os_ostream *Ls = new raw_os_ostream(LogFilename == "-" ? std::cout : Lfs);
Ls->SetUnbuffered();
if (!ALLOW_DISABLE_IR_GEN && DisableIRGeneration) {
*Ls << "Error: Build doesn't allow --no-ir-gen when not "
<< "ALLOW_DISABLE_IR_GEN!\n";
return GetReturnValue(1);
}
Ice::ClFlags Flags;
Flags.DisableInternal = DisableInternal;
Flags.SubzeroTimingEnabled = SubzeroTimingEnabled;
......@@ -269,6 +282,7 @@ int main(int argc, char **argv) {
Flags.TimingFocusOn = TimingFocusOn;
Flags.VerboseFocusOn = VerboseFocusOn;
Flags.TranslateOnly = TranslateOnly;
Flags.DisableIRGeneration = DisableIRGeneration;
Ice::GlobalContext Ctx(Ls, Os, VMask, TargetArch, OptLevel, TestPrefix,
Flags);
......
......@@ -79,8 +79,7 @@ def if_cond_flag(Value):
# shell conditional commands.
if_atts = [os.path.join(pydir, 'if.py')]
if_atts_cmd = if_atts + ['--have=' + att
for att in llvm2iceatts] + ['--command']
if_atts_cmd = if_atts + ['--have=' + att for att in llvm2iceatts]
ifl2i_atts_cmd = if_atts + [if_cond_flag('allow_llvm_ir' in llvm2iceatts),
'--command']
iflc2i_atts_cmd = if_atts + [if_cond_flag('allow_llvm_ir_as_input'
......
; Test if we can read alloca instructions.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
; Show examples where size is defined by a constant.
......@@ -159,3 +163,5 @@ entry:
; CHECK-NEXT: %array = alloca i8, i32 %n, align 16
; CHECK-NEXT: ret i32 %array
}
; NOIR: Total across all functions
......@@ -3,6 +3,10 @@
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %l2i -i %s --insts | %ifl FileCheck %s
; RUN: %lc2i -i %s --insts | %iflc FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
; TODO(kschimpf): add i8/i16. Needs bitcasts.
......@@ -965,3 +969,5 @@ entry:
; CHECK-NEXT: %lshr = lshr <4 x i32> %b, %a
; CHECK-NEXT: ret <4 x i32> %lshr
; CHECK-NEXT: }
; NOIR: Total across all functions
; Tests if we handle a branch instructions.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
define void @SimpleBranch() {
entry:
......@@ -43,3 +47,5 @@ b2:
; CHECK-NEXT: b2:
; CHECK-NEXT: br i1 %test, label %b2, label %b1
; CHECK-NEXT: }
; NOIR: Total across all functions
; Test parsing indirect calls in Subzero.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
define internal void @CallIndirectVoid(i32 %f_addr) {
entry:
......@@ -27,3 +31,5 @@ entry:
; CHECK-NEXT: %r = call i32 %f_addr(i8 1, i1 false)
; CHECK-NEXT: ret i32 %r
; CHECK-NEXT: }
; NOIR: Total across all functions
; Test handling of call instructions.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
define i32 @fib(i32 %n) {
entry:
......@@ -106,3 +110,4 @@ if.end: ; preds = %if.then, %entry
; CHECK-NEXT: ret void
; CHECK-NEXT: }
; NOIR: Total across all functions
; Tests if we can read cast operations.
; RUN: %p2i -i %s --insts --no-local-syms | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
; TODO(kschimpf) Find way to test pointer conversions (since they in general
; get removed by pnacl-freeze).
......@@ -532,3 +536,5 @@ define void @BitcastV16xi8(<16 x i8> %v) {
; CHECK-NEXT: %__3 = bitcast <16 x i8> %__0 to <8 x i16>
; CHECK-NEXT: ret void
; CHECK-NEXT: }
; NOIR: Total across all functions
; Test if we can read compare instructions.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
define i1 @IcmpI1(i32 %p1, i32 %p2) {
entry:
......@@ -469,3 +473,5 @@ entry:
; CHECK-NEXT: %vtrue = fcmp true <4 x float> %a1, %a2
; CHECK-NEXT: ret <4 x i1> %voeq
; CHECK-NEXT: }
; NOIR: Total across all functions
; Test handling of constants in function blocks.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
define void @TestIntegers() {
entry:
......@@ -152,3 +156,5 @@ entry:
ret void
; CHECK-NEXT: ret void
}
; NOIR: Total across all functions
; Test use forward type references in function blocks.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: llvm-as < %s | pnacl-freeze | pnacl-bcdis -no-records \
; RUN: | FileCheck --check-prefix=DUMP %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
define void @LoopCarriedDep() {
b0:
......@@ -116,3 +119,5 @@ b6:
; DUMP-NEXT: %b6:
; DUMP-NEXT: ret void; <@a3>
; DUMP-NEXT: }
; NOIR: Total across all functions
......@@ -3,6 +3,10 @@
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %l2i -i %s --insts | %ifl FileCheck %s
; RUN: %lc2i -i %s --insts | %iflc FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
@PrimitiveInit = internal global [4 x i8] c"\1B\00\00\00", align 4
; CHECK: @PrimitiveInit = internal global [4 x i8] c"\1B\00\00\00", align 4
......@@ -74,3 +78,5 @@ entry:
%result = sub i32 0, %size
ret i32 %result
}
; NOIR: Total across all functions
......@@ -3,6 +3,10 @@
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %l2i -i %s --insts | %ifl FileCheck %s
; RUN: %lc2i -i %s --insts | %iflc FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
@bytes = internal global [7 x i8] c"abcdefg"
; CHECK: @bytes = internal global [7 x i8] c"abcdefg"
......@@ -95,3 +99,4 @@ define void @func() {
; CHECK-NEXT: define void @func() {
; NOIR: Total across all functions
......@@ -3,6 +3,10 @@
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %l2i -i %s --insts | %ifl FileCheck %s
; RUN: %lc2i -i %s --insts | %iflc FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
define void @ExtractV4xi1(<4 x i1> %v) {
entry:
......@@ -377,3 +381,5 @@ entry:
; CHECK-NEXT: %r3 = insertelement <4 x float> %v, float %e, i32 3
; CHECK-NEXT: ret <4 x float> %r3
; CHECK-NEXT: }
; NOIR: Total across all functions
; Test if we can read load instructions.
; RUN: %p2i --no-local-syms -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
define i32 @load_i8(i32 %addr) {
entry:
......@@ -144,3 +148,4 @@ entry:
; CHECK-NEXT: ret <4 x float> %__1
}
; NOIR: Total across all functions
; Test parsing NaCl atomic instructions.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
declare i8 @llvm.nacl.atomic.load.i8(i8*, i32)
declare i16 @llvm.nacl.atomic.load.i16(i16*, i32)
......@@ -638,3 +642,4 @@ entry:
; CHECK-NEXT: ret i32 %r
; CHECK-NEXT: }
; NOIR: Total across all functions
; This tests parsing NaCl intrinsics not related to atomic operations.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
declare i8* @llvm.nacl.read.tp()
declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1)
......@@ -339,3 +343,4 @@ entry:
; CHECK-NEXT: ret void
; CHECK-NEXT: }
; NOIR: Total across all functions
; Test reading phi instructions.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
; TODO(kschimpf) Add forward reference examples.
......@@ -28,3 +32,4 @@ target:
; CHECK-NEXT: ret i32 %result
; CHECK-NEXT: }
; NOIR: Total across all functions
; Tests if we can read select instructions.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
define void @Seli1(i32 %p) {
entry:
......@@ -293,3 +297,5 @@ entry:
; CHECK-NEXT: %r = select <4 x i1> %pc, <4 x float> %pt, <4 x float> %pe
; CHECK-NEXT: ret <4 x float> %r
; CHECK-NEXT: }
; NOIR: Total across all functions
; Test if we can read store instructions.
; RUN: %p2i -i %s --insts --no-local-syms | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
define void @store_i8(i32 %addr) {
entry:
......@@ -133,3 +137,5 @@ define void @store_v4xFloat(i32 %addr, <4 x float> %v) {
; CHECK-NEXT: store <4 x float> %__1, <4 x float>* %__0, align 4
; CHECK-NEXT: ret void
}
; NOIR: Total across all functions
; Test switch instructions.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
define void @testDefaultSwitch(i32 %a) {
entry:
......@@ -490,3 +494,4 @@ exit:
; CHECK-NEXT: ret void
; CHECK-NEXT: }
; NOIR: Total across all functions
......@@ -12,6 +12,11 @@
; RUN: -default-function-prefix=h -default-global-prefix=g \
; RUN: | FileCheck --check-prefix=BAD %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
; TODO(kschimpf) Check global variable declarations, once generated.
@0 = internal global [4 x i8] zeroinitializer, align 4
......@@ -57,3 +62,5 @@ define void @h5() {
; BAD: Warning : Default global prefix 'g' potentially conflicts with name 'g'.
; BAD: Warning : Default function prefix 'h' potentially conflicts with name 'h5'.
; NOIR: Total across all functions
; Test parsing unreachable instruction.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %if --need=allow_disable_ir_gen --command \
; RUN: %p2i -i %s --args -notranslate -timing -no-ir-gen \
; RUN: | %if --need=allow_disable_ir_gen --command \
; RUN: FileCheck --check-prefix=NOIR %s
define internal i32 @divide(i32 %num, i32 %den) {
entry:
......@@ -25,3 +29,5 @@ return: ; preds = %entry
; CHECK-NEXT: %div = sdiv i32 %num, %den
; CHECK-NEXT: ret i32 %div
; CHECK-NEXT: }
; NOIR: Total across all functions
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