blob: 8cfa548e2ddf3bdff212205631b3a207fdb18a83 [file] [log] [blame]
//=---- Trees.h - Utility functions for working with GCC trees ----*- C++ -*-=//
//
// Copyright (C) 2010 to 2013 Duncan Sands.
//
// This file is part of DragonEgg.
//
// DragonEgg is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2, or (at your option) any later version.
//
// DragonEgg is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// DragonEgg; see the file COPYING. If not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
//
//===----------------------------------------------------------------------===//
// This file declares utility functions for working with GCC trees.
//===----------------------------------------------------------------------===//
#ifndef DRAGONEGG_TREES_H
#define DRAGONEGG_TREES_H
#if (GCC_MINOR < 7)
#include "flags.h" // For TYPE_OVERFLOW_UNDEFINED.
#endif
// IMPORTANT: ONLY INCLUDE GCC HEADERS IN THIS FILE! ONLY INCLUDE THIS HEADER
// AMONGST THE STANDARD GCC HEADERS!
// This is the only dragonegg header that is allowed to include GCC headers.
// As GCC headers poison standard C library routines like malloc, including
// one before an LLVM or system header may break the build. This is why GCC
// headers (and this one, as it may include GCC headers) are always included
// last.
// The following properties must hold if dragonegg is to work correctly.
#if ((BITS_PER_UNIT & 7) != 0)
#error BITS_PER_UNIT must be a multiple of 8
#endif
/// dragonegg_tree_code - Fake helper tree codes.
enum dragonegg_tree_code {
ACCESS_TYPE, // A pointer or reference type.
AGGREGATE_TYPE, // A record, union, qualified union or array type.
FLOAT_TYPE, // A scalar, complex or vector floating point type.
INTEGRAL_TYPE, // A enumeral, boolean or integer type.
RECORD_OR_UNION_TYPE, // A record, union or qualified union type.
TYPE // Any type.
};
/// isa - Return true if the given tree has the specified code.
template <enum tree_code code> bool isa(const_tree t) {
return TREE_CODE(t) == code;
}
template <enum dragonegg_tree_code code> bool isa(const_tree t) {
switch (code) {
case ACCESS_TYPE:
return POINTER_TYPE_P(t);
case AGGREGATE_TYPE:
return AGGREGATE_TYPE_P(t);
case FLOAT_TYPE:
return FLOAT_TYPE_P(t);
case INTEGRAL_TYPE:
return INTEGRAL_TYPE_P(t);
case RECORD_OR_UNION_TYPE:
return RECORD_OR_UNION_TYPE_P(t);
case TYPE:
return TYPE_P(t);
}
}
/// getAssemblerName - Return the name to use for the given tree, or an empty
/// string if it does not have a name. This is the official name that should
/// be used for everything that will end up with a name in the final assembler.
/// It should not be used for anything else: GCC will usually crash if you try
/// to use this with types, function arguments or anything else that doesn't
/// have a name in the final assembler.
std::string getAssemblerName(tree t);
/// getDescriptiveName - Return a helpful name for the given tree, or an empty
/// string if no sensible name was found. These names are used to make the IR
/// more readable, and have no official status. For example, they can be used
/// to name types because type names don't end up in the final assembler.
std::string getDescriptiveName(const_tree t);
/// main_type - Return the main variant of the given tree's type.
inline tree main_type(tree exp) { return TYPE_MAIN_VARIANT(TREE_TYPE(exp)); }
inline const_tree main_type(const_tree exp) {
return TYPE_MAIN_VARIANT(TREE_TYPE(exp));
}
/// hasNUW - Return whether overflowing unsigned operations on this type result
/// in undefined behaviour.
inline bool hasNUW(const_tree type) {
return TYPE_UNSIGNED(type) && TYPE_OVERFLOW_UNDEFINED(type);
}
/// hasNSW - Return whether overflowing signed operations on this type result
/// in undefined behaviour.
inline bool hasNSW(const_tree type) {
return !TYPE_UNSIGNED(type) && TYPE_OVERFLOW_UNDEFINED(type);
}
/// getAPIntValue - Return the specified INTEGER_CST as an APInt. The default
/// bitwidth used for the result is the precision of the constant's type, aka
/// TYPE_PRECISION. If a larger bitwidth is specified then the value is sign-
/// or zero-extended to the larger size, following the signedness of the type.
/// If a smaller bitwidth is specified then the value is truncated. This will
/// however result in an error if truncating changes the numerical value, i.e.
/// the truncated value must sign-/zero-extend to the original.
llvm::APInt getAPIntValue(const_tree exp, unsigned Bitwidth = 0);
/// isInt64 - Return true if t is an INTEGER_CST that fits in a 64 bit integer.
/// If Unsigned is false, returns whether it fits in a int64_t. If Unsigned is
/// true, returns whether the value is non-negative and fits in a uint64_t.
/// Always returns false for overflowed constants or if t is NULL.
bool isInt64(const_tree t, bool Unsigned);
/// getInt64 - Extract the value of an INTEGER_CST as a 64 bit integer. If
/// Unsigned is false, the value must fit in a int64_t. If Unsigned is true,
/// the value must be non-negative and fit in a uint64_t. Must not be used on
/// overflowed constants. These conditions can be checked by calling isInt64.
uint64_t getInt64(const_tree t, bool Unsigned);
/// OffsetIsLLVMCompatible - Return true if the given field is offset from the
/// start of the record by a constant amount which is not humongously big.
inline bool OffsetIsLLVMCompatible(const_tree field_decl) {
return isInt64(DECL_FIELD_OFFSET(field_decl), true);
}
/// getFieldOffsetInBits - Return the bit offset of a FIELD_DECL in a structure.
uint64_t getFieldOffsetInBits(const_tree field);
/// getFieldAlignment - Return (in octets) the alignment within a structure of
/// the octet containing the first bit of the given FIELD_DECL.
unsigned getFieldAlignment(const_tree field);
/// isBitfield - Returns whether to treat the specified field as a bitfield.
bool isBitfield(const_tree field_decl);
// Compatibility hacks for older versions of GCC.
#if (GCC_MINOR < 8)
// Supported allocation types:
struct va_gc {
}; // Allocation uses ggc_alloc.
// Fake vector class specialized below.
template <typename T, typename A> class vec {
};
#define INSTANTIATE_VECTOR(TT) \
template <> class vec<TT, va_gc> { \
VEC(TT, gc) & v; \
public: \
vec(VEC(TT, gc) & V) : v(V) {} \
\
bool is_empty() const { return VEC_empty(TT, &v); } \
unsigned length() const { return VEC_length(TT, &v); } \
TT &operator[](unsigned i) const { return *VEC_index(TT, &v, i); } \
bool iterate(unsigned ix, TT **ptr) const { \
return VEC_iterate(TT, &v, ix, *ptr); \
} \
}
#endif
#endif /* DRAGONEGG_TREES_H */