aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm/adlc/formsopt.hpp
blob: 8ba8e64d99cc8da4e3b8a29fc522ca31e1f3fe07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
/*
 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#ifndef SHARE_VM_ADLC_FORMSOPT_HPP
#define SHARE_VM_ADLC_FORMSOPT_HPP

// FORMSOPT.HPP - ADL Parser Target Specific Optimization Forms Classes

// Class List
class Form;
class InstructForm;
class OperandForm;
class OpClassForm;
class AttributeForm;
class RegisterForm;
class PipelineForm;
class SourceForm;
class EncodeForm;
class Component;
class Constraint;
class Predicate;
class MatchRule;
class Attribute;
class Effect;
class ExpandRule;
class RewriteRule;
class ConstructRule;
class FormatRule;
class Peephole;
class PeepMatch;
class PeepConstraint;
class EncClass;
class Interface;
class RegInterface;
class ConstInterface;
class MemInterface;
class CondInterface;
class Opcode;
class InsEncode;
class RegDef;
class RegClass;
class CodeSnippetRegClass;
class ConditionalRegClass;
class AllocClass;
class ResourceForm;
class PipeClassForm;
class PipeClassOperandForm;
class PipeClassResourceForm;
class PeepMatch;
class PeepConstraint;
class PeepReplace;
class MatchList;

class ArchDesc;

//==============================Register Allocation============================
//------------------------------RegisterForm-----------------------------------
class RegisterForm : public Form {
private:
  AllocClass *_current_ac;         // State used by iter_RegDefs()

public:
  // Public Data
  NameList    _rdefs;              // List of register definition names
  Dict        _regDef;             // map register name to RegDef*

  NameList    _rclasses;           // List of register class names
  Dict        _regClass;           // map register class name to RegClass*

  NameList    _aclasses;           // List of allocation class names
  Dict        _allocClass;         // Dictionary of allocation classes

  static int  _reg_ctr;         // Register counter
  static int  RegMask_Size();   // Compute RegMask size

  // Public Methods
  RegisterForm();
  ~RegisterForm();

  void        addRegDef(char *regName, char *callingConv, char *c_conv,
                        char * idealtype, char *encoding, char* concreteName);
  template<typename T> T* addRegClass(const char* className);

  AllocClass *addAllocClass(char *allocName);
  void        addSpillRegClass();

  // Provide iteration over all register definitions
  // in the order used by the register allocator
  void        reset_RegDefs();
  RegDef     *iter_RegDefs();
  RegDef     *getRegDef  (const char *regName);

  RegClass   *getRegClass(const char *className);

  // Return register mask, compressed chunk and register #
  uint       reg_mask(char *register_class);

  // Check that register classes are compatible with chunks
  bool       verify();

  void dump();                     // Debug printer
  void output(FILE *fp);           // Write info to output files
};

//------------------------------RegDef-----------------------------------------
class RegDef : public Form {
public:
  // Public Data
  const char *_regname;            // ADLC (Opto) Register name
  const char *_callconv;           // Calling convention
  const char *_c_conv;             // Native calling convention, 'C'
  const char *_idealtype;          // Ideal Type for register save/restore
  const char *_concrete;           // concrete register name

private:
  const char *_register_encode;   // The register encoding
  // The chunk and register mask bits define info for register allocation
  uint32      _register_num;      // Which register am I

public:
  // Public Methods
  RegDef(char  *regname, char *callconv, char *c_conv,
         char *idealtype, char *encoding, char *concrete);
  ~RegDef();                       // Destructor

  // Interface to define/redefine the register number
  void     set_register_num(uint32 new_register_num);

  // Bit pattern used for generating machine code
  const char *register_encode()   const;
  // Register number used in machine-independent code
  uint32   register_num()      const;

  void dump();                     // Debug printer
  void output(FILE *fp);           // Write info to output files
};

//------------------------------RegClass---------------------------------------
// Generic register class. This register class is the internal representation
// for the following .ad file format:
//
//  reg_class ptr(RAX, RBX, ...);
//
// where ptr is the name of the register class, RAX and RBX are registers.
//
// This register class allows registers to be spilled onto the stack. Spilling
// is allowed is field _stack_or_reg is true.
class RegClass : public Form {
public:
  // Public Data
  const char *_classid;         // Name of class
  NameList    _regDefs;         // List of registers in class
  Dict        _regDef;          // Dictionary of registers in class
protected:
  bool        _stack_or_reg;    // Allowed on any stack slot

public:
  // Public Methods
  RegClass(const char *classid);// Constructor
  virtual ~RegClass();

  void addReg(RegDef *regDef);  // Add a register to this class

  uint size() const;            // Number of registers in class
  int regs_in_word( int wordnum, bool stack_also );

  const RegDef *get_RegDef(const char *regDef_name) const;

  // Returns the lowest numbered register in the mask.
  const RegDef* find_first_elem();

  // Iteration support
  void          reset();        // Reset the following two iterators
  RegDef       *RegDef_iter();  // which move jointly,
  const char   *rd_name_iter(); // invoking either advances both.

  void dump();                  // Debug printer
  void output(FILE *fp);        // Write info to output files

  virtual bool has_stack_version() {
    return _stack_or_reg;
  }
  virtual void set_stack_version(bool flag) {
    _stack_or_reg = flag;
  }

  virtual void declare_register_masks(FILE* fp);
  virtual void build_register_masks(FILE* fp);
};

//------------------------------CodeSnippetRegClass----------------------------
// Register class that has an user-defined C++ code snippet attached to it
// to determine at runtime which register class to use. This register class is
// the internal representation for the following .ad file format:
//
//  reg_class actual_dflt_reg %{
//      if (VM_Version::has_vfp3_32()) {
//          return DFLT_REG_mask();
//      } else {
//          return DFLT_LOW_REG_mask();
//      }
//  %}
//
// where DFLT_REG_mask() and DFLT_LOW_REG_mask() are the internal names of the
// masks of register classes dflt_reg and dflt_low_reg.
//
// The attached code snippet can select also between more than two register classes.
// This register class can be, however, used only if the register class is not
// cisc-spillable (i.e., the registers of this class are not allowed on the stack,
// which is equivalent with _stack_or_reg being false).
class CodeSnippetRegClass : public RegClass {
protected:
  char* _code_snippet;
public:
  CodeSnippetRegClass(const char* classid);// Constructor
  ~CodeSnippetRegClass();

  void set_code_snippet(char* code) {
    _code_snippet = code;
  }
  char* code_snippet() {
    return _code_snippet;
  }
  void set_stack_version(bool flag) {
    assert(false, "User defined register classes are not allowed to spill to the stack.");
  }
  void declare_register_masks(FILE* fp);
  void build_register_masks(FILE* fp) {
    // We do not need to generate register masks because we select at runtime
    // between register masks generated for other register classes.
    return;
  }
};

//------------------------------ConditionalRegClass----------------------------
// Register class that has two register classes and a runtime condition attached
// to it. The condition is evaluated at runtime and either one of the register
// attached register classes is selected. This register class is the internal
// representation for the following .ad format:
//
//  reg_class_dynamic actual_dflt_reg(dflt_reg, low_reg,
//                                    %{ VM_Version::has_vfp3_32() }%
//                                    );
//
// This example is equivalent to the example used with the CodeSnippetRegClass
// register class. A ConditionalRegClass works also if a register class is cisc-spillable
// (i.e., _stack_or_reg is true), but if can select only between two register classes.
class ConditionalRegClass : public RegClass {
protected:
  // reference to condition code
  char* _condition_code;  // C++ condition code to dynamically determine which register class to use.

                          // Example syntax (equivalent to previous example):
                          //
                          //  reg_class actual_dflt_reg(dflt_reg, low_reg,
                          //                            %{ VM_Version::has_vfp3_32() }%
                          //                            );
  // reference to conditional register classes
  RegClass* _rclasses[2]; // 0 is the register class selected if the condition code returns true
                          // 1 is the register class selected if the condition code returns false
public:
  ConditionalRegClass(const char* classid);// Constructor
  ~ConditionalRegClass();

  virtual void set_stack_version(bool flag) {
    RegClass::set_stack_version(flag);
    assert((_rclasses[0] != NULL), "Register class NULL for condition code == true");
    assert((_rclasses[1] != NULL), "Register class NULL for condition code == false");
    _rclasses[0]->set_stack_version(flag);
    _rclasses[1]->set_stack_version(flag);
  }
  void declare_register_masks(FILE* fp);
  void build_register_masks(FILE* fp) {
    // We do not need to generate register masks because we select at runtime
    // between register masks generated for other register classes.
    return;
  }
  void set_rclass_at_index(int index, RegClass* rclass) {
    assert((0 <= index && index < 2), "Condition code can select only between two register classes");
    _rclasses[index] = rclass;
  }
  void set_condition_code(char* code) {
    _condition_code = code;
  }
  char* condition_code() {
    return _condition_code;
  }
};

//------------------------------AllocClass-------------------------------------
class AllocClass : public Form {
private:

public:
  // Public Data
  char    *_classid;            // Name of class
  NameList _regDefs;            // List of registers in class
  Dict     _regDef;             // Dictionary of registers in class

  // Public Methods
  AllocClass(char *classid);    // Constructor

  void addReg(RegDef *regDef);  // Add a register to this class
  uint size() {return _regDef.Size();} // Number of registers in class

  void dump();                  // Debug printer
  void output(FILE *fp);        // Write info to output files
};


//==============================Frame Handling================================
//------------------------------FrameForm-------------------------------------
class FrameForm : public Form {
private:

public:
  // Public Data
  bool  _direction;                // Direction of stack growth
  char *_sync_stack_slots;
  char *_inline_cache_reg;
  char *_interpreter_method_oop_reg;
  char *_interpreter_frame_pointer_reg;
  char *_cisc_spilling_operand_name;
  char *_frame_pointer;
  char *_c_frame_pointer;
  char *_alignment;
  bool  _return_addr_loc;
  bool  _c_return_addr_loc;
  char *_return_addr;
  char *_c_return_addr;
  char *_in_preserve_slots;
  char *_varargs_C_out_slots_killed;
  char *_calling_convention;
  char *_c_calling_convention;
  char *_return_value;
  char *_c_return_value;

  // Public Methods
  FrameForm();
  ~FrameForm();

  void dump();                     // Debug printer
  void output(FILE *fp);           // Write info to output files
};


//==============================Scheduling=====================================
//------------------------------PipelineForm-----------------------------------
class PipelineForm : public Form {
private:

public:
  // Public Data
  NameList   _reslist;            // List of pipeline resources
  FormDict   _resdict;            // Resource Name -> ResourceForm mapping
  int        _rescount;           // Number of resources (ignores OR cases)
  int        _maxcycleused;       // Largest cycle used relative to beginning of instruction

  NameList   _stages;             // List of pipeline stages on architecture
  int        _stagecnt;           // Number of stages listed

  NameList   _classlist;          // List of pipeline classes
  FormDict   _classdict;          // Class Name -> PipeClassForm mapping
  int        _classcnt;           // Number of classes

  NameList   _noplist;            // List of NOP instructions
  int        _nopcnt;             // Number of nop instructions

  bool       _variableSizeInstrs; // Indicates if this architecture has variable sized instructions
  bool       _branchHasDelaySlot; // Indicates that branches have delay slot instructions
  int        _maxInstrsPerBundle; // Indicates the maximum number of instructions for ILP
  int        _maxBundlesPerCycle; // Indicates the maximum number of bundles for ILP
  int        _instrUnitSize;      // The minimum instruction unit size, in bytes
  int        _bundleUnitSize;     // The bundle unit size, in bytes
  int        _instrFetchUnitSize; // The size of the I-fetch unit, in bytes [must be power of 2]
  int        _instrFetchUnits;    // The number of I-fetch units processed per cycle

  // Public Methods
  PipelineForm();
  ~PipelineForm();

  void dump();                    // Debug printer
  void output(FILE *fp);          // Write info to output files
};

//------------------------------ResourceForm-----------------------------------
class ResourceForm : public Form {
public:
  unsigned mask() const { return _resmask; };

private:
  // Public Data
  unsigned _resmask;         // Resource Mask (OR of resource specifier bits)

public:

  // Virtual Methods
  virtual ResourceForm  *is_resource()    const;

  // Public Methods
  ResourceForm(unsigned resmask); // Constructor
  ~ResourceForm();                // Destructor

  void dump();                    // Debug printer
  void output(FILE *fp);          // Write info to output files
};

//------------------------------PipeClassOperandForm-----------------------------
class PipeClassOperandForm : public Form {
private:

public:
  // Public Data
  const char *_stage;             // Name of Stage
  unsigned _iswrite;              // Read or Write
  unsigned _more_instrs;          // Additional Instructions

  // Public Methods
  PipeClassOperandForm(const char *stage, unsigned iswrite, unsigned more_instrs)
  : _stage(stage)
  , _iswrite(iswrite)
  , _more_instrs(more_instrs)
 {};

  ~PipeClassOperandForm() {};     // Destructor

  bool isWrite() const { return _iswrite != 0; }

  void dump();                    // Debug printer
  void output(FILE *fp);          // Write info to output files
};

//------------------------------PipeClassResourceForm--------------------------
class PipeClassResourceForm : public Form {
private:

public:
  // Public Data
  const char *_resource;          // Resource
  const char *_stage;             // Stage the resource is used in
  int         _cycles;            // Number of cycles the resource is used

  // Public Methods
  PipeClassResourceForm(const char *resource, const char *stage, int cycles)
                                  // Constructor
    : _resource(resource)
    , _stage(stage)
    , _cycles(cycles)
    {};

  ~PipeClassResourceForm() {};    // Destructor

  void dump();                    // Debug printer
  void output(FILE *fp);          // Write info to output files
};

//------------------------------PipeClassForm----------------------------------
class PipeClassForm : public Form {
private:

public:

  // Public Data
  const char       *_ident;             // Name of class
  int               _num;               // Used in name of MachNode subclass
  NameList          _parameters;        // Locally defined names
  FormDict          _localNames;        // Table of operands & their types
  FormDict          _localUsage;        // Table of operand usage
  FormList          _resUsage;          // List of resource usage
  NameList          _instructs;         // List of instructions and machine nodes that use this pipeline class
  bool              _has_fixed_latency; // Always takes this number of cycles
  int               _fixed_latency;     // Always takes this number of cycles
  int               _instruction_count; // Number of instructions in first bundle
  bool              _has_multiple_bundles;  // Indicates if 1 or multiple bundles
  bool              _has_branch_delay_slot; // Has branch delay slot as last instruction
  bool              _force_serialization;   // This node serializes relative to surrounding nodes
  bool              _may_have_no_code;      // This node may generate no code based on register allocation

  // Virtual Methods
  virtual PipeClassForm  *is_pipeclass()    const;

  // Public Methods
  PipeClassForm(const char *id, int num);
                                  // Constructor
  ~PipeClassForm();               // Destructor

  bool hasFixedLatency() { return _has_fixed_latency; }
  int fixedLatency() { return _fixed_latency; }

  void setFixedLatency(int fixed_latency) { _has_fixed_latency = 1; _fixed_latency = fixed_latency; }

  void setInstructionCount(int i)    { _instruction_count = i; }
  void setMultipleBundles(bool b)    { _has_multiple_bundles = b; }
  void setBranchDelay(bool s)        { _has_branch_delay_slot = s; }
  void setForceSerialization(bool s) { _force_serialization = s; }
  void setMayHaveNoCode(bool s)      { _may_have_no_code = s; }

  int  InstructionCount()   const { return _instruction_count; }
  bool hasMultipleBundles() const { return _has_multiple_bundles; }
  bool hasBranchDelay()     const { return _has_branch_delay_slot; }
  bool forceSerialization() const { return _force_serialization; }
  bool mayHaveNoCode()      const { return _may_have_no_code; }

  void dump();                    // Debug printer
  void output(FILE *fp);          // Write info to output files
};


//==============================Peephole Optimization==========================
//------------------------------Peephole---------------------------------------
class Peephole : public Form {
private:
  static int      _peephole_counter;// Incremented by each peephole rule parsed
  int             _peephole_number;// Remember my order in architecture description
  PeepMatch      *_match;          // Instruction pattern to match
  PeepConstraint *_constraint;     // List of additional constraints
  PeepReplace    *_replace;        // Instruction pattern to substitute in

  Peephole *_next;

public:
  // Public Methods
  Peephole();
  ~Peephole();

  // Append a peephole rule with the same root instruction
  void append_peephole(Peephole *next_peephole);

  // Store the components of this peephole rule
  void add_match(PeepMatch *only_one_match);
  void append_constraint(PeepConstraint *next_constraint);
  void add_replace(PeepReplace *only_one_replacement);

  // Access the components of this peephole rule
  int             peephole_number() { return _peephole_number; }
  PeepMatch      *match()       { return _match; }
  PeepConstraint *constraints() { return _constraint; }
  PeepReplace    *replacement() { return _replace; }
  Peephole       *next()        { return _next; }

  void dump();                     // Debug printer
  void output(FILE *fp);           // Write info to output files
};


class PeepMatch : public Form {
private:
  char *_rule;
  // NameList  _depth;                // Depth of this instruction
  NameList  _parent;
  NameList  _position;
  NameList  _instrs;               // List of instructions in match rule
  NameList  _input;                // input position in parent's instruction
  int       _max_position;

public:
  // Public Methods
  PeepMatch(char *rule);
  ~PeepMatch();

  // Insert info into the match-rule
  void  add_instruction(int parent, int position, const char *name, int input);

  // Access info about instructions in the peep-match rule
  int   max_position();
  const char *instruction_name(int position);
  // Iterate through all info on matched instructions
  void  reset();
  void  next_instruction(int &parent, int &position, const char* &name, int &input);
  // 'true' if current position in iteration is a placeholder, not matched.
  bool  is_placeholder();

  void dump();
  void output(FILE *fp);
};


class PeepConstraint : public Form {
private:
  PeepConstraint *_next;           // Additional constraints ANDed together

public:
  const int   _left_inst;
  const char* _left_op;
  const char* _relation;
  const int   _right_inst;
  const char* _right_op;

public:
  // Public Methods
  PeepConstraint(int left_inst,  char* left_op, char* relation,
                 int right_inst, char* right_op);
  ~PeepConstraint();

  // Check if constraints use instruction at position
  bool constrains_instruction(int position);

  // Add another constraint
  void append(PeepConstraint *next_peep_constraint);
  // Access the next constraint in the list
  PeepConstraint *next();

  void dump();
  void output(FILE *fp);
};


class PeepReplace : public Form {
private:
  char *_rule;
  NameList _instruction;
  NameList _operand_inst_num;
  NameList _operand_op_name;

public:

  // Public Methods
  PeepReplace(char *rule);
  ~PeepReplace();

  // Add contents of peepreplace
  void  add_instruction(char *root);
  void  add_operand( int inst_num, char *inst_operand );

  // Access contents of peepreplace
  void  reset();
  void  next_instruction(const char * &root);
  void  next_operand(int &inst_num, const char * &inst_operand );

  // Utilities
  void dump();
  void output(FILE *fp);
};


class PeepChild : public Form {
public:
  const int   _inst_num;         // Number of instruction (-1 if only named)
  const char *_inst_op;          // Instruction's operand, NULL if number == -1
  const char *_inst_name;        // Name of the instruction

public:
  PeepChild(char *inst_name)
    : _inst_num(-1), _inst_op(NULL), _inst_name(inst_name) {};
  PeepChild(int inst_num, char *inst_op, char *inst_name)
    : _inst_num(inst_num), _inst_op(inst_op), _inst_name(inst_name) {};
  ~PeepChild();

  bool  use_leaf_operand()        { return _inst_num != -1; };
  bool  generate_an_instruction() { return _inst_num == -1; }

  void dump();
  void output(FILE *fp);
};

#endif // SHARE_VM_ADLC_FORMSOPT_HPP