Coverage for /Syzygy/core/assembler.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%22220.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  //
  15    :  // This file declares implementation classes to generate assembly code.
  16    :  // The API to the assembler is intentionally very close to the API exposed
  17    :  // by the V8 assembler.
  18    :  
  19    :  #ifndef SYZYGY_CORE_ASSEMBLER_H_
  20    :  #define SYZYGY_CORE_ASSEMBLER_H_
  21    :  
  22    :  #include "base/basictypes.h"
  23    :  #include "base/logging.h"
  24    :  
  25    :  namespace core {
  26    :  
  27    :  enum RegisterCode {
  28    :    kRegisterNone = -1,
  29    :    kRegisterEax = 0,
  30    :    kRegisterEcx = 1,
  31    :    kRegisterEdx = 2,
  32    :    kRegisterEbx = 3,
  33    :    kRegisterEsp = 4,
  34    :    kRegisterEbp = 5,
  35    :    kRegisterEsi = 6,
  36    :    kRegisterEdi = 7,
  37    :    // RegisterCode must be below this value.
  38    :    kRegisterMax = 8,
  39    :  };
  40    :  
  41    :  // The condition codes by which conditional branches are determined. This enum
  42    :  // is taken from the V8 project, and has the property that the conditions are
  43    :  // defined to be bit-wise ORed into the base conditional branch opcode, and
  44    :  // they can be easily negated/inverted.
  45    :  //
  46    :  // See:
  47    :  //     http://code.google.com/p/v8/source/browse/trunk/src/ia32/assembler-ia32.h
  48    :  enum ConditionCode {
  49    :    // Any value < 0 is considered no_condition
  50    :    kNoCondition  = -1,
  51    :  
  52    :    kOverflow =  0,
  53    :    kNoOverflow =  1,
  54    :    kBelow =  2,
  55    :    kAboveEqual =  3,
  56    :    kEqual =  4,
  57    :    kNotEqual =  5,
  58    :    kBelowEqual =  6,
  59    :    kAbove =  7,
  60    :    kNegative =  8,
  61    :    kPositive =  9,
  62    :    kParityEven = 10,
  63    :    kParityOdd = 11,
  64    :    kLess = 12,
  65    :    kGreaterEqual = 13,
  66    :    kLessEqual = 14,
  67    :    kGreater = 15,
  68    :  
  69    :    // Aliases.
  70    :    kCarry = kBelow,
  71    :    kNotCarry = kAboveEqual,
  72    :    kZero = kEqual,
  73    :    kNotZero = kNotEqual,
  74    :    kSign = kNegative,
  75    :    kNotSign = kPositive,
  76    :  
  77    :    // Extents.
  78    :    kMinConditionCode = 0,
  79    :    kMaxConditionCode = 15
  80    :  };
  81    :  
  82    :  // The conditions on which a loop instruction should branch. These are modeled
  83    :  // in the same manner as ConditionCode (above).
  84    :  enum LoopCode {
  85    :    kLoopOnCounterAndNotZeroFlag = 0,  // LOOPNE and LOOPNZ
  86    :    kLoopOnCounterAndZeroFlag = 1,  // LOOPE and NOOPZ.
  87    :    kLoopOnCounter = 2,  // LOOP.
  88    :  };
  89    :  
  90  E :  inline ConditionCode NegateConditionCode(ConditionCode cc) {
  91  E :    DCHECK_GT(16, cc);
  92  E :    return static_cast<ConditionCode>(cc ^ 1);
  93  E :  }
  94    :  
  95    :  // Each instance of this class names a register.
  96    :  class Register {
  97    :   public:
  98  E :    explicit Register(RegisterCode code) : code_(code) {
  99  E :      DCHECK(code != kRegisterNone);
 100  E :    }
 101    :  
 102  E :    RegisterCode code() const { return code_; }
 103    :    void set_code(RegisterCode code) { code_ = code; }
 104    :  
 105    :   private:
 106    :    RegisterCode code_;
 107    :  };
 108    :  
 109    :  // Convenience constants for the x86 registers.
 110    :  extern const Register eax;
 111    :  extern const Register ecx;
 112    :  extern const Register edx;
 113    :  extern const Register ebx;
 114    :  extern const Register esp;
 115    :  extern const Register ebp;
 116    :  extern const Register esi;
 117    :  extern const Register edi;
 118    :  
 119    :  // Selects a scale for the Operand addressing modes.
 120    :  // The values match the encoding in the x86 SIB bytes.
 121    :  enum ScaleFactor {
 122    :    kTimes1 = 0,
 123    :    kTimes2 = 1,
 124    :    kTimes4 = 2,
 125    :    kTimes8 = 3,
 126    :  };
 127    :  
 128    :  // Size for immediate and displacement operands.
 129    :  enum ValueSize {
 130    :    kSizeNone,
 131    :    kSize8Bit,
 132    :    kSize32Bit,
 133    :  };
 134    :  
 135    :  // An instance of this class is an explicit value, which is either
 136    :  // an immediate or a displacement.
 137    :  class ValueImpl {
 138    :   public:
 139    :    ValueImpl();
 140    :    ValueImpl(uint32 value, ValueSize size);
 141    :    ValueImpl(uint32 value, ValueSize size, const void* imm_ref);
 142    :  
 143    :    // @name Accessors.
 144    :    // @{
 145  E :    uint32 value() const { return value_; }
 146  E :    const void* reference() const { return reference_; }
 147  E :    ValueSize size() const { return size_; }
 148    :    // @}
 149    :  
 150    :    // Comparison operator.
 151    :    bool operator==(const ValueImpl& rhs) const;
 152    :  
 153    :   private:
 154    :    uint32 value_;
 155    :    const void* reference_;
 156    :    ValueSize size_;
 157    :  };
 158    :  
 159    :  // Displacements and immediates behave near-identically, but are semantically
 160    :  // slightly different.
 161    :  typedef ValueImpl ImmediateImpl;
 162    :  typedef ValueImpl DisplacementImpl;
 163    :  
 164    :  // An operand implies indirection to memory through one of the myriad
 165    :  // modes supported by IA32.
 166    :  class OperandImpl {
 167    :   public:
 168    :    // A register-indirect mode.
 169    :    explicit OperandImpl(Register base);
 170    :  
 171    :    // A register-indirect with displacement mode.
 172    :    OperandImpl(Register base, const DisplacementImpl& displ);
 173    :  
 174    :    // A displacement-only mode.
 175    :    explicit OperandImpl(const DisplacementImpl& displ);
 176    :  
 177    :    // The full [base + index * scale + displ32] mode.
 178    :    // @note esp cannot be used as an index register.
 179    :    OperandImpl(Register base,
 180    :                Register index,
 181    :                ScaleFactor scale,
 182    :                const DisplacementImpl& displ);
 183    :  
 184    :    // The [base + index * scale] mode.
 185    :    // @note esp cannot be used as an index register.
 186    :    OperandImpl(Register base,
 187    :                Register index,
 188    :                ScaleFactor scale);
 189    :  
 190    :    // The [index * scale + displ32] mode - e.g. no base.
 191    :    // @note esp cannot be used as an index register.
 192    :    OperandImpl(Register index,
 193    :                ScaleFactor scale,
 194    :                const DisplacementImpl& displ);
 195    :  
 196    :    // Low-level constructor, none of the parameters are checked.
 197    :    OperandImpl(RegisterCode base,
 198    :                RegisterCode index,
 199    :                ScaleFactor scale,
 200    :                const DisplacementImpl& displacement);
 201    :  
 202    :    // @name Accessors.
 203    :    // @{
 204  E :    RegisterCode base() const { return base_; }
 205  E :    RegisterCode index() const { return index_; }
 206  E :    ScaleFactor scale() const { return scale_; }
 207  E :    const DisplacementImpl& displacement() const { return displacement_; }
 208    :    // @}
 209    :  
 210    :   private:
 211    :    // The base register involved, or none.
 212    :    RegisterCode base_;
 213    :    // The index register involved, or none.
 214    :    RegisterCode index_;
 215    :    // The scaling factor, must be kTimes1 if no index register.
 216    :    ScaleFactor scale_;
 217    :    // The displacement, if any.
 218    :    DisplacementImpl displacement_;
 219    :  };
 220    :  
 221    :  // The assembler takes care of maintaining an output location (address), and
 222    :  // generating a stream of bytes and references as instructions are assembled.
 223    :  class AssemblerImpl {
 224    :   public:
 225    :    // The assembler pushes instructions and references to
 226    :    // one of these for serialization.
 227    :    class InstructionSerializer {
 228    :     public:
 229    :      virtual void AppendInstruction(uint32 location,
 230    :                                     const uint8* bytes,
 231    :                                     size_t num_bytes,
 232    :                                     const size_t *ref_locations,
 233    :                                     const void* const* refs,
 234    :                                     size_t num_refs) = 0;
 235    :    };
 236    :  
 237    :    // Constructs an assembler that assembles to @p delegate
 238    :    // starting at @p location.
 239    :    AssemblerImpl(uint32 location, InstructionSerializer* serializer);
 240    :  
 241    :    // @name Accessors.
 242    :    // @{
 243  E :    uint32 location() const { return location_; }
 244  E :    void set_location(uint32 location) { location_ = location; }
 245    :    // @}
 246    :  
 247    :    // @name Call instructions.
 248    :    // @{
 249    :    void call(const ImmediateImpl& dst);
 250    :    void call(const OperandImpl& dst);
 251    :    // @}
 252    :  
 253    :    // @name Control flow instructions.
 254    :    // @{
 255    :    void j(ConditionCode cc, const ImmediateImpl& dst);
 256    :    void jecxz(const ImmediateImpl& dst);
 257    :    void jmp(const ImmediateImpl& dst);
 258    :    void jmp(const OperandImpl& dst);
 259    :    void l(LoopCode lc, const ImmediateImpl& dst);
 260    :    void ret();
 261    :    void ret(uint16 n);
 262    :    // @}
 263    :  
 264    :    // @name Set flags.
 265    :    // @{
 266    :    void set(ConditionCode cc, Register src);
 267    :    // @}
 268    :  
 269    :    // @name Byte mov varieties.
 270    :    // @{
 271    :    void mov_b(const OperandImpl& dst, const ImmediateImpl& src);
 272    :    void movzx_b(Register dst, const OperandImpl& src);
 273    :    // @}
 274    :  
 275    :    // @name Double-word mov varieties.
 276    :    // @{
 277    :    void mov(Register dst, Register src);
 278    :    void mov(Register dst, const OperandImpl& src);
 279    :    void mov(const OperandImpl& dst, Register src);
 280    :    void mov(Register dst, const ImmediateImpl& src);
 281    :    void mov(const OperandImpl& dst, const ImmediateImpl& src);
 282    :    void mov_fs(Register dst, const OperandImpl& src);
 283    :    void mov_fs(const OperandImpl& dst, Register src);
 284    :    // @}
 285    :  
 286    :    // @name Load effective address.
 287    :    void lea(Register dst, const OperandImpl& src);
 288    :  
 289    :    // @name Stack manipulation.
 290    :    // @{
 291    :    void push(Register src);
 292    :    void push(const ImmediateImpl& src);
 293    :    void push(const OperandImpl& src);
 294    :  
 295    :    void pop(Register dst);
 296    :    void pop(const OperandImpl& dst);
 297    :    // @}
 298    :  
 299    :    // @name Manipulation of flags.
 300    :    // @{
 301    :    void pushfd();
 302    :    void popfd();
 303    :    void lahf();
 304    :    void sahf();
 305    :    // @}
 306    :  
 307    :    // @name Arithmetic operations.
 308    :    // @{
 309    :    void test_b(Register dst, Register src);
 310    :    void test_b(Register dst, const ImmediateImpl& src);
 311    :  
 312    :    void test(Register dst, Register src);
 313    :    void test(Register dst, const OperandImpl& src);
 314    :    void test(const OperandImpl& dst, Register src);
 315    :    void test(Register dst, const ImmediateImpl& src);
 316    :    void test(const OperandImpl& dst, const ImmediateImpl& src);
 317    :  
 318    :    void cmp_b(Register dst, Register src);
 319    :    void cmp_b(Register dst, const ImmediateImpl& src);
 320    :  
 321    :    void cmp(Register dst, Register src);
 322    :    void cmp(Register dst, const OperandImpl& src);
 323    :    void cmp(const OperandImpl& dst, Register src);
 324    :    void cmp(Register dst, const ImmediateImpl& src);
 325    :    void cmp(const OperandImpl& dst, const ImmediateImpl& src);
 326    :  
 327    :    void add_b(Register dst, Register src);
 328    :    void add_b(Register dst, const ImmediateImpl& src);
 329    :  
 330    :    void add(Register dst, Register src);
 331    :    void add(Register dst, const OperandImpl& src);
 332    :    void add(const OperandImpl& dst, Register src);
 333    :    void add(Register dst, const ImmediateImpl& src);
 334    :    void add(const OperandImpl& dst, const ImmediateImpl& src);
 335    :  
 336    :    void sub_b(Register dst, Register src);
 337    :    void sub_b(Register dst, const ImmediateImpl& src);
 338    :  
 339    :    void sub(Register dst, Register src);
 340    :    void sub(Register dst, const OperandImpl& src);
 341    :    void sub(const OperandImpl& dst, Register src);
 342    :    void sub(Register dst, const ImmediateImpl& src);
 343    :    void sub(const OperandImpl& dst, const ImmediateImpl& src);
 344    :    // @}
 345    :  
 346    :    // @name Shifting operations.
 347    :    // @{
 348    :    void shl(Register dst, const ImmediateImpl& src);
 349    :    void shr(Register dst, const ImmediateImpl& src);
 350    :    // @}
 351    :  
 352    :    // @name Aliases
 353    :    // @{
 354  E :    void loop(const ImmediateImpl& dst) { l(kLoopOnCounter, dst); }
 355  E :    void loope(const ImmediateImpl& dst) { l(kLoopOnCounterAndZeroFlag, dst); }
 356  E :    void loopne(const ImmediateImpl& dst) {
 357  E :      l(kLoopOnCounterAndNotZeroFlag, dst);
 358  E :    }
 359    :    // @}
 360    :  
 361    :    // Size of an 8 bit reach branch opcode.
 362    :    static const size_t kShortBranchOpcodeSize;
 363    :    // Size of an 8 bit reach branch.
 364    :    static const size_t kShortBranchSize;
 365    :  
 366    :    // Size of a 32 bit reach branch op code.
 367    :    static const size_t kLongBranchOpcodeSize;
 368    :    // Size of an 8bit reach branch.
 369    :    static const size_t kLongBranchSize;
 370    :  
 371    :    // Size of an 8 bit reach jump opcode.
 372    :    static const size_t kShortJumpOpcodeSize;
 373    :    // Size of an 8 bit reach jump.
 374    :    static const size_t kShortJumpSize;
 375    :  
 376    :    // Size of a 32 bit reach jump op code.
 377    :    static const size_t kLongJumpOpcodeSize;
 378    :    // Size of an 8bit reach jump.
 379    :    static const size_t kLongJumpSize;
 380    :  
 381    :    // The maximum length a single instruction will assemble to.
 382    :    // No instruction on x86 can exceed 15 bytes, per specs.
 383    :    static const size_t kMaxInstructionLength = 15;
 384    :  
 385    :   private:
 386    :    class InstructionBuffer;
 387    :    // Output the instruction data in @p instr to our delegate.
 388    :    void Output(const InstructionBuffer& instr);
 389    :  
 390    :    // Stores the current location of assembly.
 391    :    uint32 location_;
 392    :  
 393    :    // The delegate we push instructions at.
 394    :    InstructionSerializer* serializer_;
 395    :  };
 396    :  
 397    :  }  // namespace core
 398    :  
 399    :  #endif  // SYZYGY_CORE_ASSEMBLER_H_

Coverage information generated Tue Jun 25 13:56:24 2013.