1//===-- Scalar.cpp --------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Utility/Scalar.h"
10#include "lldb/Utility/DataBufferHeap.h"
11#include "lldb/Utility/DataExtractor.h"
12#include "lldb/Utility/Endian.h"
13#include "lldb/Utility/Status.h"
14#include "lldb/Utility/Stream.h"
15#include "lldb/Utility/StreamString.h"
16#include "lldb/lldb-types.h"
17#include "llvm/ADT/APSInt.h"
18#include "llvm/ADT/SmallString.h"
19#include "llvm/ADT/StringExtras.h"
20
21#include <cinttypes>
22#include <cstdio>
23
24using namespace lldb;
25using namespace lldb_private;
26
27using llvm::APFloat;
28using llvm::APInt;
29using llvm::APSInt;
30
31Scalar::PromotionKey Scalar::GetPromoKey() const {
32 switch (m_type) {
33 case e_void:
34 return PromotionKey{e_void, 0, false};
35 case e_int:
36 return PromotionKey{e_int, m_integer.getBitWidth(), m_integer.isUnsigned()};
37 case e_float:
38 return GetFloatPromoKey(semantics: m_float.getSemantics());
39 }
40 llvm_unreachable("Unhandled category!");
41}
42
43Scalar::PromotionKey Scalar::GetFloatPromoKey(const llvm::fltSemantics &sem) {
44 static const llvm::fltSemantics *const order[] = {
45 &APFloat::IEEEsingle(), &APFloat::IEEEdouble(),
46 &APFloat::x87DoubleExtended()};
47 for (const auto &entry : llvm::enumerate(First: order)) {
48 if (entry.value() == &sem)
49 return PromotionKey{e_float, entry.index(), false};
50 }
51 llvm_unreachable("Unsupported semantics!");
52}
53
54// Promote to max type currently follows the ANSI C rule for type promotion in
55// expressions.
56Scalar::Type Scalar::PromoteToMaxType(Scalar &lhs, Scalar &rhs) {
57 const auto &Promote = [](Scalar &a, const Scalar &b) {
58 switch (b.GetType()) {
59 case e_void:
60 break;
61 case e_int:
62 a.IntegralPromote(bits: b.m_integer.getBitWidth(), sign: b.m_integer.isSigned());
63 break;
64 case e_float:
65 a.FloatPromote(semantics: b.m_float.getSemantics());
66 }
67 };
68
69 PromotionKey lhs_key = lhs.GetPromoKey();
70 PromotionKey rhs_key = rhs.GetPromoKey();
71
72 if (lhs_key > rhs_key)
73 Promote(rhs, lhs);
74 else if (rhs_key > lhs_key)
75 Promote(lhs, rhs);
76
77 // Make sure our type promotion worked as expected
78 if (lhs.GetPromoKey() == rhs.GetPromoKey())
79 return lhs.GetType(); // Return the resulting type
80
81 // Return the void type (zero) if we fail to promote either of the values.
82 return Scalar::e_void;
83}
84
85bool Scalar::GetData(DataExtractor &data, size_t limit_byte_size) const {
86 size_t byte_size = GetByteSize();
87 if (byte_size == 0) {
88 data.Clear();
89 return false;
90 }
91 auto buffer_up = std::make_unique<DataBufferHeap>(args&: byte_size, args: 0);
92 GetBytes(storage: buffer_up->GetData());
93 lldb::offset_t offset = 0;
94
95 if (limit_byte_size < byte_size) {
96 if (endian::InlHostByteOrder() == eByteOrderLittle) {
97 // On little endian systems if we want fewer bytes from the current
98 // type we just specify fewer bytes since the LSByte is first...
99 byte_size = limit_byte_size;
100 } else if (endian::InlHostByteOrder() == eByteOrderBig) {
101 // On big endian systems if we want fewer bytes from the current type
102 // have to advance our initial byte pointer and trim down the number of
103 // bytes since the MSByte is first
104 offset = byte_size - limit_byte_size;
105 byte_size = limit_byte_size;
106 }
107 }
108
109 data.SetData(data_sp: std::move(buffer_up), offset, length: byte_size);
110 data.SetByteOrder(endian::InlHostByteOrder());
111 return true;
112}
113
114void Scalar::GetBytes(llvm::MutableArrayRef<uint8_t> storage) const {
115 assert(storage.size() >= GetByteSize());
116
117 const auto &store = [&](const llvm::APInt &val) {
118 StoreIntToMemory(IntVal: val, Dst: storage.data(), StoreBytes: (val.getBitWidth() + 7) / 8);
119 };
120 switch (m_type) {
121 case e_void:
122 break;
123 case e_int:
124 store(m_integer);
125 break;
126 case e_float:
127 store(m_float.bitcastToAPInt());
128 break;
129 }
130}
131
132size_t Scalar::GetByteSize() const {
133 switch (m_type) {
134 case e_void:
135 break;
136 case e_int:
137 return (m_integer.getBitWidth() / 8);
138 case e_float:
139 return m_float.bitcastToAPInt().getBitWidth() / 8;
140 }
141 return 0;
142}
143
144bool Scalar::IsZero() const {
145 switch (m_type) {
146 case e_void:
147 break;
148 case e_int:
149 return m_integer.isZero();
150 case e_float:
151 return m_float.isZero();
152 }
153 return false;
154}
155
156void Scalar::GetValue(Stream &s, bool show_type) const {
157 if (show_type)
158 s.Printf(format: "(%s) ", GetTypeAsCString());
159
160 switch (m_type) {
161 case e_void:
162 break;
163 case e_int:
164 s.PutCString(cstr: llvm::toString(I: m_integer, Radix: 10));
165 break;
166 case e_float:
167 llvm::SmallString<24> string;
168 m_float.toString(Str&: string);
169 s.PutCString(cstr: string);
170 break;
171 }
172}
173
174void Scalar::TruncOrExtendTo(uint16_t bits, bool sign) {
175 m_integer.setIsSigned(sign);
176 m_integer = m_integer.extOrTrunc(width: bits);
177}
178
179bool Scalar::IntegralPromote(uint16_t bits, bool sign) {
180 switch (m_type) {
181 case e_void:
182 case e_float:
183 break;
184 case e_int:
185 if (GetPromoKey() > PromotionKey(e_int, bits, !sign))
186 break;
187 m_integer = m_integer.extOrTrunc(width: bits);
188 m_integer.setIsSigned(sign);
189 return true;
190 }
191 return false;
192}
193
194bool Scalar::FloatPromote(const llvm::fltSemantics &semantics) {
195 bool success = false;
196 switch (m_type) {
197 case e_void:
198 break;
199 case e_int:
200 m_float = llvm::APFloat(semantics);
201 m_float.convertFromAPInt(Input: m_integer, IsSigned: m_integer.isSigned(),
202 RM: llvm::APFloat::rmNearestTiesToEven);
203 success = true;
204 break;
205 case e_float:
206 if (GetFloatPromoKey(sem: semantics) < GetFloatPromoKey(sem: m_float.getSemantics()))
207 break;
208 bool ignore;
209 success = true;
210 m_float.convert(ToSemantics: semantics, RM: llvm::APFloat::rmNearestTiesToEven, losesInfo: &ignore);
211 }
212
213 if (success)
214 m_type = e_float;
215 return success;
216}
217
218const char *Scalar::GetValueTypeAsCString(Scalar::Type type) {
219 switch (type) {
220 case e_void:
221 return "void";
222 case e_int:
223 return "int";
224 case e_float:
225 return "float";
226 }
227 return "???";
228}
229
230bool Scalar::IsSigned() const {
231 switch (m_type) {
232 case e_void:
233 return false;
234 case e_int:
235 return m_integer.isSigned();
236 case e_float:
237 return true;
238 }
239 llvm_unreachable("Unrecognized type!");
240}
241
242bool Scalar::MakeSigned() {
243 bool success = false;
244
245 switch (m_type) {
246 case e_void:
247 break;
248 case e_int:
249 m_integer.setIsSigned(true);
250 success = true;
251 break;
252 case e_float:
253 success = true;
254 break;
255 }
256
257 return success;
258}
259
260bool Scalar::MakeUnsigned() {
261 bool success = false;
262
263 switch (m_type) {
264 case e_void:
265 break;
266 case e_int:
267 m_integer.setIsUnsigned(true);
268 success = true;
269 break;
270 case e_float:
271 success = true;
272 break;
273 }
274
275 return success;
276}
277
278static llvm::APInt ToAPInt(const llvm::APFloat &f, unsigned bits,
279 bool is_unsigned) {
280 llvm::APSInt result(bits, is_unsigned);
281 bool isExact;
282 f.convertToInteger(Result&: result, RM: llvm::APFloat::rmTowardZero, IsExact: &isExact);
283 return std::move(result);
284}
285
286template <typename T> T Scalar::GetAs(T fail_value) const {
287 switch (m_type) {
288 case e_void:
289 break;
290 case e_int: {
291 APSInt ext = m_integer.extOrTrunc(width: sizeof(T) * 8);
292 if (ext.isSigned())
293 return ext.getSExtValue();
294 return ext.getZExtValue();
295 }
296 case e_float:
297 return ToAPInt(m_float, sizeof(T) * 8, std::is_unsigned<T>::value)
298 .getSExtValue();
299 }
300 return fail_value;
301}
302
303signed char Scalar::SChar(signed char fail_value) const {
304 return GetAs<signed char>(fail_value);
305}
306
307unsigned char Scalar::UChar(unsigned char fail_value) const {
308 return GetAs<unsigned char>(fail_value);
309}
310
311short Scalar::SShort(short fail_value) const {
312 return GetAs<short>(fail_value);
313}
314
315unsigned short Scalar::UShort(unsigned short fail_value) const {
316 return GetAs<unsigned short>(fail_value);
317}
318
319int Scalar::SInt(int fail_value) const { return GetAs<int>(fail_value); }
320
321unsigned int Scalar::UInt(unsigned int fail_value) const {
322 return GetAs<unsigned int>(fail_value);
323}
324
325long Scalar::SLong(long fail_value) const { return GetAs<long>(fail_value); }
326
327unsigned long Scalar::ULong(unsigned long fail_value) const {
328 return GetAs<unsigned long>(fail_value);
329}
330
331long long Scalar::SLongLong(long long fail_value) const {
332 return GetAs<long long>(fail_value);
333}
334
335unsigned long long Scalar::ULongLong(unsigned long long fail_value) const {
336 return GetAs<unsigned long long>(fail_value);
337}
338
339llvm::APInt Scalar::SInt128(const llvm::APInt &fail_value) const {
340 switch (m_type) {
341 case e_void:
342 break;
343 case e_int:
344 return m_integer;
345 case e_float:
346 return ToAPInt(f: m_float, bits: 128, /*is_unsigned=*/false);
347 }
348 return fail_value;
349}
350
351llvm::APInt Scalar::UInt128(const llvm::APInt &fail_value) const {
352 switch (m_type) {
353 case e_void:
354 break;
355 case e_int:
356 return m_integer;
357 case e_float:
358 return ToAPInt(f: m_float, bits: 128, /*is_unsigned=*/true);
359 }
360 return fail_value;
361}
362
363float Scalar::Float(float fail_value) const {
364 switch (m_type) {
365 case e_void:
366 break;
367 case e_int:
368 if (m_integer.isSigned())
369 return llvm::APIntOps::RoundSignedAPIntToFloat(APIVal: m_integer);
370 return llvm::APIntOps::RoundAPIntToFloat(APIVal: m_integer);
371
372 case e_float: {
373 APFloat result = m_float;
374 bool losesInfo;
375 result.convert(ToSemantics: APFloat::IEEEsingle(), RM: APFloat::rmNearestTiesToEven,
376 losesInfo: &losesInfo);
377 return result.convertToFloat();
378 }
379 }
380 return fail_value;
381}
382
383double Scalar::Double(double fail_value) const {
384 switch (m_type) {
385 case e_void:
386 break;
387 case e_int:
388 if (m_integer.isSigned())
389 return llvm::APIntOps::RoundSignedAPIntToDouble(APIVal: m_integer);
390 return llvm::APIntOps::RoundAPIntToDouble(APIVal: m_integer);
391
392 case e_float: {
393 APFloat result = m_float;
394 bool losesInfo;
395 result.convert(ToSemantics: APFloat::IEEEdouble(), RM: APFloat::rmNearestTiesToEven,
396 losesInfo: &losesInfo);
397 return result.convertToDouble();
398 }
399 }
400 return fail_value;
401}
402
403long double Scalar::LongDouble(long double fail_value) const {
404 /// No way to get more precision at the moment.
405 return static_cast<long double>(Double(fail_value));
406}
407
408Scalar &Scalar::operator+=(Scalar rhs) {
409 Scalar copy = *this;
410 if ((m_type = PromoteToMaxType(lhs&: copy, rhs)) != Scalar::e_void) {
411 switch (m_type) {
412 case e_void:
413 break;
414 case e_int:
415 m_integer = copy.m_integer + rhs.m_integer;
416 break;
417
418 case e_float:
419 m_float = copy.m_float + rhs.m_float;
420 break;
421 }
422 }
423 return *this;
424}
425
426Scalar &Scalar::operator<<=(const Scalar &rhs) {
427 if (m_type == e_int && rhs.m_type == e_int)
428 static_cast<APInt &>(m_integer) <<= rhs.m_integer;
429 else
430 m_type = e_void;
431 return *this;
432}
433
434bool Scalar::ShiftRightLogical(const Scalar &rhs) {
435 if (m_type == e_int && rhs.m_type == e_int) {
436 m_integer = m_integer.lshr(ShiftAmt: rhs.m_integer);
437 return true;
438 }
439 m_type = e_void;
440 return false;
441}
442
443Scalar &Scalar::operator>>=(const Scalar &rhs) {
444 switch (m_type) {
445 case e_void:
446 case e_float:
447 m_type = e_void;
448 break;
449
450 case e_int:
451 switch (rhs.m_type) {
452 case e_void:
453 case e_float:
454 m_type = e_void;
455 break;
456 case e_int:
457 m_integer = m_integer.ashr(ShiftAmt: rhs.m_integer);
458 break;
459 }
460 break;
461 }
462 return *this;
463}
464
465Scalar &Scalar::operator&=(const Scalar &rhs) {
466 if (m_type == e_int && rhs.m_type == e_int)
467 m_integer &= rhs.m_integer;
468 else
469 m_type = e_void;
470 return *this;
471}
472
473bool Scalar::AbsoluteValue() {
474 switch (m_type) {
475 case e_void:
476 break;
477
478 case e_int:
479 if (m_integer.isNegative())
480 m_integer = -m_integer;
481 return true;
482
483 case e_float:
484 m_float.clearSign();
485 return true;
486 }
487 return false;
488}
489
490bool Scalar::UnaryNegate() {
491 switch (m_type) {
492 case e_void:
493 break;
494 case e_int:
495 m_integer = -m_integer;
496 return true;
497 case e_float:
498 m_float.changeSign();
499 return true;
500 }
501 return false;
502}
503
504bool Scalar::OnesComplement() {
505 if (m_type == e_int) {
506 m_integer = ~m_integer;
507 return true;
508 }
509
510 return false;
511}
512
513const Scalar lldb_private::operator+(const Scalar &lhs, const Scalar &rhs) {
514 Scalar result = lhs;
515 result += rhs;
516 return result;
517}
518
519const Scalar lldb_private::operator-(Scalar lhs, Scalar rhs) {
520 Scalar result;
521 if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) {
522 switch (result.m_type) {
523 case Scalar::e_void:
524 break;
525 case Scalar::e_int:
526 result.m_integer = lhs.m_integer - rhs.m_integer;
527 break;
528 case Scalar::e_float:
529 result.m_float = lhs.m_float - rhs.m_float;
530 break;
531 }
532 }
533 return result;
534}
535
536const Scalar lldb_private::operator/(Scalar lhs, Scalar rhs) {
537 Scalar result;
538 if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void &&
539 !rhs.IsZero()) {
540 switch (result.m_type) {
541 case Scalar::e_void:
542 break;
543 case Scalar::e_int:
544 result.m_integer = lhs.m_integer / rhs.m_integer;
545 return result;
546 case Scalar::e_float:
547 result.m_float = lhs.m_float / rhs.m_float;
548 return result;
549 }
550 }
551 // For division only, the only way it should make it here is if a promotion
552 // failed, or if we are trying to do a divide by zero.
553 result.m_type = Scalar::e_void;
554 return result;
555}
556
557const Scalar lldb_private::operator*(Scalar lhs, Scalar rhs) {
558 Scalar result;
559 if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) {
560 switch (result.m_type) {
561 case Scalar::e_void:
562 break;
563 case Scalar::e_int:
564 result.m_integer = lhs.m_integer * rhs.m_integer;
565 break;
566 case Scalar::e_float:
567 result.m_float = lhs.m_float * rhs.m_float;
568 break;
569 }
570 }
571 return result;
572}
573
574const Scalar lldb_private::operator&(Scalar lhs, Scalar rhs) {
575 Scalar result;
576 if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) {
577 if (result.m_type == Scalar::e_int)
578 result.m_integer = lhs.m_integer & rhs.m_integer;
579 else
580 result.m_type = Scalar::e_void;
581 }
582 return result;
583}
584
585const Scalar lldb_private::operator|(Scalar lhs, Scalar rhs) {
586 Scalar result;
587 if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) {
588 if (result.m_type == Scalar::e_int)
589 result.m_integer = lhs.m_integer | rhs.m_integer;
590 else
591 result.m_type = Scalar::e_void;
592 }
593 return result;
594}
595
596const Scalar lldb_private::operator%(Scalar lhs, Scalar rhs) {
597 Scalar result;
598 if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) {
599 if (!rhs.IsZero() && result.m_type == Scalar::e_int) {
600 result.m_integer = lhs.m_integer % rhs.m_integer;
601 return result;
602 }
603 }
604 result.m_type = Scalar::e_void;
605 return result;
606}
607
608const Scalar lldb_private::operator^(Scalar lhs, Scalar rhs) {
609 Scalar result;
610 if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) {
611 if (result.m_type == Scalar::e_int)
612 result.m_integer = lhs.m_integer ^ rhs.m_integer;
613 else
614 result.m_type = Scalar::e_void;
615 }
616 return result;
617}
618
619const Scalar lldb_private::operator<<(const Scalar &lhs, const Scalar &rhs) {
620 Scalar result = lhs;
621 result <<= rhs;
622 return result;
623}
624
625const Scalar lldb_private::operator>>(const Scalar &lhs, const Scalar &rhs) {
626 Scalar result = lhs;
627 result >>= rhs;
628 return result;
629}
630
631Status Scalar::SetValueFromCString(const char *value_str, Encoding encoding,
632 size_t byte_size) {
633 Status error;
634 if (value_str == nullptr || value_str[0] == '\0') {
635 error.SetErrorString("Invalid c-string value string.");
636 return error;
637 }
638 switch (encoding) {
639 case eEncodingInvalid:
640 error.SetErrorString("Invalid encoding.");
641 break;
642
643 case eEncodingSint:
644 case eEncodingUint: {
645 llvm::StringRef str = value_str;
646 bool is_signed = encoding == eEncodingSint;
647 bool is_negative = is_signed && str.consume_front(Prefix: "-");
648 APInt integer;
649 if (str.getAsInteger(Radix: 0, Result&: integer)) {
650 error.SetErrorStringWithFormatv(
651 format: "'{0}' is not a valid integer string value", args&: value_str);
652 break;
653 }
654 bool fits;
655 if (is_signed) {
656 integer = integer.zext(width: integer.getBitWidth() + 1);
657 if (is_negative)
658 integer.negate();
659 fits = integer.isSignedIntN(N: byte_size * 8);
660 } else
661 fits = integer.isIntN(N: byte_size * 8);
662 if (!fits) {
663 error.SetErrorStringWithFormatv(
664 format: "value {0} is too large to fit in a {1} byte integer value",
665 args&: value_str, args&: byte_size);
666 break;
667 }
668 m_type = e_int;
669 m_integer =
670 APSInt(std::move(integer), !is_signed).extOrTrunc(width: 8 * byte_size);
671 break;
672 }
673
674 case eEncodingIEEE754: {
675 // FIXME: It's not possible to unambiguously map a byte size to a floating
676 // point type. This function should be refactored to take an explicit
677 // semantics argument.
678 const llvm::fltSemantics &sem =
679 byte_size <= 4 ? APFloat::IEEEsingle()
680 : byte_size <= 8 ? APFloat::IEEEdouble()
681 : APFloat::x87DoubleExtended();
682 APFloat f(sem);
683 if (llvm::Expected<APFloat::opStatus> op =
684 f.convertFromString(value_str, APFloat::rmNearestTiesToEven)) {
685 m_type = e_float;
686 m_float = std::move(f);
687 } else
688 error = op.takeError();
689 break;
690 }
691
692 case eEncodingVector:
693 error.SetErrorString("vector encoding unsupported.");
694 break;
695 }
696 if (error.Fail())
697 m_type = e_void;
698
699 return error;
700}
701
702Status Scalar::SetValueFromData(const DataExtractor &data,
703 lldb::Encoding encoding, size_t byte_size) {
704 Status error;
705 switch (encoding) {
706 case lldb::eEncodingInvalid:
707 error.SetErrorString("invalid encoding");
708 break;
709 case lldb::eEncodingVector:
710 error.SetErrorString("vector encoding unsupported");
711 break;
712 case lldb::eEncodingUint:
713 case lldb::eEncodingSint: {
714 if (data.GetByteSize() < byte_size)
715 return Status("insufficient data");
716 m_type = e_int;
717 m_integer =
718 APSInt(APInt::getZero(numBits: 8 * byte_size), encoding == eEncodingUint);
719 if (data.GetByteOrder() == endian::InlHostByteOrder()) {
720 llvm::LoadIntFromMemory(IntVal&: m_integer, Src: data.GetDataStart(), LoadBytes: byte_size);
721 } else {
722 std::vector<uint8_t> buffer(byte_size);
723 std::copy_n(first: data.GetDataStart(), n: byte_size, result: buffer.rbegin());
724 llvm::LoadIntFromMemory(IntVal&: m_integer, Src: buffer.data(), LoadBytes: byte_size);
725 }
726 break;
727 }
728 case lldb::eEncodingIEEE754: {
729 lldb::offset_t offset = 0;
730
731 if (byte_size == sizeof(float))
732 operator=(data.GetFloat(offset_ptr: &offset));
733 else if (byte_size == sizeof(double))
734 operator=(data.GetDouble(offset_ptr: &offset));
735 else if (byte_size == sizeof(long double))
736 operator=(data.GetLongDouble(offset_ptr: &offset));
737 else
738 error.SetErrorStringWithFormat("unsupported float byte size: %" PRIu64 "",
739 static_cast<uint64_t>(byte_size));
740 } break;
741 }
742
743 return error;
744}
745
746bool Scalar::SignExtend(uint32_t sign_bit_pos) {
747 const uint32_t max_bit_pos = GetByteSize() * 8;
748
749 if (sign_bit_pos < max_bit_pos) {
750 switch (m_type) {
751 case Scalar::e_void:
752 case Scalar::e_float:
753 return false;
754
755 case Scalar::e_int:
756 if (max_bit_pos == sign_bit_pos)
757 return true;
758 else if (sign_bit_pos < (max_bit_pos - 1)) {
759 llvm::APInt sign_bit = llvm::APInt::getSignMask(BitWidth: sign_bit_pos + 1);
760 llvm::APInt bitwize_and = m_integer & sign_bit;
761 if (bitwize_and.getBoolValue()) {
762 llvm::APInt mask =
763 ~(sign_bit) + llvm::APInt(m_integer.getBitWidth(), 1);
764 m_integer |= APSInt(std::move(mask), m_integer.isUnsigned());
765 }
766 return true;
767 }
768 break;
769 }
770 }
771 return false;
772}
773
774size_t Scalar::GetAsMemoryData(void *dst, size_t dst_len,
775 lldb::ByteOrder dst_byte_order,
776 Status &error) const {
777 // Get a data extractor that points to the native scalar data
778 DataExtractor data;
779 if (!GetData(data)) {
780 error.SetErrorString("invalid scalar value");
781 return 0;
782 }
783
784 const size_t src_len = data.GetByteSize();
785
786 // Prepare a memory buffer that contains some or all of the register value
787 const size_t bytes_copied =
788 data.CopyByteOrderedData(src_offset: 0, // src offset
789 src_len, // src length
790 dst, // dst buffer
791 dst_len, // dst length
792 dst_byte_order); // dst byte order
793 if (bytes_copied == 0)
794 error.SetErrorString("failed to copy data");
795
796 return bytes_copied;
797}
798
799bool Scalar::ExtractBitfield(uint32_t bit_size, uint32_t bit_offset) {
800 if (bit_size == 0)
801 return true;
802
803 switch (m_type) {
804 case Scalar::e_void:
805 case Scalar::e_float:
806 break;
807
808 case Scalar::e_int:
809 m_integer >>= bit_offset;
810 m_integer = m_integer.extOrTrunc(width: bit_size).extOrTrunc(width: 8 * GetByteSize());
811 return true;
812 }
813 return false;
814}
815
816bool lldb_private::operator==(Scalar lhs, Scalar rhs) {
817 // If either entry is void then we can just compare the types
818 if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
819 return lhs.m_type == rhs.m_type;
820
821 llvm::APFloat::cmpResult result;
822 switch (Scalar::PromoteToMaxType(lhs, rhs)) {
823 case Scalar::e_void:
824 break;
825 case Scalar::e_int:
826 return lhs.m_integer == rhs.m_integer;
827 case Scalar::e_float:
828 result = lhs.m_float.compare(RHS: rhs.m_float);
829 if (result == llvm::APFloat::cmpEqual)
830 return true;
831 }
832 return false;
833}
834
835bool lldb_private::operator!=(const Scalar &lhs, const Scalar &rhs) {
836 return !(lhs == rhs);
837}
838
839bool lldb_private::operator<(Scalar lhs, Scalar rhs) {
840 if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
841 return false;
842
843 llvm::APFloat::cmpResult result;
844 switch (Scalar::PromoteToMaxType(lhs, rhs)) {
845 case Scalar::e_void:
846 break;
847 case Scalar::e_int:
848 return lhs.m_integer < rhs.m_integer;
849 case Scalar::e_float:
850 result = lhs.m_float.compare(RHS: rhs.m_float);
851 if (result == llvm::APFloat::cmpLessThan)
852 return true;
853 }
854 return false;
855}
856
857bool lldb_private::operator<=(const Scalar &lhs, const Scalar &rhs) {
858 return !(rhs < lhs);
859}
860
861bool lldb_private::operator>(const Scalar &lhs, const Scalar &rhs) {
862 return rhs < lhs;
863}
864
865bool lldb_private::operator>=(const Scalar &lhs, const Scalar &rhs) {
866 return !(lhs < rhs);
867}
868
869bool Scalar::ClearBit(uint32_t bit) {
870 switch (m_type) {
871 case e_void:
872 break;
873 case e_int:
874 m_integer.clearBit(BitPosition: bit);
875 return true;
876 case e_float:
877 break;
878 }
879 return false;
880}
881
882bool Scalar::SetBit(uint32_t bit) {
883 switch (m_type) {
884 case e_void:
885 break;
886 case e_int:
887 m_integer.setBit(bit);
888 return true;
889 case e_float:
890 break;
891 }
892 return false;
893}
894
895llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &os, const Scalar &scalar) {
896 StreamString s;
897 scalar.GetValue(s, /*show_type*/ true);
898 return os << s.GetString();
899}
900

source code of lldb/source/Utility/Scalar.cpp