brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.3 KiB · 9f6b106 Raw
119 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// REQUIRES: target={{aarch64-.+}}10// UNSUPPORTED: target={{.*-windows.*}}11 12#include <libunwind.h>13#include <stdint.h>14#include <stdio.h>15#include <stdlib.h>16#include <string.h>17#include <sys/auxv.h>18 19// Basic test of unwinding with SME lazy saves. This tests libunwind disables ZA20// (and commits a lazy save of ZA) before resuming from unwinding.21 22// Note: This test requires SME (and is setup to pass on targets without SME).23 24static bool checkHasSME() {25  constexpr int hwcap2_sme = (1 << 23);26  unsigned long hwcap2 = getauxval(AT_HWCAP2);27  return (hwcap2 & hwcap2_sme) != 0;28}29 30struct TPIDR2Block {31  void *za_save_buffer;32  uint64_t num_save_slices;33};34 35__attribute__((noinline)) void private_za() {36  // Note: Lazy save active on entry to function.37  unw_context_t context;38  unw_cursor_t cursor;39 40  unw_getcontext(&context);41  unw_init_local(&cursor, &context);42  unw_step(&cursor);43  unw_resume(&cursor);44}45 46bool isZAOn() {47  register uint64_t svcr asm("x20");48  asm(".inst 0xd53b4254" : "=r"(svcr));49  return (svcr & 0b10) != 0;50}51 52__attribute__((noinline)) void za_function_with_lazy_save() {53  register uint64_t tmp asm("x8");54 55  // SMSTART ZA (should zero ZA)56  asm(".inst 0xd503457f");57 58  // RDSVL x8, #1 (read streaming vector length)59  asm(".inst 0x04bf5828" : "=r"(tmp));60 61  // Allocate and fill ZA save buffer with 0xAA.62  size_t buffer_size = tmp * tmp;63  uint8_t *za_save_buffer = (uint8_t *)alloca(buffer_size);64  memset(za_save_buffer, 0xAA, buffer_size);65 66  TPIDR2Block block = {za_save_buffer, tmp};67  tmp = reinterpret_cast<uint64_t>(&block);68 69  // MRS TPIDR2_EL0, x8 (setup lazy save of ZA)70  asm(".inst 0xd51bd0a8" ::"r"(tmp));71 72  // ZA should be on before unwinding.73  if (!isZAOn()) {74    fprintf(stderr, __FILE__ ": fail (ZA not on before call)\n");75    abort();76  } else {77    fprintf(stderr, __FILE__ ": pass (ZA on before call)\n");78  }79 80  private_za();81 82  // ZA should be off after unwinding.83  if (isZAOn()) {84    fprintf(stderr, __FILE__ ": fail (ZA on after unwinding)\n");85    abort();86  } else {87    fprintf(stderr, __FILE__ ": pass (ZA off after unwinding)\n");88  }89 90  // MRS x8, TPIDR2_EL0 (read TPIDR2_EL0)91  asm(".inst 0xd53bd0a8" : "=r"(tmp));92  // ZA should have been saved (TPIDR2_EL0 zero).93  if (tmp != 0) {94    fprintf(stderr, __FILE__ ": fail (TPIDR2_EL0 non-null after unwinding)\n");95    abort();96  } else {97    fprintf(stderr, __FILE__ ": pass (TPIDR2_EL0 null after unwinding)\n");98  }99 100  // ZA (all zero) should have been saved to the buffer.101  for (unsigned i = 0; i < buffer_size; ++i) {102    if (za_save_buffer[i] != 0) {103      fprintf(stderr,104              __FILE__ ": fail (za_save_buffer non-zero after unwinding)\n");105      abort();106    }107  }108  fprintf(stderr, __FILE__ ": pass (za_save_buffer zero'd after unwinding)\n");109}110 111int main(int, char **) {112  if (!checkHasSME()) {113    fprintf(stderr, __FILE__ ": pass (no SME support)\n");114    return 0; // Pass (SME is required for this test to run).115  }116  za_function_with_lazy_save();117  return 0;118}119