1/* { dg-require-effective-target freorder } */
2/* { dg-options "-O2 -freorder-blocks-and-partition" } */
3#include <stdlib.h>
4
5#if !defined(NO_LABEL_VALUES) && (!defined(STACK_SIZE) || STACK_SIZE >= 4000) && __INT_MAX__ >= 2147483647
6typedef unsigned int uint32;
7typedef signed int sint32;
8
9typedef uint32 reg_t;
10
11typedef unsigned long int host_addr_t;
12typedef uint32 target_addr_t;
13typedef sint32 target_saddr_t;
14
15typedef union
16{
17  struct
18    {
19      unsigned int	offset:18;
20      unsigned int	ignore:4;
21      unsigned int	s1:8;
22      int		:2;
23      signed int	simm:14;
24      unsigned int	s3:8;
25      unsigned int	s2:8;
26      int		pad2:2;
27    } f1;
28  long long ll;
29  double d;
30} insn_t;
31
32typedef struct
33{
34  target_addr_t vaddr_tag;
35  unsigned long int rigged_paddr;
36} tlb_entry_t;
37
38typedef struct
39{
40  insn_t *pc;
41  reg_t registers[256];
42  insn_t *program;
43  tlb_entry_t tlb_tab[0x100];
44} environment_t;
45
46enum operations
47{
48  LOAD32_RR,
49  METAOP_DONE
50};
51
52host_addr_t
53f ()
54{
55  abort ();
56}
57
58reg_t
59simulator_kernel (int what, environment_t *env)
60{
61  register insn_t *pc = env->pc;
62  register reg_t *regs = env->registers;
63  register insn_t insn;
64  register int s1;
65  register reg_t r2;
66  register void *base_addr = &&sim_base_addr;
67  register tlb_entry_t *tlb = env->tlb_tab;
68
69  if (what != 0)
70    {
71      int i;
72      static void *op_map[] =
73	{
74	  &&L_LOAD32_RR,
75	  &&L_METAOP_DONE,
76	};
77      insn_t *program = env->program;
78      for (i = 0; i < what; i++)
79	program[i].f1.offset = op_map[program[i].f1.offset] - base_addr;
80    }
81
82 sim_base_addr:;
83
84  insn = *pc++;
85  r2 = (*(reg_t *) (((char *) regs) + (insn.f1.s2 << 2)));
86  s1 = (insn.f1.s1 << 2);
87  goto *(base_addr + insn.f1.offset);
88
89 L_LOAD32_RR:
90  {
91    target_addr_t vaddr_page = r2 / 4096;
92    unsigned int x = vaddr_page % 0x100;
93    insn = *pc++;
94
95    for (;;)
96      {
97	target_addr_t tag = tlb[x].vaddr_tag;
98	host_addr_t rigged_paddr = tlb[x].rigged_paddr;
99
100	if (tag == vaddr_page)
101	  {
102	    *(reg_t *) (((char *) regs) + s1) = *(uint32 *) (rigged_paddr + r2);
103	    r2 = *(reg_t *) (((char *) regs) + (insn.f1.s2 << 2));
104	    s1 = insn.f1.s1 << 2;
105	    goto *(base_addr + insn.f1.offset);
106	  }
107
108	if (((target_saddr_t) tag < 0))
109	  {
110	    *(reg_t *) (((char *) regs) + s1) = *(uint32 *) f ();
111	    r2 = *(reg_t *) (((char *) regs) + (insn.f1.s2 << 2));
112	    s1 = insn.f1.s1 << 2;
113	    goto *(base_addr + insn.f1.offset);
114	  }
115
116	x = (x - 1) % 0x100;
117      }
118
119    L_METAOP_DONE:
120      return (*(reg_t *) (((char *) regs) + s1));
121  }
122}
123
124insn_t program[2 + 1];
125
126void *malloc ();
127
128int
129main ()
130{
131  environment_t env;
132  insn_t insn;
133  int i, res;
134  host_addr_t a_page = (host_addr_t) malloc (2 * 4096);
135  target_addr_t a_vaddr = 0x123450;
136  target_addr_t vaddr_page = a_vaddr / 4096;
137  a_page = (a_page + 4096 - 1) & -4096;
138
139  env.tlb_tab[((vaddr_page) % 0x100)].vaddr_tag = vaddr_page;
140  env.tlb_tab[((vaddr_page) % 0x100)].rigged_paddr = a_page - vaddr_page * 4096;
141  insn.f1.offset = LOAD32_RR;
142  env.registers[0] = 0;
143  env.registers[2] = a_vaddr;
144  *(sint32 *) (a_page + a_vaddr % 4096) = 88;
145  insn.f1.s1 = 0;
146  insn.f1.s2 = 2;
147
148  for (i = 0; i < 2; i++)
149    program[i] = insn;
150
151  insn.f1.offset = METAOP_DONE;
152  insn.f1.s1 = 0;
153  program[2] = insn;
154
155  env.pc = program;
156  env.program = program;
157
158  res = simulator_kernel (2 + 1, &env);
159
160  if (res != 88)
161    abort ();
162  exit (0);
163}
164#else
165main(){ exit (0); }
166#endif
167