Why can't find the insl instruction in x86 document - gcc

Could any one tell me the following's means. I can't understand the insl instruction
static inline void
insl(uint32_t port, void *addr, int cnt) {
asm volatile (
"cld;"
"repne; insl;"
: "=D" (addr), "=c" (cnt)
: "d" (port), "0" (addr), "1" (cnt)
: "memory", "cc");
}

That function will read cnt dwords from the input port specified by port into the supplied output array addr.
insl is equivalent to insd: http://x86.renejeschke.de/html/file_module_x86_id_141.html
GAS syntax uses the l suffix to denote instructions operating on dword (32-bit sized) data.

Related

gcc inline assembly unreferenced input operand

I was going through the gcc inline assembly documentation when i saw this example:
int test(char p[]) {
int count;
asm("repne scasb"
: "=c" (count), "+D" (p)
: "m" (*(const char (*)[]) p), "0" (-1), "a" (0));
}
I couldn't figure out the purpose of "m" (*(const char (*)[]) p)
Looking at the generated code with and without that shows that the only difference is the initialization of a register with the address of p which is not used by repne scasb. So it appears to be redundant. Is that statement useful in any other way?

Prevent risc-v inline assembly instruction being optimized out in gcc -O3 [duplicate]

I looked into some C code from
http://www.mcs.anl.gov/~kazutomo/rdtsc.html
They use stuff like __inline__, __asm__ etc like the following:
code1:
static __inline__ tick gettick (void) {
unsigned a, d;
__asm__ __volatile__("rdtsc": "=a" (a), "=d" (d) );
return (((tick)a) | (((tick)d) << 32));
}
code2:
volatile int __attribute__((noinline)) foo2 (int a0, int a1) {
__asm__ __volatile__ ("");
}
I was wondering what does the code1 and code2 do?
(Editor's note: for this specific RDTSC use case, intrinsics are preferred: How to get the CPU cycle count in x86_64 from C++? See also https://gcc.gnu.org/wiki/DontUseInlineAsm)
The __volatile__ modifier on an __asm__ block forces the compiler's optimizer to execute the code as-is. Without it, the optimizer may think it can be either removed outright, or lifted out of a loop and cached.
This is useful for the rdtsc instruction like so:
__asm__ __volatile__("rdtsc": "=a" (a), "=d" (d) )
This takes no dependencies, so the compiler might assume the value can be cached. Volatile is used to force it to read a fresh timestamp.
When used alone, like this:
__asm__ __volatile__ ("")
It will not actually execute anything. You can extend this, though, to get a compile-time memory barrier that won't allow reordering any memory access instructions:
__asm__ __volatile__ ("":::"memory")
The rdtsc instruction is a good example for volatile. rdtsc is usually used when you need to time how long some instructions take to execute. Imagine some code like this, where you want to time r1 and r2's execution:
__asm__ ("rdtsc": "=a" (a0), "=d" (d0) )
r1 = x1 + y1;
__asm__ ("rdtsc": "=a" (a1), "=d" (d1) )
r2 = x2 + y2;
__asm__ ("rdtsc": "=a" (a2), "=d" (d2) )
Here the compiler is actually allowed to cache the timestamp, and valid output might show that each line took exactly 0 clocks to execute. Obviously this isn't what you want, so you introduce __volatile__ to prevent caching:
__asm__ __volatile__("rdtsc": "=a" (a0), "=d" (d0))
r1 = x1 + y1;
__asm__ __volatile__("rdtsc": "=a" (a1), "=d" (d1))
r2 = x2 + y2;
__asm__ __volatile__("rdtsc": "=a" (a2), "=d" (d2))
Now you'll get a new timestamp each time, but it still has a problem that both the compiler and the CPU are allowed to reorder all of these statements. It could end up executing the asm blocks after r1 and r2 have already been calculated. To work around this, you'd add some barriers that force serialization:
__asm__ __volatile__("mfence;rdtsc": "=a" (a0), "=d" (d0) :: "memory")
r1 = x1 + y1;
__asm__ __volatile__("mfence;rdtsc": "=a" (a1), "=d" (d1) :: "memory")
r2 = x2 + y2;
__asm__ __volatile__("mfence;rdtsc": "=a" (a2), "=d" (d2) :: "memory")
Note the mfence instruction here, which enforces a CPU-side barrier, and the "memory" specifier in the volatile block which enforces a compile-time barrier. On modern CPUs, you can replace mfence:rdtsc with rdtscp for something more efficient.
asm is for including native Assembly code into the C source code. E.g.
int a = 2;
asm("mov a, 3");
printf("%i", a); // will print 3
Compilers have different variants of it. __asm__ should be synonymous, maybe with some compiler-specific differences.
volatile means the variable can be modified from outside (aka not by the C program). For instance when programming a microcontroller where the memory address 0x0000x1234 is mapped to some device-specific interface (i.e. when coding for the GameBoy, buttons/screen/etc are accessed this way.)
volatile std::uint8_t* const button1 = 0x00001111;
This disabled compiler optimizations that rely on *button1 not changing unless being changed by the code.
It is also used in multi-threaded programming (not needed anymore today?) where a variable might be modified by another thread.
inline is a hint to the compiler to "inline" calls to a function.
inline int f(int a) {
return a + 1
}
int a;
int b = f(a);
This should not be compiled into a function call to f but into int b = a + 1. As if f where a macro. Compilers mostly do this optimization automatically depending on function usage/content. __inline__ in this example might have a more specific meaning.
Similarily __attribute__((noinline)) (GCC-specific syntax) prevents a function from being inlined.
The __asm__ attribute specifies the name to be used in assembler code for the function or variable.
The __volatile__ qualifier, generally used in Real-Time-Computing of embedded systems, addresses a problem with compiler tests of the status register for the ERROR or READY bit causing problems during optimization. __volatile__ was introduced as a way of telling the compiler that the object is subject to rapid change and to force every reference of the object to be a genuine reference.

gcc assembly extended register

What parameter/constraint do I have to use in order to tell the compiler to use an extended register pair as the output/input?
static inline void mac_dsp(int64_t *c, uint32_t a, uint32_t b){
//This does not compile - "madd.u [%a15]0,[%a15]0,%d15,%d2: Too many operands"
__asm__ ("madd.u %0,%0,%1,%2" : "+m" (*c) : "d" (a), "d" (b));
//This does compile but I don't explicitly want to use e2 only but let the compiler
//chose which one...
__asm__ ("madd.u %%e2,%%e2,%1,%2" : "+m" (*c) : "d" (a), "d" (b));
}
Can anyone help me here? Thank you!

Re-implement the AVX2 intrincs using asm code

Greeting everyone.
Due to some special reason, we have to re-implement the AVX2 intrics like the following way:
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
_xmm256_and_si256(__m256i s1, __m256i s2){
__m256i result;
__asm__ ("vpand %2, %1, %0": "=r"(result): "rm" "s1", "rm" "s2" ) ;
// sorry, this statement does not work
return result;
}
Corresponding function is _mm256_and_si256(__m256i s1, __m256i s2), which is an AVX2 intrincs.
After some search through google, I found some simililar such as connect some base type like int, float and long to input registers.
However, I still didn't find the way to connect the input parameters s1 and s2 to the input registers ymm1 and ymm2 which are used for the asm vpand code.
So anyone here is willing to help me to make the above example work?
Thank you so much in advance!!
The r constraint is for general purpose registers, and your asm block has wrong syntax anyway. The appropriate constraint for avx is x, and also mind that only one operand can be in memory (although that could be either one, which this template doesn't handle). Furthermore the nodebug attribute doesn't seem to exist.
As such, something like this will work better:
__attribute__((always_inline)) inline __m256i
_xmm256_and_si256(__m256i s1, __m256i s2)
{
__m256i result;
__asm__ ("vpand %2, %1, %0" : "=x"(result) : "x"(s1), "xm"(s2) );
return result;
}

Inline assembly in C

Pretty self explanatory code. Why doesn't it work!
#include <stdio.h>
int main() {
__asm__("number dw 0"); // declare number?
printf("%d",number);
__asm__("mov %eax,number"
"inc %eax"
"mov number,%eax");
printf("%d",number);
return 0;
}
cc ex1.c -o ex1
ex1.c: In function ‘main’:
ex1.c:22:17: error: ‘number’ undeclared (first use in this function)
ex1.c:22:17: note: each undeclared identifier is reported only once for each function it appears in
make: *** [ex1] Error 1
Thanks.
I have a lot of knowledge gaps to fill... the gcc manual was confusing me with regards to inline assembly as was google results for tutorials...
working on an intel i7 processor
Use this syntax, you can access variables declared in C from the inline assembly
#include <stdio.h>
int main() {
int number = 0;
printf("%d\n",number);
asm(
"mov %[number],%%eax\n"
"inc %%eax\n"
"mov %%eax,%[number]\n"
: [number] "=m" (number) : "m" (number) : "eax", "cc" );
printf("%d\n",number);
return 0;
}
You can let the compiler load number into the eax register for you by specifying the "a" constraint on the input
#include <stdio.h>
int main() {
int number = 0;
printf("%d\n",number);
asm(
"inc %%eax\n"
"mov %%eax,%[number]\n"
: [number] "=m" (number) : "a" (number) : "cc" );
printf("%d\n",number);
return 0;
}
And since x86 inc instruction can operate on memory directly you could reduce it to this
#include <stdio.h>
int main() {
int number = 0;
printf("%d\n",number);
asm(
"incl %[number]\n" /* incl -> "long" (32-bits) */
: [number] "=m" (number) : "m" (number) : "cc" );
printf("%d\n",number);
return 0;
}
For more information see gcc documentation:
6.41 Assembler Instructions with C Expression Operands

Resources