1/* Unit tests for RTL-handling. 2 Copyright (C) 2015-2020 Free Software Foundation, Inc. 3 4This file is part of GCC. 5 6GCC is free software; you can redistribute it and/or modify it under 7the terms of the GNU General Public License as published by the Free 8Software Foundation; either version 3, or (at your option) any later 9version. 10 11GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12WARRANTY; without even the implied warranty of MERCHANTABILITY or 13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14for more details. 15 16You should have received a copy of the GNU General Public License 17along with GCC; see the file COPYING3. If not see 18<http://www.gnu.org/licenses/>. */ 19 20#include "config.h" 21#include "system.h" 22#include "coretypes.h" 23#include "tm.h" 24#include "opts.h" 25#include "hash-set.h" 26#include "fixed-value.h" 27#include "alias.h" 28#include "flags.h" 29#include "symtab.h" 30#include "tree-core.h" 31#include "stor-layout.h" 32#include "tree.h" 33#include "stringpool.h" 34#include "stor-layout.h" 35#include "rtl.h" 36#include "pretty-print.h" 37#include "cfgbuild.h" 38#include "print-rtl.h" 39#include "selftest.h" 40#include "selftest-rtl.h" 41#include "function.h" 42#include "memmodel.h" 43#include "emit-rtl.h" 44 45#if CHECKING_P 46 47namespace selftest { 48 49/* Verify that PAT is printed as EXPECTED. Helper function for 50 selftests. */ 51 52static void 53verify_print_pattern (const char *expected, rtx pat) 54{ 55 pretty_printer pp; 56 print_pattern (&pp, pat, 1); 57 ASSERT_STREQ (expected, pp_formatted_text (&pp)); 58} 59 60/* Verify that X is dumped as EXPECTED_DUMP, using compact mode. 61 Use LOC as the effective location when reporting errors. */ 62 63void 64assert_rtl_dump_eq (const location &loc, const char *expected_dump, rtx x, 65 rtx_reuse_manager *reuse_manager) 66{ 67 named_temp_file tmp_out (".rtl"); 68 FILE *outfile = fopen (tmp_out.get_filename (), "w"); 69 rtx_writer w (outfile, 0, false, true, reuse_manager); 70 w.print_rtl (x); 71 fclose (outfile); 72 73 char *dump = read_file (SELFTEST_LOCATION, tmp_out.get_filename ()); 74 ASSERT_STREQ_AT (loc, expected_dump, dump); 75 free (dump); 76} 77 78/* Verify that regs are dumped as expected (in compact mode). */ 79 80static void 81test_dumping_regs () 82{ 83 /* Dumps of hard regs contain a target-specific name, so we don't test 84 it here; this can be tested in target-specific selftests. */ 85 86 /* Test dumping of virtual regs. The various virtual regs are inited as 87 Pmode, so this is target-specific. The tests below assume DImode, so 88 only run the tests for targets where Pmode is DImode. */ 89 if (Pmode == DImode) 90 { 91 ASSERT_RTL_DUMP_EQ ("(reg:DI virtual-incoming-args)", 92 virtual_incoming_args_rtx); 93 ASSERT_RTL_DUMP_EQ ("(reg:DI virtual-stack-vars)", 94 virtual_stack_vars_rtx); 95 ASSERT_RTL_DUMP_EQ ("(reg:DI virtual-stack-dynamic)", 96 virtual_stack_dynamic_rtx); 97 ASSERT_RTL_DUMP_EQ ("(reg:DI virtual-outgoing-args)", 98 virtual_outgoing_args_rtx); 99 ASSERT_RTL_DUMP_EQ ("(reg:DI virtual-cfa)", 100 virtual_cfa_rtx); 101 ASSERT_RTL_DUMP_EQ ("(reg:DI virtual-preferred-stack-boundary)", 102 virtual_preferred_stack_boundary_rtx); 103 } 104 105 /* Test dumping of non-virtual pseudos. */ 106 ASSERT_RTL_DUMP_EQ ("(reg:SI <0>)", 107 gen_raw_REG (SImode, LAST_VIRTUAL_REGISTER + 1)); 108 ASSERT_RTL_DUMP_EQ ("(reg:SI <1>)", 109 gen_raw_REG (SImode, LAST_VIRTUAL_REGISTER + 2)); 110} 111 112/* Verify that insns are dumped as expected (in compact mode). */ 113 114static void 115test_dumping_insns () 116{ 117 /* Barriers. */ 118 rtx_barrier *barrier = as_a <rtx_barrier *> (rtx_alloc (BARRIER)); 119 SET_NEXT_INSN (barrier) = NULL; 120 ASSERT_RTL_DUMP_EQ ("(cbarrier 0)\n", barrier); 121 122 /* Labels. */ 123 rtx_insn *label = gen_label_rtx (); 124 CODE_LABEL_NUMBER (label) = 42; 125 ASSERT_RTL_DUMP_EQ ("(clabel 0 42)\n", label); 126 127 LABEL_NAME (label)= "some_label"; 128 ASSERT_RTL_DUMP_EQ ("(clabel 0 42 (\"some_label\"))\n", label); 129} 130 131/* Manually exercise the rtx_reuse_manager code. */ 132 133static void 134test_dumping_rtx_reuse () 135{ 136 rtx_reuse_manager r; 137 138 rtx x = rtx_alloc (SCRATCH); 139 rtx y = rtx_alloc (SCRATCH); 140 rtx z = rtx_alloc (SCRATCH); 141 142 /* x and y will be seen more than once. */ 143 r.preprocess (x); 144 r.preprocess (x); 145 r.preprocess (y); 146 r.preprocess (y); 147 148 /* z will be only seen once. */ 149 r.preprocess (z); 150 151 /* Verify that x and y have been assigned reuse IDs. */ 152 int reuse_id_for_x; 153 ASSERT_TRUE (r.has_reuse_id (x, &reuse_id_for_x)); 154 ASSERT_EQ (0, reuse_id_for_x); 155 156 int reuse_id_for_y; 157 ASSERT_TRUE (r.has_reuse_id (y, &reuse_id_for_y)); 158 ASSERT_EQ (1, reuse_id_for_y); 159 160 /* z is only seen once and thus shouldn't get a reuse ID. */ 161 ASSERT_FALSE (r.has_reuse_id (z, NULL)); 162 163 /* The first dumps of x and y should be prefixed by reuse ID; 164 all subsequent dumps of them should show up as "reuse_rtx". */ 165 ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(0|scratch)", x, &r); 166 ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(reuse_rtx 0)", x, &r); 167 ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(reuse_rtx 0)", x, &r); 168 169 ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(1|scratch)", y, &r); 170 ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(reuse_rtx 1)", y, &r); 171 ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(reuse_rtx 1)", y, &r); 172 173 /* z only appears once and thus shouldn't be prefixed with a 174 reuse ID. */ 175 ASSERT_RTL_DUMP_EQ_WITH_REUSE ("(scratch)", z, &r); 176} 177 178/* Unit testing of "single_set". */ 179 180static void 181test_single_set () 182{ 183 /* A label is not a SET. */ 184 ASSERT_EQ (NULL_RTX, single_set (gen_label_rtx ())); 185 186 /* An unconditional jump insn is a single SET. */ 187 rtx set_pc = gen_rtx_SET (pc_rtx, 188 gen_rtx_LABEL_REF (VOIDmode, 189 gen_label_rtx ())); 190 rtx_insn *jump_insn = emit_jump_insn (set_pc); 191 ASSERT_EQ (set_pc, single_set (jump_insn)); 192 193 /* etc */ 194} 195 196/* Construct an unconditional jump to a label, and verify that 197 various properties of it are sane. */ 198 199static void 200test_uncond_jump () 201{ 202 set_new_first_and_last_insn (NULL, NULL); 203 rtx_insn *label = gen_label_rtx (); 204 rtx jump_pat = gen_rtx_SET (pc_rtx, 205 gen_rtx_LABEL_REF (VOIDmode, 206 label)); 207 ASSERT_EQ (SET, jump_pat->code); 208 ASSERT_EQ (LABEL_REF, SET_SRC (jump_pat)->code); 209 ASSERT_EQ (label, label_ref_label (SET_SRC (jump_pat))); 210 ASSERT_EQ (PC, SET_DEST (jump_pat)->code); 211 212 verify_print_pattern ("pc=L0", jump_pat); 213 214 ASSERT_RTL_DUMP_EQ ("(set (pc)\n" 215 " (label_ref 0))", 216 jump_pat); 217 218 rtx_insn *jump_insn = emit_jump_insn (jump_pat); 219 ASSERT_FALSE (any_condjump_p (jump_insn)); 220 ASSERT_TRUE (any_uncondjump_p (jump_insn)); 221 ASSERT_TRUE (pc_set (jump_insn)); 222 ASSERT_TRUE (simplejump_p (jump_insn)); 223 ASSERT_TRUE (onlyjump_p (jump_insn)); 224 ASSERT_TRUE (control_flow_insn_p (jump_insn)); 225 226 ASSERT_RTL_DUMP_EQ ("(cjump_insn 1 (set (pc)\n" 227 " (label_ref 0)))\n", 228 jump_insn); 229} 230 231template<unsigned int N> 232struct const_poly_int_tests 233{ 234 static void run (); 235}; 236 237template<> 238struct const_poly_int_tests<1> 239{ 240 static void run () {} 241}; 242 243/* Test various CONST_POLY_INT properties. */ 244 245template<unsigned int N> 246void 247const_poly_int_tests<N>::run () 248{ 249 rtx x1 = gen_int_mode (poly_int64 (1, 1), QImode); 250 rtx x255 = gen_int_mode (poly_int64 (1, 255), QImode); 251 252 /* Test that constants are unique. */ 253 ASSERT_EQ (x1, gen_int_mode (poly_int64 (1, 1), QImode)); 254 ASSERT_NE (x1, gen_int_mode (poly_int64 (1, 1), HImode)); 255 ASSERT_NE (x1, x255); 256 257 /* Test const_poly_int_value. */ 258 ASSERT_KNOWN_EQ (const_poly_int_value (x1), poly_int64 (1, 1)); 259 ASSERT_KNOWN_EQ (const_poly_int_value (x255), poly_int64 (1, -1)); 260 261 /* Test rtx_to_poly_int64. */ 262 ASSERT_KNOWN_EQ (rtx_to_poly_int64 (x1), poly_int64 (1, 1)); 263 ASSERT_KNOWN_EQ (rtx_to_poly_int64 (x255), poly_int64 (1, -1)); 264 ASSERT_MAYBE_NE (rtx_to_poly_int64 (x255), poly_int64 (1, 255)); 265 266 /* Test plus_constant of a symbol. */ 267 rtx symbol = gen_rtx_SYMBOL_REF (Pmode, "foo"); 268 rtx offset1 = gen_int_mode (poly_int64 (9, 11), Pmode); 269 rtx sum1 = gen_rtx_CONST (Pmode, gen_rtx_PLUS (Pmode, symbol, offset1)); 270 ASSERT_RTX_EQ (plus_constant (Pmode, symbol, poly_int64 (9, 11)), sum1); 271 272 /* Test plus_constant of a CONST. */ 273 rtx offset2 = gen_int_mode (poly_int64 (12, 20), Pmode); 274 rtx sum2 = gen_rtx_CONST (Pmode, gen_rtx_PLUS (Pmode, symbol, offset2)); 275 ASSERT_RTX_EQ (plus_constant (Pmode, sum1, poly_int64 (3, 9)), sum2); 276 277 /* Test a cancelling plus_constant. */ 278 ASSERT_EQ (plus_constant (Pmode, sum2, poly_int64 (-12, -20)), symbol); 279 280 /* Test plus_constant on integer constants. */ 281 ASSERT_EQ (plus_constant (QImode, const1_rtx, poly_int64 (4, -2)), 282 gen_int_mode (poly_int64 (5, -2), QImode)); 283 ASSERT_EQ (plus_constant (QImode, x1, poly_int64 (4, -2)), 284 gen_int_mode (poly_int64 (5, -1), QImode)); 285} 286 287/* Check dumping of repeated RTL vectors. */ 288 289static void 290test_dumping_repeat () 291{ 292 rtx p = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (3)); 293 XVECEXP (p, 0, 0) = const0_rtx; 294 XVECEXP (p, 0, 1) = const0_rtx; 295 XVECEXP (p, 0, 2) = const0_rtx; 296 ASSERT_RTL_DUMP_EQ ("(parallel [\n" 297 " (const_int 0) repeated x3\n" 298 " ])", 299 p); 300 301 XVECEXP (p, 0, 1) = const1_rtx; 302 ASSERT_RTL_DUMP_EQ ("(parallel [\n" 303 " (const_int 0)\n" 304 " (const_int 1)\n" 305 " (const_int 0)\n" 306 " ])", 307 p); 308} 309 310/* Run all of the selftests within this file. */ 311 312void 313rtl_tests_c_tests () 314{ 315 test_dumping_regs (); 316 test_dumping_insns (); 317 test_dumping_rtx_reuse (); 318 test_single_set (); 319 test_uncond_jump (); 320 const_poly_int_tests<NUM_POLY_INT_COEFFS>::run (); 321 test_dumping_repeat (); 322 323 /* Purge state. */ 324 set_first_insn (NULL); 325 set_last_insn (NULL); 326} 327 328} // namespace selftest 329#endif /* #if CHECKING_P */ 330