https://github.com/igorkudrin created https://github.com/llvm/llvm-project/pull/179022
This reapplies #175292 with the fixed test. The original test used integer types with different bit widths on different platforms. ----- Original message: This allows expressions that use these conversions to be executed when JIT is not available. >From 3094efbe089c08392d5e1a68df0a1a636a951e1f Mon Sep 17 00:00:00 2001 From: Igor Kudrin <[email protected]> Date: Fri, 30 Jan 2026 11:19:01 -0800 Subject: [PATCH] Reapply "[lldb] Add FP conversion instructions to IR interpreter" This reapplies #175292 with the fixed test. The original test used integer types with different bit widths on different platforms. ----- Original message: This allows expressions that use these conversions to be executed when JIT is not available. --- lldb/source/Expression/IRInterpreter.cpp | 86 ++++++++++++++ .../ir-interpreter/TestIRInterpreter.py | 109 ++++++++++++++++++ 2 files changed, 195 insertions(+) diff --git a/lldb/source/Expression/IRInterpreter.cpp b/lldb/source/Expression/IRInterpreter.cpp index 48b4dd67d2d89..5ca64843d5900 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) { @@ -1257,6 +1271,78 @@ 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; + 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) { + std::string s; + raw_string_ostream rso(s); + rso << "Conversion error: " << S << " cannot be converted to "; + if (inst->getOpcode() == Instruction::FPToUI) + rso << "unsigned "; + rso << *inst->getType(); + LLDB_LOGF(log, "%s", s.c_str()); + error = lldb_private::Status::FromErrorString(s.c_str()); + return false; + } + 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..800c591def7c8 100644 --- a/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py +++ b/lldb/test/API/commands/expression/ir-interpreter/TestIRInterpreter.py @@ -172,3 +172,112 @@ 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 = [ + "int32_t $i = 3", + "int32_t $n = -3", + "uint32_t $u = 5", + "int64_t $l = -7", + "float $f = 9.0625", + "double $d = 13.75", + "float $nf = -11.25", + ] + + expressions = [ + "$i + $f", # sitofp i32 to float + "$d - $n", # sitofp i32 to double + "$u + $f", # uitofp i32 to float + "$u + $d", # uitofp i32 to double + "(int32_t)$d", # fptosi double to i32 + "(int32_t)$f", # fptosi float to i32 + "(int64_t)$d", # fptosi double to i64 + "(int16_t)$f", # fptosi float to i16 + "(int64_t)$nf", # fptosi float to i64 + "(uint16_t)$f", # fptoui float to i16 + "(uint32_t)$d", # fptoui double to i32 + "(uint64_t)$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: + 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 + # Calling a function forces the expression to be executed with JIT. + 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, + ) + + def test_fpconv_ub(self): + target = self.dbg.GetDummyTarget() + + set_up_expressions = [ + "float $f = 3e9", + "double $d = 1e20", + "float $nf = -1.5", + ] + + expressions = [ + ( + "(int32_t)$f", + "Conversion error: (float) 3.0E+9 cannot be converted to i32", + ), + ( + "(uint32_t)$nf", + "Conversion error: (float) -1.5 cannot be converted to unsigned i32", + ), + ( + "(int64_t)$d", + "Conversion error: (float) 1.0E+20 cannot be converted to i64", + ), + ( + "(uint64_t)$d", + "Conversion error: (float) 1.0E+20 cannot be converted to unsigned i64", + ), + ] + + 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[0]) + self.assertIn(expression[1], str(result.GetError())) + + # The conversion should succeed if the destination type can represent the result. + self.expect_expr( + "(uint32_t)$f", result_type="uint32_t", result_value="3000000000" + ) + self.expect_expr("(int32_t)$nf", result_type="int32_t", result_value="-1") _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
