in fx/native_interpreter/interpreter.cpp [48:121]
at::Tensor __call__(std::vector<at::Tensor> inputs) {
// Environment to hold local variables
std::unordered_map<std::string, at::Tensor> environment;
// Load inputs according to the specified names
if (inputs.size() != input_names_.size()) {
std::stringstream err;
err << "Expected " << input_names_.size() << " inputs, but got "
<< inputs.size() << "!";
throw std::runtime_error(err.str());
}
for (size_t i = 0; i < inputs.size(); ++i) {
environment[input_names_[i]] = inputs[i];
}
if (!output_name_) {
throw std::runtime_error("Output name not specified!");
}
for (InstructionType &instr : instructions_) {
// Retrieve all input values for this op
std::vector<at::Tensor> inputs;
for (const auto &input_name : std::get<1>(instr)) {
// Operator output values shadow constants.
// Imagine all constants are defined in statements at the beginning
// of a function (a la K&R C). Any definition of an output value must
// necessarily come after constant definition in textual order. Thus,
// We look up values in the environment first then the constant table
// second to implement this shadowing behavior
if (environment.find(input_name) != environment.end()) {
inputs.push_back(environment.at(input_name));
} else if (constants_.find(input_name) != constants_.end()) {
inputs.push_back(constants_.at(input_name));
} else {
std::stringstream err;
err << "Instruction referenced unknown value " << input_name << "!";
throw std::runtime_error(err.str());
}
}
// Run the specified operation
at::Tensor result;
const auto &op = std::get<0>(instr);
if (op == "add") {
if (inputs.size() != 2) {
throw std::runtime_error("Unexpected number of inputs for add op!");
}
result = inputs[0] + inputs[1];
} else if (op == "mul") {
if (inputs.size() != 2) {
throw std::runtime_error("Unexpected number of inputs for mul op!");
}
result = inputs[0] * inputs[1];
} else {
std::stringstream err;
err << "Unknown operator " << op << "!";
throw std::runtime_error(err.str());
}
// Write back result into environment
const auto &output_name = std::get<2>(instr);
environment[output_name] = std::move(result);
}
if (!environment.count(*output_name_)) {
std::stringstream err;
err << "Execution expected an output value with name ";
err << *output_name_;
err << " but no instruction produced a value with that name!";
throw std::runtime_error(err.str());
}
return environment.at(*output_name_);
}