https://github.com/igorkudrin updated https://github.com/llvm/llvm-project/pull/175292
>From ba9318db283858884e395ec2329ef2f8891370b4 Mon Sep 17 00:00:00 2001 From: Igor Kudrin <[email protected]> Date: Thu, 8 Jan 2026 22:53:38 -0800 Subject: [PATCH 1/4] [lldb] Add FP conversion instructions to IR interpreter This allows expressions that use these conversions to be executed when JIT is not available. --- lldb/source/Expression/IRInterpreter.cpp | 73 +++++++++++++++++++ .../ir-interpreter/TestIRInterpreter.py | 70 ++++++++++++++++++ 2 files changed, 143 insertions(+) diff --git a/lldb/source/Expression/IRInterpreter.cpp b/lldb/source/Expression/IRInterpreter.cpp index 91404831aeb9b..3c43646f51eff 100644 --- a/lldb/source/Expression/IRInterpreter.cpp +++ b/lldb/source/Expression/IRInterpreter.cpp @@ -611,6 +611,8 @@ bool IRInterpreter::CanInterpret(llvm::Module &module, llvm::Function &function, } break; case Instruction::And: case Instruction::AShr: + case Instruction::FPToUI: + case Instruction::FPToSI: case Instruction::IntToPtr: case Instruction::PtrToInt: case Instruction::Load: @@ -635,6 +637,18 @@ bool IRInterpreter::CanInterpret(llvm::Module &module, llvm::Function &function, case Instruction::FMul: case Instruction::FDiv: break; + case Instruction::UIToFP: + case Instruction::SIToFP: + case Instruction::FPTrunc: + case Instruction::FPExt: + if (!ii.getType()->isFloatTy() && !ii.getType()->isDoubleTy()) { + LLDB_LOGF(log, "Unsupported instruction: %s", + PrintValue(&ii).c_str()); + error = + lldb_private::Status::FromErrorString(unsupported_opcode_error); + return false; + } + break; } for (unsigned oi = 0, oe = ii.getNumOperands(); oi != oe; ++oi) { @@ -1256,6 +1270,65 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function, LLDB_LOGF(log, " = : %s", frame.SummarizeValue(inst).c_str()); } } break; + case Instruction::FPToUI: + case Instruction::FPToSI: { + Value *src_operand = inst->getOperand(0); + + lldb_private::Scalar S; + if (!frame.EvaluateValue(S, src_operand, module)) { + LLDB_LOGF(log, "Couldn't evaluate %s", PrintValue(src_operand).c_str()); + error = lldb_private::Status::FromErrorString(bad_value_error); + return false; + } + + assert(inst->getType()->isIntegerTy() && "Unexpected target type"); + llvm::APSInt result(inst->getType()->getIntegerBitWidth(), + /*isUnsigned=*/inst->getOpcode() == + Instruction::FPToUI); + assert(S.GetType() == lldb_private::Scalar::e_float && + "Unexpected source type"); + bool isExact; + S.GetAPFloat().convertToInteger(result, llvm::APFloat::rmTowardZero, + &isExact); + lldb_private::Scalar R(result); + + frame.AssignValue(inst, R, module); + if (log) { + LLDB_LOGF(log, "Interpreted a %s", inst->getOpcodeName()); + LLDB_LOGF(log, " Src : %s", frame.SummarizeValue(src_operand).c_str()); + LLDB_LOGF(log, " = : %s", frame.SummarizeValue(inst).c_str()); + } + } break; + case Instruction::UIToFP: + case Instruction::SIToFP: + case Instruction::FPTrunc: + case Instruction::FPExt: { + Value *src_operand = inst->getOperand(0); + + lldb_private::Scalar S; + if (!frame.EvaluateValue(S, src_operand, module)) { + LLDB_LOGF(log, "Couldn't evaluate %s", PrintValue(src_operand).c_str()); + error = lldb_private::Status::FromErrorString(bad_value_error); + return false; + } + lldb_private::Scalar R; + + Type *result_type = inst->getType(); + assert( + (result_type->isFloatTy() || result_type->isDoubleTy()) && + "Unsupported result type; CanInterpret() should have checked that"); + if (result_type->isFloatTy()) + R = S.Float(); + else + R = S.Double(); + + frame.AssignValue(inst, R, module); + if (log) { + LLDB_LOGF(log, "Interpreted a %s", inst->getOpcodeName()); + LLDB_LOGF(log, " Src : %s", frame.SummarizeValue(src_operand).c_str()); + LLDB_LOGF(log, " = : %s", frame.SummarizeValue(inst).c_str()); + } + } break; case Instruction::Load: { const LoadInst *load_inst = cast<LoadInst>(inst); diff --git a/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py b/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py index 23188ef898d56..26be9ab952db7 100644 --- a/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py +++ b/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py @@ -172,3 +172,73 @@ def test_type_conversions(self): self.assertEqual(short_val.GetValueAsSigned(), -1) long_val = target.EvaluateExpression("(long) " + short_val.GetName()) self.assertEqual(long_val.GetValueAsSigned(), -1) + + def test_fpconv(self): + self.build_and_run() + + interp_options = lldb.SBExpressionOptions() + interp_options.SetLanguage(lldb.eLanguageTypeC_plus_plus) + interp_options.SetAllowJIT(False) + + jit_options = lldb.SBExpressionOptions() + jit_options.SetLanguage(lldb.eLanguageTypeC_plus_plus) + jit_options.SetAllowJIT(True) + + set_up_expressions = [ + "int $i = 3", + "int $n = -3", + "unsigned $u = 5", + "long $l = -7", + "float $f = 9.0625", + "double $d = 13.75", + "float $nf = -11.25", + ] + + expressions = [ + "$i + $f", + "$d - $n", + "$u + $f", + "$u + $d", + "(int)$d", + "(int)$f", + "(long)$d", + "(short)$f", + "(long)$nf", + "(unsigned short)$f", + "(unsigned)$d", + "(unsigned long)$d", + "(float)$d", + "(double)$f", + "(double)$nf", + ] + + for expression in set_up_expressions: + self.frame().EvaluateExpression(expression, interp_options) + + func_call = "(int)getpid()" + if lldbplatformutil.getPlatform() == "windows": + func_call = "(int)GetCurrentProcessId()" + + for expression in expressions: + interp_expression = expression + jit_expression = func_call + "; " + expression + + interp_result = ( + self.frame() + .EvaluateExpression(interp_expression, interp_options) + ) + jit_result = ( + self.frame() + .EvaluateExpression(jit_expression, jit_options) + ) + + self.assertEqual( + interp_result.GetValue(), + jit_result.GetValue(), + "Values match for " + expression, + ) + self.assertEqual( + interp_result.GetTypeName(), + jit_result.GetTypeName(), + "Types match for " + expression, + ) >From 61d9e3cf6757f853dabb1a7c6a72bb7b656ce325 Mon Sep 17 00:00:00 2001 From: Igor Kudrin <[email protected]> Date: Fri, 9 Jan 2026 22:43:53 -0800 Subject: [PATCH 2/4] fixup! formatting --- .../expression/ir-interpreter/TestIRInterpreter.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py b/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py index 26be9ab952db7..3ce15d801818c 100644 --- a/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py +++ b/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py @@ -223,14 +223,10 @@ def test_fpconv(self): interp_expression = expression jit_expression = func_call + "; " + expression - interp_result = ( - self.frame() - .EvaluateExpression(interp_expression, interp_options) - ) - jit_result = ( - self.frame() - .EvaluateExpression(jit_expression, jit_options) + interp_result = self.frame().EvaluateExpression( + interp_expression, interp_options ) + jit_result = self.frame().EvaluateExpression(jit_expression, jit_options) self.assertEqual( interp_result.GetValue(), >From a3df8184cd2f364a463a0301ba64e61f897f542d Mon Sep 17 00:00:00 2001 From: Igor Kudrin <[email protected]> Date: Mon, 12 Jan 2026 18:26:59 -0800 Subject: [PATCH 3/4] fixup! add comments to test expressions --- .../ir-interpreter/TestIRInterpreter.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py b/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py index 3ce15d801818c..2163d045ef872 100644 --- a/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py +++ b/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py @@ -195,21 +195,21 @@ def test_fpconv(self): ] expressions = [ - "$i + $f", - "$d - $n", - "$u + $f", - "$u + $d", - "(int)$d", - "(int)$f", - "(long)$d", - "(short)$f", - "(long)$nf", - "(unsigned short)$f", - "(unsigned)$d", - "(unsigned long)$d", - "(float)$d", - "(double)$f", - "(double)$nf", + "$i + $f", # sitofp i32 to float + "$d - $n", # sitofp i32 to double + "$u + $f", # uitofp i32 to float + "$u + $d", # uitofp i32 to double + "(int)$d", # fptosi double to i32 + "(int)$f", # fptosi float to i32 + "(long)$d", # fptosi double to i64 + "(short)$f", # fptosi float to i16 + "(long)$nf", # fptosi float to i64 + "(unsigned short)$f", # fptoui float to i16 + "(unsigned)$d", # fptoui double to i32 + "(unsigned long)$d", # fptoui double to i64 + "(float)$d", # fptrunc double to float + "(double)$f", # fpext float to double + "(double)$nf", # fpext float to double ] for expression in set_up_expressions: >From 8480377627a33ebfa671e8a5be411eb8dcca7d00 Mon Sep 17 00:00:00 2001 From: Igor Kudrin <[email protected]> Date: Mon, 12 Jan 2026 18:34:40 -0800 Subject: [PATCH 4/4] fixup! reject invalid conversions --- lldb/source/Expression/IRInterpreter.cpp | 21 +++++++++++-- .../ir-interpreter/TestIRInterpreter.py | 31 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/lldb/source/Expression/IRInterpreter.cpp b/lldb/source/Expression/IRInterpreter.cpp index 3c43646f51eff..f6365ac948f37 100644 --- a/lldb/source/Expression/IRInterpreter.cpp +++ b/lldb/source/Expression/IRInterpreter.cpp @@ -70,6 +70,13 @@ static std::string PrintType(const Type *type, bool truncate = false) { return s; } +static std::string PrintScalar(const lldb_private::Scalar &value) { + std::string s; + raw_string_ostream rso(s); + rso << value; + return s; +} + static bool CanIgnoreCall(const CallInst *call) { const llvm::Function *called_function = call->getCalledFunction(); @@ -477,6 +484,8 @@ static const char *timeout_error = "Reached timeout while interpreting expression"; static const char *too_many_functions_error = "Interpreter doesn't handle modules with multiple function bodies."; +static const char *bad_conversion_error = + "Interpreter couldn't convert a value"; static bool CanResolveConstant(llvm::Constant *constant) { switch (constant->getValueID()) { @@ -1288,8 +1297,16 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function, assert(S.GetType() == lldb_private::Scalar::e_float && "Unexpected source type"); bool isExact; - S.GetAPFloat().convertToInteger(result, llvm::APFloat::rmTowardZero, - &isExact); + llvm::APFloatBase::opStatus status = S.GetAPFloat().convertToInteger( + result, llvm::APFloat::rmTowardZero, &isExact); + // Casting floating point values that are out of bounds of the target type + // is undefined behaviour. + if (status & llvm::APFloatBase::opInvalidOp) { + LLDB_LOGF(log, "Couldn't convert %s to %s", PrintScalar(S).c_str(), + PrintType(inst->getType()).c_str()); + error = lldb_private::Status::FromErrorString(bad_conversion_error); + return false; + } lldb_private::Scalar R(result); frame.AssignValue(inst, R, module); diff --git a/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py b/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py index 2163d045ef872..e86089178d50b 100644 --- a/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py +++ b/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py @@ -238,3 +238,34 @@ def test_fpconv(self): jit_result.GetTypeName(), "Types match for " + expression, ) + + def test_fpconv_ub(self): + target = self.dbg.GetDummyTarget() + + set_up_expressions = [ + "float $f = 3e9", + "double $d = 1e20", + "float $nf = -1.5", + ] + + expressions = [ + "(int)$f", + "(long)$d", + "(unsigned)$nf", + ] + + for expression in set_up_expressions: + target.EvaluateExpression(expression) + + # The IR Interpreter returns an error if a value cannot be converted. + for expression in expressions: + result = target.EvaluateExpression(expression) + self.assertIn( + "Interpreter couldn't convert a value", str(result.GetError()) + ) + + # The conversion should succeed if the destination type can represent the result. + self.expect_expr( + "(unsigned)$f", result_type="unsigned int", result_value="3000000000" + ) + self.expect_expr("(int)$nf", result_type="int", result_value="-1") _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
