kpdev42 updated this revision to Diff 450244. kpdev42 added a comment. Update test case so it compares JIT’ed and interpreted FP division results and also check operations on float type. Patch doesn’t implement long double, because IR interpreter currently doesn’t support instruction argument size of more than 64 bit which includes both fp128 and int128. This deserves a separate patch, I think
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D126359/new/ https://reviews.llvm.org/D126359 Files: lldb/source/Expression/IRInterpreter.cpp lldb/test/API/lang/c/fpeval/Makefile lldb/test/API/lang/c/fpeval/TestFPEval.py lldb/test/API/lang/c/fpeval/main.c
Index: lldb/test/API/lang/c/fpeval/main.c =================================================================== --- /dev/null +++ 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. +} Index: lldb/test/API/lang/c/fpeval/TestFPEval.py =================================================================== --- /dev/null +++ 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())) + Index: lldb/test/API/lang/c/fpeval/Makefile =================================================================== --- /dev/null +++ lldb/test/API/lang/c/fpeval/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules Index: lldb/source/Expression/IRInterpreter.cpp =================================================================== --- lldb/source/Expression/IRInterpreter.cpp +++ lldb/source/Expression/IRInterpreter.cpp @@ -167,6 +167,18 @@ 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 @@ 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<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 @@ 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<BinaryOperator>(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<ICmpInst>(inst); + const CmpInst *icmp_inst = cast<CmpInst>(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();
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits