I'm trying to do a very simple thing with gcc assembler extension:
While compiling my solution:
v <- rep(v, 5e4)
microbenchmark(
rangeWhich = rangeWhich(v),
range_find = range_find(v),
richwhich = {w <- which(v)
w[c(1L, length(w))]},
match = c(match(T,v),length(v)-match(T,rev(v))+1)
)
Unit: microseconds
expr min lq mean median uq max neval
rangeWhich 1.284 3.2090 16.50914 20.211 26.7875 29.836 100
range_find 9.945 21.4945 32.02652 26.948 34.1660 144.042 100
richwhich 2941.756 3022.5975 3243.02081 3130.227 3247.6405 5403.911 100
match 45696.329 46771.8175 50662.45708 47359.526 48718.6055 131439.661 100
with the following switches:
#include <stdio.h>
#define inf_int volatile unsigned long long
int main(int argc, char *argv[]){
inf_int zero = 0;
inf_int one = 1;
inf_int infinity = ~0;
printf("value of zero, one, infinity = %llu, %llu, %llu\n", zero, one, infinity);
__asm__ volatile (
"addq $1, %0"
: "=r" (infinity)
);
__asm__ volatile (
"addq $1, %0"
: "=r" (zero)
);
__asm__ volatile (
"addq $1, %0"
: "=r" (one)
);
printf("value of zero, one, infinity = %llu, %llu, %llu\n", zero, one, infinity);
return 0;
}
I'd expect the following result from running gcc -std=c99 --pedantic -Wall -c main.c -o main.o
gcc -std=c99 --pedantic -Wall main.o -o main
:
value of zero, one, infinity = 0, 1, 18446744073709551615
value of zero, one, infinity = 1, 2, 0
but the result I get is this:
value of zero, one, infinity = 0, 1, 18446744073709551615
value of zero, one, infinity = 60, 61, 59
Interestingly, if I add a single char to the first main
I get the following, off-by-one, output:
value of zerao, one, infinity = 0, 1, 18446744073709551615
value of zero, one, infinity = 61, 62, 60
Even more interestingly, I can fix the behaviour by adding (optional) output registers. But this would be wasteful because of using 2*more registers, and doesn't help me understand why the previous piece exhibits undefined behaviour.
printf
edit
compiling with clang with the same options gives undefined behaviour as well:
value of zerao, one, infinity = 0, 1, 18446744073709551615
value of zero, one, infinity = 2147483590, 2147483591, 2147483592
edit 2
as suggested by Olaf, I've tried with #include <stdio.h>
#define inf_int volatile unsigned long long
int main(int argc, char *argv[]){
inf_int zero = 0;
inf_int one = 1;
inf_int infinity = ~0;
printf("value of zerao, one, infinity = %llu, %llu, %llu\n", zero, one, infinity);
__asm__ volatile (
"addq $1, %0 \n\t"
"movq %0, %1"
: "=r" (zero)
: "r" (zero)
);
__asm__ volatile (
"addq $1, %0 \n\t"
"movq %0, %1"
: "=r" (one)
: "r" (one)
);
__asm__ volatile (
"addq $1, %0 \n\t"
"movq %0, %1"
: "=r" (infinity)
: "r" (infinity)
);
printf("value of zero, one, infinity = %llu, %llu, %llu\n", zero, one, infinity);
return 0;
}
from uint64_t
. The result of running the program is still undefined.
stdint.h
答案 0 :(得分:7)
Your first code does not specify any inputs to the asm statements so the chosen register has an undefined value (which in this case was initially the return value of OrderInputFilter
). The second example repeats the error of using an undefined value and adds further undefined behaviour by overwriting the input register with the output.
You could use two registers like:
printf
You could use an input/output argument:
__asm__ (
"movq %1, %0 \n\t"
"addq $1, %0"
: "=r" (zero)
: "r" (zero)
);
Which can be in memory as well as a register:
__asm__ (
"addq $1, %0"
: "+r" (zero)
);
Or you could tie the input to the output:
__asm__ (
"addq $1, %0"
: "+rm" (zero)
);
And finally there is no need for any of the __asm__ (
"addq $1, %0"
: "=rm" (zero)
: "0" (zero)
);
modifiers.
答案 1 :(得分:1)
To wrap it all up:
inline assembly is not the part of C standard, it's an extension so portability (even across compilers on the same hardware) is not guaranteed.
one good way to write it is following:
select u.*
from users u
where not exists (select 1
from addresses a
where a.username = u.username and
a.city = 'Peoria'
);