// asmt region markers and probes for GCC and Clang, C and C++, at any
// optimisation level:
//
//   ASMT_BEGIN(hot);
//   for (int i = 0; i < n; ++i) s += a[i];
//   ASMT_END(hot);
//   // asmt build.o --region=mark:hot
//
// Probes appear in listings as `opaque` / `early-clobber` notes with live
// g/v/k counts, in the `probes` metric and as JSON `probe`. Defining
// ASMT_NO_PROBES turns ASMT_OPAQUE into a no-op and ASMT_EC_COPY into an
// assignment.
#ifndef ASMT_MARKERS_H
#define ASMT_MARKERS_H

// Local labels `asmt.begin.<name>.<n>` / `asmt.end.<name>.<n>`; no
// instructions. A region is every instruction reachable from a BEGIN label
// before an END label of the same name, one region per label copy (`<n>` is
// unique per inlined or duplicated copy). The compiler may move independent
// work across markers.
#define ASMT_BEGIN(name) __asm__ __volatile__("asmt.begin." #name ".%=:" :)
#define ASMT_END(name)   __asm__ __volatile__("asmt.end." #name ".%=:" :)

#ifdef ASMT_NO_PROBES
#define ASMT_OPAQUE(x, c)     ((void)(x))
#define ASMT_EC_COPY(out, in) ((out) = (in))
#else
// Makes x opaque to the optimiser without emitting instructions: it is
// materialised in constraint class `c` ("r" gpr, "x" xmm0-15, "v" any vector
// register, "m" memory) and treated as modified, e.g. `ASMT_OPAQUE(acc, "v");`.
#define ASMT_OPAQUE(x, c) __asm__ __volatile__("asmt.opaque.%=:" : "+" c(x))
// Copies vector `in` to `out` with one vmovaps whose output is early-clobber
// (never shares the input's register), in both AT&T and Intel asm dialects,
// e.g. `ASMT_EC_COPY(tmp, v);`.
#define ASMT_EC_COPY(out, in)                                        \
  __asm__ __volatile__("asmt.ec.%=: {vmovaps %1, %0|vmovaps %0, %1}" \
                       : "=&v"(out)                                  \
                       : "v"(in))
#endif

#endif  // ASMT_MARKERS_H
