1//===-- ubsan_value.cc ----------------------------------------------------===//
2//
3// This file is distributed under the University of Illinois Open Source
4// License. See LICENSE.TXT for details.
5//
6//===----------------------------------------------------------------------===//
7//
8// Representation of a runtime value, as marshaled from the generated code to
9// the ubsan runtime.
10//
11//===----------------------------------------------------------------------===//
12
13#include "ubsan_platform.h"
14#if CAN_SANITIZE_UB
15#include "ubsan_value.h"
16#include "sanitizer_common/sanitizer_common.h"
17#include "sanitizer_common/sanitizer_libc.h"
18
19using namespace __ubsan;
20
21SIntMax Value::getSIntValue() const {
22  CHECK(getType().isSignedIntegerTy());
23  if (isInlineInt()) {
24    // Val was zero-extended to ValueHandle. Sign-extend from original width
25    // to SIntMax.
26    const unsigned ExtraBits =
27      sizeof(SIntMax) * 8 - getType().getIntegerBitWidth();
28    return SIntMax(Val) << ExtraBits >> ExtraBits;
29  }
30  if (getType().getIntegerBitWidth() == 64)
31    return *reinterpret_cast<s64*>(Val);
32#if HAVE_INT128_T
33  if (getType().getIntegerBitWidth() == 128)
34    return *reinterpret_cast<s128*>(Val);
35#else
36  if (getType().getIntegerBitWidth() == 128)
37    UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
38#endif
39  UNREACHABLE("unexpected bit width");
40}
41
42UIntMax Value::getUIntValue() const {
43  CHECK(getType().isUnsignedIntegerTy());
44  if (isInlineInt())
45    return Val;
46  if (getType().getIntegerBitWidth() == 64)
47    return *reinterpret_cast<u64*>(Val);
48#if HAVE_INT128_T
49  if (getType().getIntegerBitWidth() == 128)
50    return *reinterpret_cast<u128*>(Val);
51#else
52  if (getType().getIntegerBitWidth() == 128)
53    UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
54#endif
55  UNREACHABLE("unexpected bit width");
56}
57
58UIntMax Value::getPositiveIntValue() const {
59  if (getType().isUnsignedIntegerTy())
60    return getUIntValue();
61  SIntMax Val = getSIntValue();
62  CHECK(Val >= 0);
63  return Val;
64}
65
66/// Get the floating-point value of this object, extended to a long double.
67/// These are always passed by address (our calling convention doesn't allow
68/// them to be passed in floating-point registers, so this has little cost).
69FloatMax Value::getFloatValue() const {
70  CHECK(getType().isFloatTy());
71  if (isInlineFloat()) {
72    switch (getType().getFloatBitWidth()) {
73#if 0
74      // FIXME: OpenCL / NEON 'half' type. LLVM can't lower the conversion
75      //        from '__fp16' to 'long double'.
76      case 16: {
77        __fp16 Value;
78        internal_memcpy(&Value, &Val, 4);
79        return Value;
80      }
81#endif
82      case 32: {
83        float Value;
84#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
85       // For big endian the float value is in the last 4 bytes.
86       // On some targets we may only have 4 bytes so we count backwards from
87       // the end of Val to account for both the 32-bit and 64-bit cases.
88       internal_memcpy(&Value, ((const char*)(&Val + 1)) - 4, 4);
89#else
90       internal_memcpy(&Value, &Val, 4);
91#endif
92        return Value;
93      }
94      case 64: {
95        double Value;
96        internal_memcpy(&Value, &Val, 8);
97        return Value;
98      }
99    }
100  } else {
101    switch (getType().getFloatBitWidth()) {
102    case 64: return *reinterpret_cast<double*>(Val);
103    case 80: return *reinterpret_cast<long double*>(Val);
104    case 96: return *reinterpret_cast<long double*>(Val);
105    case 128: return *reinterpret_cast<long double*>(Val);
106    }
107  }
108  UNREACHABLE("unexpected floating point bit width");
109}
110
111#endif  // CAN_SANITIZE_UB
112