Home | History | Annotate | Download | only in test
      1 // Copyright 2013, 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 "cctest.h"
     31 #include "a64/macro-assembler-a64.h"
     32 #include "a64/simulator-a64.h"
     33 #include "a64/disasm-a64.h"
     34 #include "a64/cpu-a64.h"
     35 
     36 namespace vixl {
     37 
     38 // RegisterDump: Object allowing integer, floating point and flags registers
     39 // to be saved to itself for future reference.
     40 class RegisterDump {
     41  public:
     42   RegisterDump() : completed_(false) {
     43     VIXL_ASSERT(sizeof(dump_.d_[0]) == kDRegSizeInBytes);
     44     VIXL_ASSERT(sizeof(dump_.s_[0]) == kSRegSizeInBytes);
     45     VIXL_ASSERT(sizeof(dump_.d_[0]) == kXRegSizeInBytes);
     46     VIXL_ASSERT(sizeof(dump_.s_[0]) == kWRegSizeInBytes);
     47     VIXL_ASSERT(sizeof(dump_.x_[0]) == kXRegSizeInBytes);
     48     VIXL_ASSERT(sizeof(dump_.w_[0]) == kWRegSizeInBytes);
     49   }
     50 
     51   // The Dump method generates code to store a snapshot of the register values.
     52   // It needs to be able to use the stack temporarily, and requires that the
     53   // current stack pointer is sp, and is properly aligned.
     54   //
     55   // The dumping code is generated though the given MacroAssembler. No registers
     56   // are corrupted in the process, but the stack is used briefly. The flags will
     57   // be corrupted during this call.
     58   void Dump(MacroAssembler* assm);
     59 
     60   // Register accessors.
     61   inline int32_t wreg(unsigned code) const {
     62     if (code == kSPRegInternalCode) {
     63       return wspreg();
     64     }
     65     VIXL_ASSERT(RegAliasesMatch(code));
     66     return dump_.w_[code];
     67   }
     68 
     69   inline int64_t xreg(unsigned code) const {
     70     if (code == kSPRegInternalCode) {
     71       return spreg();
     72     }
     73     VIXL_ASSERT(RegAliasesMatch(code));
     74     return dump_.x_[code];
     75   }
     76 
     77   // FPRegister accessors.
     78   inline uint32_t sreg_bits(unsigned code) const {
     79     VIXL_ASSERT(FPRegAliasesMatch(code));
     80     return dump_.s_[code];
     81   }
     82 
     83   inline float sreg(unsigned code) const {
     84     return rawbits_to_float(sreg_bits(code));
     85   }
     86 
     87   inline uint64_t dreg_bits(unsigned code) const {
     88     VIXL_ASSERT(FPRegAliasesMatch(code));
     89     return dump_.d_[code];
     90   }
     91 
     92   inline double dreg(unsigned code) const {
     93     return rawbits_to_double(dreg_bits(code));
     94   }
     95 
     96   // Stack pointer accessors.
     97   inline int64_t spreg() const {
     98     VIXL_ASSERT(SPRegAliasesMatch());
     99     return dump_.sp_;
    100   }
    101 
    102   inline int64_t wspreg() const {
    103     VIXL_ASSERT(SPRegAliasesMatch());
    104     return dump_.wsp_;
    105   }
    106 
    107   // Flags accessors.
    108   inline uint64_t flags_nzcv() const {
    109     VIXL_ASSERT(IsComplete());
    110     VIXL_ASSERT((dump_.flags_ & ~Flags_mask) == 0);
    111     return dump_.flags_ & Flags_mask;
    112   }
    113 
    114   inline bool IsComplete() const {
    115     return completed_;
    116   }
    117 
    118  private:
    119   // Indicate whether the dump operation has been completed.
    120   bool completed_;
    121 
    122   // Check that the lower 32 bits of x<code> exactly match the 32 bits of
    123   // w<code>. A failure of this test most likely represents a failure in the
    124   // ::Dump method, or a failure in the simulator.
    125   bool RegAliasesMatch(unsigned code) const {
    126     VIXL_ASSERT(IsComplete());
    127     VIXL_ASSERT(code < kNumberOfRegisters);
    128     return ((dump_.x_[code] & kWRegMask) == dump_.w_[code]);
    129   }
    130 
    131   // As RegAliasesMatch, but for the stack pointer.
    132   bool SPRegAliasesMatch() const {
    133     VIXL_ASSERT(IsComplete());
    134     return ((dump_.sp_ & kWRegMask) == dump_.wsp_);
    135   }
    136 
    137   // As RegAliasesMatch, but for floating-point registers.
    138   bool FPRegAliasesMatch(unsigned code) const {
    139     VIXL_ASSERT(IsComplete());
    140     VIXL_ASSERT(code < kNumberOfFPRegisters);
    141     return (dump_.d_[code] & kSRegMask) == dump_.s_[code];
    142   }
    143 
    144   // Store all the dumped elements in a simple struct so the implementation can
    145   // use offsetof to quickly find the correct field.
    146   struct dump_t {
    147     // Core registers.
    148     uint64_t x_[kNumberOfRegisters];
    149     uint32_t w_[kNumberOfRegisters];
    150 
    151     // Floating-point registers, as raw bits.
    152     uint64_t d_[kNumberOfFPRegisters];
    153     uint32_t s_[kNumberOfFPRegisters];
    154 
    155     // The stack pointer.
    156     uint64_t sp_;
    157     uint64_t wsp_;
    158 
    159     // NZCV flags, stored in bits 28 to 31.
    160     // bit[31] : Negative
    161     // bit[30] : Zero
    162     // bit[29] : Carry
    163     // bit[28] : oVerflow
    164     uint64_t flags_;
    165   } dump_;
    166 };
    167 
    168 // Some of these methods don't use the RegisterDump argument, but they have to
    169 // accept them so that they can overload those that take register arguments.
    170 bool Equal32(uint32_t expected, const RegisterDump*, uint32_t result);
    171 bool Equal64(uint64_t expected, const RegisterDump*, uint64_t result);
    172 
    173 bool EqualFP32(float expected, const RegisterDump*, float result);
    174 bool EqualFP64(double expected, const RegisterDump*, double result);
    175 
    176 bool Equal32(uint32_t expected, const RegisterDump* core, const Register& reg);
    177 bool Equal64(uint64_t expected, const RegisterDump* core, const Register& reg);
    178 
    179 bool EqualFP32(float expected, const RegisterDump* core,
    180                const FPRegister& fpreg);
    181 bool EqualFP64(double expected, const RegisterDump* core,
    182                const FPRegister& fpreg);
    183 
    184 bool Equal64(const Register& reg0, const RegisterDump* core,
    185              const Register& reg1);
    186 
    187 bool EqualNzcv(uint32_t expected, uint32_t result);
    188 
    189 bool EqualRegisters(const RegisterDump* a, const RegisterDump* b);
    190 
    191 // Populate the w, x and r arrays with registers from the 'allowed' mask. The
    192 // r array will be populated with <reg_size>-sized registers,
    193 //
    194 // This allows for tests which use large, parameterized blocks of registers
    195 // (such as the push and pop tests), but where certain registers must be
    196 // avoided as they are used for other purposes.
    197 //
    198 // Any of w, x, or r can be NULL if they are not required.
    199 //
    200 // The return value is a RegList indicating which registers were allocated.
    201 RegList PopulateRegisterArray(Register* w, Register* x, Register* r,
    202                               int reg_size, int reg_count, RegList allowed);
    203 
    204 // As PopulateRegisterArray, but for floating-point registers.
    205 RegList PopulateFPRegisterArray(FPRegister* s, FPRegister* d, FPRegister* v,
    206                                 int reg_size, int reg_count, RegList allowed);
    207 
    208 // Ovewrite the contents of the specified registers. This enables tests to
    209 // check that register contents are written in cases where it's likely that the
    210 // correct outcome could already be stored in the register.
    211 //
    212 // This always overwrites X-sized registers. If tests are operating on W
    213 // registers, a subsequent write into an aliased W register should clear the
    214 // top word anyway, so clobbering the full X registers should make tests more
    215 // rigorous.
    216 void Clobber(MacroAssembler* masm, RegList reg_list,
    217              uint64_t const value = 0xfedcba9876543210);
    218 
    219 // As Clobber, but for FP registers.
    220 void ClobberFP(MacroAssembler* masm, RegList reg_list,
    221                double const value = kFP64SignallingNaN);
    222 
    223 // As Clobber, but for a CPURegList with either FP or integer registers. When
    224 // using this method, the clobber value is always the default for the basic
    225 // Clobber or ClobberFP functions.
    226 void Clobber(MacroAssembler* masm, CPURegList reg_list);
    227 
    228 
    229 }  // namespace vixl
    230 
    231 #endif  // VIXL_A64_TEST_UTILS_A64_H_
    232