Home | History | Annotate | Download | only in test
      1 // Copyright 2014, ARM Limited
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are met:
      6 //
      7 //   * Redistributions of source code must retain the above copyright notice,
      8 //     this list of conditions and the following disclaimer.
      9 //   * Redistributions in binary form must reproduce the above copyright notice,
     10 //     this list of conditions and the following disclaimer in the documentation
     11 //     and/or other materials provided with the distribution.
     12 //   * Neither the name of ARM Limited nor the names of its contributors may be
     13 //     used to endorse or promote products derived from this software without
     14 //     specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
     17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
     20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 
     27 #ifndef VIXL_A64_TEST_UTILS_A64_H_
     28 #define VIXL_A64_TEST_UTILS_A64_H_
     29 
     30 #include "test-runner.h"
     31 #include "vixl/a64/macro-assembler-a64.h"
     32 #include "vixl/a64/simulator-a64.h"
     33 #include "vixl/a64/disasm-a64.h"
     34 #include "vixl/a64/cpu-a64.h"
     35 
     36 namespace vixl {
     37 
     38 // Signalling and quiet NaNs in double format, constructed such that the bottom
     39 // 32 bits look like a signalling or quiet NaN (as appropriate) when interpreted
     40 // as a float. These values are not architecturally significant, but they're
     41 // useful in tests for initialising registers.
     42 extern const double kFP64SignallingNaN;
     43 extern const double kFP64QuietNaN;
     44 
     45 // Signalling and quiet NaNs in float format.
     46 extern const float kFP32SignallingNaN;
     47 extern const float kFP32QuietNaN;
     48 
     49 // Structure representing Q registers in a RegisterDump.
     50 struct vec128_t {
     51   uint64_t l;
     52   uint64_t h;
     53 };
     54 
     55 // RegisterDump: Object allowing integer, floating point and flags registers
     56 // to be saved to itself for future reference.
     57 class RegisterDump {
     58  public:
     59   RegisterDump() : completed_(false) {
     60     VIXL_ASSERT(sizeof(dump_.d_[0]) == kDRegSizeInBytes);
     61     VIXL_ASSERT(sizeof(dump_.s_[0]) == kSRegSizeInBytes);
     62     VIXL_ASSERT(sizeof(dump_.d_[0]) == kXRegSizeInBytes);
     63     VIXL_ASSERT(sizeof(dump_.s_[0]) == kWRegSizeInBytes);
     64     VIXL_ASSERT(sizeof(dump_.x_[0]) == kXRegSizeInBytes);
     65     VIXL_ASSERT(sizeof(dump_.w_[0]) == kWRegSizeInBytes);
     66     VIXL_ASSERT(sizeof(dump_.q_[0]) == kQRegSizeInBytes);
     67   }
     68 
     69   // The Dump method generates code to store a snapshot of the register values.
     70   // It needs to be able to use the stack temporarily, and requires that the
     71   // current stack pointer is sp, and is properly aligned.
     72   //
     73   // The dumping code is generated though the given MacroAssembler. No registers
     74   // are corrupted in the process, but the stack is used briefly. The flags will
     75   // be corrupted during this call.
     76   void Dump(MacroAssembler* assm);
     77 
     78   // Register accessors.
     79   inline int32_t wreg(unsigned code) const {
     80     if (code == kSPRegInternalCode) {
     81       return wspreg();
     82     }
     83     VIXL_ASSERT(RegAliasesMatch(code));
     84     return dump_.w_[code];
     85   }
     86 
     87   inline int64_t xreg(unsigned code) const {
     88     if (code == kSPRegInternalCode) {
     89       return spreg();
     90     }
     91     VIXL_ASSERT(RegAliasesMatch(code));
     92     return dump_.x_[code];
     93   }
     94 
     95   // FPRegister accessors.
     96   inline uint32_t sreg_bits(unsigned code) const {
     97     VIXL_ASSERT(FPRegAliasesMatch(code));
     98     return dump_.s_[code];
     99   }
    100 
    101   inline float sreg(unsigned code) const {
    102     return rawbits_to_float(sreg_bits(code));
    103   }
    104 
    105   inline uint64_t dreg_bits(unsigned code) const {
    106     VIXL_ASSERT(FPRegAliasesMatch(code));
    107     return dump_.d_[code];
    108   }
    109 
    110   inline double dreg(unsigned code) const {
    111     return rawbits_to_double(dreg_bits(code));
    112   }
    113 
    114   inline vec128_t qreg(unsigned code) const {
    115     return dump_.q_[code];
    116   }
    117 
    118   // Stack pointer accessors.
    119   inline int64_t spreg() const {
    120     VIXL_ASSERT(SPRegAliasesMatch());
    121     return dump_.sp_;
    122   }
    123 
    124   inline int64_t wspreg() const {
    125     VIXL_ASSERT(SPRegAliasesMatch());
    126     return dump_.wsp_;
    127   }
    128 
    129   // Flags accessors.
    130   inline uint64_t flags_nzcv() const {
    131     VIXL_ASSERT(IsComplete());
    132     VIXL_ASSERT((dump_.flags_ & ~Flags_mask) == 0);
    133     return dump_.flags_ & Flags_mask;
    134   }
    135 
    136   inline bool IsComplete() const {
    137     return completed_;
    138   }
    139 
    140  private:
    141   // Indicate whether the dump operation has been completed.
    142   bool completed_;
    143 
    144   // Check that the lower 32 bits of x<code> exactly match the 32 bits of
    145   // w<code>. A failure of this test most likely represents a failure in the
    146   // ::Dump method, or a failure in the simulator.
    147   bool RegAliasesMatch(unsigned code) const {
    148     VIXL_ASSERT(IsComplete());
    149     VIXL_ASSERT(code < kNumberOfRegisters);
    150     return ((dump_.x_[code] & kWRegMask) == dump_.w_[code]);
    151   }
    152 
    153   // As RegAliasesMatch, but for the stack pointer.
    154   bool SPRegAliasesMatch() const {
    155     VIXL_ASSERT(IsComplete());
    156     return ((dump_.sp_ & kWRegMask) == dump_.wsp_);
    157   }
    158 
    159   // As RegAliasesMatch, but for floating-point registers.
    160   bool FPRegAliasesMatch(unsigned code) const {
    161     VIXL_ASSERT(IsComplete());
    162     VIXL_ASSERT(code < kNumberOfFPRegisters);
    163     return (dump_.d_[code] & kSRegMask) == dump_.s_[code];
    164   }
    165 
    166   // Store all the dumped elements in a simple struct so the implementation can
    167   // use offsetof to quickly find the correct field.
    168   struct dump_t {
    169     // Core registers.
    170     uint64_t x_[kNumberOfRegisters];
    171     uint32_t w_[kNumberOfRegisters];
    172 
    173     // Floating-point registers, as raw bits.
    174     uint64_t d_[kNumberOfFPRegisters];
    175     uint32_t s_[kNumberOfFPRegisters];
    176 
    177     // Vector registers.
    178     vec128_t q_[kNumberOfVRegisters];
    179 
    180     // The stack pointer.
    181     uint64_t sp_;
    182     uint64_t wsp_;
    183 
    184     // NZCV flags, stored in bits 28 to 31.
    185     // bit[31] : Negative
    186     // bit[30] : Zero
    187     // bit[29] : Carry
    188     // bit[28] : oVerflow
    189     uint64_t flags_;
    190   } dump_;
    191 };
    192 
    193 // Some of these methods don't use the RegisterDump argument, but they have to
    194 // accept them so that they can overload those that take register arguments.
    195 bool Equal32(uint32_t expected, const RegisterDump*, uint32_t result);
    196 bool Equal64(uint64_t expected, const RegisterDump*, uint64_t result);
    197 
    198 bool EqualFP32(float expected, const RegisterDump*, float result);
    199 bool EqualFP64(double expected, const RegisterDump*, double result);
    200 
    201 bool Equal32(uint32_t expected, const RegisterDump* core, const Register& reg);
    202 bool Equal64(uint64_t expected, const RegisterDump* core, const Register& reg);
    203 
    204 bool EqualFP32(float expected, const RegisterDump* core,
    205                const FPRegister& fpreg);
    206 bool EqualFP64(double expected, const RegisterDump* core,
    207                const FPRegister& fpreg);
    208 
    209 bool Equal64(const Register& reg0, const RegisterDump* core,
    210              const Register& reg1);
    211 bool Equal128(uint64_t expected_h, uint64_t expected_l,
    212               const RegisterDump* core, const VRegister& reg);
    213 
    214 bool EqualNzcv(uint32_t expected, uint32_t result);
    215 
    216 bool EqualRegisters(const RegisterDump* a, const RegisterDump* b);
    217 
    218 // Populate the w, x and r arrays with registers from the 'allowed' mask. The
    219 // r array will be populated with <reg_size>-sized registers,
    220 //
    221 // This allows for tests which use large, parameterized blocks of registers
    222 // (such as the push and pop tests), but where certain registers must be
    223 // avoided as they are used for other purposes.
    224 //
    225 // Any of w, x, or r can be NULL if they are not required.
    226 //
    227 // The return value is a RegList indicating which registers were allocated.
    228 RegList PopulateRegisterArray(Register* w, Register* x, Register* r,
    229                               int reg_size, int reg_count, RegList allowed);
    230 
    231 // As PopulateRegisterArray, but for floating-point registers.
    232 RegList PopulateFPRegisterArray(FPRegister* s, FPRegister* d, FPRegister* v,
    233                                 int reg_size, int reg_count, RegList allowed);
    234 
    235 // Ovewrite the contents of the specified registers. This enables tests to
    236 // check that register contents are written in cases where it's likely that the
    237 // correct outcome could already be stored in the register.
    238 //
    239 // This always overwrites X-sized registers. If tests are operating on W
    240 // registers, a subsequent write into an aliased W register should clear the
    241 // top word anyway, so clobbering the full X registers should make tests more
    242 // rigorous.
    243 void Clobber(MacroAssembler* masm, RegList reg_list,
    244              uint64_t const value = 0xfedcba9876543210);
    245 
    246 // As Clobber, but for FP registers.
    247 void ClobberFP(MacroAssembler* masm, RegList reg_list,
    248                double const value = kFP64SignallingNaN);
    249 
    250 // As Clobber, but for a CPURegList with either FP or integer registers. When
    251 // using this method, the clobber value is always the default for the basic
    252 // Clobber or ClobberFP functions.
    253 void Clobber(MacroAssembler* masm, CPURegList reg_list);
    254 
    255 }  // namespace vixl
    256 
    257 #endif  // VIXL_A64_TEST_UTILS_A64_H_
    258