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 #include "test-utils-a64.h"
     28 
     29 #include <math.h>   // Needed for isnan().
     30 
     31 #include "cctest.h"
     32 #include "a64/macro-assembler-a64.h"
     33 #include "a64/simulator-a64.h"
     34 #include "a64/disasm-a64.h"
     35 #include "a64/cpu-a64.h"
     36 
     37 #define __ masm->
     38 
     39 namespace vixl {
     40 
     41 bool Equal32(uint32_t expected, const RegisterDump*, uint32_t result) {
     42   if (result != expected) {
     43     printf("Expected 0x%08" PRIx32 "\t Found 0x%08" PRIx32 "\n",
     44            expected, result);
     45   }
     46 
     47   return expected == result;
     48 }
     49 
     50 
     51 bool Equal64(uint64_t expected, const RegisterDump*, uint64_t result) {
     52   if (result != expected) {
     53     printf("Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n",
     54            expected, result);
     55   }
     56 
     57   return expected == result;
     58 }
     59 
     60 
     61 bool EqualFP32(float expected, const RegisterDump*, float result) {
     62   if (float_to_rawbits(expected) == float_to_rawbits(result)) {
     63     return true;
     64   } else {
     65     if (isnan(expected) || (expected == 0.0)) {
     66       printf("Expected 0x%08" PRIx32 "\t Found 0x%08" PRIx32 "\n",
     67              float_to_rawbits(expected), float_to_rawbits(result));
     68     } else {
     69       printf("Expected %.9f (0x%08" PRIx32 ")\t "
     70              "Found %.9f (0x%08" PRIx32 ")\n",
     71              expected, float_to_rawbits(expected),
     72              result, float_to_rawbits(result));
     73     }
     74     return false;
     75   }
     76 }
     77 
     78 
     79 bool EqualFP64(double expected, const RegisterDump*, double result) {
     80   if (double_to_rawbits(expected) == double_to_rawbits(result)) {
     81     return true;
     82   }
     83 
     84   if (isnan(expected) || (expected == 0.0)) {
     85     printf("Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n",
     86            double_to_rawbits(expected), double_to_rawbits(result));
     87   } else {
     88     printf("Expected %.17f (0x%016" PRIx64 ")\t "
     89            "Found %.17f (0x%016" PRIx64 ")\n",
     90            expected, double_to_rawbits(expected),
     91            result, double_to_rawbits(result));
     92   }
     93   return false;
     94 }
     95 
     96 
     97 bool Equal32(uint32_t expected, const RegisterDump* core, const Register& reg) {
     98   VIXL_ASSERT(reg.Is32Bits());
     99   // Retrieve the corresponding X register so we can check that the upper part
    100   // was properly cleared.
    101   int64_t result_x = core->xreg(reg.code());
    102   if ((result_x & 0xffffffff00000000) != 0) {
    103     printf("Expected 0x%08" PRIx32 "\t Found 0x%016" PRIx64 "\n",
    104            expected, result_x);
    105     return false;
    106   }
    107   uint32_t result_w = core->wreg(reg.code());
    108   return Equal32(expected, core, result_w);
    109 }
    110 
    111 
    112 bool Equal64(uint64_t expected,
    113              const RegisterDump* core,
    114              const Register& reg) {
    115   VIXL_ASSERT(reg.Is64Bits());
    116   uint64_t result = core->xreg(reg.code());
    117   return Equal64(expected, core, result);
    118 }
    119 
    120 
    121 bool EqualFP32(float expected,
    122                const RegisterDump* core,
    123                const FPRegister& fpreg) {
    124   VIXL_ASSERT(fpreg.Is32Bits());
    125   // Retrieve the corresponding D register so we can check that the upper part
    126   // was properly cleared.
    127   uint64_t result_64 = core->dreg_bits(fpreg.code());
    128   if ((result_64 & 0xffffffff00000000) != 0) {
    129     printf("Expected 0x%08" PRIx32 " (%f)\t Found 0x%016" PRIx64 "\n",
    130            float_to_rawbits(expected), expected, result_64);
    131     return false;
    132   }
    133 
    134   return EqualFP32(expected, core, core->sreg(fpreg.code()));
    135 }
    136 
    137 
    138 bool EqualFP64(double expected,
    139                const RegisterDump* core,
    140                const FPRegister& fpreg) {
    141   VIXL_ASSERT(fpreg.Is64Bits());
    142   return EqualFP64(expected, core, core->dreg(fpreg.code()));
    143 }
    144 
    145 
    146 bool Equal64(const Register& reg0,
    147              const RegisterDump* core,
    148              const Register& reg1) {
    149   VIXL_ASSERT(reg0.Is64Bits() && reg1.Is64Bits());
    150   int64_t expected = core->xreg(reg0.code());
    151   int64_t result = core->xreg(reg1.code());
    152   return Equal64(expected, core, result);
    153 }
    154 
    155 
    156 static char FlagN(uint32_t flags) {
    157   return (flags & NFlag) ? 'N' : 'n';
    158 }
    159 
    160 
    161 static char FlagZ(uint32_t flags) {
    162   return (flags & ZFlag) ? 'Z' : 'z';
    163 }
    164 
    165 
    166 static char FlagC(uint32_t flags) {
    167   return (flags & CFlag) ? 'C' : 'c';
    168 }
    169 
    170 
    171 static char FlagV(uint32_t flags) {
    172   return (flags & VFlag) ? 'V' : 'v';
    173 }
    174 
    175 
    176 bool EqualNzcv(uint32_t expected, uint32_t result) {
    177   VIXL_ASSERT((expected & ~NZCVFlag) == 0);
    178   VIXL_ASSERT((result & ~NZCVFlag) == 0);
    179   if (result != expected) {
    180     printf("Expected: %c%c%c%c\t Found: %c%c%c%c\n",
    181         FlagN(expected), FlagZ(expected), FlagC(expected), FlagV(expected),
    182         FlagN(result), FlagZ(result), FlagC(result), FlagV(result));
    183     return false;
    184   }
    185 
    186   return true;
    187 }
    188 
    189 
    190 bool EqualRegisters(const RegisterDump* a, const RegisterDump* b) {
    191   for (unsigned i = 0; i < kNumberOfRegisters; i++) {
    192     if (a->xreg(i) != b->xreg(i)) {
    193       printf("x%d\t Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n",
    194              i, a->xreg(i), b->xreg(i));
    195       return false;
    196     }
    197   }
    198 
    199   for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
    200     uint64_t a_bits = a->dreg_bits(i);
    201     uint64_t b_bits = b->dreg_bits(i);
    202     if (a_bits != b_bits) {
    203       printf("d%d\t Expected 0x%016" PRIx64 "\t Found 0x%016" PRIx64 "\n",
    204              i, a_bits, b_bits);
    205       return false;
    206     }
    207   }
    208 
    209   return true;
    210 }
    211 
    212 
    213 RegList PopulateRegisterArray(Register* w, Register* x, Register* r,
    214                               int reg_size, int reg_count, RegList allowed) {
    215   RegList list = 0;
    216   int i = 0;
    217   for (unsigned n = 0; (n < kNumberOfRegisters) && (i < reg_count); n++) {
    218     if (((UINT64_C(1) << n) & allowed) != 0) {
    219       // Only assign allowed registers.
    220       if (r) {
    221         r[i] = Register(n, reg_size);
    222       }
    223       if (x) {
    224         x[i] = Register(n, kXRegSize);
    225       }
    226       if (w) {
    227         w[i] = Register(n, kWRegSize);
    228       }
    229       list |= (UINT64_C(1) << n);
    230       i++;
    231     }
    232   }
    233   // Check that we got enough registers.
    234   VIXL_ASSERT(CountSetBits(list, kNumberOfRegisters) == reg_count);
    235 
    236   return list;
    237 }
    238 
    239 
    240 RegList PopulateFPRegisterArray(FPRegister* s, FPRegister* d, FPRegister* v,
    241                                 int reg_size, int reg_count, RegList allowed) {
    242   RegList list = 0;
    243   int i = 0;
    244   for (unsigned n = 0; (n < kNumberOfFPRegisters) && (i < reg_count); n++) {
    245     if (((UINT64_C(1) << n) & allowed) != 0) {
    246       // Only assigned allowed registers.
    247       if (v) {
    248         v[i] = FPRegister(n, reg_size);
    249       }
    250       if (d) {
    251         d[i] = FPRegister(n, kDRegSize);
    252       }
    253       if (s) {
    254         s[i] = FPRegister(n, kSRegSize);
    255       }
    256       list |= (UINT64_C(1) << n);
    257       i++;
    258     }
    259   }
    260   // Check that we got enough registers.
    261   VIXL_ASSERT(CountSetBits(list, kNumberOfFPRegisters) == reg_count);
    262 
    263   return list;
    264 }
    265 
    266 
    267 void Clobber(MacroAssembler* masm, RegList reg_list, uint64_t const value) {
    268   Register first = NoReg;
    269   for (unsigned i = 0; i < kNumberOfRegisters; i++) {
    270     if (reg_list & (UINT64_C(1) << i)) {
    271       Register xn(i, kXRegSize);
    272       // We should never write into sp here.
    273       VIXL_ASSERT(!xn.Is(sp));
    274       if (!xn.IsZero()) {
    275         if (!first.IsValid()) {
    276           // This is the first register we've hit, so construct the literal.
    277           __ Mov(xn, value);
    278           first = xn;
    279         } else {
    280           // We've already loaded the literal, so re-use the value already
    281           // loaded into the first register we hit.
    282           __ Mov(xn, first);
    283         }
    284       }
    285     }
    286   }
    287 }
    288 
    289 
    290 void ClobberFP(MacroAssembler* masm, RegList reg_list, double const value) {
    291   FPRegister first = NoFPReg;
    292   for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
    293     if (reg_list & (UINT64_C(1) << i)) {
    294       FPRegister dn(i, kDRegSize);
    295       if (!first.IsValid()) {
    296         // This is the first register we've hit, so construct the literal.
    297         __ Fmov(dn, value);
    298         first = dn;
    299       } else {
    300         // We've already loaded the literal, so re-use the value already loaded
    301         // into the first register we hit.
    302         __ Fmov(dn, first);
    303       }
    304     }
    305   }
    306 }
    307 
    308 
    309 void Clobber(MacroAssembler* masm, CPURegList reg_list) {
    310   if (reg_list.type() == CPURegister::kRegister) {
    311     // This will always clobber X registers.
    312     Clobber(masm, reg_list.list());
    313   } else if (reg_list.type() == CPURegister::kFPRegister) {
    314     // This will always clobber D registers.
    315     ClobberFP(masm, reg_list.list());
    316   } else {
    317     VIXL_UNREACHABLE();
    318   }
    319 }
    320 
    321 
    322 void RegisterDump::Dump(MacroAssembler* masm) {
    323   VIXL_ASSERT(__ StackPointer().Is(sp));
    324 
    325   // Ensure that we don't unintentionally clobber any registers.
    326   UseScratchRegisterScope temps(masm);
    327   temps.ExcludeAll();
    328 
    329   // Preserve some temporary registers.
    330   Register dump_base = x0;
    331   Register dump = x1;
    332   Register tmp = x2;
    333   Register dump_base_w = dump_base.W();
    334   Register dump_w = dump.W();
    335   Register tmp_w = tmp.W();
    336 
    337   // Offsets into the dump_ structure.
    338   const int x_offset = offsetof(dump_t, x_);
    339   const int w_offset = offsetof(dump_t, w_);
    340   const int d_offset = offsetof(dump_t, d_);
    341   const int s_offset = offsetof(dump_t, s_);
    342   const int sp_offset = offsetof(dump_t, sp_);
    343   const int wsp_offset = offsetof(dump_t, wsp_);
    344   const int flags_offset = offsetof(dump_t, flags_);
    345 
    346   __ Push(xzr, dump_base, dump, tmp);
    347 
    348   // Load the address where we will dump the state.
    349   __ Mov(dump_base, reinterpret_cast<uintptr_t>(&dump_));
    350 
    351   // Dump the stack pointer (sp and wsp).
    352   // The stack pointer cannot be stored directly; it needs to be moved into
    353   // another register first. Also, we pushed four X registers, so we need to
    354   // compensate here.
    355   __ Add(tmp, sp, 4 * kXRegSizeInBytes);
    356   __ Str(tmp, MemOperand(dump_base, sp_offset));
    357   __ Add(tmp_w, wsp, 4 * kXRegSizeInBytes);
    358   __ Str(tmp_w, MemOperand(dump_base, wsp_offset));
    359 
    360   // Dump X registers.
    361   __ Add(dump, dump_base, x_offset);
    362   for (unsigned i = 0; i < kNumberOfRegisters; i += 2) {
    363     __ Stp(Register::XRegFromCode(i), Register::XRegFromCode(i + 1),
    364            MemOperand(dump, i * kXRegSizeInBytes));
    365   }
    366 
    367   // Dump W registers.
    368   __ Add(dump, dump_base, w_offset);
    369   for (unsigned i = 0; i < kNumberOfRegisters; i += 2) {
    370     __ Stp(Register::WRegFromCode(i), Register::WRegFromCode(i + 1),
    371            MemOperand(dump, i * kWRegSizeInBytes));
    372   }
    373 
    374   // Dump D registers.
    375   __ Add(dump, dump_base, d_offset);
    376   for (unsigned i = 0; i < kNumberOfFPRegisters; i += 2) {
    377     __ Stp(FPRegister::DRegFromCode(i), FPRegister::DRegFromCode(i + 1),
    378            MemOperand(dump, i * kDRegSizeInBytes));
    379   }
    380 
    381   // Dump S registers.
    382   __ Add(dump, dump_base, s_offset);
    383   for (unsigned i = 0; i < kNumberOfFPRegisters; i += 2) {
    384     __ Stp(FPRegister::SRegFromCode(i), FPRegister::SRegFromCode(i + 1),
    385            MemOperand(dump, i * kSRegSizeInBytes));
    386   }
    387 
    388   // Dump the flags.
    389   __ Mrs(tmp, NZCV);
    390   __ Str(tmp, MemOperand(dump_base, flags_offset));
    391 
    392   // To dump the values that were in tmp amd dump, we need a new scratch
    393   // register.  We can use any of the already dumped registers since we can
    394   // easily restore them.
    395   Register dump2_base = x10;
    396   Register dump2 = x11;
    397   VIXL_ASSERT(!AreAliased(dump_base, dump, tmp, dump2_base, dump2));
    398 
    399   // Don't lose the dump_ address.
    400   __ Mov(dump2_base, dump_base);
    401 
    402   __ Pop(tmp, dump, dump_base, xzr);
    403 
    404   __ Add(dump2, dump2_base, w_offset);
    405   __ Str(dump_base_w, MemOperand(dump2, dump_base.code() * kWRegSizeInBytes));
    406   __ Str(dump_w, MemOperand(dump2, dump.code() * kWRegSizeInBytes));
    407   __ Str(tmp_w, MemOperand(dump2, tmp.code() * kWRegSizeInBytes));
    408 
    409   __ Add(dump2, dump2_base, x_offset);
    410   __ Str(dump_base, MemOperand(dump2, dump_base.code() * kXRegSizeInBytes));
    411   __ Str(dump, MemOperand(dump2, dump.code() * kXRegSizeInBytes));
    412   __ Str(tmp, MemOperand(dump2, tmp.code() * kXRegSizeInBytes));
    413 
    414   // Finally, restore dump2_base and dump2.
    415   __ Ldr(dump2_base, MemOperand(dump2, dump2_base.code() * kXRegSizeInBytes));
    416   __ Ldr(dump2, MemOperand(dump2, dump2.code() * kXRegSizeInBytes));
    417 
    418   completed_ = true;
    419 }
    420 
    421 }  // namespace vixl
    422