CACAO
MachineOperand.hpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/MachineOperand.hpp - MachineOperand
2 
3  Copyright (C) 2013
4  CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 
6  This file is part of CACAO.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2, or (at
11  your option) any later version.
12 
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  02110-1301, USA.
22 
23 */
24 
25 #ifndef _JIT_COMPILER2_MACHINEOPERAND
26 #define _JIT_COMPILER2_MACHINEOPERAND
27 
29 #include "toolbox/OStream.hpp"
30 #include "vm/types.hpp"
31 
35 #include <cassert>
36 
37 MM_MAKE_NAME(MachineOperand)
38 
39 namespace cacao {
40 
41 // forward declarations
42 class OStream;
43 
44 namespace jit {
45 namespace compiler2 {
46 
47 class StackSlotManager;
48 
49 class VoidOperand;
50 class Register;
51 class StackSlot;
52 class ManagedStackSlot;
53 class Immediate;
54 class Address;
55 class CONSTInst;
56 
57 class MachineOperandDesc;
58 class MachineOperand;
59 
60 class EmbeddedMachineOperand : public memory::ManagerMixin<EmbeddedMachineOperand> {
61 public:
64 
65  explicit EmbeddedMachineOperand (MachineOperand *op) : dummy(op), real(NULL) {}
66 };
67 
68 /**
69  * Operands that can be directly used by the machine (register, memory, stackslot)
70  */
71 class MachineOperand : public memory::ManagerMixin<MachineOperand> {
72 public:
73  enum OperandID {
80  VoidOperandID
81  };
82  typedef const void* IdentifyTy;
83  typedef std::size_t IdentifyOffsetTy;
84  typedef std::size_t IdentifySizeTy;
86  typedef embedded_operand_list::iterator operand_iterator;
87  typedef embedded_operand_list::const_iterator const_operand_iterator;
88 private:
89  static std::size_t id_counter;
90  std::size_t id;
93 protected:
94  /**
95  * TODO describe
96  */
98  virtual IdentifyTy id_base() const { return static_cast<IdentifyTy>(this); }
99  virtual IdentifyOffsetTy id_offset() const { return 0; }
100  virtual IdentifySizeTy id_size() const { return 1; }
101 public:
102  std::size_t get_id() const { return id; }
103 
104  explicit MachineOperand(OperandID op_id, Type::TypeID type)
105  : id(id_counter++), op_id(op_id), type(type), embedded_operands() {}
106 
107  OperandID get_OperandID() const { return op_id; }
108  Type::TypeID get_type() const { return type; }
109 
110  virtual const char* get_name() const = 0;
111 
112  virtual ~MachineOperand() {}
113  virtual MachineOperand* to_MachineOperand() { return this; }
114  virtual VoidOperand* to_VoidOperand() { return 0; }
115  virtual Register* to_Register() { return 0; }
116  virtual StackSlot* to_StackSlot() { return 0; }
117  virtual ManagedStackSlot* to_ManagedStackSlot() { return 0; }
118  virtual Immediate* to_Immediate() { return 0; }
119  virtual Address* to_Address() { return 0; }
120 
121  bool is_MachineOperand() const { return op_id == MachineOperandID; }
122  bool is_VoidOperand() const { return op_id == VoidOperandID; }
123  bool is_Register() const { return op_id == RegisterID; }
124  bool is_StackSlot() const { return op_id == StackSlotID; }
125  bool is_ManagedStackSlot() const { return op_id == ManagedStackSlotID; }
126  bool is_Immediate() const { return op_id == ImmediateID; }
127  bool is_Address() const { return op_id == AddressID; }
128 
129  bool is_stackslot() const { return is_StackSlot() || is_ManagedStackSlot(); }
130 
131  /**
132  */
133  bool aquivalence_less(const MachineOperand& MO) const {
134  if (id_base() != MO.id_base()) {
135  return id_base() < MO.id_base();
136  }
137  return id_offset()+id_size() <= MO.id_offset();
138  }
139  bool aquivalent(const MachineOperand& MO) const {
140  return !(aquivalence_less(MO) || MO.aquivalence_less(*this));
141  }
142 
143  /**
144  * True if operand is virtual and must be assigned
145  * during register allocation
146  */
147  virtual bool is_virtual() const { return false; }
148  /**
149  * Return true if operand is processed during register allocation.
150  * This implies is_virtual().
151  *
152  * @see is_virtual()
153  */
154  virtual bool needs_allocation() const { return is_virtual(); }
155  bool has_embedded_operands() { return op_size() != 0; }
156  std::size_t op_size() const {
157  return embedded_operands.size();
158  }
160  assert(i < embedded_operands.size());
161  return embedded_operands[i];
162  }
163  const EmbeddedMachineOperand &get(std::size_t i) const {
164  assert(i < embedded_operands.size());
165  return embedded_operands[i];
166  }
167  EmbeddedMachineOperand &get(std::size_t i) {
168  assert(i < embedded_operands.size());
169  return embedded_operands[i];
170  }
172  return embedded_operands.begin();
173  }
175  return embedded_operands.end();
176  }
178  for (operand_iterator i = begin(), e =end(); i != e; ++i) {
179  if (op->aquivalent(*i->dummy))
180  return i;
181  }
182  return end();
183  }
185  return embedded_operands.front();
186  }
188  return embedded_operands.back();
189  }
191  return embedded_operands.begin();
192  }
194  return embedded_operands.end();
195  }
196 
197  virtual OStream& print(OStream &OS) const {
198  return OS << get_name() /* << " (" << get_type() << ")" */;
199  }
200 };
201 
202 class VoidOperand : public MachineOperand {
203 public:
204  VoidOperand() : MachineOperand(VoidOperandID, Type::VoidTypeID) {}
205  virtual const char* get_name() const {
206  return "VoidOperand";
207  }
208  virtual VoidOperand* to_VoidOperand() { return this; }
209 };
210 
211 class UnassignedReg;
212 class VirtualRegister;
213 class MachineRegister;
214 class MachineAddress;
215 
216 class Register : public MachineOperand {
217 public:
218  Register(Type::TypeID type) : MachineOperand(RegisterID, type) {}
219  virtual const char* get_name() const {
220  return "Register";
221  }
222  virtual bool needs_allocation() const { return true; }
223  virtual Register* to_Register() { return this; }
224  virtual UnassignedReg* to_UnassignedReg() { return 0; }
225  virtual VirtualRegister* to_VirtualRegister() { return 0; }
226  virtual MachineRegister* to_MachineRegister() { return 0; }
227  virtual ~Register() {}
228 };
229 
230 
231 class UnassignedReg : public Register {
232 public:
234  virtual const char* get_name() const {
235  return "UnassignedReg";
236  }
237  virtual UnassignedReg* to_UnassignedReg() { return this; }
238 };
239 
240 class VirtualRegister : public Register {
241 private:
242  static unsigned vreg_counter;
243  const unsigned vreg;
244 public:
246  vreg(vreg_counter++) {}
247 
248  virtual VirtualRegister* to_VirtualRegister() { return this; }
249  virtual const char* get_name() const {
250  return "vreg";
251  }
252  virtual OStream& print(OStream &OS) const {
253  return MachineOperand::print(OS) << get_id();
254  }
255  virtual bool is_virtual() const { return true; }
256  unsigned get_id() const { return vreg; }
257 };
258 
259 class StackSlot : public MachineOperand {
260 private:
261  int index; ///< index of the stackslot
262 public:
263  /**
264  * @param index index of the stackslot
265  */
267  : MachineOperand(StackSlotID, type), index(index) {}
268  virtual StackSlot* to_StackSlot() { return this; }
269  int get_index() const { return index; }
270  virtual const char* get_name() const {
271  return "StackSlot";
272  }
273  virtual OStream& print(OStream &OS) const {
274  return MachineOperand::print(OS) << get_index();
275  }
276 };
277 
278 /**
279  * A "virtual" slot that will eventually be mapped to a machine-level slot.
280  *
281  * A ManagedStackSlot may be used to store spill-registers (as needed during
282  * register allocation) or to store arguments of method invocations.
283  * ManagedStackSlots may only be constructed via a corresponding StackSlotManager
284  * and will eventually be mapped to actual machine-level slots during code
285  * generation.
286  *
287  * Note that there is no one-to-one mapping between actual machine-level slots
288  * and ManagedStackSlots. Multiple ManagedStackSlots might map to the same
289  * machine-level slot which is the case for those slots that are used for
290  * storing arguments for method invocations.
291  */
293 private:
294 
295  /**
296  * The StackSlotManager that created (and owns) this slot.
297  */
299 
300  /**
301  * Represents the slot's position in the virtual stack frame.
302  *
303  * Note that multiple ManagedStackSlots might use the same index, since they
304  * may be mapped to the same position in the stack frame (which is the case
305  * for slots that are used for storing arguments for method invocations).
306  */
308 
309  /**
310  * Construct a ManagedStackSlot.
311  *
312  * @param SSM The StackSlotManager that created (and owns) this slot.
313  * @param type The type of the slot.
314  */
316  : MachineOperand(ManagedStackSlotID,type), parent(SSM) {}
317 
318 public:
319 
320  /**
321  * Conversion method.
322  */
323  virtual ManagedStackSlot* to_ManagedStackSlot() { return this; }
324 
325  /**
326  * @return A human-readable name of this slot.
327  */
328  virtual const char* get_name() const {
329  return "ManagedStackSlot";
330  }
331 
332  /**
333  * @return The index representing this slot's position in the virtual
334  * stack frame.
335  */
336  u4 get_index() const { return index; }
337 
338  /**
339  * Set the index of the slot.
340  *
341  * @param index The corresponding index.
342  */
343  void set_index(unsigned index) { this->index = index; }
344 
345  /**
346  * @return The StackSlotManager that created (and owns) this slot.
347  */
348  StackSlotManager *get_parent() const { return parent; }
349 
350  /**
351  * Print a human-readable representation of this slot.
352  *
353  * @param OS The stream to print to.
354  *
355  * @return The corresponding stream.
356  */
357  virtual OStream& print(OStream &OS) const {
358  return MachineOperand::print(OS) << get_id();
359  }
360 
361  friend class StackSlotManager;
362 };
363 
364 class Immediate : public MachineOperand {
365 private:
366  typedef union {
367  int32_t i;
368  int64_t l;
369  float f;
370  double d;
371  void *anyptr;
372  java_handle_t *stringconst; /* for ACONST with string */
373  classref_or_classinfo c; /* for ACONST with class */
374  } val_operand_t;
376 public:
379  : MachineOperand(ImmediateID, type) {
380  value.i = val;
381  }
383  : MachineOperand(ImmediateID, type) {
384  value.l = val;
385  }
386  Immediate(float val, Type::FloatType type)
387  : MachineOperand(ImmediateID, type) {
388  value.f = val;
389  }
390  Immediate(double val, Type::DoubleType type)
391  : MachineOperand(ImmediateID, type) {
392  value.d = val;
393  }
394 
395  /// TODO How to handle addresses as immediates?
397  : MachineOperand(ImmediateID, type) {
398  value.l = val;
399  }
400 
401  virtual Immediate* to_Immediate() { return this; }
402  virtual const char* get_name() const {
403  return "Immediate";
404  }
405  template<typename T>
406  T get_value() const;
407 
408  double get_Int() const {
409  assert(get_type() == Type::IntTypeID);
410  return value.i;
411  }
412  double get_Long() const {
413  assert(get_type() == Type::LongTypeID);
414  return value.l;
415  }
416  double get_Float() const {
417  assert(get_type() == Type::FloatTypeID);
418  return value.f;
419  }
420  double get_Double() const {
421  assert(get_type() == Type::DoubleTypeID);
422  return value.d;
423  }
424 };
425 
426 class Address : public MachineOperand {
427 public:
428 
429  /// Construct an Address.
430  ///
431  /// @param type The type of the data referenced by this Address.
432  Address(Type::TypeID type) : MachineOperand(AddressID, type) {}
433 
434  virtual Address* to_Address() { return this; }
435  virtual MachineAddress* to_MachineAddress() = 0;
436  virtual const char* get_name() const {
437  return "Address";
438  }
439 };
440 
441 #if 0
442 class MachineOperandType {
443 public:
444  enum TYPE {
445  NONE = 0,
446  REGISTER_VALUE = 1<<0, ///< register with a value
447  REGISTER_MEM = 1<<1, ///< register with a memory address
448  IMMEDIATE = 1<<2, ///< immediate value
449  ABSOLUTE_ADDR = 1<<3, ///< absolute code address
450  PIC_ADDR = 1<<4, ///< absolute code address (position independent code).
451  ///< The absolute value might changes but offsets are still valid.
452  PC_REL_ADDR = 1<<5, ///< code address offset
453  ALL = REGISTER_VALUE | REGISTER_MEM | IMMEDIATE | ABSOLUTE_ADDR | PIC_ADDR | PC_REL_ADDR
454  };
455 private:
456  unsigned type;
457 public:
458  /// default constructor
459  MachineOperandType() {
460  type = NONE;
461  }
462  MachineOperandType(unsigned t) {
463  set_type(t);
464  }
465  /// copy constructor
466  MachineOperandType(const MachineOperandType &MO) {
467  type = MO.type;
468  }
469  /// copy assignment operator
470  MachineOperandType& operator=(const MachineOperandType &rhs) {
471  type = rhs.type;
472  return *this;
473  }
474  bool takes(const TYPE t) const {
475  return (type & t);
476  }
477  unsigned get_type() const {
478  return type;
479  }
480  void set_type(unsigned t) {
481  assert( t <= ALL);
482  type = t;
483  }
484 };
485 #endif
486 
487 extern VoidOperand NoOperand;
488 #if 0
489 OStream& operator<<(OStream &OS, const MachineOperandType &MO);
490 #endif
492  return MO.print(OS);
493 }
495  if (!MO) {
496  return OS << "(MachineOperand) NULL";
497  }
498  return OS << *MO;
499 }
500 
501 struct MachineOperandComp : public std::binary_function<MachineOperand*,MachineOperand*,bool> {
502  bool operator()(MachineOperand* lhs, MachineOperand *rhs) const {
503  return lhs->aquivalence_less(*rhs);
504  }
505 };
506 
508 
509 
510 } // end namespace compiler2
511 } // end namespace jit
512 } // end namespace cacao
513 
514 namespace std {
515 
516 template<>
517 struct hash<cacao::jit::compiler2::MachineOperand*> {
519  return v->get_id();
520  }
521 };
522 
523 template<>
524 struct less<cacao::jit::compiler2::MachineOperand*> {
527  return lhs->get_id() < rhs->get_id();
528  }
529 };
530 
531 #if 0
532 template<>
533 struct equal_to<cacao::jit::compiler2::MachineOperand*> {
534  bool operator()(cacao::jit::compiler2::MachineOperand *lhs,
536  return lhs->aquivalent(*rhs);
537  }
538 };
539 #endif
540 
541 } // end namespace standard
542 
543 #endif /* _JIT_COMPILER2_MACHINEOPERAND */
544 
545 
546 /*
547  * These are local overrides for various environment variables in Emacs.
548  * Please do not remove this and leave it at the end of the file, where
549  * Emacs will automagically detect them.
550  * ---------------------------------------------------------------------
551  * Local variables:
552  * mode: c++
553  * indent-tabs-mode: t
554  * c-basic-offset: 4
555  * tab-width: 4
556  * End:
557  * vim:noexpandtab:sw=4:ts=4:
558  */
EmbeddedMachineOperand & operator[](std::size_t i)
embedded_operand_list::iterator operand_iterator
#define hash(_i1, _i2)
Definition: peephole.c:55
std::size_t index
virtual const char * get_name() const
virtual const char * get_name() const
virtual OStream & print(OStream &OS) const
virtual IdentifyTy id_base() const
virtual ManagedStackSlot * to_ManagedStackSlot()
virtual OStream & print(OStream &OS) const
u2 op
Definition: disass.cpp:129
Custom new/delete handler mixin.
Definition: Manager.hpp:43
const_operand_iterator end() const
bool aquivalence_less(const MachineOperand &MO) const
#define MM_MAKE_NAME(x)
Definition: memstats.hpp:128
Immediate(s8 val, Type::LongType type)
virtual ManagedStackSlot * to_ManagedStackSlot()
Conversion method.
Immediate(float val, Type::FloatType type)
Descriptor of a MachineOperand.
PassInfo::IDTy id
bool operator()(cacao::jit::compiler2::MachineOperand *lhs, cacao::jit::compiler2::MachineOperand *rhs) const
Immediate(double val, Type::DoubleType type)
virtual VoidOperand * to_VoidOperand()
virtual UnassignedReg * to_UnassignedReg()
int64_t s8
Definition: types.hpp:48
virtual VirtualRegister * to_VirtualRegister()
virtual OStream & print(OStream &OS) const
Print a human-readable representation of this slot.
virtual const char * get_name() const
alloc::vector< EmbeddedMachineOperand >::type embedded_operand_list
virtual Register * to_Register()
std::list< T, Allocator< T > > type
Definition: list.hpp:38
operand_iterator find(MachineOperand *op)
virtual bool is_virtual() const
True if operand is virtual and must be assigned during register allocation.
u4 index
Represents the slot&#39;s position in the virtual stack frame.
MachineOperand(OperandID op_id, Type::TypeID type)
std::vector< T, Allocator< T > > type
Definition: vector.hpp:38
A &quot;virtual&quot; slot that will eventually be mapped to a machine-level slot.
Simple stream class for formatted output.
Definition: OStream.hpp:141
virtual VirtualRegister * to_VirtualRegister()
virtual const char * get_name() const
virtual bool is_virtual() const
True if operand is virtual and must be assigned during register allocation.
virtual VoidOperand * to_VoidOperand()
MIIterator i
virtual MachineRegister * to_MachineRegister()
virtual Immediate * to_Immediate()
alloc::list< MachineOperand * >::type OperandFile
int32_t s4
Definition: types.hpp:45
embedded_operand_list::const_iterator const_operand_iterator
StackSlot(int index, Type::TypeID type)
OStream & OS
OStream & operator<<(OStream &OS, const std::string &t)
Definition: OStream.hpp:459
std::size_t operator()(cacao::jit::compiler2::MachineOperand *v) const
virtual bool needs_allocation() const
Return true if operand is processed during register allocation.
ManagedStackSlot(StackSlotManager *SSM, Type::TypeID type)
Construct a ManagedStackSlot.
Address(Type::TypeID type)
Construct an Address.
MIIterator e
bool aquivalent(const MachineOperand &MO) const
StackSlotManager * get_parent() const
uint32_t u4
Definition: types.hpp:46
#define I(value)
Definition: codegen.c:279
virtual const char * get_name() const
virtual const char * get_name() const
StackSlotManager * parent
The StackSlotManager that created (and owns) this slot.
virtual const char * get_name() const
Operands that can be directly used by the machine (register, memory, stackslot)
virtual StackSlot * to_StackSlot()
Immediate(s8 val, Type::ReferenceType type)
TODO How to handle addresses as immediates?
void set_index(unsigned index)
Set the index of the slot.
virtual IdentifyOffsetTy id_offset() const
bool operator()(MachineOperand *lhs, MachineOperand *rhs) const
Immediate(s4 val, Type::IntType type)
embedded_operand_list embedded_operands
TODO describe.
int index
index of the stackslot
const_operand_iterator begin() const
virtual bool needs_allocation() const
Return true if operand is processed during register allocation.
virtual IdentifySizeTy id_size() const
LoopTreeGraph * parent
virtual MachineOperand * to_MachineOperand()
virtual OStream & print(OStream &OS) const
EmbeddedMachineOperand & front()
virtual const char * get_name() const
virtual UnassignedReg * to_UnassignedReg()