blob: 63ef745381eb61ec93b78b86d294e216d48c9f5e [file] [log] [blame] [edit]
//===- llvm/unittest/Bitcode/NaClParseInstsTest.cpp ----------------------===//
// Tests parser for PNaCl bitcode instructions.
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Tests record errors in the function block when parsing PNaCl bitcode.
// TODO(kschimpf) Add more tests.
#include "NaClMungeTest.h"
#include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h"
using namespace llvm;
namespace naclmungetest {
// Note: alignment stored as 0 or log2(Alignment)+1.
uint64_t getEncAlignPower(unsigned Power) {
return Power + 1;
}
uint64_t getEncAlignZero() { return 0; }
/// Test how we report a call arg that refers to nonexistent call argument
TEST(NaClParseInstsTest, NonexistantCallArg) {
const uint64_t BitcodeRecords[] = {
1, naclbitc::BLK_CODE_ENTER, naclbitc::MODULE_BLOCK_ID, 2, Terminator,
1, naclbitc::BLK_CODE_ENTER, naclbitc::TYPE_BLOCK_ID_NEW, 2, Terminator,
3, naclbitc::TYPE_CODE_NUMENTRY, 3, Terminator,
3, naclbitc::TYPE_CODE_INTEGER, 32, Terminator,
3, naclbitc::TYPE_CODE_VOID, Terminator,
3, naclbitc::TYPE_CODE_FUNCTION, 0, 1, 0, 0, Terminator,
0, naclbitc::BLK_CODE_EXIT, Terminator,
3, naclbitc::MODULE_CODE_FUNCTION, 2, 0, 1, 0, Terminator,
3, naclbitc::MODULE_CODE_FUNCTION, 2, 0, 0, 0, Terminator,
1, naclbitc::BLK_CODE_ENTER, naclbitc::FUNCTION_BLOCK_ID, 2, Terminator,
3, naclbitc::FUNC_CODE_DECLAREBLOCKS, 1, Terminator,
// Note: 100 is a bad value index in next line.
3, naclbitc::FUNC_CODE_INST_CALL, 0, 4, 2, 100, Terminator,
3, naclbitc::FUNC_CODE_INST_RET, Terminator,
0, naclbitc::BLK_CODE_EXIT, Terminator,
0, naclbitc::BLK_CODE_EXIT, Terminator
};
// Show text of base input.
NaClObjDumpMunger DumpMunger(ARRAY_TERM(BitcodeRecords));
EXPECT_FALSE(DumpMunger.runTest());
EXPECT_EQ(
" 0:0|<65532, 80, 69, 88, 69, 1, 0,|Magic Number: 'PEXE' (80, 69, "
"88, 69)\n"
" | 8, 0, 17, 0, 4, 0, 2, 0, 0, |PNaCl Version: 2\n"
" | 0> |\n"
" 16:0|1: <65535, 8, 2> |module { // BlockID = 8\n"
" 24:0| 1: <65535, 17, 2> | types { // BlockID = 17\n"
" 32:0| 3: <1, 3> | count 3;\n"
" 34:4| 3: <7, 32> | @t0 = i32;\n"
" 37:6| 3: <2> | @t1 = void;\n"
" 39:4| 3: <21, 0, 1, 0, 0> | @t2 = void (i32, i32);\n"
" 44:2| 0: <65534> | }\n"
" 48:0| 3: <8, 2, 0, 1, 0> | declare external void @f0(i32"
", i32);\n"
" 52:6| 3: <8, 2, 0, 0, 0> | define external void @f1(i32,"
" i32);\n"
" 57:4| 1: <65535, 12, 2> | function void @f1(i32 %p0, "
"i32 %p1) {\n"
" | | // BlockID "
"= 12\n"
" 64:0| 3: <1, 1> | blocks 1;\n"
" | | %b0:\n"
" 66:4| 3: <34, 0, 4, 2, 100> | call void @f0(i32 %p0, i32"
" @f0);\n"
"Error(66:4): Invalid relative value id: 100 (Must be <= 4)\n"
" 72:6| 3: <10> | ret void;\n"
" 74:4| 0: <65534> | }\n"
" 76:0|0: <65534> |}\n",
DumpMunger.getTestResults());
NaClParseBitcodeMunger Munger(ARRAY_TERM(BitcodeRecords));
EXPECT_FALSE(Munger.runTest(true));
EXPECT_EQ(
"Error(72:6): Invalid call argument: Index 1\n"
"Error: Invalid value in record\n",
Munger.getTestResults());
}
/// Test how we recognize alignments in alloca instructions.
TEST(NaClParseInstsTests, BadAllocaAlignment) {
const uint64_t BitcodeRecords[] = {
1, naclbitc::BLK_CODE_ENTER, naclbitc::MODULE_BLOCK_ID, 2, Terminator,
1, naclbitc::BLK_CODE_ENTER, naclbitc::TYPE_BLOCK_ID_NEW, 2, Terminator,
3, naclbitc::TYPE_CODE_NUMENTRY, 4, Terminator,
3, naclbitc::TYPE_CODE_INTEGER, 32, Terminator,
3, naclbitc::TYPE_CODE_VOID, Terminator,
3, naclbitc::TYPE_CODE_FUNCTION, 0, 1, 0, Terminator,
3, naclbitc::TYPE_CODE_INTEGER, 8, Terminator,
0, naclbitc::BLK_CODE_EXIT, Terminator,
3, naclbitc::MODULE_CODE_FUNCTION, 2, 0, 0, 0, Terminator,
1, naclbitc::BLK_CODE_ENTER, naclbitc::FUNCTION_BLOCK_ID, 2, Terminator,
3, naclbitc::FUNC_CODE_DECLAREBLOCKS, 1, Terminator,
3, naclbitc::FUNC_CODE_INST_ALLOCA, 1, getEncAlignPower(0), Terminator,
3, naclbitc::FUNC_CODE_INST_RET, Terminator,
0, naclbitc::BLK_CODE_EXIT, Terminator,
0, naclbitc::BLK_CODE_EXIT, Terminator
};
const uint64_t ReplaceIndex = 11; // index for FUNC_CODE_INST_ALLOCA
// Show text when alignment is 1.
NaClObjDumpMunger DumpMunger(ARRAY_TERM(BitcodeRecords));
EXPECT_TRUE(DumpMunger.runTest());
EXPECT_EQ(
" 0:0|<65532, 80, 69, 88, 69, 1, 0,|Magic Number: 'PEXE' (80, 69, "
"88, 69)\n"
" | 8, 0, 17, 0, 4, 0, 2, 0, 0, |PNaCl Version: 2\n"
" | 0> |\n"
" 16:0|1: <65535, 8, 2> |module { // BlockID = 8\n"
" 24:0| 1: <65535, 17, 2> | types { // BlockID = 17\n"
" 32:0| 3: <1, 4> | count 4;\n"
" 34:4| 3: <7, 32> | @t0 = i32;\n"
" 37:6| 3: <2> | @t1 = void;\n"
" 39:4| 3: <21, 0, 1, 0> | @t2 = void (i32);\n"
" 43:4| 3: <7, 8> | @t3 = i8;\n"
" 46:0| 0: <65534> | }\n"
" 48:0| 3: <8, 2, 0, 0, 0> | define external void @f0(i32"
");\n"
" 52:6| 1: <65535, 12, 2> | function void @f0(i32 %p0) {"
" \n"
" | | // BlockID "
"= 12\n"
" 60:0| 3: <1, 1> | blocks 1;\n"
" | | %b0:\n"
" 62:4| 3: <19, 1, 1> | %v0 = alloca i8, i32 %p0, "
"align 1;\n"
" 65:6| 3: <10> | ret void;\n"
" 67:4| 0: <65534> | }\n"
" 68:0|0: <65534> |}\n",
DumpMunger.getTestResults());
NaClParseBitcodeMunger Munger(ARRAY_TERM(BitcodeRecords));
EXPECT_TRUE(Munger.runTest(true));
// Show what happens when changing alignment to 0.
const uint64_t Align0[] = {
ReplaceIndex, NaClMungedBitcode::Replace,
3, naclbitc::FUNC_CODE_INST_ALLOCA, 1, getEncAlignZero(), Terminator,
};
EXPECT_TRUE(Munger.runTest(ARRAY(Align0), true));
EXPECT_TRUE(DumpMunger.runTestForAssembly(ARRAY(Align0)));
EXPECT_EQ(
" %v0 = alloca i8, i32 %p0, align 0;\n",
DumpMunger.getLinesWithSubstring("alloca"));
// Show what happens when changing alignment to 2**30.
const uint64_t Align30[] = {
ReplaceIndex, NaClMungedBitcode::Replace,
3, naclbitc::FUNC_CODE_INST_ALLOCA, 1, getEncAlignPower(30), Terminator,
};
EXPECT_FALSE(Munger.runTest(ARRAY(Align30), true));
EXPECT_EQ(
"Error(65:6): Alignment can't be greater than 2**29. Found: 2**30\n"
"Error: Invalid value in record\n",
Munger.getTestResults());
EXPECT_FALSE(DumpMunger.runTestForAssembly(ARRAY(Align30)));
EXPECT_EQ(
" %v0 = alloca i8, i32 %p0, align 0;\n",
DumpMunger.getLinesWithSubstring("alloca"));
EXPECT_EQ(
"Error(62:4): Alignment can't be greater than 2**29. Found: 2**30\n",
DumpMunger.getLinesWithSubstring("Error"));
// Show what happens when changing alignment to 2**29.
const uint64_t Align29[] = {
ReplaceIndex, NaClMungedBitcode::Replace,
3, naclbitc::FUNC_CODE_INST_ALLOCA, 1, getEncAlignPower(29), Terminator,
};
EXPECT_TRUE(Munger.runTest(ARRAY(Align29), true));
EXPECT_EQ(
"Successful parse!\n",
Munger.getTestResults());
EXPECT_TRUE(DumpMunger.runTestForAssembly(ARRAY(Align29)));
EXPECT_EQ(
" %v0 = alloca i8, i32 %p0, align 536870912;\n",
DumpMunger.getLinesWithSubstring("alloca"));
}
// Test how we recognize alignments in load instructions.
TEST(NaClParseInstsTests, BadLoadAlignment) {
const uint64_t BitcodeRecords[] = {
1, naclbitc::BLK_CODE_ENTER, naclbitc::MODULE_BLOCK_ID, 2, Terminator,
1, naclbitc::BLK_CODE_ENTER, naclbitc::TYPE_BLOCK_ID_NEW, 2, Terminator,
3, naclbitc::TYPE_CODE_NUMENTRY, 2, Terminator,
3, naclbitc::TYPE_CODE_INTEGER, 32, Terminator,
3, naclbitc::TYPE_CODE_FUNCTION, 0, 0, 0, Terminator,
0, naclbitc::BLK_CODE_EXIT, Terminator,
3, naclbitc::MODULE_CODE_FUNCTION, 1, 0, 0, 0, Terminator,
1, naclbitc::BLK_CODE_ENTER, naclbitc::FUNCTION_BLOCK_ID, 2, Terminator,
3, naclbitc::FUNC_CODE_DECLAREBLOCKS, 1, Terminator,
3, naclbitc::FUNC_CODE_INST_LOAD, 1, getEncAlignPower(0), 0, Terminator,
3, naclbitc::FUNC_CODE_INST_RET, 1, Terminator,
0, naclbitc::BLK_CODE_EXIT, Terminator,
0, naclbitc::BLK_CODE_EXIT, Terminator
};
const uint64_t ReplaceIndex = 9; // index for FUNC_CODE_INST_LOAD
// Show text when alignment is 1.
NaClObjDumpMunger DumpMunger(ARRAY_TERM(BitcodeRecords));
EXPECT_TRUE(DumpMunger.runTest());
EXPECT_EQ(
" 0:0|<65532, 80, 69, 88, 69, 1, 0,|Magic Number: 'PEXE' (80, 69, "
"88, 69)\n"
" | 8, 0, 17, 0, 4, 0, 2, 0, 0, |PNaCl Version: 2\n"
" | 0> |\n"
" 16:0|1: <65535, 8, 2> |module { // BlockID = 8\n"
" 24:0| 1: <65535, 17, 2> | types { // BlockID = 17\n"
" 32:0| 3: <1, 2> | count 2;\n"
" 34:4| 3: <7, 32> | @t0 = i32;\n"
" 37:6| 3: <21, 0, 0, 0> | @t1 = i32 (i32);\n"
" 41:6| 0: <65534> | }\n"
" 44:0| 3: <8, 1, 0, 0, 0> | define external i32 @f0(i32"
");\n"
" 48:6| 1: <65535, 12, 2> | function i32 @f0(i32 %p0) {"
" \n"
" | | // BlockID "
"= 12\n"
" 56:0| 3: <1, 1> | blocks 1;\n"
" | | %b0:\n"
" 58:4| 3: <20, 1, 1, 0> | %v0 = load i32* %p0, "
"align 1;\n"
" 62:4| 3: <10, 1> | ret i32 %v0;\n"
" 65:0| 0: <65534> | }\n"
" 68:0|0: <65534> |}\n",
DumpMunger.getTestResults());
NaClParseBitcodeMunger Munger(ARRAY_TERM(BitcodeRecords));
EXPECT_TRUE(Munger.runTest(true));
// Show what happens when changing alignment to 0.
const uint64_t Align0[] = {
ReplaceIndex, NaClMungedBitcode::Replace,
3, naclbitc::FUNC_CODE_INST_LOAD, 1, getEncAlignZero(), 0, Terminator,
};
// Note: Correct alignment is not checked by Munger (i.e. the PNaCl
// bitcode reader). It is checked later by the PNaCl ABI checker in
// pnacl-llc. On the other hand, the DumpMunger checks alignment for
// loads while parsing.
EXPECT_TRUE(Munger.runTest(ARRAY(Align0), true));
EXPECT_FALSE(DumpMunger.runTestForAssembly(ARRAY(Align0)));
EXPECT_EQ(
" %v0 = load i32* %p0, align 0;\n"
"Error(58:4): load: Illegal alignment for i32. Expects: 1\n",
DumpMunger.getLinesWithSubstring("load"));
// Show what happens when changing alignment to 4.
const uint64_t Align4[] = {
ReplaceIndex, NaClMungedBitcode::Replace,
3, naclbitc::FUNC_CODE_INST_LOAD, 1, getEncAlignPower(2), 0, Terminator,
};
EXPECT_TRUE(Munger.runTest(ARRAY(Align4), true));
EXPECT_FALSE(DumpMunger.runTestForAssembly(ARRAY(Align4)));
EXPECT_EQ(
" %v0 = load i32* %p0, align 4;\n"
"Error(58:4): load: Illegal alignment for i32. Expects: 1\n",
DumpMunger.getLinesWithSubstring("load"));
// Show what happens when changing alignment to 2**29.
const uint64_t Align29[] = {
ReplaceIndex, NaClMungedBitcode::Replace,
3, naclbitc::FUNC_CODE_INST_LOAD, 1, getEncAlignPower(29), 0, Terminator,
};
EXPECT_TRUE(Munger.runTest(ARRAY(Align29), true));
EXPECT_FALSE(DumpMunger.runTestForAssembly(ARRAY(Align29)));
EXPECT_EQ(
" %v0 = load i32* %p0, align 536870912;\n"
"Error(58:4): load: Illegal alignment for i32. Expects: 1\n",
DumpMunger.getLinesWithSubstring("load"));
// Show what happens when changing alignment to 2**30.
const uint64_t Align30[] = {
ReplaceIndex, NaClMungedBitcode::Replace,
3, naclbitc::FUNC_CODE_INST_LOAD, 1, getEncAlignPower(30), 0, Terminator,
};
EXPECT_FALSE(Munger.runTest(ARRAY(Align30), true));
EXPECT_EQ(
"Error(62:4): Alignment can't be greater than 2**29. Found: 2**30\n"
"Error: Invalid value in record\n",
Munger.getTestResults());
EXPECT_FALSE(DumpMunger.runTestForAssembly(ARRAY(Align30)));
EXPECT_EQ(
" %v0 = load i32* %p0, align 0;\n"
"Error(58:4): load: Illegal alignment for i32. Expects: 1\n",
DumpMunger.getLinesWithSubstring("load"));
}
// Test how we recognize alignments in store instructions.
TEST(NaClParseInstsTests, BadStoreAlignment) {
const uint64_t BitcodeRecords[] = {
1, naclbitc::BLK_CODE_ENTER, naclbitc::MODULE_BLOCK_ID, 2, Terminator,
1, naclbitc::BLK_CODE_ENTER, naclbitc::TYPE_BLOCK_ID_NEW, 2, Terminator,
3, naclbitc::TYPE_CODE_NUMENTRY, 3, Terminator,
3, naclbitc::TYPE_CODE_FLOAT, Terminator,
3, naclbitc::TYPE_CODE_INTEGER, 32, Terminator,
3, naclbitc::TYPE_CODE_FUNCTION, 0, 0, 1, 0, Terminator,
0, naclbitc::BLK_CODE_EXIT, Terminator,
3, naclbitc::MODULE_CODE_FUNCTION, 2, 0, 0, 0, Terminator,
1, naclbitc::BLK_CODE_ENTER, naclbitc::FUNCTION_BLOCK_ID, 2, Terminator,
3, naclbitc::FUNC_CODE_DECLAREBLOCKS, 1, Terminator,
3, naclbitc::FUNC_CODE_INST_STORE, 2, 1, getEncAlignPower(0), Terminator,
3, naclbitc::FUNC_CODE_INST_RET, 1, Terminator,
0, naclbitc::BLK_CODE_EXIT, Terminator,
0, naclbitc::BLK_CODE_EXIT, Terminator
};
const uint64_t ReplaceIndex = 10; // index for FUNC_CODE_INST_STORE
// Show text when alignment is 1.
NaClObjDumpMunger DumpMunger(ARRAY_TERM(BitcodeRecords));
EXPECT_TRUE(DumpMunger.runTest());
EXPECT_EQ(
" 0:0|<65532, 80, 69, 88, 69, 1, 0,|Magic Number: 'PEXE' (80, 69, "
"88, 69)\n"
" | 8, 0, 17, 0, 4, 0, 2, 0, 0, |PNaCl Version: 2\n"
" | 0> |\n"
" 16:0|1: <65535, 8, 2> |module { // BlockID = 8\n"
" 24:0| 1: <65535, 17, 2> | types { // BlockID = 17\n"
" 32:0| 3: <1, 3> | count 3;\n"
" 34:4| 3: <3> | @t0 = float;\n"
" 36:2| 3: <7, 32> | @t1 = i32;\n"
" 39:4| 3: <21, 0, 0, 1, 0> | @t2 = float (i32, float);\n"
" 44:2| 0: <65534> | }\n"
" 48:0| 3: <8, 2, 0, 0, 0> | define external \n"
" | | float @f0(i32, float);\n"
" 52:6| 1: <65535, 12, 2> | function \n"
" | | float @f0(i32 %p0, float "
"%p1) { \n"
" | | // BlockID "
"= 12\n"
" 60:0| 3: <1, 1> | blocks 1;\n"
" | | %b0:\n"
" 62:4| 3: <24, 2, 1, 1> | store float %p1, float* "
"%p0, \n"
" | | align 1;\n"
" 66:4| 3: <10, 1> | ret float %p1;\n"
" 69:0| 0: <65534> | }\n"
" 72:0|0: <65534> |}\n",
DumpMunger.getTestResults());
NaClParseBitcodeMunger Munger(ARRAY_TERM(BitcodeRecords));
EXPECT_TRUE(Munger.runTest(true));
// Show what happens when changing alignment to 0.
const uint64_t Align0[] = {
ReplaceIndex, NaClMungedBitcode::Replace,
3, naclbitc::FUNC_CODE_INST_STORE, 2, 1, getEncAlignZero(), Terminator,
};
// Note: Correct alignment is not checked by Munger (i.e. the PNaCl
// bitcode reader). It is checked later by the PNaCl ABI checker in
// pnacl-llc. On the other hand, the DumpMunger checks alignment for
// stores while parsing.
EXPECT_TRUE(Munger.runTest(ARRAY(Align0), true));
EXPECT_FALSE(DumpMunger.runTestForAssembly(ARRAY(Align0)));
EXPECT_EQ(
" store float %p1, float* %p0, align 0;\n"
"Error(62:4): store: Illegal alignment for float. Expects: 1 or 4\n",
DumpMunger.getLinesWithSubstring("store"));
// Show what happens when changing alignment to 4.
const uint64_t Align4[] = {
ReplaceIndex, NaClMungedBitcode::Replace,
3, naclbitc::FUNC_CODE_INST_STORE, 2, 1, getEncAlignPower(2), Terminator,
};
EXPECT_TRUE(Munger.runTest(ARRAY(Align4), true));
EXPECT_TRUE(DumpMunger.runTestForAssembly(ARRAY(Align4)));
// Show what happens when changing alignment to 8.
const uint64_t Align8[] = {
ReplaceIndex, NaClMungedBitcode::Replace,
3, naclbitc::FUNC_CODE_INST_STORE, 2, 1, getEncAlignPower(3), Terminator,
};
EXPECT_TRUE(Munger.runTest(ARRAY(Align8), true));
EXPECT_FALSE(DumpMunger.runTestForAssembly(ARRAY(Align8)));
EXPECT_EQ(
" store float %p1, float* %p0, align 8;\n"
"Error(62:4): store: Illegal alignment for float. Expects: 1 or 4\n",
DumpMunger.getLinesWithSubstring("store"));
// Show what happens when changing alignment to 2**29.
const uint64_t Align29[] = {
ReplaceIndex, NaClMungedBitcode::Replace,
3, naclbitc::FUNC_CODE_INST_STORE, 2, 1, getEncAlignPower(29), Terminator,
};
EXPECT_TRUE(Munger.runTest(ARRAY(Align29), true));
EXPECT_FALSE(DumpMunger.runTestForAssembly(ARRAY(Align29)));
EXPECT_EQ(
" store float %p1, float* %p0, align 536870912;\n"
"Error(62:4): store: Illegal alignment for float. Expects: 1 or 4\n",
DumpMunger.getLinesWithSubstring("store"));
// Show what happens when changing alignment to 2**30.
const uint64_t Align30[] = {
ReplaceIndex, NaClMungedBitcode::Replace,
3, naclbitc::FUNC_CODE_INST_STORE, 2, 1, getEncAlignPower(30), Terminator,
};
EXPECT_FALSE(Munger.runTest(ARRAY(Align30), true));
EXPECT_EQ(
"Error(66:4): Alignment can't be greater than 2**29. Found: 2**30\n"
"Error: Invalid value in record\n",
Munger.getTestResults());
EXPECT_FALSE(DumpMunger.runTestForAssembly(ARRAY(Align30)));
EXPECT_EQ(
" store float %p1, float* %p0, align 0;\n"
"Error(62:4): store: Illegal alignment for float. Expects: 1 or 4\n",
DumpMunger.getLinesWithSubstring("store"));
}
} // end of namespace naclmungetest