From 664e8b22acc1093274b5f3faafe50d98f4ebe8fa Mon Sep 17 00:00:00 2001 From: Axel Naumann Date: Fri, 22 Feb 2013 15:59:54 +0000 Subject: [PATCH] Reduce the amount of headers needed by the dynamic scopes at runtime: * Make GenericValue, clang::QualType opaque in Value * Move LifetimeHandler implementation into source; requires separate header * Also: * Value: replace CPP macros by overloads git-svn-id: http://root.cern.ch/svn/root/trunk@48675 27541ba8-7e3a-0410-8455-c3a389f83636 --- .../DynamicLookupLifetimeHandler.h | 85 ++++++++++ .../DynamicLookupRuntimeUniverse.h | 76 +-------- include/cling/Interpreter/RuntimeUniverse.h | 17 +- include/cling/Interpreter/StoredValueRef.h | 2 +- include/cling/Interpreter/Value.h | 153 ++++++++---------- lib/Interpreter/DynamicLookup.cpp | 37 ++++- lib/Interpreter/ExecutionContext.cpp | 3 + lib/Interpreter/StoredValueRef.cpp | 11 +- lib/Interpreter/Value.cpp | 107 ++++++++++++ lib/Interpreter/ValuePrinter.cpp | 1 + 10 files changed, 309 insertions(+), 183 deletions(-) create mode 100644 include/cling/Interpreter/DynamicLookupLifetimeHandler.h create mode 100644 lib/Interpreter/Value.cpp diff --git a/include/cling/Interpreter/DynamicLookupLifetimeHandler.h b/include/cling/Interpreter/DynamicLookupLifetimeHandler.h new file mode 100644 index 00000000..73e063e3 --- /dev/null +++ b/include/cling/Interpreter/DynamicLookupLifetimeHandler.h @@ -0,0 +1,85 @@ +//--------------------------------------------------------------------*- C++ -*- +// CLING - the C++ LLVM-based InterpreterG :) +// version: $Id$ +// author: Vassil Vassilev +//------------------------------------------------------------------------------ +#ifndef CLING_DYNAMIC_LOOKUP_LIFETIME_HANDLER_H +#define CLING_DYNAMIC_LOOKUP_LIFETIME_HANDLER_H + +#include + +namespace clang { + class DeclContext; +} + +namespace cling { + class DynamicExprInfo; + class Interpreter; + +/// \brief Contains declarations for cling's runtime. +namespace runtime { + + /// \brief Provides private definitions for the dynamic scopes and runtime + /// bindings. These builtins should not be used for other purposes. + namespace internal { + extern Interpreter* gCling; + + /// \brief LifetimeHandler is used in case of initialization using address + /// on the automatic store (stack) instead of EvaluateT. + /// + /// The reason is to avoid the copy constructors that might be private. + /// This is part of complex transformation, which aims to preserve the + /// code behavior. For example: + /// @code + /// int i = 5; + /// MyClass my(dep->Symbol(i)) + /// @endcode + /// where dep->Symbol() is a symbol not known at compile-time + /// transformed into: + /// @code + /// cling::runtime::internal::LifetimeHandler + /// __unique("dep->Sybmol(*(int*)@)",(void*[]){&i}, DC, "MyClass"); + /// MyClass &my(*(MyClass*)__unique.getMemory()); + /// @endcode + class LifetimeHandler { + private: + /// \brief The Interpreter handling this storage element. + Interpreter* m_Interpreter; + + /// \brief The memory on the free store, where the object will be + /// created. + void* m_Memory; + + /// \brief The type of the object that will be created. + std::string m_Type; + + public: + /// \brief Constructs an expression, which creates the object on the + /// free store and tells the interpreter to evaluate it. + /// + /// @param[in] ExprInfo Helper structure that keeps information about + /// the expression that is being replaced and the addresses of the + /// variables that the replaced expression contains. + /// @param[in] DC The declaration context, in which the expression will + /// be evaluated at runtime + /// @param[in] type The type of the object, which will help to delete + /// it, when the LifetimeHandler goes out of scope. + /// + LifetimeHandler(DynamicExprInfo* ExprInfo, + clang::DeclContext* DC, + const char* type, + Interpreter* Interp = gCling); + + ///\brief Returns the created object. + void* getMemory() const { return m_Memory; } + + /// \brief Clears up the free store, when LifetimeHandler goes out of + /// scope. + /// + ~LifetimeHandler(); + }; + } +} // end namespace runtime +} // end namespace cling + +#endif // CLING_DYNAMIC_LOOKUP_LIFETIME_HANDLER_H diff --git a/include/cling/Interpreter/DynamicLookupRuntimeUniverse.h b/include/cling/Interpreter/DynamicLookupRuntimeUniverse.h index ea0e60cd..836e217d 100644 --- a/include/cling/Interpreter/DynamicLookupRuntimeUniverse.h +++ b/include/cling/Interpreter/DynamicLookupRuntimeUniverse.h @@ -17,17 +17,12 @@ #include "cling/Interpreter/RuntimeUniverse.h" #endif #include "cling/Interpreter/DynamicExprInfo.h" -#include "cling/Interpreter/ValuePrinter.h" +#include "cling/Interpreter/DynamicLookupLifetimeHandler.h" #include "cling/Interpreter/StoredValueRef.h" -#include "llvm/Support/raw_ostream.h" - -#include - namespace cling { - /// \brief Used to stores the declarations, which are going to be - /// available only at runtime. These are cling runtime builtins. +/// \brief Contains declarations for cling's runtime. namespace runtime { /// \brief Provides builtins, which are neccessary for the dynamic scopes @@ -68,71 +63,6 @@ namespace runtime { cling::runtime::gCling->Evaluate(ExprInfo->getExpr(), DC, ExprInfo->isValuePrinterRequested()); } - - /// \brief LifetimeHandler is used in case of initialization using address - /// on the automatic store (stack) instead of EvaluateT. - /// - /// The reason is to avoid the copy constructors that might be private. - /// This is part of complex transformation, which aims to preserve the - /// code behavior. For example: - /// @code - /// int i = 5; - /// MyClass my(dep->Symbol(i)) - /// @endcode - /// where dep->Symbol() is a symbol not known at compile-time - /// transformed into: - /// @code - /// cling::runtime::internal::LifetimeHandler - /// __unique("dep->Sybmol(*(int*)@)",(void*[]){&i}, DC, "MyClass"); - /// MyClass &my(*(MyClass*)__unique.getMemory()); - /// @endcode - class LifetimeHandler { - private: - /// \brief The memory on the free store, where the object will be - /// created. - void* m_Memory; - - /// \brief The type of the object that will be created. - std::string m_Type; - public: - /// \brief Constructs an expression, which creates the object on the - /// free store and tells the interpreter to evaluate it. - /// - /// @param[in] ExprInfo Helper structure that keeps information about - /// the expression that is being replaced and the addresses of the - /// variables that the replaced expression contains. - /// @param[in] DC The declaration context, in which the expression will - /// be evaluated at runtime - /// @param[in] type The type of the object, which will help to delete - /// it, when the LifetimeHandler goes out of scope. - /// - LifetimeHandler(DynamicExprInfo* ExprInfo, - clang::DeclContext* DC, - const char* type) { - m_Type = type; - std::string ctor("new "); - ctor += type; - ctor += ExprInfo->getExpr(); - StoredValueRef res = cling::runtime::gCling->Evaluate(ctor.c_str(), DC, - ExprInfo->isValuePrinterRequested() - ); - m_Memory = (void*)res.get().getGV().PointerVal; - } - - ///\brief Returns the created object. - void* getMemory() const { return m_Memory; } - - /// \brief Clears up the free store, when LifetimeHandler goes out of - /// scope. - /// - ~LifetimeHandler() { - std::string str; - llvm::raw_string_ostream stream(str); - stream<<"delete ("<< m_Type << "*) "<< m_Memory << ";"; - stream.flush(); - cling::runtime::gCling->execute(str); - } - }; - } + } // end nmespace internal } // end namespace runtime } // end namespace cling diff --git a/include/cling/Interpreter/RuntimeUniverse.h b/include/cling/Interpreter/RuntimeUniverse.h index 1c966ba7..1f2f49f3 100644 --- a/include/cling/Interpreter/RuntimeUniverse.h +++ b/include/cling/Interpreter/RuntimeUniverse.h @@ -3,16 +3,13 @@ // version: $Id$ // author: Vassil Vassilev //------------------------------------------------------------------------------ -#ifndef __CLING__ -#error "This file must not be included by compiled programs." -#else - -#ifdef CLING_RUNTIME_UNIVERSE_H -#error "CLING_RUNTIME_UNIVERSE_H Must only include once." -#else - +#ifndef CLING_RUNTIME_UNIVERSE_H #define CLING_RUNTIME_UNIVERSE_H +#if !defined(__CLING__) && !defined(__COMPILING_CLING__) +#error "This file must not be included by compiled programs." +#endif + #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS // needed by System/DataTypes.h #endif @@ -90,6 +87,4 @@ extern "C" { } #endif // __cplusplus -#endif // CLING_RUNTIME_UNIVERSE_H (error) - -#endif // __CLING__ +#endif // CLING_RUNTIME_UNIVERSE_H diff --git a/include/cling/Interpreter/StoredValueRef.h b/include/cling/Interpreter/StoredValueRef.h index c455c59b..38982fab 100644 --- a/include/cling/Interpreter/StoredValueRef.h +++ b/include/cling/Interpreter/StoredValueRef.h @@ -26,7 +26,7 @@ namespace cling { /// \brief Number of bytes that need to be allocated to hold a value /// of our type - int64_t getAllocSizeInBytes(const clang::ASTContext& ctx) const; + long long getAllocSizeInBytes(const clang::ASTContext& ctx) const; /// \brief Memory allocated for value, owned by this value /// diff --git a/include/cling/Interpreter/Value.h b/include/cling/Interpreter/Value.h index 270dc9ff..197aa1f0 100644 --- a/include/cling/Interpreter/Value.h +++ b/include/cling/Interpreter/Value.h @@ -7,14 +7,16 @@ #ifndef CLING_VALUE_H #define CLING_VALUE_H -#include "clang/AST/Type.h" -#include "clang/AST/CanonicalType.h" - -#include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/Type.h" +#include +#include +namespace llvm { + class Type; + struct GenericValue; +} namespace clang { class ASTContext; + class QualType; } namespace cling { @@ -32,35 +34,43 @@ namespace cling { /// void types /// 3. Parameters for calls given an llvm::Function and a clang::FunctionDecl. class Value { - private: - /// \brief Forward decl for typed access specializations - template struct TypedAccess; - protected: /// \brief value - llvm::GenericValue m_GV; + char /*llvm::GenericValue*/ m_GV[32]; // 24 bytes on 64bit - /// \brief the value's type according to clang - clang::QualType m_ClangType; + /// \brief the value's type according to clang, stored as void* to reduce + /// dependencies. + void* /*clang::QualType*/ m_ClangType; /// \brief the value's type according to clang const llvm::Type* m_LLVMType; + enum EStorageType { + kSignedIntegerOrEnumerationType, + kUnsignedIntegerOrEnumerationType, + kDoubleType, + kFloatType, + kLongDoubleType, + kPointerType, + kUnsupportedType + }; + + /// \brief Retrieve the underlying, canonical, desugared, unqualified type. + EStorageType getStorageType() const; + public: /// \brief Default constructor, creates a value that IsInvalid(). Value() {} /// \brief Construct a valid Value. - Value(const llvm::GenericValue& v, clang::QualType t) - : m_GV(v), m_ClangType(t), m_LLVMType(0) { } + Value(const llvm::GenericValue& v, clang::QualType t); Value(const llvm::GenericValue& v, clang::QualType clangTy, - const llvm::Type* llvmTy) - : m_GV(v), m_ClangType(clangTy), m_LLVMType(llvmTy) { } + const llvm::Type* llvmTy); - llvm::GenericValue getGV() const { return m_GV; } - void setGV(llvm::GenericValue GV) { m_GV = GV; } - clang::QualType getClangType() const { return m_ClangType; } + llvm::GenericValue getGV() const; + void setGV(llvm::GenericValue GV); + clang::QualType getClangType() const; const llvm::Type* getLLVMType() const { return m_LLVMType; } void setLLVMType(const llvm::Type* Ty) { m_LLVMType = Ty; } @@ -68,13 +78,10 @@ namespace cling { // /// Determine whether the Value has been set by checking /// whether the type is valid. - bool isValid() const { return !m_ClangType.isNull(); } + bool isValid() const; /// \brief Determine whether the Value is set but void. - bool isVoid(const clang::ASTContext& ASTContext) const { - return isValid() - && m_ClangType.getDesugaredType(ASTContext)->isVoidType(); - } + bool isVoid(const clang::ASTContext& ASTContext) const; /// \brief Determine whether the Value is set and not void. // @@ -87,6 +94,24 @@ namespace cling { template T getAs() const; + template + T* getAs(T**) const { return (T*)getAs((void**)0); } + void* getAs(void**) const; + double getAs(double*) const; + long double getAs(long double*) const; + float getAs(float*) const; + bool getAs(bool*) const; + signed char getAs(signed char*) const; + unsigned char getAs(unsigned char*) const; + signed short getAs(signed short*) const; + unsigned short getAs(unsigned short*) const; + signed int getAs(signed int*) const; + unsigned int getAs(unsigned int*) const; + signed long getAs(signed long*) const; + unsigned long getAs(unsigned long*) const; + signed long long getAs(signed long long*) const; + unsigned long long getAs(unsigned long long*) const; + /// \brief Get the value. // /// Get the value cast to T. This is similar to reinterpret_cast(value), @@ -96,83 +121,31 @@ namespace cling { T simplisticCastAs() const; }; - template - struct Value::TypedAccess{ - T extract(const llvm::GenericValue& value) { - return *reinterpret_cast(value.PointerVal); - } - }; - template - struct Value::TypedAccess{ - T* extract(const llvm::GenericValue& value) { - return reinterpret_cast(value.PointerVal); - } - }; - -#define CLING_VALUE_TYPEDACCESS(TYPE, GETTER) \ - template<> \ - struct Value::TypedAccess { \ - TYPE extract(const llvm::GenericValue& value) { \ - return value.GETTER; \ - } \ - } - -#define CLING_VALUE_TYPEDACCESS_SIGNED(TYPE) \ - CLING_VALUE_TYPEDACCESS(signed TYPE, IntVal.getSExtValue()) - -#define CLING_VALUE_TYPEDACCESS_UNSIGNED(TYPE) \ - CLING_VALUE_TYPEDACCESS(unsigned TYPE, IntVal.getZExtValue()) - -#define CLING_VALUE_TYPEDACCESS_BOTHSIGNS(TYPE) \ - CLING_VALUE_TYPEDACCESS_SIGNED(TYPE); \ - CLING_VALUE_TYPEDACCESS_UNSIGNED(TYPE); - - CLING_VALUE_TYPEDACCESS(double, DoubleVal); - //CLING_VALUE_TYPEDACCESS(long double, ???); - CLING_VALUE_TYPEDACCESS(float, FloatVal); - - CLING_VALUE_TYPEDACCESS(bool, IntVal.getBoolValue()); - - CLING_VALUE_TYPEDACCESS_BOTHSIGNS(char) - CLING_VALUE_TYPEDACCESS_BOTHSIGNS(short) - CLING_VALUE_TYPEDACCESS_BOTHSIGNS(int) - CLING_VALUE_TYPEDACCESS_BOTHSIGNS(long) - CLING_VALUE_TYPEDACCESS_BOTHSIGNS(long long) - -#undef CLING_VALUE_TYPEDACCESS_BOTHSIGNS -#undef CLING_VALUE_TYPEDACCESS_UNSIGNED -#undef CLING_VALUE_TYPEDACCESS_SIGNED -#undef CLING_VALUE_TYPEDACCESS template T Value::getAs() const { // T *must* correspond to type. Else use simplisticCastAs()! - TypedAccess VI; - return VI.extract(m_GV); + return getAs((T*)0); } template T Value::simplisticCastAs() const { - const clang::Type* desugCanon = m_ClangType->getUnqualifiedDesugaredType(); - desugCanon = desugCanon->getCanonicalTypeUnqualified()->getTypePtr() - ->getUnqualifiedDesugaredType(); - if (desugCanon->isSignedIntegerOrEnumerationType()) { + EStorageType storageType = getStorageType(); + switch (storageType) { + case kSignedIntegerOrEnumerationType: return (T) getAs(); - } else if (desugCanon->isUnsignedIntegerOrEnumerationType()) { + case kUnsignedIntegerOrEnumerationType: return (T) getAs(); - } else if (desugCanon->isRealFloatingType()) { - const clang::BuiltinType* BT = desugCanon->getAs(); - if (BT->getKind() == clang::BuiltinType::Double) - return (T) getAs(); - else if (BT->getKind() == clang::BuiltinType::Float) - return (T) getAs(); - /* not yet supported in JIT: - else if (BT->getKind() == clang::BuiltinType::LongDouble) - return (T) getAs(); - */ - } else if (desugCanon->isPointerType() || desugCanon->isObjectType()) { + case kDoubleType: + return (T) getAs(); + case kFloatType: + return (T) getAs(); + case kLongDoubleType: + return (T) getAs(); + case kPointerType: return (T) (size_t) getAs(); + case kUnsupportedType: + assert("unsupported type in Value, cannot cast simplistically!" && 0); } - assert("unsupported type in Value, cannot cast simplistically!" && 0); return T(); } } // end namespace cling diff --git a/lib/Interpreter/DynamicLookup.cpp b/lib/Interpreter/DynamicLookup.cpp index 9280c4de..db75fa2f 100644 --- a/lib/Interpreter/DynamicLookup.cpp +++ b/lib/Interpreter/DynamicLookup.cpp @@ -8,9 +8,13 @@ #include "cling/Interpreter/Interpreter.h" #include "cling/Interpreter/InterpreterCallbacks.h" +#include "cling/Interpreter/DynamicExprInfo.h" +#include "cling/Interpreter/StoredValueRef.h" #include "cling/Interpreter/Transaction.h" #include "cling/Utils/AST.h" +#include "llvm/ExecutionEngine/GenericValue.h" + #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Lex/Preprocessor.h" @@ -18,6 +22,8 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Template.h" +#include "cling/Interpreter/DynamicLookupLifetimeHandler.h" + using namespace clang; namespace { @@ -362,7 +368,8 @@ namespace cling { llvm::SmallVector Inits; // Add MyClass in LifetimeHandler unique(DynamicExprInfo* ExprInfo // DC, - // "MyClass") + // "MyClass" + // /*, Interp = gCling*/) // Build Arg0 DynamicExprInfo Inits.push_back(BuildDynamicExprInfo(E)); // Build Arg1 DeclContext* DC @@ -651,7 +658,7 @@ namespace cling { } Expr* EvaluateTSynthesizer::ConstructCStyleCasePtrExpr(QualType Ty, - uint64_t Ptr) { + uint64_t Ptr) { if (!Ty->isPointerType()) Ty = m_Context->getPointerType(Ty); TypeSourceInfo* TSI = m_Context->CreateTypeSourceInfo(Ty); @@ -825,4 +832,30 @@ namespace cling { // end Helpers + namespace runtime { + namespace internal { + // Implementations from DynamicLookupLifetimeHandler.h + LifetimeHandler::LifetimeHandler(DynamicExprInfo* ExprInfo, + clang::DeclContext* DC, + const char* type, + Interpreter* Interp /* = gCling */): + m_Interpreter(Interp), m_Type(type) { + std::string ctor("new "); + ctor += type; + ctor += ExprInfo->getExpr(); + StoredValueRef res = Interp->Evaluate(ctor.c_str(), DC, + ExprInfo->isValuePrinterRequested() + ); + m_Memory = (void*)res.get().getGV().PointerVal; + } + + LifetimeHandler::~LifetimeHandler() { + std::string str; + llvm::raw_string_ostream stream(str); + stream << "delete (" << m_Type << "*) " << m_Memory << ";"; + stream.flush(); + m_Interpreter->execute(str); + } + } // end namespace internal + } // end namespace runtime } // end namespace cling diff --git a/lib/Interpreter/ExecutionContext.cpp b/lib/Interpreter/ExecutionContext.cpp index 0707dae3..3efae59e 100644 --- a/lib/Interpreter/ExecutionContext.cpp +++ b/lib/Interpreter/ExecutionContext.cpp @@ -8,12 +8,15 @@ #include "cling/Interpreter/StoredValueRef.h" +#include "clang/AST/Type.h" + #include "llvm/Constants.h" #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Assembly/PrintModulePass.h" +#include "llvm/ExecutionEngine/GenericValue.h" #include "llvm/ExecutionEngine/JIT.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/DynamicLibrary.h" diff --git a/lib/Interpreter/StoredValueRef.cpp b/lib/Interpreter/StoredValueRef.cpp index f3f6b356..772c8cf3 100644 --- a/lib/Interpreter/StoredValueRef.cpp +++ b/lib/Interpreter/StoredValueRef.cpp @@ -7,6 +7,7 @@ #include "cling/Interpreter/StoredValueRef.h" #include "cling/Interpreter/ValuePrinter.h" #include "clang/AST/ASTContext.h" +#include "llvm/ExecutionEngine/GenericValue.h" using namespace cling; using namespace clang; @@ -15,9 +16,7 @@ using namespace llvm; StoredValueRef::StoredValue::StoredValue(const ASTContext& ctx, QualType clangTy, const llvm::Type* llvm_Ty) - :m_Mem(0) { - m_ClangType = clangTy; - m_LLVMType = llvm_Ty; + :Value(GenericValue(), clangTy, llvm_Ty), m_Mem(0) { if (!(clangTy->isIntegralOrEnumerationType() || clangTy->isRealFloatingType() || clangTy->hasPointerRepresentation())) { @@ -25,7 +24,7 @@ StoredValueRef::StoredValue::StoredValue(const ASTContext& ctx, if (size > sizeof(m_Buf)) m_Mem = new char[size]; else m_Mem = m_Buf; - m_GV = llvm::PTOGV(m_Mem); + setGV(llvm::PTOGV(m_Mem)); }; } @@ -34,9 +33,9 @@ StoredValueRef::StoredValue::~StoredValue() { delete [] m_Mem; } -int64_t StoredValueRef::StoredValue::getAllocSizeInBytes( +long long StoredValueRef::StoredValue::getAllocSizeInBytes( const ASTContext& ctx) const { - return ctx.getTypeSizeInChars(m_ClangType).getQuantity(); + return (long long) ctx.getTypeSizeInChars(getClangType()).getQuantity(); } diff --git a/lib/Interpreter/Value.cpp b/lib/Interpreter/Value.cpp new file mode 100644 index 00000000..f30d97cf --- /dev/null +++ b/lib/Interpreter/Value.cpp @@ -0,0 +1,107 @@ +//------------------------------------------------------------------------------ +// CLING - the C++ LLVM-based InterpreterG :) +// version: $Id: Value.cpp 48537 2013-02-11 17:30:03Z vvassilev $ +// author: Axel Naumann +//------------------------------------------------------------------------------ + +#include "cling/Interpreter/Value.h" + +#include "llvm/ExecutionEngine/GenericValue.h" + +#include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" + +namespace cling { + +Value::Value(const llvm::GenericValue& v, clang::QualType t) + : m_ClangType(t.getAsOpaquePtr()), m_LLVMType(0) +{ + setGV(v); +} + +Value::Value(const llvm::GenericValue& v, clang::QualType clangTy, + const llvm::Type* llvmTy) + : m_ClangType(clangTy.getAsOpaquePtr()), m_LLVMType(llvmTy) +{ + setGV(v); +} + +llvm::GenericValue Value::getGV() const { + return reinterpret_cast(m_GV); +} +void Value::setGV(llvm::GenericValue GV) { + reinterpret_cast(m_GV) = GV; +} + +clang::QualType Value::getClangType() const { + assert(sizeof(clang::QualType) <= sizeof(m_ClangType) && "m_ClangType too small!"); + return clang::QualType::getFromOpaquePtr(m_ClangType); +} + +bool Value::isValid() const { return !getClangType().isNull(); } + +bool Value::isVoid(const clang::ASTContext& ASTContext) const { + return isValid() + && getClangType().getDesugaredType(ASTContext)->isVoidType(); +} + +Value::EStorageType Value::getStorageType() const { + const clang::Type* desugCanon = getClangType()->getUnqualifiedDesugaredType(); + desugCanon = desugCanon->getCanonicalTypeUnqualified()->getTypePtr() + ->getUnqualifiedDesugaredType(); + if (desugCanon->isSignedIntegerOrEnumerationType()) + return kSignedIntegerOrEnumerationType; + else if (desugCanon->isUnsignedIntegerOrEnumerationType()) + return kUnsignedIntegerOrEnumerationType; + else if (desugCanon->isRealFloatingType()) { + const clang::BuiltinType* BT = desugCanon->getAs(); + if (BT->getKind() == clang::BuiltinType::Double) + return kDoubleType; + else if (BT->getKind() == clang::BuiltinType::Float) + return kFloatType; + else if (BT->getKind() == clang::BuiltinType::LongDouble) + return kLongDoubleType; + } else if (desugCanon->isPointerType() || desugCanon->isObjectType()) + return kPointerType; + return kUnsupportedType; +} + +void* Value::getAs(void**) const { return getGV().PointerVal; } +double Value::getAs(double*) const { return getGV().DoubleVal; } +long double Value::getAs(long double*) const { + return getAs((double*)0); +} +float Value::getAs(float*) const { return getGV().FloatVal; } +bool Value::getAs(bool*) const { return getGV().IntVal.getBoolValue(); } +signed char Value::getAs(signed char*) const { + return (signed char) getAs((signed long long*)0); +} +unsigned char Value::getAs(unsigned char*) const { + return (unsigned char) getAs((unsigned long long*)0); +} +signed short Value::getAs(signed short*) const { + return (signed short) getAs((signed long long*)0); +} +unsigned short Value::getAs(unsigned short*) const { + return (unsigned short) getAs((unsigned long long*)0); +} +signed int Value::getAs(signed int*) const { + return (signed int) getAs((signed long long*)0); +} +unsigned int Value::getAs(unsigned int*) const { + return (unsigned int) getAs((unsigned long long*)0); +} +signed long Value::getAs(signed long*) const { + return (long) getAs((signed long long*)0); +} +unsigned long Value::getAs(unsigned long*) const { + return (signed long) getAs((unsigned long long*)0); +} +signed long long Value::getAs(signed long long*) const { + return getGV().IntVal.getSExtValue(); +} +unsigned long long Value::getAs(unsigned long long*) const { + return getGV().IntVal.getZExtValue(); +} + +} // namespace cling diff --git a/lib/Interpreter/ValuePrinter.cpp b/lib/Interpreter/ValuePrinter.cpp index 36c21962..fefea01c 100644 --- a/lib/Interpreter/ValuePrinter.cpp +++ b/lib/Interpreter/ValuePrinter.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Type.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/ExecutionEngine/GenericValue.h" #include #include