blob: a4f3ad34e14862e0b59323883e4ecc542c4ffbdb [file] [log] [blame]
//===------ Trees.cpp - Utility functions for working with GCC trees ------===//
//
// 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 defines utility functions for working with GCC trees.
//===----------------------------------------------------------------------===//
// LLVM headers
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/Twine.h"
// System headers
#include <gmp.h>
// GCC headers
#include "auto-host.h"
#ifndef ENABLE_BUILD_WITH_CXX
#include <cstring> // Otherwise included by system.h with C linkage.
extern "C" {
#endif
#include "config.h"
// Stop GCC declaring 'getopt' as it can clash with the system's declaration.
#undef HAVE_DECL_GETOPT
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "flags.h"
#ifndef ENABLE_BUILD_WITH_CXX
} // extern "C"
#endif
// Trees header.
#include "dragonegg/Trees.h"
using namespace llvm;
/// concatIfNotEmpty - Concatenate the given strings if they are both non-empty.
/// Otherwise return the empty string.
static std::string
concatIfNotEmpty(const std::string &Left, const std::string &Right) {
if (Left.empty() || Right.empty())
return std::string();
return Left + Right;
}
/// 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 in the final assembler.
std::string getAssemblerName(tree t) {
tree ident = DECL_ASSEMBLER_NAME(t);
if (!ident)
// Does not have a name.
return std::string();
// Replace any leading star by '\1'.
const char *Name = IDENTIFIER_POINTER(ident);
if (*Name != '*')
return std::string(Name, IDENTIFIER_LENGTH(ident));
return "\1" + std::string(Name + 1, IDENTIFIER_LENGTH(ident) - 1);
}
/// 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.
std::string getDescriptiveName(const_tree t) {
if (!t)
return std::string(); // Occurs when recursing.
// Name identifier nodes after their contents. This gives the desired effect
// when called recursively.
if (isa<IDENTIFIER_NODE>(t))
return std::string(IDENTIFIER_POINTER(t), IDENTIFIER_LENGTH(t));
// Handle declarations of all kinds.
if (DECL_P(t)) {
// If the declaration comes with a name then use it.
if (DECL_NAME(t)) // Always an identifier node.
return getDescriptiveName(DECL_NAME(t));
// Use a generic name for function results.
if (isa<RESULT_DECL>(t))
return "<retval>";
// Labels have their own numeric unique identifiers.
if (isa<LABEL_DECL>(t) && LABEL_DECL_UID(t) != -1) {
Twine LUID(LABEL_DECL_UID(t));
return ("L" + LUID).str();
}
// Otherwise use the generic UID.
const char *Annotation = isa<CONST_DECL>(t) ? "C." : "D.";
Twine UID(DECL_UID(t));
return (Annotation + UID).str();
}
// Handle types of all kinds.
if (isa<TYPE>(t)) {
// If the type comes with a name then use it.
const std::string &TypeName = getDescriptiveName(TYPE_NAME(t));
if (!TypeName.empty()) {
// Annotate the name with a description of the type's class.
if (isa<ENUMERAL_TYPE>(t))
return "enum." + TypeName;
if (isa<RECORD_TYPE>(t))
return "struct." + TypeName;
if (isa<QUAL_UNION_TYPE>(t))
return "qualunion." + TypeName;
if (isa<UNION_TYPE>(t))
return "union." + TypeName;
return TypeName;
}
// Try to deduce a useful name.
if (isa<ARRAY_TYPE>(t))
// If the element type is E, name the array E[] (regardless of the number
// of dimensions).
return concatIfNotEmpty(getDescriptiveName(TREE_TYPE(t)), "[]");
if (isa<COMPLEX_TYPE>(t))
// If the element type is E, name the complex number complex.E.
return concatIfNotEmpty("complex.", getDescriptiveName(TREE_TYPE(t)));
if (isa<POINTER_TYPE>(t))
// If the element type is E, name the pointer E*.
return concatIfNotEmpty(getDescriptiveName(TREE_TYPE(t)), "*");
if (isa<REFERENCE_TYPE>(t))
// If the element type is E, name the reference E&.
return concatIfNotEmpty(getDescriptiveName(TREE_TYPE(t)), "&");
return TypeName;
}
// Handle SSA names.
if (isa<SSA_NAME>(t)) {
Twine NameVersion(SSA_NAME_VERSION(t));
return concatIfNotEmpty(getDescriptiveName(SSA_NAME_VAR(t)),
("_" + NameVersion).str());
}
// A mysterious tree, just give up.
return std::string();
}
/// 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.
APInt getAPIntValue(const_tree exp, unsigned Bitwidth) {
assert(isa<INTEGER_CST>(exp) && "Expected an integer constant!");
double_int val = tree_to_double_int(exp);
unsigned DefaultWidth = TYPE_PRECISION(TREE_TYPE(exp));
APInt DefaultValue;
if (integerPartWidth == HOST_BITS_PER_WIDE_INT) {
DefaultValue = APInt(DefaultWidth, /*numWords*/ 2, (integerPart *)&val);
} else {
assert(integerPartWidth == 2 * HOST_BITS_PER_WIDE_INT &&
"Unsupported host integer width!");
unsigned ShiftAmt = HOST_BITS_PER_WIDE_INT;
integerPart Part =
integerPart((unsigned HOST_WIDE_INT) val.low) +
(integerPart((unsigned HOST_WIDE_INT) val.high) << ShiftAmt);
DefaultValue = APInt(DefaultWidth, Part);
}
if (!Bitwidth || Bitwidth == DefaultWidth)
return DefaultValue;
if (Bitwidth > DefaultWidth)
return TYPE_UNSIGNED(TREE_TYPE(exp)) ? DefaultValue.zext(Bitwidth)
: DefaultValue.sext(Bitwidth);
assert((TYPE_UNSIGNED(TREE_TYPE(exp)) ||
DefaultValue.trunc(Bitwidth).sext(DefaultWidth) == DefaultValue) &&
"Truncating changed signed value!");
assert((!TYPE_UNSIGNED(TREE_TYPE(exp)) ||
DefaultValue.trunc(Bitwidth).zext(DefaultWidth) == DefaultValue) &&
"Truncating changed unsigned value!");
return DefaultValue.trunc(Bitwidth);
}
/// 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.
bool isInt64(const_tree t, bool Unsigned) {
if (!t)
return false;
if (HOST_BITS_PER_WIDE_INT == 64)
return host_integerp(t, Unsigned) && !TREE_OVERFLOW(t);
assert(HOST_BITS_PER_WIDE_INT == 32 &&
"Only 32- and 64-bit hosts supported!");
return (isa<INTEGER_CST>(t) && !TREE_OVERFLOW(t)) &&
((TYPE_UNSIGNED(TREE_TYPE(t)) == Unsigned) ||
// If the constant is signed and we want an unsigned result, check
// that the value is non-negative. If the constant is unsigned and
// we want a signed result, check it fits in 63 bits.
(HOST_WIDE_INT) TREE_INT_CST_HIGH(t) >= 0);
}
/// 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) {
assert(isInt64(t, Unsigned) && "invalid constant!");
(void) Unsigned; // Otherwise unused if asserts off - avoid compiler warning.
unsigned HOST_WIDE_INT LO = (unsigned HOST_WIDE_INT) TREE_INT_CST_LOW(t);
if (HOST_BITS_PER_WIDE_INT == 64) {
return (uint64_t) LO;
} else {
assert(HOST_BITS_PER_WIDE_INT == 32 &&
"Only 32- and 64-bit hosts supported!");
unsigned HOST_WIDE_INT HI = (unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH(t);
return ((uint64_t) HI << 32) | (uint64_t) LO;
}
}
/// getFieldOffsetInBits - Return the bit offset of a FIELD_DECL in a structure.
uint64_t getFieldOffsetInBits(const_tree field) {
assert(OffsetIsLLVMCompatible(field) && "Offset is not constant!");
uint64_t Result = getInt64(DECL_FIELD_BIT_OFFSET(field), true);
Result += getInt64(DECL_FIELD_OFFSET(field), true) * BITS_PER_UNIT;
return Result;
}
/// 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) {
// DECL_OFFSET_ALIGN is the maximum power-of-two that is known to divide
// DECL_FIELD_OFFSET*BITS_PER_UNIT. The field itself is offset a further
// DECL_FIELD_BIT_OFFSET bits.
assert(DECL_OFFSET_ALIGN(field) > 0 && (DECL_OFFSET_ALIGN(field) & 7) == 0 &&
"Field has no or wrong alignment!");
uint64_t FieldBitOffset = getInt64(DECL_FIELD_BIT_OFFSET(field), true);
return MinAlign(DECL_OFFSET_ALIGN(field) / 8, FieldBitOffset / 8);
}
/// isBitfield - Returns whether to treat the specified field as a bitfield.
bool isBitfield(const_tree field_decl) {
if (!DECL_BIT_FIELD(field_decl))
return false;
// A bitfield. But do we need to treat it as one?
assert(DECL_FIELD_BIT_OFFSET(field_decl) && "Bitfield with no bit offset!");
if (TREE_INT_CST_LOW(DECL_FIELD_BIT_OFFSET(field_decl)) & 7)
// Does not start on a byte boundary - must treat as a bitfield.
return true;
if (!isInt64(TYPE_SIZE(TREE_TYPE(field_decl)), true))
// No size or variable sized - play safe, treat as a bitfield.
return true;
uint64_t TypeSizeInBits = getInt64(TYPE_SIZE(TREE_TYPE(field_decl)), true);
assert(!(TypeSizeInBits & 7) && "A type with a non-byte size!");
assert(DECL_SIZE(field_decl) && "Bitfield with no bit size!");
uint64_t FieldSizeInBits = getInt64(DECL_SIZE(field_decl), true);
if (FieldSizeInBits < TypeSizeInBits)
// Not wide enough to hold the entire type - treat as a bitfield.
return true;
return false;
}