<commit_before>/*
 * This file is part of libFirm.
 * Copyright (C) 2012 University of Karlsruhe.
 */

/**
 * @file
 * @brief    Memory disambiguator
 * @author   <NAME>
 * @date     27.12.2006
 */
#include <stdlib.h>
#include <stdbool.h>

#include "adt/pmap.h"
#include "irnode_t.h"
#include "irgraph_t.h"
#include "irprog_t.h"
#include "irmemory_t.h"
#include "irmemory.h"
#include "irflag.h"
#include "hashptr.h"
#include "irflag.h"
#include "irouts.h"
#include "irgwalk.h"
#include "irprintf.h"
#include "debug.h"
#include "error.h"
#include "typerep.h"
#include "type_t.h"

/** The debug handle. */
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
DEBUG_ONLY(static firm_dbg_module_t *dbgcall = NULL;)

/** The source language specific language disambiguator function. */
static DISAMBIGUATOR_FUNC language_disambuigator = NULL;

/** The global memory disambiguator options. */
static unsigned global_mem_disamgig_opt = aa_opt_no_opt;

const char *get_ir_alias_relation_name(ir_alias_relation rel)
{
#define X(a) case a: return #a
	switch (rel) {
	X(ir_no_alias);
	X(ir_may_alias);
	X(ir_sure_alias);
	}
#undef X
	panic("UNKNOWN alias relation");
}

unsigned get_irg_memory_disambiguator_options(const ir_graph *irg)
{
	unsigned opt = irg->mem_disambig_opt;
	if (opt & aa_opt_inherited)
		return global_mem_disamgig_opt;
	return opt;
}

void set_irg_memory_disambiguator_options(ir_graph *irg, unsigned options)
{
	irg->mem_disambig_opt = options & ~aa_opt_inherited;
}

void set_irp_memory_disambiguator_options(unsigned options)
{
	global_mem_disamgig_opt = options;
}

ir_storage_class_class_t get_base_sc(ir_storage_class_class_t x)
{
	return x & ~ir_sc_modifiers;
}

/**
 * Find the base address and entity of an Sel node.
 *
 * @param sel  the node
 * @param pEnt after return points to the base entity.
 *
 * @return the base address.
 */
static ir_node *find_base_adr(const ir_node *sel, ir_entity **pEnt)
{
	ir_node *ptr = get_Sel_ptr(sel);

	while (is_Sel(ptr)) {
		sel = ptr;
		ptr = get_Sel_ptr(sel);
	}
	*pEnt = get_Sel_entity(sel);
	return ptr;
}

/**
 * Check if a given Const node is greater or equal a given size.
 *
 * @param cns   a Const node
 * @param size  a integer size
 *
 * @return ir_no_alias if the Const is greater, ir_may_alias else
 */
static ir_alias_relation check_const(const ir_node *cns, int size)
{
	ir_tarval *tv = get_Const_tarval(cns);

	if (size == 0)
		return tarval_is_null(tv) ? ir_may_alias : ir_no_alias;
	ir_tarval *tv_size = new_tarval_from_long(size, get_tarval_mode(tv));
	return tarval_cmp(tv_size, tv) & (ir_relation_less_equal) ? ir_no_alias : ir_may_alias;
}

/**
 * Treat idx1 and idx2 as integer indexes and check if they differ always more than size.
 *
 * @param idx1  a node representing the first index
 * @param idx2  a node representing the second index
 * @param size  an integer size
 *
 * @return ir_sure_alias iff idx1 == idx2
 *         ir_no_alias iff they ALWAYS differ more than size
 *         ir_may_alias else
 */
static ir_alias_relation different_index(const ir_node *idx1,
                                         const ir_node *idx2, int size)
{
	if (idx1 == idx2)
		return ir_sure_alias;
	if (is_Const(idx1) && is_Const(idx2)) {
		/* both are const, we can compare them */
		ir_tarval *tv1 = get_Const_tarval(idx1);
		ir_tarval *tv2 = get_Const_tarval(idx2);
		if (size == 0)
			return tv1 == tv2 ? ir_sure_alias : ir_no_alias;

		/* arg, modes may be different */
		ir_mode *m1 = get_tarval_mode(tv1);
		ir_mode *m2 = get_tarval_mode(tv2);
		if (m1 != m2) {
			int size = get_mode_size_bits(m1) - get_mode_size_bits(m2);

			if (size < 0) {
				/* m1 is a small mode, cast up */
				m1 = mode_is_signed(m1) ? find_signed_mode(m2) : find_unsigned_mode(m2);
				if (m1 == NULL) {
					/* should NOT happen, but if it does we give up here */
					return ir_may_alias;
				}
				tv1 = tarval_convert_to(tv1, m1);
			} else if (size > 0) {
				/* m2 is a small mode, cast up */
				m2 = mode_is_signed(m2) ? find_signed_mode(m1) : find_unsigned_mode(m1);
				if (m2 == NULL) {
					/* should NOT happen, but if it does we give up here */
					return ir_may_alias;
				}
				tv2 = tarval_convert_to(tv2, m2);
			}
			/* here the size should be identical, check for signed */
			if (get_mode_sign(m1) != get_mode_sign(m2)) {
				/* find the signed */
				if (mode_is_signed(m2)) {
					ir_tarval *t = tv1;
					tv1 = tv2;
					tv2 = t;
					ir_mode *tm = m1;
					m1 = m2;
					m2 = tm;
				}

				/* m1 is now the signed one */
				if (!tarval_is_negative(tv1)) {
					/* tv1 is signed, but >= 0, simply cast into unsigned */
					tv1 = tarval_convert_to(tv1, m2);
				} else {
					ir_tarval *tv_size = new_tarval_from_long(size, m2);
					if (tarval_cmp(tv2, tv_size) & (ir_relation_greater_equal)) {
						/* tv1 is negative and tv2 >= tv_size, so the difference is bigger than size */
						return ir_no_alias;
					}
					/* tv_size > tv2, so we can subtract without overflow */
					tv2 = tarval_sub(tv_size, tv2, NULL);

					/* tv1 is < 0, so we can negate it */
					tv1 = tarval_neg(tv1);

					/* cast it into unsigned. for two-complement it does the right thing for MIN_INT */
					tv1 = tarval_convert_to(tv1, m2);

					/* now we can compare without overflow */
					return tarval_cmp(tv1, tv2) & (ir_relation_greater_equal) ? ir_no_alias : ir_may_alias;
				}
			}
		}
		if (tarval_cmp(tv1, tv2) == ir_relation_greater) {
			ir_tarval *t = tv1;
			tv1 = tv2;
			tv2 = t;
		}
		/* tv1 is now the "smaller" one */
		ir_tarval *tv      = tarval_sub(tv2, tv1, NULL);
		ir_tarval *tv_size = new_tarval_from_long(size, get_tarval_mode(tv));
		return tarval_cmp(tv_size, tv) & (ir_relation_less_equal) ? ir_no_alias : ir_may_alias;
	}

	/* Note: we rely here on the fact that normalization puts constants on the RIGHT side */
	if (is_Add(idx1)) {
		ir_node *l1 = get_Add_left(idx1);
		ir_node *r1 = get_Add_right(idx1);

		if (l1 == idx2) {
			/* x + c == y */
			if (is_Const(r1))
				return check_const(r1, size);
		}
		if (is_Add(idx2)) {
			/* both are Adds, check if they are of x + a == x + b kind */
			ir_node *l2 = get_Add_left(idx2);
			ir_node *r2 = get_Add_right(idx2);

			if (l1 == l2)
				return different_index(r1, r2, size);
			else if (l1 == r2)
				return different_index(r1, l2, size);
			else if (r1 == r2)
				return different_index(l1, l2, size);
			else if (r1 == l2)
				return different_index(l1, r2, size);
		}
	}
	if (is_Add(idx2)) {
		ir_node *l2 = get_Add_left(idx2);
		ir_node *r2 = get_Add_right(idx2);

		if (l2 == idx1) {
			/* x + c == y */
			if (is_Const(r2))
				return check_const(r2, size);
		}
	}

	if (is_Sub(idx1)) {
		ir_node *l1 = get_Sub_left(idx1);
		ir_node *r1 = get_Sub_right(idx1);

		if (l1 == idx2) {
			/* x - c == y */
			if (is_Const(r1))
				return check_const(r1, size);
		}

		if (is_Sub(idx2)) {
			/* both are Subs, check if they are of x - a == x - b kind */
			ir_node *l2 = get_Sub_left(idx2);

			if (l1 == l2) {
				ir_node *r2 = get_Sub_right(idx2);
				return different_index(r1, r2, size);
			}
		}
	}
	if (is_Sub(idx2)) {
		ir_node *l2 = get_Sub_left(idx2);
		ir_node *r2 = get_Sub_right(idx2);

		if (l2 == idx1) {
			/* x - c == y */
			if (is_Const(r2))
				return check_const(r2, size);
		}

	}
	return ir_may_alias;
}

/**
 * Two Sel addresses have the same base address, check if their offsets are
 * different.
 *
 * @param adr1  The first address.
 * @param adr2  The second address.
 */
static ir_alias_relation different_sel_offsets(const ir_node *sel1,
                                               const ir_node *sel2)
{
	/* TODO: fix */
	(void) sel1;
	(void) sel2;
#if 0
	ir_entity *ent1 = get_Sel_entity(sel1);
	ir_entity *ent2 = get_Sel_entity(sel2);
	int i, check_arr = 0;

	if (ent1 == ent2)
		check_arr = 1;
	else {
		ir_type *tp1 = get_entity_type(ent1);
		ir_type *tp2 = get_entity_type(ent2);

		if (tp1 == tp2)
			check_arr = 1;
		else if (get_type_state(tp1) == layout_fixed && get_type_state(tp2) == layout_fixed &&
		         get_type_size_bytes(tp1) == get_type_size_bytes(tp2))
			check_arr = 1;
	}
	if (check_arr) {
		/* we select an entity of same size, check for indexes */
		int n = get_Sel_n_indexs(sel1);
		int have_no = 0;

		if (n > 0 && n == get_Sel_n_indexs(sel2)) {
			/* same non-zero number of indexes, an array access, check */
			for (i = 0; i < n; ++i) {
				ir_node *idx1 = get_Sel_index(sel1, i);
				ir_node *idx2 = get_Sel_index(sel2, i);
				ir_alias_relation res = different_index(idx1, idx2, 0); /* we can safely IGNORE the size here if it's at least >0 */

				if (res == may_alias)
					return may_alias;
				else if (res == no_alias)
					have_no = 1;
			}
			/* if we have at least one no_alias, there is no alias relation, else we have sure */
			return have_no > 0 ? no_alias : sure_alias;
		}
	}
#else
	(void) different_index;
#endif
	return ir_may_alias;
}

/**
 * Determine the alias relation by checking if adr1 and adr2 are pointer
 * to different type.
 *
 * @param adr1    The first address.
 * @param adr2    The second address.
 */
static ir_alias_relation different_types(const ir_node *adr1,
                                         const ir_node *adr2)
{
	ir_entity *ent1 = NULL;
	ir_entity *ent2 = NULL;

	if (is_SymConst_addr_ent(adr1))
		ent1 = get_SymConst_entity(adr1);
	else if (is_Sel(adr1))
		ent1 = get_Sel_entity(adr1);

	if (is_SymConst_addr_ent(adr2))
		ent2 = get_SymConst_entity(adr2);
	else if (is_Sel(adr2))
		ent2 = get_Sel_entity(adr2);

	if (ent1 != NULL && ent2 != NULL) {
		ir_type *tp1 = get_entity_type(ent1);
		ir_type *tp2 = get_entity_type(ent2);

		if (tp1 != tp2) {
			/* do deref until no pointer types are found */
			while (is_Pointer_type(tp1) && is_Pointer_type(tp2)) {
				tp1 = get_pointer_points_to_type(tp1);
				tp2 = get_pointer_points_to_type(tp2);
			}

			if (get_type_tpop(tp1) != get_type_tpop(tp2)) {
				/* different type structure */
				return ir_no_alias;
			}
			if (is_Class_type(tp1)) {
				/* check class hierarchy */
				if (!is_SubClass_of(tp1, tp2) && !is_SubClass_of(tp2, tp1))
					return ir_no_alias;
			} else {
				/* different types */
				return ir_no_alias;
			}
		}
	}
	return ir_may_alias;
}

/**
 * Returns non-zero if a node is a result on a malloc-like routine.
 *
 * @param node  the Proj node to test
 */
static int is_malloc_Result(const ir_node *node)
{
	node = get_Proj_pred(node);
	if (!is_Proj(node))
		return 0;
	node = get_Proj_pred(node);
	if (!is_Call(node))
		return 0;
	node = get_Call_ptr(node);
	if (is_SymConst_addr_ent(node)) {
		ir_entity *ent = get_SymConst_entity(node);

		if (get_entity_additional_properties(ent) & mtp_property_malloc)
			return 1;
		return 0;
	}
	return 0;
}

ir_storage_class_class_t classify_pointer(const ir_node *irn,
                                          const ir_entity *ent)
{
	ir_graph                *irg = get_irn_irg(irn);
	ir_storage_class_class_t res = ir_sc_pointer;
	if (is_SymConst_addr_ent(irn)) {
		ir_entity *entity = get_SymConst_entity(irn);
		ir_type   *owner  = get_entity_owner(entity);
		res = owner == get_tls_type() ? ir_sc_tls : ir_sc_globalvar;
		if (!(get_entity_usage(entity) & ir_usage_address_taken))
			res |= ir_sc_modifier_nottaken;
	} else if (irn == get_irg_frame(irg)) {
		res = ir_sc_localvar;
		if (ent != NULL && !(get_entity_usage(ent) & ir_usage_address_taken))
			res |= ir_sc_modifier_nottaken;
	} else if (is_Proj(irn) && is_malloc_Result(irn)) {
		return ir_sc_malloced;
	} else if (is_Const(irn)) {
		return ir_sc_globaladdr;
	} else if (is_arg_Proj(irn)) {
		res |= ir_sc_modifier_argument;
	}

	return res;
}

static const ir_node *skip_bitfield_sels(const ir_node *adr)
{
	while (is_Sel(adr)) {
		ir_entity *entity = get_Sel_entity(adr);
		if (is_compound_type(get_entity_owner(entity)) &&
			get_entity_bitfield_size(entity) > 0) {
			adr = get_Sel_ptr(adr);
		} else {
			break;
		}
	}
	return adr;
}

/**
 * Determine the alias relation between two addresses.
 *
 * @param addr1  pointer address of the first memory operation
 * @param type1  the type of the accessed data through addr1
 * @param addr2  pointer address of the second memory operation
 * @param type2  the type of the accessed data through addr2
 *
 * @return found memory relation
 */
static ir_alias_relation _get_alias_relation(
	const ir_node *adr1, const ir_type *const type1,
	const ir_node *adr2, const ir_type *const type2)
{

	if (!get_opt_alias_analysis())
		return ir_may_alias;

	if (adr1 == adr2)
		return ir_sure_alias;

	ir_graph *const irg     = get_irn_irg(adr1);
	unsigned  const options = get_irg_memory_disambiguator_options(irg);

	/* The Armageddon switch */
	if (options & aa_opt_no_alias)
		return ir_no_alias;

	/* do the addresses have constants offsets from the same base?
	 *  Note: nodes are normalized to have constants at right inputs,
	 *        sub X, C is normalized to add X, -C
	 */
	long           offset1            = 0;
	long           offset2            = 0;
	const ir_node *sym_offset1        = NULL;
	const ir_node *sym_offset2        = NULL;
	const ir_node *orig_adr1          = adr1;
	const ir_node *orig_adr2          = adr2;
	bool           have_const_offsets = true;

	/*
	 * Currently, only expressions with at most one symbolic
	 * offset can be handled.  To extend this, change
	 * sym_offset{1,2} to be sets, and compare the sets.
	 */

	while (is_Add(adr1)) {
		ir_node *ptr_node;
		ir_node *int_node;

		ir_mode *mode_left = get_irn_mode(get_Add_left(adr1));

		if (mode_is_reference(mode_left)) {
			ptr_node = get_Add_left(adr1);
			int_node = get_Add_right(adr1);
		} else {
			ptr_node = get_Add_right(adr1);
			int_node = get_Add_left(adr1);
		}

		if (is_Const(int_node)) {
			ir_tarval *tv  = get_Const_tarval(int_node);
			offset1       += get_tarval_long(tv);
		} else if (sym_offset1 == NULL) {
			sym_offset1 = int_node;
		} else {
			// adr1 has more than one symbolic offset.
			// Give up
			have_const_offsets = false;
		}

		adr1 = ptr_node;
	}

	while (is_Add(adr2)) {
		ir_node *ptr_node;
		ir_node *int_node;

		ir_mode *mode_left = get_irn_mode(get_Add_left(adr2));

		if (mode_is_reference(mode_left)) {
			ptr_node = get_Add_left(adr2);
			int_node = get_Add_right(adr2);
		} else {
			ptr_node = get_Add_right(adr2);
			int_node = get_Add_left(adr2);
		}

		if (is_Const(int_node)) {
			ir_tarval *tv  = get_Const_tarval(int_node);
			offset2       += get_tarval_long(tv);
		} else if (sym_offset2 == NULL) {
			sym_offset2 = int_node;
		} else {
			// adr2 has more than one symbolic offset.
			// Give up
			have_const_offsets = false;
		}

		adr2 = ptr_node;
	}

	unsigned type_size = get_type_size_bytes(type1);
	if (get_type_size_bytes(type2) > type_size) {
		type_size = get_type_size_bytes(type2);
	}

	/* same base address -> compare offsets if possible.
	 * FIXME: type long is not sufficient for this task ...
	 */
	if (adr1 == adr2 && sym_offset1 == sym_offset2 && have_const_offsets) {
		if ((unsigned long)labs(offset2 - offset1) >= type_size)
			return ir_no_alias;
		else
			return ir_sure_alias;
	}

	 /*
	  * Bitfields can be constructed as Sels from its base address.
	  * As they have different entities, the disambiguator would find that they
	  * are alias free. While this is true for its values, it is false for the
	  * addresses (strictly speaking, the Sel's are NOT the addresses of the
	  * bitfields).
	  * So, skip those bitfield selecting Sel's.
	  */
	adr1 = skip_bitfield_sels(adr1);
	adr2 = skip_bitfield_sels(adr2);

	/* skip Sels */
	const ir_node *base1 = adr1;
	const ir_node *base2 = adr2;
	ir_entity *ent1  = NULL;
	ir_entity *ent2  = NULL;
	if (is_Sel(adr1)) {
		base1 = find_base_adr(adr1, &ent1);
	}
	if (is_Sel(adr2)) {
		base2 = find_base_adr(adr2, &ent2);
	}
<commit_msg>Make alias analysis more exact.<commit_after>/*
 * This file is part of libFirm.
 * Copyright (C) 2012 University of Karlsruhe.
 */

/**
 * @file
 * @brief    Memory disambiguator
 * @author   <NAME>
 * @date     27.12.2006
 */
#include <stdlib.h>
#include <stdbool.h>

#include "adt/pmap.h"
#include "irnode_t.h"
#include "irgraph_t.h"
#include "irprog_t.h"
#include "irmemory_t.h"
#include "irmemory.h"
#include "irflag.h"
#include "hashptr.h"
#include "irflag.h"
#include "irouts.h"
#include "irgwalk.h"
#include "irprintf.h"
#include "debug.h"
#include "error.h"
#include "typerep.h"
#include "type_t.h"

/** The debug handle. */
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
DEBUG_ONLY(static firm_dbg_module_t *dbgcall = NULL;)

/** The source language specific language disambiguator function. */
static DISAMBIGUATOR_FUNC language_disambuigator = NULL;

/** The global memory disambiguator options. */
static unsigned global_mem_disamgig_opt = aa_opt_no_opt;

const char *get_ir_alias_relation_name(ir_alias_relation rel)
{
#define X(a) case a: return #a
	switch (rel) {
	X(ir_no_alias);
	X(ir_may_alias);
	X(ir_sure_alias);
	}
#undef X
	panic("UNKNOWN alias relation");
}

unsigned get_irg_memory_disambiguator_options(const ir_graph *irg)
{
	unsigned opt = irg->mem_disambig_opt;
	if (opt & aa_opt_inherited)
		return global_mem_disamgig_opt;
	return opt;
}

void set_irg_memory_disambiguator_options(ir_graph *irg, unsigned options)
{
	irg->mem_disambig_opt = options & ~aa_opt_inherited;
}

void set_irp_memory_disambiguator_options(unsigned options)
{
	global_mem_disamgig_opt = options;
}

ir_storage_class_class_t get_base_sc(ir_storage_class_class_t x)
{
	return x & ~ir_sc_modifiers;
}

/**
 * Find the base address and entity of an Sel node.
 *
 * @param sel  the node
 * @param pEnt after return points to the base entity.
 *
 * @return the base address.
 */
static ir_node *find_base_adr(const ir_node *sel, ir_entity **pEnt)
{
	ir_node *ptr = get_Sel_ptr(sel);

	while (is_Sel(ptr)) {
		sel = ptr;
		ptr = get_Sel_ptr(sel);
	}
	*pEnt = get_Sel_entity(sel);
	return ptr;
}

/**
 * Check if a given Const node is greater or equal a given size.
 *
 * @param cns   a Const node
 * @param size  a integer size
 *
 * @return ir_no_alias if the Const is greater, ir_may_alias else
 */
static ir_alias_relation check_const(const ir_node *cns, int size)
{
	ir_tarval *tv = get_Const_tarval(cns);

	if (size == 0)
		return tarval_is_null(tv) ? ir_may_alias : ir_no_alias;
	ir_tarval *tv_size = new_tarval_from_long(size, get_tarval_mode(tv));
	return tarval_cmp(tv_size, tv) & (ir_relation_less_equal) ? ir_no_alias : ir_may_alias;
}

/**
 * Treat idx1 and idx2 as integer indexes and check if they differ always more than size.
 *
 * @param idx1  a node representing the first index
 * @param idx2  a node representing the second index
 * @param size  an integer size
 *
 * @return ir_sure_alias iff idx1 == idx2
 *         ir_no_alias iff they ALWAYS differ more than size
 *         ir_may_alias else
 */
static ir_alias_relation different_index(const ir_node *idx1,
                                         const ir_node *idx2, int size)
{
	if (idx1 == idx2)
		return ir_sure_alias;
	if (is_Const(idx1) && is_Const(idx2)) {
		/* both are const, we can compare them */
		ir_tarval *tv1 = get_Const_tarval(idx1);
		ir_tarval *tv2 = get_Const_tarval(idx2);
		if (size == 0)
			return tv1 == tv2 ? ir_sure_alias : ir_no_alias;

		/* arg, modes may be different */
		ir_mode *m1 = get_tarval_mode(tv1);
		ir_mode *m2 = get_tarval_mode(tv2);
		if (m1 != m2) {
			int size = get_mode_size_bits(m1) - get_mode_size_bits(m2);

			if (size < 0) {
				/* m1 is a small mode, cast up */
				m1 = mode_is_signed(m1) ? find_signed_mode(m2) : find_unsigned_mode(m2);
				if (m1 == NULL) {
					/* should NOT happen, but if it does we give up here */
					return ir_may_alias;
				}
				tv1 = tarval_convert_to(tv1, m1);
			} else if (size > 0) {
				/* m2 is a small mode, cast up */
				m2 = mode_is_signed(m2) ? find_signed_mode(m1) : find_unsigned_mode(m1);
				if (m2 == NULL) {
					/* should NOT happen, but if it does we give up here */
					return ir_may_alias;
				}
				tv2 = tarval_convert_to(tv2, m2);
			}
			/* here the size should be identical, check for signed */
			if (get_mode_sign(m1) != get_mode_sign(m2)) {
				/* find the signed */
				if (mode_is_signed(m2)) {
					ir_tarval *t = tv1;
					tv1 = tv2;
					tv2 = t;
					ir_mode *tm = m1;
					m1 = m2;
					m2 = tm;
				}

				/* m1 is now the signed one */
				if (!tarval_is_negative(tv1)) {
					/* tv1 is signed, but >= 0, simply cast into unsigned */
					tv1 = tarval_convert_to(tv1, m2);
				} else {
					ir_tarval *tv_size = new_tarval_from_long(size, m2);
					if (tarval_cmp(tv2, tv_size) & (ir_relation_greater_equal)) {
						/* tv1 is negative and tv2 >= tv_size, so the difference is bigger than size */
						return ir_no_alias;
					}
					/* tv_size > tv2, so we can subtract without overflow */
					tv2 = tarval_sub(tv_size, tv2, NULL);

					/* tv1 is < 0, so we can negate it */
					tv1 = tarval_neg(tv1);

					/* cast it into unsigned. for two-complement it does the right thing for MIN_INT */
					tv1 = tarval_convert_to(tv1, m2);

					/* now we can compare without overflow */
					return tarval_cmp(tv1, tv2) & (ir_relation_greater_equal) ? ir_no_alias : ir_may_alias;
				}
			}
		}
		if (tarval_cmp(tv1, tv2) == ir_relation_greater) {
			ir_tarval *t = tv1;
			tv1 = tv2;
			tv2 = t;
		}
		/* tv1 is now the "smaller" one */
		ir_tarval *tv      = tarval_sub(tv2, tv1, NULL);
		ir_tarval *tv_size = new_tarval_from_long(size, get_tarval_mode(tv));
		return tarval_cmp(tv_size, tv) & (ir_relation_less_equal) ? ir_no_alias : ir_may_alias;
	}

	/* Note: we rely here on the fact that normalization puts constants on the RIGHT side */
	if (is_Add(idx1)) {
		ir_node *l1 = get_Add_left(idx1);
		ir_node *r1 = get_Add_right(idx1);

		if (l1 == idx2) {
			/* x + c == y */
			if (is_Const(r1))
				return check_const(r1, size);
		}
		if (is_Add(idx2)) {
			/* both are Adds, check if they are of x + a == x + b kind */
			ir_node *l2 = get_Add_left(idx2);
			ir_node *r2 = get_Add_right(idx2);

			if (l1 == l2)
				return different_index(r1, r2, size);
			else if (l1 == r2)
				return different_index(r1, l2, size);
			else if (r1 == r2)
				return different_index(l1, l2, size);
			else if (r1 == l2)
				return different_index(l1, r2, size);
		}
	}
	if (is_Add(idx2)) {
		ir_node *l2 = get_Add_left(idx2);
		ir_node *r2 = get_Add_right(idx2);

		if (l2 == idx1) {
			/* x + c == y */
			if (is_Const(r2))
				return check_const(r2, size);
		}
	}

	if (is_Sub(idx1)) {
		ir_node *l1 = get_Sub_left(idx1);
		ir_node *r1 = get_Sub_right(idx1);

		if (l1 == idx2) {
			/* x - c == y */
			if (is_Const(r1))
				return check_const(r1, size);
		}

		if (is_Sub(idx2)) {
			/* both are Subs, check if they are of x - a == x - b kind */
			ir_node *l2 = get_Sub_left(idx2);

			if (l1 == l2) {
				ir_node *r2 = get_Sub_right(idx2);
				return different_index(r1, r2, size);
			}
		}
	}
	if (is_Sub(idx2)) {
		ir_node *l2 = get_Sub_left(idx2);
		ir_node *r2 = get_Sub_right(idx2);

		if (l2 == idx1) {
			/* x - c == y */
			if (is_Const(r2))
				return check_const(r2, size);
		}

	}
	return ir_may_alias;
}

/**
 * Two Sel addresses have the same base address, check if their offsets are
 * different.
 *
 * @param adr1  The first address.
 * @param adr2  The second address.
 */
static ir_alias_relation different_sel_offsets(const ir_node *sel1,
                                               const ir_node *sel2)
{
	/* TODO: fix */
	(void) sel1;
	(void) sel2;
#if 0
	ir_entity *ent1 = get_Sel_entity(sel1);
	ir_entity *ent2 = get_Sel_entity(sel2);
	int i, check_arr = 0;

	if (ent1 == ent2)
		check_arr = 1;
	else {
		ir_type *tp1 = get_entity_type(ent1);
		ir_type *tp2 = get_entity_type(ent2);

		if (tp1 == tp2)
			check_arr = 1;
		else if (get_type_state(tp1) == layout_fixed && get_type_state(tp2) == layout_fixed &&
		         get_type_size_bytes(tp1) == get_type_size_bytes(tp2))
			check_arr = 1;
	}
	if (check_arr) {
		/* we select an entity of same size, check for indexes */
		int n = get_Sel_n_indexs(sel1);
		int have_no = 0;

		if (n > 0 && n == get_Sel_n_indexs(sel2)) {
			/* same non-zero number of indexes, an array access, check */
			for (i = 0; i < n; ++i) {
				ir_node *idx1 = get_Sel_index(sel1, i);
				ir_node *idx2 = get_Sel_index(sel2, i);
				ir_alias_relation res = different_index(idx1, idx2, 0); /* we can safely IGNORE the size here if it's at least >0 */

				if (res == may_alias)
					return may_alias;
				else if (res == no_alias)
					have_no = 1;
			}
			/* if we have at least one no_alias, there is no alias relation, else we have sure */
			return have_no > 0 ? no_alias : sure_alias;
		}
	}
#else
	(void) different_index;
#endif
	return ir_may_alias;
}

/**
 * Determine the alias relation by checking if adr1 and adr2 are pointer
 * to different type.
 *
 * @param adr1    The first address.
 * @param adr2    The second address.
 */
static ir_alias_relation different_types(const ir_node *adr1,
                                         const ir_node *adr2)
{
	ir_entity *ent1 = NULL;
	ir_entity *ent2 = NULL;

	if (is_SymConst_addr_ent(adr1))
		ent1 = get_SymConst_entity(adr1);
	else if (is_Sel(adr1))
		ent1 = get_Sel_entity(adr1);

	if (is_SymConst_addr_ent(adr2))
		ent2 = get_SymConst_entity(adr2);
	else if (is_Sel(adr2))
		ent2 = get_Sel_entity(adr2);

	if (ent1 != NULL && ent2 != NULL) {
		ir_type *tp1 = get_entity_type(ent1);
		ir_type *tp2 = get_entity_type(ent2);

		if (tp1 != tp2) {
			/* do deref until no pointer types are found */
			while (is_Pointer_type(tp1) && is_Pointer_type(tp2)) {
				tp1 = get_pointer_points_to_type(tp1);
				tp2 = get_pointer_points_to_type(tp2);
			}

			if (get_type_tpop(tp1) != get_type_tpop(tp2)) {
				/* different type structure */
				return ir_no_alias;
			}
			if (is_Class_type(tp1)) {
				/* check class hierarchy */
				if (!is_SubClass_of(tp1, tp2) && !is_SubClass_of(tp2, tp1))
					return ir_no_alias;
			} else {
				/* different types */
				return ir_no_alias;
			}
		}
	}
	return ir_may_alias;
}

/**
 * Returns non-zero if a node is a result on a malloc-like routine.
 *
 * @param node  the Proj node to test
 */
static int is_malloc_Result(const ir_node *node)
{
	node = get_Proj_pred(node);
	if (!is_Proj(node))
		return 0;
	node = get_Proj_pred(node);
	if (!is_Call(node))
		return 0;
	node = get_Call_ptr(node);
	if (is_SymConst_addr_ent(node)) {
		ir_entity *ent = get_SymConst_entity(node);

		if (get_entity_additional_properties(ent) & mtp_property_malloc)
			return 1;
		return 0;
	}
	return 0;
}

ir_storage_class_class_t classify_pointer(const ir_node *irn,
                                          const ir_entity *ent)
{
	ir_graph                *irg = get_irn_irg(irn);
	ir_storage_class_class_t res = ir_sc_pointer;
	if (is_SymConst_addr_ent(irn)) {
		ir_entity *entity = get_SymConst_entity(irn);
		ir_type   *owner  = get_entity_owner(entity);
		res = owner == get_tls_type() ? ir_sc_tls : ir_sc_globalvar;
		if (!(get_entity_usage(entity) & ir_usage_address_taken))
			res |= ir_sc_modifier_nottaken;
	} else if (irn == get_irg_frame(irg)) {
		res = ir_sc_localvar;
		if (ent != NULL && !(get_entity_usage(ent) & ir_usage_address_taken))
			res |= ir_sc_modifier_nottaken;
	} else if (is_Proj(irn) && is_malloc_Result(irn)) {
		return ir_sc_malloced;
	} else if (is_Const(irn)) {
		return ir_sc_globaladdr;
	} else if (is_arg_Proj(irn)) {
		res |= ir_sc_modifier_argument;
	}

	return res;
}

static const ir_node *skip_bitfield_sels(const ir_node *adr)
{
	while (is_Sel(adr)) {
		ir_entity *entity = get_Sel_entity(adr);
		if (is_compound_type(get_entity_owner(entity)) &&
			get_entity_bitfield_size(entity) > 0) {
			adr = get_Sel_ptr(adr);
		} else {
			break;
		}
	}
	return adr;
}

/**
 * Determine the alias relation between two addresses.
 *
 * @param addr1  pointer address of the first memory operation
 * @param type1  the type of the accessed data through addr1
 * @param addr2  pointer address of the second memory operation
 * @param type2  the type of the accessed data through addr2
 *
 * @return found memory relation
 */
static ir_alias_relation _get_alias_relation(
	const ir_node *adr1, const ir_type *const type1,
	const ir_node *adr2, const ir_type *const type2)
{

	if (!get_opt_alias_analysis())
		return ir_may_alias;

	if (adr1 == adr2)
		return ir_sure_alias;

	ir_graph *const irg     = get_irn_irg(adr1);
	unsigned  const options = get_irg_memory_disambiguator_options(irg);

	/* The Armageddon switch */
	if (options & aa_opt_no_alias)
		return ir_no_alias;

	/* do the addresses have constants offsets from the same base?
	 *  Note: sub X, C is normalized to add X, -C
	 */
	long           offset1            = 0;
	long           offset2            = 0;
	const ir_node *sym_offset1        = NULL;
	const ir_node *sym_offset2        = NULL;
	const ir_node *orig_adr1          = adr1;
	const ir_node *orig_adr2          = adr2;
	bool           have_const_offsets = true;

	/*
	 * Currently, only expressions with at most one symbolic
	 * offset can be handled.  To extend this, change
	 * sym_offset{1,2} to be sets, and compare the sets.
	 */

	while (is_Add(adr1)) {
		ir_node *ptr_node;
		ir_node *int_node;

		ir_mode *mode_left = get_irn_mode(get_Add_left(adr1));

		if (mode_is_reference(mode_left)) {
			ptr_node = get_Add_left(adr1);
			int_node = get_Add_right(adr1);
		} else {
			ptr_node = get_Add_right(adr1);
			int_node = get_Add_left(adr1);
		}

		if (is_Const(int_node)) {
			ir_tarval *tv  = get_Const_tarval(int_node);
			offset1       += get_tarval_long(tv);
		} else if (sym_offset1 == NULL) {
			sym_offset1 = int_node;
		} else {
			// adr1 has more than one symbolic offset.
			// Give up
			have_const_offsets = false;
		}

		adr1 = ptr_node;
	}

	while (is_Add(adr2)) {
		ir_node *ptr_node;
		ir_node *int_node;

		ir_mode *mode_left = get_irn_mode(get_Add_left(adr2));

		if (mode_is_reference(mode_left)) {
			ptr_node = get_Add_left(adr2);
			int_node = get_Add_right(adr2);
		} else {
			ptr_node = get_Add_right(adr2);
			int_node = get_Add_left(adr2);
		}

		if (is_Const(int_node)) {
			ir_tarval *tv  = get_Const_tarval(int_node);
			offset2       += get_tarval_long(tv);
		} else if (sym_offset2 == NULL) {
			sym_offset2 = int_node;
		} else {
			// adr2 has more than one symbolic offset.
			// Give up
			have_const_offsets = false;
		}

		adr2 = ptr_node;
	}

	unsigned type_size = get_type_size_bytes(type1);
	if (get_type_size_bytes(type2) > type_size) {
		type_size = get_type_size_bytes(type2);
	}

	/* same base address -> compare offsets if possible.
	 * FIXME: type long is not sufficient for this task ...
	 */
	if (adr1 == adr2 && sym_offset1 == sym_offset2 && have_const_offsets) {
		unsigned long first_offset, last_offset;
		unsigned first_type_size;

		if (offset1 <= offset2) {
			first_offset = offset1;
			last_offset = offset2;
			first_type_size = get_type_size_bytes(type1);
		} else {
			first_offset = offset2;
			last_offset = offset1;
			first_type_size = get_type_size_bytes(type2);
		}

		if (first_offset + first_type_size <= last_offset)
			return ir_no_alias;
		else
			return ir_sure_alias;
	}

	 /*
	  * Bitfields can be constructed as Sels from its base address.
	  * As they have different entities, the disambiguator would find that they
	  * are alias free. While this is true for its values, it is false for the
	  * addresses (strictly speaking, the Sel's are NOT the addresses of the
	  * bitfields).
	  * So, skip those bitfield selecting Sel's.
	  */
	adr1 = skip_bitfield_sels(adr1);
	adr2 = skip_bitfield_sels(adr2);

	/* skip Sels */
	const ir_node *base1 = adr1;
	const ir_node *base2 = adr2;
	ir_entity *ent1  = NULL;
	ir_entity *ent2  = NULL;
	if (is_Sel(adr1)) {
		base1 = find_base_adr(adr1, &ent1);
	}
	if (is_Sel(adr2)) {
		base2 = find_base_adr(adr2, &ent2);
	}

{'fraction_non_alphanumeric': 0.1154511976330616, 'fraction_numerical': 0.02108841396241856, 'mean_word_length': 3.305149051490515, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6154391', 'n_tokens_mistral': 13537, 'n_tokens_neox': 12258, 'n_words': 3148}