diff --git a/lldb/source/Expression/IRInterpreter.cpp b/lldb/source/Expression/IRInterpreter.cpp --- a/lldb/source/Expression/IRInterpreter.cpp +++ b/lldb/source/Expression/IRInterpreter.cpp @@ -167,6 +167,18 @@ const Constant *constant = dyn_cast(value); if (constant) { + if (constant->getValueID() == Value::ConstantFPVal) { + if (auto *cfp = dyn_cast(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 @@ 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 @@ 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 @@ } break; case Instruction::GetElementPtr: break; + case Instruction::FCmp: case Instruction::ICmp: { - ICmpInst *icmp_inst = dyn_cast(&ii); + CmpInst *cmp_inst = dyn_cast(&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 @@ 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 @@ 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 @@ 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(inst); if (!bin_op) { @@ -748,12 +789,15 @@ 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 @@ R.MakeUnsigned(); result = L / R; break; + case Instruction::FDiv: + result = L / R; + break; case Instruction::SRem: L.MakeSigned(); R.MakeSigned(); @@ -1028,8 +1075,9 @@ LLDB_LOGF(log, " Poffset : %s", frame.SummarizeValue(inst).c_str()); } } break; + case Instruction::FCmp: case Instruction::ICmp: { - const ICmpInst *icmp_inst = cast(inst); + const CmpInst *icmp_inst = cast(inst); CmpInst::Predicate predicate = icmp_inst->getPredicate(); @@ -1059,9 +1107,11 @@ 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 @@ 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 --- /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 --- /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 --- /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. +}