re PR rtl-optimization/37922 (code generation error)

2008-12-18  Kenneth Zadeck <zadeck@naturalbridge.com>

	PR rtl-optimization/37922
	* dse.c (bb_info): Added regs_live field.
	(look_for_hardregs): New function.
	(replace_read): Added regs_live parameter and code to check that
	shift sequence does not clobber live hardregs.
	(check_mem_read_rtx): Added parameter to replace_read.
	(dse_step1): Added regs_live bitmap and initialize it.
	(rest_of_handle_dse): Added DF_NOTES problem and earlier call to
	df_analyze.
	* df-problems.c Renamed to 
	df_simulate_initialize_backwards.
	(df_simulate_one_insn): Renamed to
	df_simulate_one_insn_backwards.
	(df_simulate_artificial_refs_at_top): Renamed to 
	df_simulate_finalize_backwards.
	(df_simulate_initialized_forwards,
	df_simulate_one_insn_forwards,
	df_simulate_finalize_backwards): New functions.
	* df.h (df_simulate_artificial_refs_at_end): Renamed to 
	df_simulate_initialize_backwards.
	(df_simulate_one_insn): Renamed to
	df_simulate_one_insn_backwards.
	(df_simulate_artificial_refs_at_top): Renamed to 
	df_simulate_finalize_backwards.
	(df_simulate_initialized_forwards,
	df_simulate_one_insn_forwards,
	df_simulate_finalize_backwards): New functions.
	* ra-conflict.c (global_conflicts): Renamed
	df_simulate_artificial_refs_at_end to
	df_simulate_initialize_backwards.
	* sel-sched.c (propagate_lv_set): Renamed df_simulate_one_insn to
	df_simulate_one_insn_backwards.
	* ifcvt.c (dead_or_predicable): Renamed
	df_simulate_artificial_refs_at_end to
	df_simulate_initialize_backwards. Renamed df_simulate_one_insn to
	df_simulate_one_insn_backwards.
	* recog.c (peephole2_optimize): Ditto.
	* rtl-factoring (collect_pattern_seqs, clear_regs_live_in_seq): Ditto.

2008-12-18  Kenneth Zadeck <zadeck@naturalbridge.com>

	PR rtl-optimization/37922
	* g++.dg/torture/pr37922.C: New test.

From-SVN: r142809
This commit is contained in:
Kenneth Zadeck 2008-12-18 13:38:39 +00:00 committed by Kenneth Zadeck
parent fb5bc08bb3
commit 02b47899e1
12 changed files with 743 additions and 35 deletions

View File

@ -1,3 +1,44 @@
2008-12-18 Kenneth Zadeck <zadeck@naturalbridge.com>
PR rtl-optimization/37922
* dse.c (bb_info): Added regs_live field.
(look_for_hardregs): New function.
(replace_read): Added regs_live parameter and code to check that
shift sequence does not clobber live hardregs.
(check_mem_read_rtx): Added parameter to replace_read.
(dse_step1): Added regs_live bitmap and initialize it.
(rest_of_handle_dse): Added DF_NOTES problem and earlier call to
df_analyze.
* df-problems.c Renamed to
df_simulate_initialize_backwards.
(df_simulate_one_insn): Renamed to
df_simulate_one_insn_backwards.
(df_simulate_artificial_refs_at_top): Renamed to
df_simulate_finalize_backwards.
(df_simulate_initialized_forwards,
df_simulate_one_insn_forwards,
df_simulate_finalize_backwards): New functions.
* df.h (df_simulate_artificial_refs_at_end): Renamed to
df_simulate_initialize_backwards.
(df_simulate_one_insn): Renamed to
df_simulate_one_insn_backwards.
(df_simulate_artificial_refs_at_top): Renamed to
df_simulate_finalize_backwards.
(df_simulate_initialized_forwards,
df_simulate_one_insn_forwards,
df_simulate_finalize_backwards): New functions.
* ra-conflict.c (global_conflicts): Renamed
df_simulate_artificial_refs_at_end to
df_simulate_initialize_backwards.
* sel-sched.c (propagate_lv_set): Renamed df_simulate_one_insn to
df_simulate_one_insn_backwards.
* ifcvt.c (dead_or_predicable): Renamed
df_simulate_artificial_refs_at_end to
df_simulate_initialize_backwards. Renamed df_simulate_one_insn to
df_simulate_one_insn_backwards.
* recog.c (peephole2_optimize): Ditto.
* rtl-factoring (collect_pattern_seqs, clear_regs_live_in_seq): Ditto.
2008-12-18 Jakub Jelinek <jakub@redhat.com>
PR middle-end/38533

View File

@ -607,7 +607,7 @@ dce_process_block (basic_block bb, bool redo_out, bitmap au)
bitmap_copy (local_live, DF_LR_OUT (bb));
df_simulate_artificial_refs_at_end (bb, local_live);
df_simulate_initialize_backwards (bb, local_live);
FOR_BB_INSNS_REVERSE (bb, insn)
if (INSN_P (insn))
@ -636,7 +636,7 @@ dce_process_block (basic_block bb, bool redo_out, bitmap au)
df_simulate_uses (insn, local_live);
}
df_simulate_artificial_refs_at_top (bb, local_live);
df_simulate_finalize_backwards (bb, local_live);
block_changed = !bitmap_equal_p (local_live, DF_LR_IN (bb));
if (block_changed)

View File

@ -3759,24 +3759,19 @@ df_simulate_fixup_sets (basic_block bb, bitmap live)
The following three functions are used only for BACKWARDS scanning:
i.e. they process the defs before the uses.
df_simulate_artificial_refs_at_end should be called first with a
df_simulate_initialize_backwards should be called first with a
bitvector copyied from the DF_LIVE_OUT or DF_LR_OUT. Then
df_simulate_one_insn should be called for each insn in the block,
starting with the last on. Finally,
df_simulate_artificial_refs_at_top can be called to get a new value
df_simulate_one_insn_backwards should be called for each insn in
the block, starting with the last on. Finally,
df_simulate_finalize_backwards can be called to get a new value
of the sets at the top of the block (this is rarely used).
It would be not be difficult to define a similar set of functions
that work in the forwards direction. In that case the functions
would ignore the use sets and look for the REG_DEAD and REG_UNUSED
notes.
----------------------------------------------------------------------------*/
----------------------------------------------------------------------------*/
/* Apply the artificial uses and defs at the end of BB in a backwards
direction. */
void
df_simulate_artificial_refs_at_end (basic_block bb, bitmap live)
df_simulate_initialize_backwards (basic_block bb, bitmap live)
{
df_ref *def_rec;
df_ref *use_rec;
@ -3801,7 +3796,7 @@ df_simulate_artificial_refs_at_end (basic_block bb, bitmap live)
/* Simulate the backwards effects of INSN on the bitmap LIVE. */
void
df_simulate_one_insn (basic_block bb, rtx insn, bitmap live)
df_simulate_one_insn_backwards (basic_block bb, rtx insn, bitmap live)
{
if (! INSN_P (insn))
return;
@ -3816,7 +3811,7 @@ df_simulate_one_insn (basic_block bb, rtx insn, bitmap live)
direction. */
void
df_simulate_artificial_refs_at_top (basic_block bb, bitmap live)
df_simulate_finalize_backwards (basic_block bb, bitmap live)
{
df_ref *def_rec;
#ifdef EH_USES
@ -3840,3 +3835,92 @@ df_simulate_artificial_refs_at_top (basic_block bb, bitmap live)
}
#endif
}
/*----------------------------------------------------------------------------
The following three functions are used only for FORWARDS scanning:
i.e. they process the defs and the REG_DEAD and REG_UNUSED notes.
Thus it is important to add the DF_NOTES problem to the stack of
problems computed before using these functions.
df_simulate_initialize_forwards should be called first with a
bitvector copyied from the DF_LIVE_IN or DF_LR_IN. Then
df_simulate_one_insn_forwards should be called for each insn in
the block, starting with the last on. Finally,
df_simulate_finalize_forwards can be called to get a new value
of the sets at the bottom of the block (this is rarely used).
----------------------------------------------------------------------------*/
/* Apply the artificial uses and defs at the top of BB in a backwards
direction. */
void
df_simulate_initialize_forwards (basic_block bb, bitmap live)
{
df_ref *def_rec;
int bb_index = bb->index;
for (def_rec = df_get_artificial_defs (bb_index); *def_rec; def_rec++)
{
df_ref def = *def_rec;
if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
bitmap_clear_bit (live, DF_REF_REGNO (def));
}
}
/* Simulate the backwards effects of INSN on the bitmap LIVE. */
void
df_simulate_one_insn_forwards (basic_block bb, rtx insn, bitmap live)
{
rtx link;
if (! INSN_P (insn))
return;
/* Make sure that the DF_NOTES really is an active df problem. */
gcc_assert (df_note);
df_simulate_defs (insn, live);
/* Clear all of the registers that go dead. */
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
{
switch (REG_NOTE_KIND (link))
case REG_DEAD:
case REG_UNUSED:
{
rtx reg = XEXP (link, 0);
int regno = REGNO (reg);
if (regno < FIRST_PSEUDO_REGISTER)
{
int n = hard_regno_nregs[regno][GET_MODE (reg)];
while (--n >= 0)
bitmap_clear_bit (live, regno + n);
}
else
bitmap_clear_bit (live, regno);
break;
default:
break;
}
}
df_simulate_fixup_sets (bb, live);
}
/* Apply the artificial uses and defs at the end of BB in a backwards
direction. */
void
df_simulate_finalize_forwards (basic_block bb, bitmap live)
{
df_ref *def_rec;
int bb_index = bb->index;
for (def_rec = df_get_artificial_defs (bb_index); *def_rec; def_rec++)
{
df_ref def = *def_rec;
if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0)
bitmap_clear_bit (live, DF_REF_REGNO (def));
}
}

View File

@ -959,9 +959,12 @@ extern void df_note_add_problem (void);
extern void df_simulate_find_defs (rtx, bitmap);
extern void df_simulate_defs (rtx, bitmap);
extern void df_simulate_uses (rtx, bitmap);
extern void df_simulate_artificial_refs_at_end (basic_block, bitmap);
extern void df_simulate_one_insn (basic_block, rtx, bitmap);
extern void df_simulate_artificial_refs_at_top (basic_block, bitmap);
extern void df_simulate_initialize_backwards (basic_block, bitmap);
extern void df_simulate_one_insn_backwards (basic_block, rtx, bitmap);
extern void df_simulate_finalize_backwards (basic_block, bitmap);
extern void df_simulate_initialize_forwards (basic_block, bitmap);
extern void df_simulate_one_insn_forwards (basic_block, rtx, bitmap);
extern void df_simulate_finalize_forwards (basic_block, bitmap);
/* Functions defined in df-scan.c. */

View File

@ -374,6 +374,10 @@ struct bb_info
operations. */
bool apply_wild_read;
/* The following 4 bitvectors hold information about which positions
of which stores are live or dead. They are indexed by
get_bitmap_index. */
/* The set of store positions that exist in this block before a wild read. */
bitmap gen;
@ -401,6 +405,14 @@ struct bb_info
just initializes the vector from one of the out sets of the
successors of the block. */
bitmap out;
/* The following bitvector is indexed by the reg number. It
contains the set of regs that are live at the current instruction
being processed. While it contains info for all of the
registers, only the pseudos are actually examined. It is used to
assure that shift sequences that are inserted do not accidently
clobber live hard regs. */
bitmap regs_live;
};
typedef struct bb_info *bb_info_t;
@ -1533,6 +1545,25 @@ find_shift_sequence (int access_size,
}
/* Call back for note_stores to find the hard regs set or clobbered by
insn. Data is a bitmap of the hardregs set so far. */
static void
look_for_hardregs (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
{
bitmap regs_set = (bitmap) data;
if (REG_P (x)
&& REGNO (x) < FIRST_PSEUDO_REGISTER)
{
int regno = REGNO (x);
int n = hard_regno_nregs[regno][GET_MODE (x)];
while (--n >= 0)
bitmap_set_bit (regs_set, regno + n);
}
}
/* Take a sequence of:
A <- r1
...
@ -1566,13 +1597,13 @@ find_shift_sequence (int access_size,
static bool
replace_read (store_info_t store_info, insn_info_t store_insn,
read_info_t read_info, insn_info_t read_insn, rtx *loc)
read_info_t read_info, insn_info_t read_insn, rtx *loc, bitmap regs_live)
{
enum machine_mode store_mode = GET_MODE (store_info->mem);
enum machine_mode read_mode = GET_MODE (read_info->mem);
int shift;
int access_size; /* In bytes. */
rtx insns, read_reg;
rtx insns, this_insn, read_reg;
if (!dbg_cnt (dse))
return false;
@ -1624,6 +1655,34 @@ replace_read (store_info_t store_info, insn_info_t store_insn,
insns = get_insns ();
end_sequence ();
if (insns != NULL_RTX)
{
/* Now we have to scan the set of new instructions to see if the
sequence contains and sets of hardregs that happened to be
live at this point. For instance, this can happen if one of
the insns sets the CC and the CC happened to be live at that
point. This does occasionally happen, see PR 37922. */
bitmap regs_set = BITMAP_ALLOC (NULL);
for (this_insn = insns; this_insn != NULL_RTX; this_insn = NEXT_INSN (this_insn))
note_stores (PATTERN (this_insn), look_for_hardregs, regs_set);
bitmap_and_into (regs_set, regs_live);
if (!bitmap_empty_p (regs_set))
{
if (dump_file)
{
fprintf (dump_file,
"abandoning replacement because sequence clobbers live hardregs:");
df_print_regset (dump_file, regs_set);
}
BITMAP_FREE (regs_set);
return false;
}
BITMAP_FREE (regs_set);
}
if (validate_change (read_insn->insn, loc, read_reg, 0))
{
deferred_change_t deferred_change =
@ -1842,7 +1901,7 @@ check_mem_read_rtx (rtx *loc, void *data)
if ((store_info->positions_needed & mask) == mask
&& replace_read (store_info, i_ptr,
read_info, insn_info, loc))
read_info, insn_info, loc, bb_info->regs_live))
return 0;
}
/* The bases are the same, just see if the offsets
@ -1911,7 +1970,7 @@ check_mem_read_rtx (rtx *loc, void *data)
if ((store_info->positions_needed & mask) == mask
&& replace_read (store_info, i_ptr,
read_info, insn_info, loc))
read_info, insn_info, loc, bb_info->regs_live))
return 0;
}
@ -2139,7 +2198,8 @@ static void
dse_step1 (void)
{
basic_block bb;
bitmap regs_live = BITMAP_ALLOC (NULL);
cselib_init (false);
all_blocks = BITMAP_ALLOC (NULL);
bitmap_set_bit (all_blocks, ENTRY_BLOCK);
@ -2152,6 +2212,10 @@ dse_step1 (void)
memset (bb_info, 0, sizeof (struct bb_info));
bitmap_set_bit (all_blocks, bb->index);
bb_info->regs_live = regs_live;
bitmap_copy (regs_live, DF_LR_IN (bb));
df_simulate_initialize_forwards (bb, regs_live);
bb_table[bb->index] = bb_info;
cselib_discard_hook = remove_useless_values;
@ -2172,6 +2236,8 @@ dse_step1 (void)
if (INSN_P (insn))
scan_insn (bb_info, insn);
cselib_process_insn (insn);
if (INSN_P (insn))
df_simulate_one_insn_forwards (bb, insn, regs_live);
}
/* This is something of a hack, because the global algorithm
@ -2238,8 +2304,10 @@ dse_step1 (void)
free_alloc_pool (cse_store_info_pool);
}
bb_info->regs_live = NULL;
}
BITMAP_FREE (regs_live);
cselib_finish ();
htab_empty (rtx_group_table);
}
@ -3239,6 +3307,11 @@ rest_of_handle_dse (void)
df_set_flags (DF_DEFER_INSN_RESCAN);
/* Need the notes since we must track live hardregs in the forwards
direction. */
df_note_add_problem ();
df_analyze ();
dse_step0 ();
dse_step1 ();
dse_step2_init ();

View File

@ -3950,13 +3950,13 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
/* The loop below takes the set of live registers
after JUMP, and calculates the live set before EARLIEST. */
bitmap_copy (test_live, df_get_live_in (other_bb));
df_simulate_artificial_refs_at_end (test_bb, test_live);
df_simulate_initialize_backwards (test_bb, test_live);
for (insn = jump; ; insn = prev)
{
if (INSN_P (insn))
{
df_simulate_find_defs (insn, test_set);
df_simulate_one_insn (test_bb, insn, test_live);
df_simulate_one_insn_backwards (test_bb, insn, test_live);
}
prev = PREV_INSN (insn);
if (insn == earliest)

View File

@ -774,7 +774,7 @@ global_conflicts (void)
bitmap_iterator bi;
bitmap_copy (live, DF_LIVE_OUT (bb));
df_simulate_artificial_refs_at_end (bb, live);
df_simulate_initialize_backwards (bb, live);
sparseset_clear (allocnos_live);
memset (live_subregs_used, 0, max_allocno * sizeof (int));

View File

@ -3039,7 +3039,7 @@ peephole2_optimize (void)
/* Start up propagation. */
bitmap_copy (live, DF_LR_OUT (bb));
df_simulate_artificial_refs_at_end (bb, live);
df_simulate_initialize_backwards (bb, live);
bitmap_copy (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
for (insn = BB_END (bb); ; insn = prev)
@ -3059,7 +3059,7 @@ peephole2_optimize (void)
&& peep2_insn_data[peep2_current].insn == NULL_RTX)
peep2_current_count++;
peep2_insn_data[peep2_current].insn = insn;
df_simulate_one_insn (bb, insn, live);
df_simulate_one_insn_backwards (bb, insn, live);
COPY_REG_SET (peep2_insn_data[peep2_current].live_before, live);
if (RTX_FRAME_RELATED_P (insn))
@ -3218,7 +3218,7 @@ peephole2_optimize (void)
peep2_current_count++;
peep2_insn_data[i].insn = x;
df_insn_rescan (x);
df_simulate_one_insn (bb, x, live);
df_simulate_one_insn_backwards (bb, x, live);
bitmap_copy (peep2_insn_data[i].live_before, live);
}
x = PREV_INSN (x);

View File

@ -464,7 +464,7 @@ collect_pattern_seqs (void)
/* Initialize liveness propagation. */
INIT_REG_SET (&live);
bitmap_copy (&live, DF_LR_OUT (bb));
df_simulate_artificial_refs_at_end (bb, &live);
df_simulate_initialize_backwards (bb, &live);
/* Propagate liveness info and mark insns where a stack reg is live. */
insn = BB_END (bb);
@ -486,7 +486,7 @@ collect_pattern_seqs (void)
}
if (insn == BB_HEAD (bb))
break;
df_simulate_one_insn (bb, insn, &live);
df_simulate_one_insn_backwards (bb, insn, &live);
insn = prev;
}
@ -572,11 +572,11 @@ clear_regs_live_in_seq (HARD_REG_SET * regs, rtx insn, int length)
bb = BLOCK_FOR_INSN (insn);
INIT_REG_SET (&live);
bitmap_copy (&live, DF_LR_OUT (bb));
df_simulate_artificial_refs_at_end (bb, &live);
df_simulate_initialize_backwards (bb, &live);
/* Propagate until INSN if found. */
for (x = BB_END (bb); x != insn; x = PREV_INSN (x))
df_simulate_one_insn (bb, x, &live);
df_simulate_one_insn_backwards (bb, x, &live);
/* Clear registers live after INSN. */
renumbered_reg_set_to_hard_reg_set (&hlive, &live);
@ -586,7 +586,7 @@ clear_regs_live_in_seq (HARD_REG_SET * regs, rtx insn, int length)
for (i = 0; i < length;)
{
rtx prev = PREV_INSN (x);
df_simulate_one_insn (bb, x, &live);
df_simulate_one_insn_backwards (bb, x, &live);
if (INSN_P (x))
{

View File

@ -2947,7 +2947,7 @@ propagate_lv_set (regset lv, insn_t insn)
if (INSN_NOP_P (insn))
return;
df_simulate_one_insn (BLOCK_FOR_INSN (insn), insn, lv);
df_simulate_one_insn_backwards (BLOCK_FOR_INSN (insn), insn, lv);
}
/* Return livness set at the end of BB. */

View File

@ -1,3 +1,8 @@
2008-12-18 Kenneth Zadeck <zadeck@naturalbridge.com>
PR rtl-optimization/37922
* g++.dg/torture/pr37922.C: New test.
2008-12-18 Daniel Kraft <d@domob.eu>
PR fortran/31822

View File

@ -0,0 +1,502 @@
// { dg-do run }
// { dg-options "-fpic" { target fpic } }
typedef __SIZE_TYPE__ size_t;
template <typename NumType>
inline
NumType
absolute(NumType const& x)
{
if (x < NumType(0)) return -x;
return x;
}
class trivial_accessor
{
public:
typedef size_t index_type;
struct index_value_type {};
trivial_accessor() : size_(0) {}
trivial_accessor(size_t const& n) : size_(n) {}
size_t size_1d() const { return size_; }
protected:
size_t size_;
};
namespace N0
{
template <typename ElementType,
typename AccessorType = trivial_accessor>
class const_ref
{
public:
typedef ElementType value_type;
typedef size_t size_type;
typedef AccessorType accessor_type;
typedef typename accessor_type::index_type index_type;
typedef typename accessor_type::index_value_type index_value_type;
const_ref() {}
const_ref(const ElementType* begin, accessor_type const& accessor)
: begin_(begin), accessor_(accessor)
{
init();
}
const_ref(const ElementType* begin, index_value_type const& n0)
: begin_(begin), accessor_(n0)
{
init();
}
const_ref(const ElementType* begin, index_value_type const& n0,
index_value_type const& n1)
: begin_(begin), accessor_(n0, n1)
{
init();
}
const_ref(const ElementType* begin, index_value_type const& n0,
index_value_type const& n1,
index_value_type const& n2)
: begin_(begin), accessor_(n0, n1, n2)
{
init();
}
accessor_type const& accessor() const { return accessor_; }
size_type size() const { return size_; }
const ElementType* begin() const { return begin_; }
const ElementType* end() const { return end_; }
ElementType const&
operator[](size_type i) const { return begin_[i]; }
const_ref<ElementType>
as_1d() const
{
return const_ref<ElementType>(begin_, size_);
}
protected:
void
init()
{
size_ = accessor_.size_1d();
end_ = begin_ + size_;
}
const ElementType* begin_;
accessor_type accessor_;
size_type size_;
const ElementType* end_;
};
}
template <typename ElementType,
typename AccessorType = trivial_accessor>
class ref : public N0::const_ref<ElementType, AccessorType>
{
public:
typedef ElementType value_type;
typedef size_t size_type;
typedef N0::const_ref<ElementType, AccessorType> base_class;
typedef AccessorType accessor_type;
typedef typename accessor_type::index_type index_type;
ref() {}
ElementType*
begin() const { return const_cast<ElementType*>(this->begin_); }
ElementType*
end() const { return const_cast<ElementType*>(this->end_); }
ElementType&
operator[](size_type i) const { return begin()[i]; }
};
namespace N1 {
template <typename ElementType, size_t N>
class tiny_plain
{
public:
typedef ElementType value_type;
typedef size_t size_type;
static const size_t fixed_size=N;
ElementType elems[N];
tiny_plain() {}
static size_type size() { return N; }
ElementType* begin() { return elems; }
const ElementType* begin() const { return elems; }
ElementType* end() { return elems+N; }
const ElementType* end() const { return elems+N; }
ElementType& operator[](size_type i) { return elems[i]; }
ElementType const& operator[](size_type i) const { return elems[i]; }
};
template <typename ElementType, size_t N>
class tiny : public tiny_plain<ElementType, N>
{
public:
typedef ElementType value_type;
typedef size_t size_type;
typedef tiny_plain<ElementType, N> base_class;
tiny() {}
};
}
template <typename NumType>
class mat3 : public N1::tiny_plain<NumType, 9>
{
public:
typedef typename N1::tiny_plain<NumType, 9> base_type;
mat3() {}
mat3(NumType const& e00, NumType const& e01, NumType const& e02,
NumType const& e10, NumType const& e11, NumType const& e12,
NumType const& e20, NumType const& e21, NumType const& e22)
: base_type(e00, e01, e02, e10, e11, e12, e20, e21, e22)
{}
mat3(base_type const& a)
: base_type(a)
{}
NumType const&
operator()(size_t r, size_t c) const
{
return this->elems[r * 3 + c];
}
NumType&
operator()(size_t r, size_t c)
{
return this->elems[r * 3 + c];
}
NumType
trace() const
{
mat3 const& m = *this;
return m[0] + m[4] + m[8];
}
NumType
determinant() const
{
mat3 const& m = *this;
return m[0] * (m[4] * m[8] - m[5] * m[7])
- m[1] * (m[3] * m[8] - m[5] * m[6])
+ m[2] * (m[3] * m[7] - m[4] * m[6]);
}
};
template <typename NumType>
inline
mat3<NumType>
operator-(mat3<NumType> const& v)
{
mat3<NumType> result;
for(size_t i=0;i<9;i++) {
result[i] = -v[i];
}
return result;
}
class mat_grid : public N1::tiny<size_t, 2>
{
public:
typedef N1::tiny<size_t, 2> index_type;
typedef index_type::value_type index_value_type;
mat_grid() { this->elems[0]=0; this->elems[1]=0; }
mat_grid(index_type const& n) : index_type(n) {}
mat_grid(index_value_type const& n0, index_value_type const& n1)
{ this->elems[0]=n0; this->elems[1]=n1; }
size_t size_1d() const { return elems[0] * elems[1]; }
size_t
operator()(index_value_type const& r, index_value_type const& c) const
{
return r * elems[1] + c;
}
};
template <typename NumType, typename AccessorType = mat_grid>
class mat_const_ref : public N0::const_ref<NumType, AccessorType>
{
public:
typedef AccessorType accessor_type;
typedef typename N0::const_ref<NumType, AccessorType> base_type;
typedef typename accessor_type::index_value_type index_value_type;
mat_const_ref() {}
mat_const_ref(const NumType* begin, accessor_type const& grid)
: base_type(begin, grid)
{}
mat_const_ref(const NumType* begin, index_value_type const& n_rows,
index_value_type const& n_columns)
: base_type(begin, accessor_type(n_rows, n_columns))
{}
accessor_type
grid() const { return this->accessor(); }
index_value_type const&
n_rows() const { return this->accessor()[0]; }
index_value_type const&
n_columns() const { return this->accessor()[1]; }
NumType const&
operator()(index_value_type const& r, index_value_type const& c) const
{
return this->begin()[this->accessor()(r, c)];
}
};
template <typename NumType, typename AccessorType = mat_grid>
class mat_ref : public mat_const_ref<NumType, AccessorType>
{
public:
typedef AccessorType accessor_type;
typedef mat_const_ref<NumType, AccessorType> base_type;
typedef typename accessor_type::index_value_type index_value_type;
mat_ref() {}
mat_ref(NumType* begin, accessor_type const& grid)
: base_type(begin, grid)
{}
mat_ref(NumType* begin, index_value_type n_rows,
index_value_type n_columns)
: base_type(begin, accessor_type(n_rows, n_columns))
{}
NumType*
begin() const { return const_cast<NumType*>(this->begin_); }
NumType*
end() const { return const_cast<NumType*>(this->end_); }
NumType&
operator[](index_value_type const& i) const { return begin()[i]; }
NumType&
operator()(index_value_type const& r, index_value_type const& c) const
{
return this->begin()[this->accessor()(r, c)];
}
};
template <typename AnyType>
inline void
swap(AnyType* a, AnyType* b, size_t n)
{
for(size_t i=0;i<n;i++) {
AnyType t = a[i]; a[i] = b[i]; b[i] = t;
}
}
template <typename IntType>
size_t
form_t(mat_ref<IntType>& m,
mat_ref<IntType> const& t)
{
typedef size_t size_t;
size_t mr = m.n_rows();
size_t mc = m.n_columns();
size_t tc = t.n_columns();
if (tc) {
}
size_t i, j;
for (i = j = 0; i < mr && j < mc;) {
size_t k = i; while (k < mr && m(k,j) == 0) k++;
if (k == mr)
j++;
else {
if (i != k) {
swap(&m(i,0), &m(k,0), mc);
if (tc) swap(&t(i,0), &t(k,0), tc);
}
for (k++; k < mr; k++) {
IntType a = absolute(m(k, j));
if (a != 0 && a < absolute(m(i,j))) {
swap(&m(i,0), &m(k,0), mc);
if (tc) swap(&t(i,0), &t(k,0), tc);
}
}
if (m(i,j) < 0) {
for(size_t ic=0;ic<mc;ic++) m(i,ic) *= -1;
if (tc) for(size_t ic=0;ic<tc;ic++) t(i,ic) *= -1;
}
bool cleared = true;
for (k = i+1; k < mr; k++) {
IntType a = m(k,j) / m(i,j);
if (a != 0) {
for(size_t ic=0;ic<mc;ic++) m(k,ic) -= a * m(i,ic);
if (tc) for(size_t ic=0;ic<tc;ic++) t(k,ic) -= a * t(i,ic);
}
if (m(k,j) != 0) cleared = false;
}
if (cleared) { i++; j++; }
}
}
m = mat_ref<IntType>(m.begin(), i, mc);
return i;
}
template <typename IntType>
size_t
form(mat_ref<IntType>& m)
{
mat_ref<IntType> t(0,0,0);
return form_t(m, t);
}
typedef mat3<int> sg_mat3;
class rot_mx
{
public:
explicit
rot_mx(sg_mat3 const& m, int denominator=1)
: num_(m), den_(denominator)
{}
sg_mat3 const&
num() const { return num_; }
sg_mat3&
num() { return num_; }
int const&
operator[](size_t i) const { return num_[i]; }
int&
operator[](size_t i) { return num_[i]; }
int
const& operator()(int r, int c) const { return num_(r, c); }
int&
operator()(int r, int c) { return num_(r, c); }
int const&
den() const { return den_; }
int&
den() { return den_; }
rot_mx
minus_unit_mx() const
{
rot_mx result(*this);
for (size_t i=0;i<9;i+=4) result[i] -= den_;
return result;
}
rot_mx
operator-() const { return rot_mx(-num_, den_); }
int
type() const;
int
order(int type=0) const;
private:
sg_mat3 num_;
int den_;
};
class rot_mx_info
{
public:
rot_mx_info(rot_mx const& r);
int type() const { return type_; }
private:
int type_;
};
int rot_mx::type() const
{
int det = num_.determinant();
if (det == -1 || det == 1) {
switch (num_.trace()) {
case -3: return -1;
case -2: return -6;
case -1: if (det == -1) return -4;
else return 2;
case 0: if (det == -1) return -3;
else return 3;
case 1: if (det == -1) return -2;
else return 4;
case 2: return 6;
case 3: return 1;
}
}
return 0;
}
int rot_mx::order(int type) const
{
if (type == 0) type = rot_mx::type();
if (type > 0) return type;
if (type % 2) return -type * 2;
return -type;
}
rot_mx_info::rot_mx_info(rot_mx const& r)
: type_(r.type())
{
if (type_ == 0) {
return;
}
rot_mx proper_r = r;
int proper_order = type_;
// THE PROBLEM IS AROUND HERE
if (proper_order < 0) {
proper_order *= -1;
proper_r = -proper_r; // THIS FAILS ...
}
if (proper_order > 1) {
rot_mx rmi = proper_r.minus_unit_mx(); // ... THEREFORE WRONG HERE
mat_ref<int> re_mx(rmi.num().begin(), 3, 3);
if (form(re_mx) != 2) {
type_ = 0;
}
}
}
int main()
{
N1::tiny<int, 9> e;
e[0] = 1; e[1] = 0; e[2] = 0;
e[3] = 0; e[4] = -1; e[5] = 0;
e[6] = 0; e[7] = 0; e[8] = 1;
rot_mx r(e);
rot_mx_info ri(r);
if (ri.type() != -2)
__builtin_abort ();
return 0;
}