[XLA:Tool] Make Hlo parser report the location of the already defined instrucion/computation.

PiperOrigin-RevId: 185213461
This commit is contained in:
A. Unique TensorFlower 2018-02-09 16:57:14 -08:00 committed by TensorFlower Gardener
parent 7a5d775685
commit 816f59e6ab
2 changed files with 58 additions and 19 deletions

View File

@ -220,10 +220,13 @@ class HloParser {
bool AddComputation(const string& name, HloComputation* computation, bool AddComputation(const string& name, HloComputation* computation,
LocTy name_loc); LocTy name_loc);
// The map from the instruction name to the instruction. This does not own the // The map from the instruction/computation name to the
// instructions. // instruction/computation itself and it's location. This does not own the
std::unordered_map<string, HloInstruction*> instruction_pool_; // pointers.
std::unordered_map<string, HloComputation*> computation_pool_; std::unordered_map<string, std::pair<HloInstruction*, LocTy>>
instruction_pool_;
std::unordered_map<string, std::pair<HloComputation*, LocTy>>
computation_pool_;
HloLexer lexer_; HloLexer lexer_;
std::unique_ptr<HloModule> module_; std::unique_ptr<HloModule> module_;
@ -340,15 +343,16 @@ bool HloParser::ParseComputation(HloComputation** entry_computation) {
return false; return false;
} }
HloInstruction* root = std::pair<HloInstruction*, LocTy>* root_node =
tensorflow::gtl::FindPtrOrNull(instruction_pool_, root_name); tensorflow::gtl::FindOrNull(instruction_pool_, root_name);
// This means some instruction was marked as ROOT but we didn't find it in the // This means some instruction was marked as ROOT but we didn't find it in the
// pool, which should not happen. // pool, which should not happen.
if (!root_name.empty() && root == nullptr) { if (!root_name.empty() && root_node == nullptr) {
LOG(FATAL) << "instruction " << root_name LOG(FATAL) << "instruction " << root_name
<< " was marked as ROOT but the parser has not seen it before"; << " was marked as ROOT but the parser has not seen it before";
} }
HloInstruction* root = root_node == nullptr ? nullptr : root_node->first;
// Now root can be either an existing instruction or a nullptr. If it's a // Now root can be either an existing instruction or a nullptr. If it's a
// nullptr, the implementation of Builder will set the last instruction as // nullptr, the implementation of Builder will set the last instruction as
// root instruction. // root instruction.
@ -1229,13 +1233,13 @@ bool HloParser::ParseInstructionNames(
if (!ParseName(&name)) { if (!ParseName(&name)) {
return Error(loc, "expects a instruction name"); return Error(loc, "expects a instruction name");
} }
HloInstruction* instr = std::pair<HloInstruction*, LocTy>* instr =
tensorflow::gtl::FindPtrOrNull(instruction_pool_, name); tensorflow::gtl::FindOrNull(instruction_pool_, name);
if (!instr) { if (!instr) {
return TokenError( return TokenError(
Printf("instruction '%s' is not defined", name.c_str())); Printf("instruction '%s' is not defined", name.c_str()));
} }
instructions->push_back(instr); instructions->push_back(instr->first);
} while (EatIfPresent(TokKind::kComma)); } while (EatIfPresent(TokKind::kComma));
return ParseToken(TokKind::kRbrace, return ParseToken(TokKind::kRbrace,
@ -1705,12 +1709,12 @@ bool HloParser::ParseOperands(std::vector<HloInstruction*>* operands) {
if (!ParseName(&name)) { if (!ParseName(&name)) {
return false; return false;
} }
HloInstruction* instruction = std::pair<HloInstruction*, LocTy>* instruction =
tensorflow::gtl::FindPtrOrNull(instruction_pool_, name); tensorflow::gtl::FindOrNull(instruction_pool_, name);
if (!instruction) { if (!instruction) {
return Error(loc, StrCat("instruction does not exist: ", name)); return Error(loc, StrCat("instruction does not exist: ", name));
} }
operands->push_back(instruction); operands->push_back(instruction->first);
} while (EatIfPresent(TokKind::kComma)); } while (EatIfPresent(TokKind::kComma));
} }
return ParseToken(TokKind::kRparen, "expects ')' at the end of operands"); return ParseToken(TokKind::kRparen, "expects ')' at the end of operands");
@ -1957,10 +1961,12 @@ bool HloParser::ParseComputationName(HloComputation** value) {
if (!ParseName(&name)) { if (!ParseName(&name)) {
return Error(loc, "expects computation name"); return Error(loc, "expects computation name");
} }
*value = tensorflow::gtl::FindPtrOrNull(computation_pool_, name); std::pair<HloComputation*, LocTy>* computation =
if (*value == nullptr) { tensorflow::gtl::FindOrNull(computation_pool_, name);
if (computation == nullptr) {
return Error(loc, StrCat("computation does not exist: ", name)); return Error(loc, StrCat("computation does not exist: ", name));
} }
*value = computation->first;
return true; return true;
} }
@ -2576,18 +2582,22 @@ bool HloParser::EatIfPresent(TokKind kind) {
bool HloParser::AddInstruction(const string& name, HloInstruction* instruction, bool HloParser::AddInstruction(const string& name, HloInstruction* instruction,
LocTy name_loc) { LocTy name_loc) {
auto result = instruction_pool_.insert({name, instruction}); auto result = instruction_pool_.insert({name, {instruction, name_loc}});
if (!result.second) { if (!result.second) {
return Error(name_loc, StrCat("instruction already exists: ", name)); Error(name_loc, StrCat("instruction already exists: ", name));
return Error(/*loc=*/result.first->second.second,
"instruction previously defined here");
} }
return true; return true;
} }
bool HloParser::AddComputation(const string& name, HloComputation* computation, bool HloParser::AddComputation(const string& name, HloComputation* computation,
LocTy name_loc) { LocTy name_loc) {
auto result = computation_pool_.insert({name, computation}); auto result = computation_pool_.insert({name, {computation, name_loc}});
if (!result.second) { if (!result.second) {
return Error(name_loc, StrCat("computation already exists: ", name)); Error(name_loc, StrCat("computation already exists: ", name));
return Error(/*loc=*/result.first->second.second,
"computation previously defined here");
} }
return true; return true;
} }

View File

@ -1275,6 +1275,35 @@ ENTRY consts {
"one computation should have only one ROOT"); "one computation should have only one ROOT");
} }
TEST_F(HloParserTest, InstructionExists) {
const string original = R"(HloModule comp_exists
c1 {
instr = f32[1]{0} constant({12345})
}
c2 {
instr = f32[1]{0} constant({67890})
})";
ExpectHasSubstr(Parse(original).status().error_message(),
R"(was parsing 3:3: error: instruction previously defined here
instr = f32[1]{0} constant({12345})
^)");
}
TEST_F(HloParserTest, ComputationExists) {
const string original = R"(HloModule comp_exists
comp {
const1 = f32[1]{0} constant({12345})
}
comp {
const2 = f32[1]{0} constant({67890})
})";
ExpectHasSubstr(Parse(original).status().error_message(),
R"(was parsing 2:1: error: computation previously defined here
comp {
^)");
}
} // namespace } // namespace
} // namespace tools } // namespace tools
} // namespace xla } // namespace xla