Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SFINAE on assembly?

Is it possible to use metaprogramming tricks to allow SFINAE on assembly blocks? For example to detect if an instruction like "CPUID" is available on a processor: (this is not valid code, but illustrates what I would like to achieve)

// This should work if `CPUID` is a valid instruction on the target architecture
template <
  class... T,
  class = decltype(sizeof...(T), asm volatile("CPUID":::)
>
bool f(T...) {
    return true;
}

// This should fail because `BLAH` is not an instruction
template <
  class... T,
  class = decltype(sizeof...(T), asm volatile("BLAH":::)
>
bool f(T...) {
    return true;
}
like image 826
Vincent Avatar asked Jan 29 '18 13:01

Vincent


People also ask

What is meant by SFINAE?

Substitution failure is not an error (SFINAE) refers to a situation in C++ where an invalid substitution of template parameters is not in itself an error. David Vandevoorde first introduced the acronym SFINAE to describe related programming techniques.

Will concepts replace SFINAE?

So the simple answer is YES.


1 Answers

It is impossible to achieve what is formulated in the question the way it is formulated for multiple reasons listed below. However, by generalizing the idea it may become something that might be making sense to include into some future revision of the language.

The reasons why it will not work:

  1. asm blocks are opaque to the C++ compiler. The syntax of such blocks is compiler-specific. I do not think that MS VC++ accepts clobber lists the way it is supported by GCC and Intel compiler. Moreover, Microsoft's x86_64 compilers stopped supporting assembly blocks as they force people to use intrinsics. By the way, maybe relying on presence of intrinsic functions can be used to offer a compile-time CPU dispatching instead? Could be worth exploring this idea.

  2. asm blocks are target architecture-specific. There are other ways to detect the target architecture at compile-time.

  3. The very notion of an instruction being present/absent is very vague. Which entity is authorized to make a decision on any given asm expression: the assembler program that translates its text into machine code or the target processor itself that runs the actual code? Both choices are problematic.

    • As an example, "MOV" is a popular mnemonic name for a multitude of architectures. But is it the same instruction in all cases? The semantics bound to the mnemonic is unlikely to match between non-related architectures.
    • Merely being successful in assembling does not mean it will execute fine. For example, on Intel 64 architecture an instruction may fault with #UD (undefined instruction signal) even if it is correct, because its behavior depends on runtime values of CR0 and CR4 registers which are controlled by an operating system. An assembler program will process it just fine in any case. One has to run the code. But what if we do cross-compilation, and cannot run it as the target processor does not match the host processor?

As it is, there is no way to know the outcome of an opaque block without executing it first. So, the compiler may want to call an arbitrary program to return a value which then will be used for template expansion. Such a program can then do processor- or instruction-sensing and return its findings to guide compilation further.

Now this looks abstract enough to be a language feature, as we dictate no assumptions on the nature of such an external program. There are still portability (+ cross-compiling) issues and security (running an external program is risky) issues. All in all, it looks better to me to rely on existing macrodefinitions coming into compiler from the environment.

like image 127
Grigory Rechistov Avatar answered Nov 13 '22 04:11

Grigory Rechistov