<commit_before>//===- seec/Trace/RuntimeValue.hpp ---------------------------------- C++ -===//
//
//                                    SeeC
//
// This file is distributed under The MIT License (MIT). See LICENSE.TXT for
// details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
//===----------------------------------------------------------------------===//

#ifndef SEEC_TRACE_RUNTIMEVALUE_HPP
#define SEEC_TRACE_RUNTIMEVALUE_HPP

#include "seec/Trace/TraceFormat.hpp"

#include "llvm/IR/DerivedTypes.h"
#include "llvm/ADT/APInt.h"

#include <cstdint>
#include <limits>

namespace seec {

namespace trace {

class RuntimeValue {
  offset_uint RecordOffset;

  RuntimeValueRecord Data;

public:
  RuntimeValue()
  : RecordOffset(seec::trace::noOffset()),
    Data()
  {}

  offset_uint getRecordOffset() const { return RecordOffset; }

  bool assigned() const { return RecordOffset != seec::trace::noOffset(); }
  
  void set(offset_uint Offset, RuntimeValueRecord Value) {
    RecordOffset = Offset;
    Data = Value;
  }
  
  void clear() { RecordOffset = seec::trace::noOffset(); }

  // set for integral values
  template<typename T>
  void set(offset_uint Offset,
           T&& Value,
           // dummy parameter to enable only for integers
            typename std::enable_if<
              std::is_integral<
                typename std::remove_reference<T>::type
              >::value
            >::type *Dummy = nullptr
           ) {
    RecordOffset = Offset;
    Data.UInt64 = static_cast<uint64_t>(Value);
  }
  
  void set(offset_uint Offset, uintptr_t Value) {
    RecordOffset = Offset;
    Data.UIntPtr = Value;
  }

  void set(offset_uint Offset, float Value) {
    RecordOffset = Offset;
    Data.Float = Value;
  }

  void set(offset_uint Offset, double Value) {
    RecordOffset = Offset;
    Data.Double = Value;
  }
  
  void set(offset_uint Offset, long double Value) {
    RecordOffset = Offset;
    Data.LongDouble = Value;
  }
  
  llvm::APInt getAPInt(llvm::IntegerType *Type, bool isSigned = false) const {
    auto BitWidth = Type->getBitWidth();
    
    assert(BitWidth <= 64 && "Can't get int with more than 64 bits.");
    
    uint64_t Value = Data.UInt64;
    
    // If they want a signed value, and it appears that the run-time value
    // would have been negative, then fill the extra bits in the uint64_t
    // with 1s (as though it were an int64_t).
    if (isSigned && (Value & Type->getSignBit())) {
      uint64_t BitMask = Type->getBitMask();
      Value |= ~BitMask;
    }
    
    return llvm::APInt(BitWidth, Value, isSigned);
  }
  
  decltype(Data) const &getData() const { return Data; }
  
  uint64_t getUInt64() const { return Data.UInt64; }
  
  uintptr_t getUIntPtr() const { return Data.UIntPtr; }

  float getFloat() const { return Data.Float; }

  double getDouble() const { return Data.Double; }
  
  long double getLongDouble() const { return Data.LongDouble; }
};

template<typename T, typename Enable = void>
struct GetAsImpl; // do not implement

// Specialization to get signed integer types.
template<typename T><commit_msg>Add RuntimeValue methods to retrieve APFloat or APSInt.<commit_after>//===- seec/Trace/RuntimeValue.hpp ---------------------------------- C++ -===//
//
//                                    SeeC
//
// This file is distributed under The MIT License (MIT). See LICENSE.TXT for
// details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
//===----------------------------------------------------------------------===//

#ifndef SEEC_TRACE_RUNTIMEVALUE_HPP
#define SEEC_TRACE_RUNTIMEVALUE_HPP

#include "seec/Trace/TraceFormat.hpp"

#include "llvm/IR/DerivedTypes.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/Support/ErrorHandling.h"

#include <cstdint>
#include <cfloat>
#include <limits>

namespace seec {

namespace trace {

class RuntimeValue {
  offset_uint RecordOffset;

  RuntimeValueRecord Data;

public:
  RuntimeValue()
  : RecordOffset(seec::trace::noOffset()),
    Data()
  {}

  offset_uint getRecordOffset() const { return RecordOffset; }

  bool assigned() const { return RecordOffset != seec::trace::noOffset(); }
  
  void set(offset_uint Offset, RuntimeValueRecord Value) {
    RecordOffset = Offset;
    Data = Value;
  }
  
  void clear() { RecordOffset = seec::trace::noOffset(); }

  // set for integral values
  template<typename T>
  void set(offset_uint Offset,
           T&& Value,
           // dummy parameter to enable only for integers
            typename std::enable_if<
              std::is_integral<
                typename std::remove_reference<T>::type
              >::value
            >::type *Dummy = nullptr
           ) {
    RecordOffset = Offset;
    Data.UInt64 = static_cast<uint64_t>(Value);
  }
  
  void set(offset_uint Offset, uintptr_t Value) {
    RecordOffset = Offset;
    Data.UIntPtr = Value;
  }

  void set(offset_uint Offset, float Value) {
    RecordOffset = Offset;
    Data.Float = Value;
  }

  void set(offset_uint Offset, double Value) {
    RecordOffset = Offset;
    Data.Double = Value;
  }
  
  void set(offset_uint Offset, long double Value) {
    RecordOffset = Offset;
    Data.LongDouble = Value;
  }

  llvm::APFloat getAPFloat(llvm::Type *Type) const {
    switch (Type->getTypeID()) {
      case llvm::Type::FloatTyID:    return llvm::APFloat(Data.Float);
      case llvm::Type::DoubleTyID:   return llvm::APFloat(Data.Double);
      case llvm::Type::X86_FP80TyID:
      {
        assert(LDBL_MANT_DIG == 64);
        uint64_t Vals[2] = {0, 0}; // 16 bytes.
        memcpy(reinterpret_cast<char *>(Vals),
               reinterpret_cast<char const *>(&(Data.LongDouble)),
               10);
        return llvm::APFloat(llvm::APFloat::x87DoubleExtended,
                             llvm::APInt(80, Vals));
      }
      case llvm::Type::HalfTyID:      break; // TODO
      case llvm::Type::FP128TyID:     break; // TODO
      case llvm::Type::PPC_FP128TyID: break; // TODO
      case llvm::Type::VoidTyID:      break;
      case llvm::Type::LabelTyID:     break;
      case llvm::Type::MetadataTyID:  break;
      case llvm::Type::X86_MMXTyID:   break;
      case llvm::Type::IntegerTyID:   break;
      case llvm::Type::FunctionTyID:  break;
      case llvm::Type::StructTyID:    break;
      case llvm::Type::ArrayTyID:     break;
      case llvm::Type::PointerTyID:   break;
      case llvm::Type::VectorTyID:    break;
      case llvm::Type::NumTypeIDs:    break;
    }

    llvm_unreachable("getAPFloat called with unsupported type.");
    return llvm::APFloat(0.0);
  }
  
  llvm::APInt getAPInt(llvm::IntegerType *Type, bool isSigned = false) const {
    auto BitWidth = Type->getBitWidth();
    
    assert(BitWidth <= 64 && "Can't get int with more than 64 bits.");
    
    uint64_t Value = Data.UInt64;
    
    // If they want a signed value, and it appears that the run-time value
    // would have been negative, then fill the extra bits in the uint64_t
    // with 1s (as though it were an int64_t).
    if (isSigned && (Value & Type->getSignBit())) {
      uint64_t BitMask = Type->getBitMask();
      Value |= ~BitMask;
    }
    
    return llvm::APInt(BitWidth, Value, isSigned);
  }

  llvm::APSInt getAPSInt(llvm::IntegerType *Type) const {
    return llvm::APSInt(getAPInt(Type, true));
  }
  
  decltype(Data) const &getData() const { return Data; }
  
  uint64_t getUInt64() const { return Data.UInt64; }
  
  uintptr_t getUIntPtr() const { return Data.UIntPtr; }

  float getFloat() const { return Data.Float; }

  double getDouble() const { return Data.Double; }
  
  long double getLongDouble() const { return Data.LongDouble; }
};

template<typename T, typename Enable = void>
struct GetAsImpl; // do not implement

// Specialization to get signed integer types.
template<typename T>
{'fraction_non_alphanumeric': 0.16434225405201658, 'fraction_numerical': 0.009925870084181429, 'mean_word_length': 2.3901192504258946, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3850249', 'n_tokens_mistral': 2501, 'n_tokens_neox': 2409, 'n_words': 621}