Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 //===- subzero/src/PNaClTranslator.cpp - ICE from bitcode -----------------===// | 1 //===- subzero/src/PNaClTranslator.cpp - ICE from bitcode -----------------===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| (...skipping 1296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1307 return nullptr; | 1307 return nullptr; |
| 1308 std::string Buffer; | 1308 std::string Buffer; |
| 1309 raw_string_ostream StrBuf(Buffer); | 1309 raw_string_ostream StrBuf(Buffer); |
| 1310 StrBuf << "Value index " << Index << " not defined!"; | 1310 StrBuf << "Value index " << Index << " not defined!"; |
| 1311 Fatal(StrBuf.str()); | 1311 Fatal(StrBuf.str()); |
| 1312 } | 1312 } |
| 1313 return Op; | 1313 return Op; |
| 1314 } | 1314 } |
| 1315 | 1315 |
| 1316 private: | 1316 private: |
| 1317 typedef std::unordered_map<NaClBcIndexSize_t, Ice::Operand *> OperandMap; | |
| 1318 | |
| 1319 Ice::TimerMarker Timer; | 1317 Ice::TimerMarker Timer; |
| 1320 // The number of words in the bitstream defining the function block. | 1318 // The number of words in the bitstream defining the function block. |
| 1321 uint64_t NumBytesDefiningFunction = 0; | 1319 uint64_t NumBytesDefiningFunction = 0; |
| 1320 // Maximum number of records that can appear in the function block, based on | |
| 1321 // the number of bytes defining the function block. | |
| 1322 uint64_t MaxRecordsInBlock = 0; | |
| 1322 // The corresponding ICE function defined by the function block. | 1323 // The corresponding ICE function defined by the function block. |
| 1323 std::unique_ptr<Ice::Cfg> Func; | 1324 std::unique_ptr<Ice::Cfg> Func; |
| 1324 // The index to the current basic block being built. | 1325 // The index to the current basic block being built. |
| 1325 NaClBcIndexSize_t CurrentBbIndex = 0; | 1326 NaClBcIndexSize_t CurrentBbIndex = 0; |
| 1326 // The number of basic blocks declared for the function block. | 1327 // The number of basic blocks declared for the function block. |
| 1327 NaClBcIndexSize_t DeclaredNumberBbs = 0; | 1328 NaClBcIndexSize_t DeclaredNumberBbs = 0; |
| 1328 // The basic block being built. | 1329 // The basic block being built. |
| 1329 Ice::CfgNode *CurrentNode = nullptr; | 1330 Ice::CfgNode *CurrentNode = nullptr; |
| 1330 // The ID for the function. | 1331 // The ID for the function. |
| 1331 NaClBcIndexSize_t FcnId; | 1332 NaClBcIndexSize_t FcnId; |
| 1332 // The corresponding function declaration. | 1333 // The corresponding function declaration. |
| 1333 Ice::FunctionDeclaration *FuncDecl; | 1334 Ice::FunctionDeclaration *FuncDecl; |
| 1334 // Holds the dividing point between local and global absolute value indices. | 1335 // Holds the dividing point between local and global absolute value indices. |
| 1335 size_t CachedNumGlobalValueIDs; | 1336 size_t CachedNumGlobalValueIDs; |
| 1336 // Holds operands local to the function block, based on indices | 1337 // Holds operands local to the function block, based on indices |
| 1337 // defined in the bitcode file. | 1338 // defined in the bitcode file. |
| 1338 OperandMap LocalOperands; | 1339 std::vector<Ice::Operand *> LocalOperands; |
|
Jim Stichnoth
2015/08/17 19:41:03
It occurs to me that using STL containers with the
Karl
2015/08/17 19:47:34
Acknowledged.
| |
| 1339 // Holds the index within LocalOperands corresponding to the next | 1340 // Holds the index within LocalOperands corresponding to the next |
| 1340 // instruction that generates a value. | 1341 // instruction that generates a value. |
| 1341 NaClBcIndexSize_t NextLocalInstIndex; | 1342 NaClBcIndexSize_t NextLocalInstIndex; |
| 1342 // True if the last processed instruction was a terminating | 1343 // True if the last processed instruction was a terminating |
| 1343 // instruction. | 1344 // instruction. |
| 1344 bool InstIsTerminating = false; | 1345 bool InstIsTerminating = false; |
| 1345 // Upper limit of alignment power allowed by LLVM | 1346 // Upper limit of alignment power allowed by LLVM |
| 1346 static const uint32_t AlignPowerLimit = 29; | 1347 static const uint32_t AlignPowerLimit = 29; |
| 1347 | 1348 |
| 1348 // Extracts the corresponding Alignment to use, given the AlignPower | 1349 // Extracts the corresponding Alignment to use, given the AlignPower |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1363 Alignment = 1; | 1364 Alignment = 1; |
| 1364 } | 1365 } |
| 1365 | 1366 |
| 1366 bool ParseBlock(unsigned BlockID) override; | 1367 bool ParseBlock(unsigned BlockID) override; |
| 1367 | 1368 |
| 1368 void ProcessRecord() override; | 1369 void ProcessRecord() override; |
| 1369 | 1370 |
| 1370 void EnterBlock(unsigned NumWords) final { | 1371 void EnterBlock(unsigned NumWords) final { |
| 1371 // Note: Bitstream defines words as 32-bit values. | 1372 // Note: Bitstream defines words as 32-bit values. |
| 1372 NumBytesDefiningFunction = NumWords * sizeof(uint32_t); | 1373 NumBytesDefiningFunction = NumWords * sizeof(uint32_t); |
| 1374 // We know that all records are minimally defined by a two-bit abreviation. | |
| 1375 MaxRecordsInBlock = NumBytesDefiningFunction * (CHAR_BIT >> 1); | |
| 1373 } | 1376 } |
| 1374 | 1377 |
| 1375 void ExitBlock() override; | 1378 void ExitBlock() override; |
| 1376 | 1379 |
| 1377 bool verifyAllForwardRefsDefined(); | |
| 1378 | |
| 1379 // Creates and appends a new basic block to the list of basic blocks. | 1380 // Creates and appends a new basic block to the list of basic blocks. |
| 1380 Ice::CfgNode *installNextBasicBlock() { | 1381 Ice::CfgNode *installNextBasicBlock() { |
| 1381 assert(!isIRGenerationDisabled()); | 1382 assert(!isIRGenerationDisabled()); |
| 1382 Ice::CfgNode *Node = Func->makeNode(); | 1383 Ice::CfgNode *Node = Func->makeNode(); |
| 1383 return Node; | 1384 return Node; |
| 1384 } | 1385 } |
| 1385 | 1386 |
| 1386 // Returns the Index-th basic block in the list of basic blocks. | 1387 // Returns the Index-th basic block in the list of basic blocks. |
| 1387 Ice::CfgNode *getBasicBlock(NaClBcIndexSize_t Index) { | 1388 Ice::CfgNode *getBasicBlock(NaClBcIndexSize_t Index) { |
| 1388 assert(!isIRGenerationDisabled()); | 1389 assert(!isIRGenerationDisabled()); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1462 return 0; | 1463 return 0; |
| 1463 } | 1464 } |
| 1464 return BaseIndex - Id; | 1465 return BaseIndex - Id; |
| 1465 } | 1466 } |
| 1466 | 1467 |
| 1467 // Sets element Index (in the local operands list) to Op. | 1468 // Sets element Index (in the local operands list) to Op. |
| 1468 void setOperand(NaClBcIndexSize_t Index, Ice::Operand *Op) { | 1469 void setOperand(NaClBcIndexSize_t Index, Ice::Operand *Op) { |
| 1469 assert(Op || isIRGenerationDisabled()); | 1470 assert(Op || isIRGenerationDisabled()); |
| 1470 // Check if simple push works. | 1471 // Check if simple push works. |
| 1471 NaClBcIndexSize_t LocalIndex = Index - CachedNumGlobalValueIDs; | 1472 NaClBcIndexSize_t LocalIndex = Index - CachedNumGlobalValueIDs; |
| 1472 | 1473 if (LocalIndex == LocalOperands.size()) { |
| 1473 // If element not defined, set it. | 1474 LocalOperands.push_back(Op); |
| 1474 Ice::Operand *&IndexedOp = LocalOperands[LocalIndex]; | |
| 1475 if (IndexedOp == nullptr) { | |
| 1476 IndexedOp = Op; | |
| 1477 return; | 1475 return; |
| 1478 } | 1476 } |
| 1479 | 1477 |
| 1480 // See if forward reference matchers. | 1478 // Must be forward reference, expand vector to accommodate. |
| 1481 if (IndexedOp == Op) | 1479 if (LocalIndex >= LocalOperands.size()) { |
| 1480 if (LocalIndex > MaxRecordsInBlock) { | |
| 1481 std::string Buffer; | |
| 1482 raw_string_ostream StrBuf(Buffer); | |
| 1483 StrBuf << "Forward reference @" << Index << " too big. Have " | |
| 1484 << CachedNumGlobalValueIDs << " globals and function contains " | |
| 1485 << NumBytesDefiningFunction << " bytes"; | |
| 1486 Fatal(StrBuf.str()); | |
| 1487 // Recover by using index one beyond the maximal allowed. | |
| 1488 LocalIndex = MaxRecordsInBlock; | |
| 1489 } | |
| 1490 LocalOperands.resize(LocalIndex + 1); | |
| 1491 } | |
| 1492 | |
| 1493 // If element not defined, set it. | |
| 1494 Ice::Operand *OldOp = LocalOperands[LocalIndex]; | |
| 1495 if (OldOp == nullptr) { | |
| 1496 LocalOperands[LocalIndex] = Op; | |
| 1497 return; | |
| 1498 } | |
| 1499 | |
| 1500 // See if forward reference matches. | |
| 1501 if (OldOp == Op) | |
| 1482 return; | 1502 return; |
| 1483 | 1503 |
| 1484 // Error has occurred. | 1504 // Error has occurred. |
| 1485 std::string Buffer; | 1505 std::string Buffer; |
| 1486 raw_string_ostream StrBuf(Buffer); | 1506 raw_string_ostream StrBuf(Buffer); |
| 1487 StrBuf << "Multiple definitions for index " << Index << ": " << *Op | 1507 StrBuf << "Multiple definitions for index " << Index << ": " << *Op |
| 1488 << " and " << *IndexedOp; | 1508 << " and " << *OldOp; |
| 1489 Error(StrBuf.str()); | 1509 Error(StrBuf.str()); |
| 1490 IndexedOp = Op; | 1510 LocalOperands[LocalIndex] = Op; |
| 1491 } | 1511 } |
| 1492 | 1512 |
| 1493 // Returns the relative operand (wrt to BaseIndex) referenced by | 1513 // Returns the relative operand (wrt to BaseIndex) referenced by |
| 1494 // the given value Index. | 1514 // the given value Index. |
| 1495 Ice::Operand *getRelativeOperand(NaClBcIndexSize_t Index, | 1515 Ice::Operand *getRelativeOperand(NaClBcIndexSize_t Index, |
| 1496 NaClBcIndexSize_t BaseIndex) { | 1516 NaClBcIndexSize_t BaseIndex) { |
| 1497 return getOperand(convertRelativeToAbsIndex(Index, BaseIndex)); | 1517 return getOperand(convertRelativeToAbsIndex(Index, BaseIndex)); |
| 1498 } | 1518 } |
| 1499 | 1519 |
| 1500 // Returns the absolute index of the next value generating instruction. | 1520 // Returns the absolute index of the next value generating instruction. |
| (...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1981 void appendErrorInstruction(Ice::Type Ty) { | 2001 void appendErrorInstruction(Ice::Type Ty) { |
| 1982 // Note: we don't worry about downstream translation errors because | 2002 // Note: we don't worry about downstream translation errors because |
| 1983 // the function will not be translated if any errors occur. | 2003 // the function will not be translated if any errors occur. |
| 1984 if (Ty == Ice::IceType_void) | 2004 if (Ty == Ice::IceType_void) |
| 1985 return; | 2005 return; |
| 1986 Ice::Variable *Var = getNextInstVar(Ty); | 2006 Ice::Variable *Var = getNextInstVar(Ty); |
| 1987 CurrentNode->appendInst(Ice::InstAssign::create(Func.get(), Var, Var)); | 2007 CurrentNode->appendInst(Ice::InstAssign::create(Func.get(), Var, Var)); |
| 1988 } | 2008 } |
| 1989 }; | 2009 }; |
| 1990 | 2010 |
| 1991 bool FunctionParser::verifyAllForwardRefsDefined() { | |
| 1992 NaClBcIndexSize_t NumInstructions = | |
| 1993 NextLocalInstIndex - CachedNumGlobalValueIDs; | |
| 1994 if (NumInstructions == LocalOperands.size()) | |
| 1995 return true; | |
| 1996 // Find undefined forward references and report. | |
| 1997 std::vector<NaClBcIndexSize_t> UndefinedFwdRefs; | |
| 1998 for (const OperandMap::value_type &Elmt : LocalOperands) | |
| 1999 if (Elmt.first >= NextLocalInstIndex) | |
| 2000 UndefinedFwdRefs.push_back(Elmt.first); | |
| 2001 std::sort(UndefinedFwdRefs.begin(), UndefinedFwdRefs.end()); | |
| 2002 for (const NaClBcIndexSize_t Index : UndefinedFwdRefs) { | |
| 2003 std::string Buffer; | |
| 2004 raw_string_ostream StrBuf(Buffer); | |
| 2005 StrBuf << "Instruction forward reference not defined: " << Index; | |
| 2006 Error(StrBuf.str()); | |
| 2007 } | |
| 2008 return false; | |
| 2009 } | |
| 2010 | |
| 2011 void FunctionParser::ExitBlock() { | 2011 void FunctionParser::ExitBlock() { |
| 2012 // Check if the last instruction in the function was terminating. | 2012 // Check if the last instruction in the function was terminating. |
| 2013 if (!InstIsTerminating) { | 2013 if (!InstIsTerminating) { |
| 2014 Error("Last instruction in function not terminator"); | 2014 Error("Last instruction in function not terminator"); |
| 2015 if (isIRGenerationDisabled()) | 2015 if (isIRGenerationDisabled()) |
| 2016 return; | 2016 return; |
| 2017 // Recover by inserting an unreachable instruction. | 2017 // Recover by inserting an unreachable instruction. |
| 2018 CurrentNode->appendInst(Ice::InstUnreachable::create(Func.get())); | 2018 CurrentNode->appendInst(Ice::InstUnreachable::create(Func.get())); |
| 2019 } | 2019 } |
| 2020 ++CurrentBbIndex; | 2020 ++CurrentBbIndex; |
| 2021 if (CurrentBbIndex != DeclaredNumberBbs) { | 2021 if (CurrentBbIndex != DeclaredNumberBbs) { |
| 2022 std::string Buffer; | 2022 std::string Buffer; |
| 2023 raw_string_ostream StrBuf(Buffer); | 2023 raw_string_ostream StrBuf(Buffer); |
| 2024 StrBuf << "Function declared " << DeclaredNumberBbs | 2024 StrBuf << "Function declared " << DeclaredNumberBbs |
| 2025 << " basic blocks, but defined " << CurrentBbIndex << "."; | 2025 << " basic blocks, but defined " << CurrentBbIndex << "."; |
| 2026 Error(StrBuf.str()); | 2026 Error(StrBuf.str()); |
| 2027 } | 2027 } |
| 2028 if (isIRGenerationDisabled()) | 2028 if (isIRGenerationDisabled()) |
| 2029 return; | 2029 return; |
| 2030 if (!verifyAllForwardRefsDefined()) | |
| 2031 return; | |
| 2032 // Before translating, check for blocks without instructions, and | 2030 // Before translating, check for blocks without instructions, and |
| 2033 // insert unreachable. This shouldn't happen, but be safe. | 2031 // insert unreachable. This shouldn't happen, but be safe. |
| 2034 size_t Index = 0; | 2032 size_t Index = 0; |
| 2035 for (Ice::CfgNode *Node : Func->getNodes()) { | 2033 for (Ice::CfgNode *Node : Func->getNodes()) { |
| 2036 if (Node->getInsts().empty()) { | 2034 if (Node->getInsts().empty()) { |
| 2037 std::string Buffer; | 2035 std::string Buffer; |
| 2038 raw_string_ostream StrBuf(Buffer); | 2036 raw_string_ostream StrBuf(Buffer); |
| 2039 StrBuf << "Basic block " << Index << " contains no instructions"; | 2037 StrBuf << "Basic block " << Index << " contains no instructions"; |
| 2040 Error(StrBuf.str()); | 2038 Error(StrBuf.str()); |
| 2041 Node->appendInst(Ice::InstUnreachable::create(Func.get())); | 2039 Node->appendInst(Ice::InstUnreachable::create(Func.get())); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 2071 switch (Record.GetCode()) { | 2069 switch (Record.GetCode()) { |
| 2072 case naclbitc::FUNC_CODE_DECLAREBLOCKS: { | 2070 case naclbitc::FUNC_CODE_DECLAREBLOCKS: { |
| 2073 // DECLAREBLOCKS: [n] | 2071 // DECLAREBLOCKS: [n] |
| 2074 if (!isValidRecordSize(1, "count")) | 2072 if (!isValidRecordSize(1, "count")) |
| 2075 return; | 2073 return; |
| 2076 if (DeclaredNumberBbs > 0) { | 2074 if (DeclaredNumberBbs > 0) { |
| 2077 Error("Duplicate function block count record"); | 2075 Error("Duplicate function block count record"); |
| 2078 return; | 2076 return; |
| 2079 } | 2077 } |
| 2080 | 2078 |
| 2079 // Check for bad large sizes, since they can make ridiculous memory | |
| 2080 // requests and hang the user for large amounts of time. | |
| 2081 uint64_t NumBbs = Values[0]; | 2081 uint64_t NumBbs = Values[0]; |
| 2082 | 2082 if (NumBbs > MaxRecordsInBlock) { |
| 2083 // Check for bad large sizes, since they can make ridiculous memory | |
| 2084 // requests and hang the user for large amounts of time. Note: We know | |
| 2085 // that each basic block must have a terminator instruction, and each | |
| 2086 // instruction is minimally defined by a two-bit abreviation. | |
| 2087 uint64_t MaxBbs = NumBytesDefiningFunction * (CHAR_BIT >> 1); | |
| 2088 if (NumBbs > MaxBbs) { | |
| 2089 std::string Buffer; | 2083 std::string Buffer; |
| 2090 raw_string_ostream StrBuf(Buffer); | 2084 raw_string_ostream StrBuf(Buffer); |
| 2091 StrBuf << "Function defines " << NumBbs | 2085 StrBuf << "Function defines " << NumBbs |
| 2092 << " basic blocks, which is too big for a function containing " | 2086 << " basic blocks, which is too big for a function containing " |
| 2093 << NumBytesDefiningFunction << " bytes"; | 2087 << NumBytesDefiningFunction << " bytes"; |
| 2094 Error(StrBuf.str()); | 2088 Error(StrBuf.str()); |
| 2095 NumBbs = MaxBbs; | 2089 NumBbs = MaxRecordsInBlock; |
| 2096 } | 2090 } |
| 2097 | 2091 |
| 2098 if (NumBbs == 0) { | 2092 if (NumBbs == 0) { |
| 2099 Error("Functions must contain at least one basic block."); | 2093 Error("Functions must contain at least one basic block."); |
| 2100 NumBbs = 1; | 2094 NumBbs = 1; |
| 2101 } | 2095 } |
| 2102 | 2096 |
| 2103 DeclaredNumberBbs = NumBbs; | 2097 DeclaredNumberBbs = NumBbs; |
| 2104 if (isIRGenerationDisabled()) | 2098 if (isIRGenerationDisabled()) |
| 2105 return; | 2099 return; |
| (...skipping 1069 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3175 } | 3169 } |
| 3176 if (InputStreamFile.getBitcodeBytes().getExtent() % 4 != 0) { | 3170 if (InputStreamFile.getBitcodeBytes().getExtent() % 4 != 0) { |
| 3177 ErrStream | 3171 ErrStream |
| 3178 << IRFilename | 3172 << IRFilename |
| 3179 << ": Bitcode stream should be a multiple of 4 bytes in length.\n"; | 3173 << ": Bitcode stream should be a multiple of 4 bytes in length.\n"; |
| 3180 llvm::report_fatal_error("Bitcode stream should be a multiple of 4 bytes"); | 3174 llvm::report_fatal_error("Bitcode stream should be a multiple of 4 bytes"); |
| 3181 } | 3175 } |
| 3182 } | 3176 } |
| 3183 | 3177 |
| 3184 } // end of namespace Ice | 3178 } // end of namespace Ice |
| OLD | NEW |