Skip to content

Commit f395e48

Browse files
committed
[lldb][RISCV] Implement reading of aggregate return value
1 parent 50d65a5 commit f395e48

File tree

2 files changed

+118
-69
lines changed

2 files changed

+118
-69
lines changed

lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp

Lines changed: 118 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -490,9 +490,11 @@ static bool SetSizedFloat(Scalar &scalar, uint64_t raw_value,
490490
static ValueObjectSP GetValObjFromIntRegs(Thread &thread,
491491
const RegisterContextSP &reg_ctx,
492492
llvm::Triple::ArchType machine,
493-
uint32_t type_flags,
493+
const CompilerType &compiler_type,
494494
uint32_t byte_size) {
495495
Value value;
496+
value.SetCompilerType(compiler_type);
497+
496498
ValueObjectSP return_valobj_sp;
497499
auto reg_info_a0 =
498500
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
@@ -545,11 +547,11 @@ static ValueObjectSP GetValObjFromIntRegs(Thread &thread,
545547
return return_valobj_sp;
546548
}
547549

548-
if (type_flags & eTypeIsInteger) {
549-
const bool is_signed = (type_flags & eTypeIsSigned) != 0;
550+
if (compiler_type.IsInteger()) {
551+
const bool is_signed = compiler_type.IsSigned();
550552
if (!SetSizedInteger(value.GetScalar(), raw_value, byte_size, is_signed))
551553
return return_valobj_sp;
552-
} else if (type_flags & eTypeIsFloat) {
554+
} else if (compiler_type.IsFloat()) {
553555
if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size))
554556
return return_valobj_sp;
555557
} else
@@ -564,16 +566,16 @@ static ValueObjectSP GetValObjFromIntRegs(Thread &thread,
564566
static ValueObjectSP
565567
GetValObjFromFPRegs(Thread &thread, const RegisterContextSP &reg_ctx,
566568
llvm::Triple::ArchType machine, uint32_t arch_fp_flags,
567-
uint32_t type_flags, uint32_t byte_size) {
569+
CompilerType &compiler_type, uint32_t byte_size) {
568570
auto reg_info_fa0 = reg_ctx->GetRegisterInfoByName("fa0");
569571
bool use_fp_regs = false;
570572
ValueObjectSP return_valobj_sp;
571573

572574
switch (arch_fp_flags) {
573575
// fp return value in integer registers a0 and possibly a1
574576
case ArchSpec::eRISCV_float_abi_soft:
575-
return_valobj_sp =
576-
GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size);
577+
return_valobj_sp = GetValObjFromIntRegs(thread, reg_ctx, machine,
578+
compiler_type, byte_size);
577579
return return_valobj_sp;
578580
// fp return value in fp register fa0 (only float)
579581
case ArchSpec::eRISCV_float_abi_single:
@@ -602,7 +604,102 @@ GetValObjFromFPRegs(Thread &thread, const RegisterContextSP &reg_ctx,
602604
value, ConstString(""));
603605
}
604606
// we should never reach this, but if we do, use the integer registers
605-
return GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size);
607+
return GetValObjFromIntRegs(thread, reg_ctx, machine, compiler_type,
608+
byte_size);
609+
}
610+
611+
static DataExtractor CopyReturnValueToBuffer(ExecutionContext &exe_ctx,
612+
RegisterValue &a0_reg_value,
613+
RegisterValue &a1_reg_value,
614+
const size_t xlen_byte_size,
615+
const uint32_t byte_size) {
616+
617+
DataExtractor a0_extractor;
618+
DataExtractor a1_extractor;
619+
620+
// RISC-V ABI states:
621+
// "Aggregates whose total size is no more than XLEN bits
622+
// are passed in a register, with the fields laid out as though
623+
// they were passed in memory."
624+
if (byte_size <= xlen_byte_size) {
625+
// value is stored only in a0
626+
a0_reg_value.GetData(a0_extractor);
627+
// shrink data to the size of the return value
628+
return DataExtractor{a0_extractor, /*offset=*/0, byte_size};
629+
}
630+
631+
// "Aggregates whose total size is no more than 2×XLEN bits
632+
// are passed in a pair of registers;"
633+
if (byte_size <= 2 * xlen_byte_size) {
634+
// value is stored in a0 and a1 consecutively
635+
a0_reg_value.GetData(a0_extractor);
636+
a1_reg_value.GetData(a1_extractor);
637+
a0_extractor.Append(a1_extractor);
638+
// shrink data to the size of the return value
639+
return DataExtractor{a0_extractor, /*offset=*/0, byte_size};
640+
}
641+
642+
// "Aggregates larger than 2×XLEN bits are passed by reference
643+
// and are replaced in the argument list with the address"
644+
const lldb::addr_t value_addr =
645+
a1_reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS, nullptr);
646+
647+
if (value_addr == LLDB_INVALID_ADDRESS)
648+
return DataExtractor{};
649+
650+
Status error;
651+
WritableDataBufferSP data_sp(new DataBufferHeap(byte_size, 0));
652+
if (exe_ctx.GetProcessRef().ReadMemory(value_addr, data_sp->GetBytes(),
653+
byte_size, error) != byte_size ||
654+
error.Fail())
655+
return DataExtractor{};
656+
657+
DataExtractor data;
658+
data.SetData(data_sp);
659+
return data;
660+
}
661+
662+
static ValueObjectSP GetAggregateObj(Thread &thread, RegisterContextSP reg_ctx,
663+
const CompilerType &compiler_type,
664+
const size_t xlen_byte_size,
665+
const uint32_t byte_size) {
666+
const RegisterInfo *a0_reg_info =
667+
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
668+
669+
const RegisterInfo *a1_reg_info =
670+
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2);
671+
672+
if (!a0_reg_info || !a1_reg_info)
673+
return ValueObjectSP{};
674+
675+
RegisterValue a0_reg_value;
676+
RegisterValue a1_reg_value;
677+
678+
if (!reg_ctx->ReadRegister(a0_reg_info, a0_reg_value) ||
679+
!reg_ctx->ReadRegister(a1_reg_info, a1_reg_value))
680+
return ValueObjectSP{};
681+
682+
if (a0_reg_value.GetType() == RegisterValue::Type::eTypeInvalid ||
683+
a1_reg_value.GetType() == RegisterValue::Type::eTypeInvalid)
684+
return ValueObjectSP{};
685+
686+
ExecutionContext exe_ctx(thread.shared_from_this());
687+
DataExtractor data = CopyReturnValueToBuffer(
688+
exe_ctx, a0_reg_value, a1_reg_value, xlen_byte_size, byte_size);
689+
690+
if (data.GetByteSize() != byte_size)
691+
return ValueObjectSP{};
692+
693+
const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();
694+
const uint32_t address_byte_size =
695+
exe_ctx.GetProcessRef().GetAddressByteSize();
696+
data.SetByteOrder(byte_order);
697+
data.SetAddressByteSize(address_byte_size);
698+
699+
ValueObjectSP return_valobj_sp =
700+
ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),
701+
compiler_type, ConstString(""), data);
702+
return return_valobj_sp;
606703
}
607704

608705
ValueObjectSP
@@ -617,23 +714,21 @@ ABISysV_riscv::GetReturnValueObjectSimple(Thread &thread,
617714
if (!reg_ctx)
618715
return return_valobj_sp;
619716

620-
Value value;
621-
value.SetCompilerType(compiler_type);
622-
623-
const uint32_t type_flags = compiler_type.GetTypeInfo();
624717
const size_t byte_size =
625718
llvm::expectedToOptional(compiler_type.GetByteSize(&thread)).value_or(0);
626719
const ArchSpec arch = thread.GetProcess()->GetTarget().GetArchitecture();
627720
const llvm::Triple::ArchType machine = arch.GetMachine();
628721

629722
// Integer return type.
630-
if (type_flags & eTypeIsInteger) {
631-
return_valobj_sp =
632-
GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size);
723+
if (compiler_type.IsInteger()) {
724+
return_valobj_sp = GetValObjFromIntRegs(thread, reg_ctx, machine,
725+
compiler_type, byte_size);
633726
return return_valobj_sp;
634727
}
635728
// Pointer return type.
636-
else if (type_flags & eTypeIsPointer) {
729+
if (compiler_type.IsPointerType()) {
730+
Value value;
731+
value.SetCompilerType(compiler_type);
637732
auto reg_info_a0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,
638733
LLDB_REGNUM_GENERIC_ARG1);
639734
value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_a0, 0);
@@ -642,7 +737,7 @@ ABISysV_riscv::GetReturnValueObjectSimple(Thread &thread,
642737
value, ConstString(""));
643738
}
644739
// Floating point return type.
645-
else if (type_flags & eTypeIsFloat) {
740+
if (compiler_type.IsFloat()) {
646741
uint32_t float_count = 0;
647742
bool is_complex = false;
648743

@@ -651,58 +746,16 @@ ABISysV_riscv::GetReturnValueObjectSimple(Thread &thread,
651746
const uint32_t arch_fp_flags =
652747
arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask;
653748
return_valobj_sp = GetValObjFromFPRegs(
654-
thread, reg_ctx, machine, arch_fp_flags, type_flags, byte_size);
749+
thread, reg_ctx, machine, arch_fp_flags, compiler_type, byte_size);
655750
return return_valobj_sp;
656751
}
657752
}
658-
// Unsupported return type.
659-
return return_valobj_sp;
660-
}
661-
662-
ValueObjectSP
663-
ABISysV_riscv::GetReturnValueObjectImpl(lldb_private::Thread &thread,
664-
llvm::Type &type) const {
665-
Value value;
666-
ValueObjectSP return_valobj_sp;
667-
668-
auto reg_ctx = thread.GetRegisterContext();
669-
if (!reg_ctx)
670-
return return_valobj_sp;
671-
672-
uint32_t type_flags = 0;
673-
if (type.isIntegerTy())
674-
type_flags = eTypeIsInteger;
675-
else if (type.isVoidTy())
676-
type_flags = eTypeIsPointer;
677-
else if (type.isFloatTy())
678-
type_flags = eTypeIsFloat;
679-
680-
const uint32_t byte_size = type.getPrimitiveSizeInBits() / CHAR_BIT;
681-
const ArchSpec arch = thread.GetProcess()->GetTarget().GetArchitecture();
682-
const llvm::Triple::ArchType machine = arch.GetMachine();
753+
// Aggregate return type
754+
if (compiler_type.IsAggregateType()) {
755+
size_t xlen_byte_size = m_is_rv64 ? 8 : 4;
683756

684-
// Integer return type.
685-
if (type_flags & eTypeIsInteger) {
686-
return_valobj_sp =
687-
GetValObjFromIntRegs(thread, reg_ctx, machine, type_flags, byte_size);
688-
return return_valobj_sp;
689-
}
690-
// Pointer return type.
691-
else if (type_flags & eTypeIsPointer) {
692-
auto reg_info_a0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,
693-
LLDB_REGNUM_GENERIC_ARG1);
694-
value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_a0, 0);
695-
value.SetValueType(Value::ValueType::Scalar);
696-
return ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),
697-
value, ConstString(""));
698-
}
699-
// Floating point return type.
700-
else if (type_flags & eTypeIsFloat) {
701-
const uint32_t arch_fp_flags =
702-
arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask;
703-
return_valobj_sp = GetValObjFromFPRegs(
704-
thread, reg_ctx, machine, arch_fp_flags, type_flags, byte_size);
705-
return return_valobj_sp;
757+
return GetAggregateObj(thread, reg_ctx, compiler_type, xlen_byte_size,
758+
byte_size);
706759
}
707760
// Unsupported return type.
708761
return return_valobj_sp;

lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@ class ABISysV_riscv : public lldb_private::RegInfoBasedABI {
4747
GetReturnValueObjectImpl(lldb_private::Thread &thread,
4848
lldb_private::CompilerType &type) const override;
4949

50-
// Specialized to work with llvm IR types.
51-
lldb::ValueObjectSP GetReturnValueObjectImpl(lldb_private::Thread &thread,
52-
llvm::Type &type) const override;
53-
5450
lldb::UnwindPlanSP CreateFunctionEntryUnwindPlan() override;
5551

5652
lldb::UnwindPlanSP CreateDefaultUnwindPlan() override;

0 commit comments

Comments
 (0)