[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