[Lldb-commits] [lldb] f63e2cf - [LLDB] Add basic floating point ops to IR interpreter
Pavel Kosov via lldb-commits
lldb-commits at lists.llvm.org
Wed Aug 10 06:35:42 PDT 2022
Author: Pavel Kosov
Date: 2022-08-10T16:34:52+03:00
New Revision: f63e2cfb7f5235d4d5148988e8a0ef86004da66e
URL: https://github.com/llvm/llvm-project/commit/f63e2cfb7f5235d4d5148988e8a0ef86004da66e
DIFF: https://github.com/llvm/llvm-project/commit/f63e2cfb7f5235d4d5148988e8a0ef86004da66e.diff
LOG: [LLDB] Add basic floating point ops to IR interpreter
Patch adds support for fadd, fsub, fdiv, fmul and fcmp to IR interpreter.
~~~
OS Laboratory. Huawei RRI. Saint-Petersburg
Reviewed By: clayborg
Differential Revision: https://reviews.llvm.org/D126359
Added:
lldb/test/API/lang/c/fpeval/Makefile
lldb/test/API/lang/c/fpeval/TestFPEval.py
lldb/test/API/lang/c/fpeval/main.c
Modified:
lldb/source/Expression/IRInterpreter.cpp
Removed:
################################################################################
diff --git a/lldb/source/Expression/IRInterpreter.cpp b/lldb/source/Expression/IRInterpreter.cpp
index a6efeb3f960f7..d03fea6ffce3c 100644
--- a/lldb/source/Expression/IRInterpreter.cpp
+++ b/lldb/source/Expression/IRInterpreter.cpp
@@ -167,6 +167,18 @@ class InterpreterStackFrame {
const Constant *constant = dyn_cast<Constant>(value);
if (constant) {
+ if (constant->getValueID() == Value::ConstantFPVal) {
+ if (auto *cfp = dyn_cast<ConstantFP>(constant)) {
+ if (cfp->getType()->isDoubleTy())
+ scalar = cfp->getValueAPF().convertToDouble();
+ else if (cfp->getType()->isFloatTy())
+ scalar = cfp->getValueAPF().convertToFloat();
+ else
+ return false;
+ return true;
+ }
+ return false;
+ }
APInt value_apint;
if (!ResolveConstantValue(value_apint, constant))
@@ -189,9 +201,18 @@ class InterpreterStackFrame {
lldb::offset_t offset = 0;
if (value_size <= 8) {
- uint64_t u64value = value_extractor.GetMaxU64(&offset, value_size);
- return AssignToMatchType(scalar, llvm::APInt(64, u64value),
- value->getType());
+ Type *ty = value->getType();
+ if (ty->isDoubleTy()) {
+ scalar = value_extractor.GetDouble(&offset);
+ return true;
+ } else if (ty->isFloatTy()) {
+ scalar = value_extractor.GetFloat(&offset);
+ return true;
+ } else {
+ uint64_t u64value = value_extractor.GetMaxU64(&offset, value_size);
+ return AssignToMatchType(scalar, llvm::APInt(64, u64value),
+ value->getType());
+ }
}
return false;
@@ -205,11 +226,15 @@ class InterpreterStackFrame {
return false;
lldb_private::Scalar cast_scalar;
-
- scalar.MakeUnsigned();
- if (!AssignToMatchType(cast_scalar, scalar.UInt128(llvm::APInt()),
- value->getType()))
- return false;
+ Type *vty = value->getType();
+ if (vty->isFloatTy() || vty->isDoubleTy()) {
+ cast_scalar = scalar;
+ } else {
+ scalar.MakeUnsigned();
+ if (!AssignToMatchType(cast_scalar, scalar.UInt128(llvm::APInt()),
+ value->getType()))
+ return false;
+ }
size_t value_byte_size = m_target_data.getTypeStoreSize(value->getType());
@@ -543,16 +568,17 @@ bool IRInterpreter::CanInterpret(llvm::Module &module, llvm::Function &function,
} break;
case Instruction::GetElementPtr:
break;
+ case Instruction::FCmp:
case Instruction::ICmp: {
- ICmpInst *icmp_inst = dyn_cast<ICmpInst>(&ii);
+ CmpInst *cmp_inst = dyn_cast<CmpInst>(&ii);
- if (!icmp_inst) {
+ if (!cmp_inst) {
error.SetErrorToGenericError();
error.SetErrorString(interpreter_internal_error);
return false;
}
- switch (icmp_inst->getPredicate()) {
+ switch (cmp_inst->getPredicate()) {
default: {
LLDB_LOGF(log, "Unsupported ICmp predicate: %s",
PrintValue(&ii).c_str());
@@ -561,11 +587,17 @@ bool IRInterpreter::CanInterpret(llvm::Module &module, llvm::Function &function,
error.SetErrorString(unsupported_opcode_error);
return false;
}
+ case CmpInst::FCMP_OEQ:
case CmpInst::ICMP_EQ:
+ case CmpInst::FCMP_UNE:
case CmpInst::ICMP_NE:
+ case CmpInst::FCMP_OGT:
case CmpInst::ICMP_UGT:
+ case CmpInst::FCMP_OGE:
case CmpInst::ICMP_UGE:
+ case CmpInst::FCMP_OLT:
case CmpInst::ICMP_ULT:
+ case CmpInst::FCMP_OLE:
case CmpInst::ICMP_ULE:
case CmpInst::ICMP_SGT:
case CmpInst::ICMP_SGE:
@@ -595,6 +627,11 @@ bool IRInterpreter::CanInterpret(llvm::Module &module, llvm::Function &function,
case Instruction::Xor:
case Instruction::ZExt:
break;
+ case Instruction::FAdd:
+ case Instruction::FSub:
+ case Instruction::FMul:
+ case Instruction::FDiv:
+ break;
}
for (unsigned oi = 0, oe = ii.getNumOperands(); oi != oe; ++oi) {
@@ -709,7 +746,11 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
case Instruction::AShr:
case Instruction::And:
case Instruction::Or:
- case Instruction::Xor: {
+ case Instruction::Xor:
+ case Instruction::FAdd:
+ case Instruction::FSub:
+ case Instruction::FMul:
+ case Instruction::FDiv: {
const BinaryOperator *bin_op = dyn_cast<BinaryOperator>(inst);
if (!bin_op) {
@@ -748,12 +789,15 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
default:
break;
case Instruction::Add:
+ case Instruction::FAdd:
result = L + R;
break;
case Instruction::Mul:
+ case Instruction::FMul:
result = L * R;
break;
case Instruction::Sub:
+ case Instruction::FSub:
result = L - R;
break;
case Instruction::SDiv:
@@ -766,6 +810,9 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
R.MakeUnsigned();
result = L / R;
break;
+ case Instruction::FDiv:
+ result = L / R;
+ break;
case Instruction::SRem:
L.MakeSigned();
R.MakeSigned();
@@ -1028,8 +1075,9 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
LLDB_LOGF(log, " Poffset : %s", frame.SummarizeValue(inst).c_str());
}
} break;
+ case Instruction::FCmp:
case Instruction::ICmp: {
- const ICmpInst *icmp_inst = cast<ICmpInst>(inst);
+ const CmpInst *icmp_inst = cast<CmpInst>(inst);
CmpInst::Predicate predicate = icmp_inst->getPredicate();
@@ -1059,9 +1107,11 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
default:
return false;
case CmpInst::ICMP_EQ:
+ case CmpInst::FCMP_OEQ:
result = (L == R);
break;
case CmpInst::ICMP_NE:
+ case CmpInst::FCMP_UNE:
result = (L != R);
break;
case CmpInst::ICMP_UGT:
@@ -1074,16 +1124,28 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function,
R.MakeUnsigned();
result = (L >= R);
break;
+ case CmpInst::FCMP_OGE:
+ result = (L >= R);
+ break;
+ case CmpInst::FCMP_OGT:
+ result = (L > R);
+ break;
case CmpInst::ICMP_ULT:
L.MakeUnsigned();
R.MakeUnsigned();
result = (L < R);
break;
+ case CmpInst::FCMP_OLT:
+ result = (L < R);
+ break;
case CmpInst::ICMP_ULE:
L.MakeUnsigned();
R.MakeUnsigned();
result = (L <= R);
break;
+ case CmpInst::FCMP_OLE:
+ result = (L <= R);
+ break;
case CmpInst::ICMP_SGT:
L.MakeSigned();
R.MakeSigned();
diff --git a/lldb/test/API/lang/c/fpeval/Makefile b/lldb/test/API/lang/c/fpeval/Makefile
new file mode 100644
index 0000000000000..10495940055b6
--- /dev/null
+++ b/lldb/test/API/lang/c/fpeval/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/lang/c/fpeval/TestFPEval.py b/lldb/test/API/lang/c/fpeval/TestFPEval.py
new file mode 100644
index 0000000000000..694d1ed7aa99d
--- /dev/null
+++ b/lldb/test/API/lang/c/fpeval/TestFPEval.py
@@ -0,0 +1,101 @@
+"""Tests IR interpreter handling of basic floating point operations (fadd, fsub, etc)."""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class FPEvalTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ self.jit_opts = lldb.SBExpressionOptions()
+ self.jit_opts.SetAllowJIT(True)
+ self.no_jit_opts = lldb.SBExpressionOptions()
+ self.no_jit_opts.SetAllowJIT(False)
+ # Find the line number to break inside main().
+ self.line = line_number('main.c', '// Set break point at this line.')
+
+ def test(self):
+ """Test floating point expressions while jitter is disabled."""
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+ # Break inside the main.
+ lldbutil.run_break_set_by_file_and_line(
+ self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
+
+
+ value = self.frame().EvaluateExpression("a + b", self.no_jit_opts)
+
+ self.runCmd("run", RUN_SUCCEEDED)
+ # test double
+ self.expect("expr --allow-jit false -- a + b", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['double', '44'])
+ self.expect("expr --allow-jit false -- a - b", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['double', '40'])
+ self.expect("expr --allow-jit false -- a / b", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['double', '21'])
+ self.expect("expr --allow-jit false -- a * b", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['double', '84'])
+ self.expect("expr --allow-jit false -- a + 2", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['double', '44'])
+ self.expect("expr --allow-jit false -- a > b", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['true'])
+ self.expect("expr --allow-jit false -- a >= b", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['true'])
+ self.expect("expr --allow-jit false -- a < b", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['false'])
+ self.expect("expr --allow-jit false -- a <= b", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['false'])
+ self.expect("expr --allow-jit false -- a == b", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['false'])
+ self.expect("expr --allow-jit false -- a != b", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['true'])
+
+ # test single
+ self.expect("expr --allow-jit false -- f + q", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['float', '44'])
+ self.expect("expr --allow-jit false -- f - q", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['float', '40'])
+ self.expect("expr --allow-jit false -- f / q", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['float', '21'])
+ self.expect("expr --allow-jit false -- f * q", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['float', '84'])
+ self.expect("expr --allow-jit false -- f + 2", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['float', '44'])
+ self.expect("expr --allow-jit false -- f > q", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['true'])
+ self.expect("expr --allow-jit false -- f >= q", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['true'])
+ self.expect("expr --allow-jit false -- f < q", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['false'])
+ self.expect("expr --allow-jit false -- f <= q", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['false'])
+ self.expect("expr --allow-jit false -- f == q", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['false'])
+ self.expect("expr --allow-jit false -- f != q", VARIABLES_DISPLAYED_CORRECTLY,
+ substrs=['true'])
+
+ # compare jit and interpreter output
+ self.assertTrue(self.process().IsValid())
+ thread = lldbutil.get_stopped_thread(self.process(), lldb.eStopReasonBreakpoint)
+ self.assertTrue(thread.IsValid())
+ frame = thread.GetSelectedFrame()
+ self.assertTrue(frame.IsValid())
+
+ dividents = [42, 79, 666]
+ divisors = [1.618, 2.718281828, 3.1415926535, 6.62607015]
+
+ for x in dividents:
+ for y in divisors:
+ vardef = "double x = {0}, y = {1};".format(x, y)
+ v1 = frame.EvaluateExpression("{0}; eval(x, y, 2)".format(vardef), self.jit_opts)
+ v2 = frame.EvaluateExpression("{0}; x / y".format(vardef), self.no_jit_opts)
+ self.assertTrue(v1.IsValid() and v2.IsValid())
+ self.assertTrue(str(v1.GetData()) == str(v2.GetData()))
+
diff --git a/lldb/test/API/lang/c/fpeval/main.c b/lldb/test/API/lang/c/fpeval/main.c
new file mode 100644
index 0000000000000..3b44b7005206e
--- /dev/null
+++ b/lldb/test/API/lang/c/fpeval/main.c
@@ -0,0 +1,16 @@
+double eval(double a, double b, int op) {
+ switch (op) {
+ case 0: return a+b;
+ case 1: return a-b;
+ case 2: return a/b;
+ case 3: return a*b;
+ default: return 0;
+ }
+}
+
+int main (int argc, char const *argv[])
+{
+ double a = 42.0, b = 2.0;
+ float f = 42.0, q = 2.0;
+ return 0; //// Set break point at this line.
+}
More information about the lldb-commits
mailing list