mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-24 10:07:48 +00:00
[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 llvm-svn: 269340
This commit is contained in:
parent
bc8397cdf0
commit
3fe7158174
@ -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'])
|
@ -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;
|
||||
}
|
@ -63,7 +63,8 @@ CommandObjectExpression::CommandOptions::g_option_table[] =
|
||||
{ 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::SetOptionValue (CommandInterpreter &int
|
||||
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::OptionParsingStarting (CommandInterpret
|
||||
m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact;
|
||||
auto_apply_fixits = eLazyBoolCalculate;
|
||||
top_level = false;
|
||||
allow_jit = true;
|
||||
}
|
||||
|
||||
const OptionDefinition*
|
||||
@ -325,6 +339,9 @@ CommandObjectExpression::EvaluateExpression(const char *expr,
|
||||
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)
|
||||
|
@ -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;
|
||||
|
@ -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::Module &module,
|
||||
case Instruction::Alloca:
|
||||
case Instruction::BitCast:
|
||||
case Instruction::Br:
|
||||
case Instruction::PHI:
|
||||
break;
|
||||
case Instruction::Call:
|
||||
{
|
||||
@ -1063,6 +1068,46 @@ IRInterpreter::Interpret (llvm::Module &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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user