Author: mamai Date: Thu May 12 15:00:53 2016 New Revision: 269340 URL: http://llvm.org/viewvc/llvm-project?rev=269340&view=rev Log: [LLDB] Added support for PHI nodes to IR interpreter
This allows expressions such as 'i == 1 || i == 2` to be executed using the IR interpreter, instead of relying on JIT code injection (which may not be available on some platforms). Patch by cameron314 Differential Revision: http://reviews.llvm.org/D19124 Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/ lldb/trunk/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/TestIRInterpreterPHINodes.py lldb/trunk/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/main.cpp Modified: lldb/trunk/source/Commands/CommandObjectExpression.cpp lldb/trunk/source/Commands/CommandObjectExpression.h lldb/trunk/source/Expression/IRInterpreter.cpp Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/TestIRInterpreterPHINodes.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/TestIRInterpreterPHINodes.py?rev=269340&view=auto ============================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/TestIRInterpreterPHINodes.py (added) +++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/TestIRInterpreterPHINodes.py Thu May 12 15:00:53 2016 @@ -0,0 +1,40 @@ +""" +Test PHI nodes work in the IR interpreter. +""" + +import os, os.path + +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + +class IRInterpreterPHINodesTestCase(TestBase): + mydir = TestBase.compute_mydir(__file__) + + def test_phi_node_support(self): + """Test support for PHI nodes in the IR interpreter.""" + + self.build() + exe = os.path.join(os.getcwd(), 'a.out') + self.runCmd('file ' + exe, CURRENT_EXECUTABLE_SET) + + # Break on the first assignment to i + line = line_number('main.cpp', 'i = 5') + lldbutil.run_break_set_by_file_and_line(self, 'main.cpp', line, num_expected_locations=1, loc_exact=True) + + self.runCmd('run', RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint + self.expect('thread list', STOPPED_DUE_TO_BREAKPOINT, + substrs = ['stopped', 'stop reason = breakpoint']) + + self.runCmd('s') + + # The logical 'or' causes a PHI node to be generated. Execute without JIT + # to test that the interpreter can handle this + self.expect('expr -j 0 -- i == 3 || i == 5', substrs=['true']) + + self.runCmd('s') + self.expect('expr -j 0 -- i == 3 || i == 5', substrs=['false']) + self.runCmd('s') + self.expect('expr -j 0 -- i == 3 || i == 5', substrs=['true']) Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/main.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/main.cpp?rev=269340&view=auto ============================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/main.cpp (added) +++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/main.cpp Thu May 12 15:00:53 2016 @@ -0,0 +1,17 @@ +//===-- main.cpp ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +int main() +{ + int i; + i = 5; + i = 2; + i = 3; + return 0; +} Modified: lldb/trunk/source/Commands/CommandObjectExpression.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectExpression.cpp?rev=269340&r1=269339&r2=269340&view=diff ============================================================================== --- lldb/trunk/source/Commands/CommandObjectExpression.cpp (original) +++ lldb/trunk/source/Commands/CommandObjectExpression.cpp Thu May 12 15:00:53 2016 @@ -63,7 +63,8 @@ CommandObjectExpression::CommandOptions: { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Specifies the Language to use when parsing the expression. If not set the target.language setting is used." }, { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "apply-fixits", 'X', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "If true, simple FixIt hints will be automatically applied to the expression." }, { LLDB_OPT_SET_1, false, "description-verbosity", 'v', OptionParser::eOptionalArgument, nullptr, g_description_verbosity_type, 0, eArgTypeDescriptionVerbosity, "How verbose should the output of this expression be, if the object description is asked for."}, - { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "top-level", 'p', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Interpret the expression as top-level definitions rather than code to be immediately executed."} + { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "top-level", 'p', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Interpret the expression as top-level definitions rather than code to be immediately executed."}, + { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "allow-jit", 'j', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Controls whether the expression can fall back to being JITted if it's not supported by the interpreter (defaults to true)."} }; uint32_t @@ -111,6 +112,18 @@ CommandObjectExpression::CommandOptions: error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg); break; } + + case 'j': + { + bool success; + bool tmp_value = Args::StringToBoolean(option_arg, true, &success); + if (success) + allow_jit = tmp_value; + else + error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg); + break; + } + case 't': { bool success; @@ -197,6 +210,7 @@ CommandObjectExpression::CommandOptions: m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact; auto_apply_fixits = eLazyBoolCalculate; top_level = false; + allow_jit = true; } const OptionDefinition* @@ -325,6 +339,9 @@ CommandObjectExpression::EvaluateExpress options.SetTryAllThreads(m_command_options.try_all_threads); options.SetDebug(m_command_options.debug); options.SetLanguage(m_command_options.language); + options.SetExecutionPolicy(m_command_options.allow_jit ? + EvaluateExpressionOptions::default_execution_policy : + lldb_private::eExecutionPolicyNever); bool auto_apply_fixits; if (m_command_options.auto_apply_fixits == eLazyBoolCalculate) Modified: lldb/trunk/source/Commands/CommandObjectExpression.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectExpression.h?rev=269340&r1=269339&r2=269340&view=diff ============================================================================== --- lldb/trunk/source/Commands/CommandObjectExpression.h (original) +++ lldb/trunk/source/Commands/CommandObjectExpression.h Thu May 12 15:00:53 2016 @@ -57,6 +57,7 @@ public: bool top_level; bool unwind_on_error; bool ignore_breakpoints; + bool allow_jit; bool show_types; bool show_summary; bool debug; Modified: lldb/trunk/source/Expression/IRInterpreter.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/IRInterpreter.cpp?rev=269340&r1=269339&r2=269340&view=diff ============================================================================== --- lldb/trunk/source/Expression/IRInterpreter.cpp (original) +++ lldb/trunk/source/Expression/IRInterpreter.cpp Thu May 12 15:00:53 2016 @@ -106,6 +106,7 @@ public: DataLayout &m_target_data; lldb_private::IRExecutionUnit &m_execution_unit; const BasicBlock *m_bb; + const BasicBlock *m_prev_bb; BasicBlock::const_iterator m_ii; BasicBlock::const_iterator m_ie; @@ -121,7 +122,9 @@ public: lldb::addr_t stack_frame_bottom, lldb::addr_t stack_frame_top) : m_target_data (target_data), - m_execution_unit (execution_unit) + m_execution_unit (execution_unit), + m_bb (nullptr), + m_prev_bb (nullptr) { m_byte_order = (target_data.isLittleEndian() ? lldb::eByteOrderLittle : lldb::eByteOrderBig); m_addr_byte_size = (target_data.getPointerSize(0)); @@ -137,6 +140,7 @@ public: void Jump (const BasicBlock *bb) { + m_prev_bb = m_bb; m_bb = bb; m_ii = m_bb->begin(); m_ie = m_bb->end(); @@ -569,6 +573,7 @@ IRInterpreter::CanInterpret (llvm::Modul case Instruction::Alloca: case Instruction::BitCast: case Instruction::Br: + case Instruction::PHI: break; case Instruction::Call: { @@ -1063,6 +1068,46 @@ IRInterpreter::Interpret (llvm::Module & } } continue; + case Instruction::PHI: + { + const PHINode *phi_inst = dyn_cast<PHINode>(inst); + + if (!phi_inst) + { + if (log) + log->Printf("getOpcode() returns PHI, but instruction is not a PHINode"); + error.SetErrorToGenericError(); + error.SetErrorString(interpreter_internal_error); + return false; + } + if (!frame.m_prev_bb) + { + if (log) + log->Printf("Encountered PHI node without having jumped from another basic block"); + error.SetErrorToGenericError(); + error.SetErrorString(interpreter_internal_error); + return false; + } + + Value* value = phi_inst->getIncomingValueForBlock(frame.m_prev_bb); + lldb_private::Scalar result; + if (!frame.EvaluateValue(result, value, module)) + { + if (log) + log->Printf("Couldn't evaluate %s", PrintValue(value).c_str()); + error.SetErrorToGenericError(); + error.SetErrorString(bad_value_error); + return false; + } + frame.AssignValue(inst, result, module); + + if (log) + { + log->Printf("Interpreted a %s", inst->getOpcodeName()); + log->Printf(" Incoming value : %s", frame.SummarizeValue(value).c_str()); + } + } + break; case Instruction::GetElementPtr: { const GetElementPtrInst *gep_inst = dyn_cast<GetElementPtrInst>(inst); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits