在32位Visual Studio C++中可以使用以下代码.是否有使用内在函数的64位等效项,因为64位版本的Visual Studio C++不支持内联ASM?
FORCEINLINE bool bAtomicCAS8(volatile UINT8 *dest, UINT8 oldval, UINT8 newval)
{
bool result=false;
__asm
{
mov al,oldval
mov edx,dest
mov cl,newval
lock cmpxchg byte ptr [edx],cl
setz result
}
return(result);
}
Run Code Online (Sandbox Code Playgroud)
以下instrinsics在Visual Studio C++下编译
_InterlockedCompareExchange16
_InterlockedCompareExchange
_InterlockedCompareExchange64
_InterlockedCompareExchange128
Run Code Online (Sandbox Code Playgroud)
我正在寻找的是什么
_InterlockedCompareExchange8
Run Code Online (Sandbox Code Playgroud)
但这似乎并不存在.
如果我有以下C++代码来比较两个128位无符号整数,使用内联amd-64 asm:
struct uint128_t {
uint64_t lo, hi;
};
inline bool operator< (const uint128_t &a, const uint128_t &b)
{
uint64_t temp;
bool result;
__asm__(
"cmpq %3, %2;"
"sbbq %4, %1;"
"setc %0;"
: // outputs:
/*0*/"=r,1,2"(result),
/*1*/"=r,r,r"(temp)
: // inputs:
/*2*/"r,r,r"(a.lo),
/*3*/"emr,emr,emr"(b.lo),
/*4*/"emr,emr,emr"(b.hi),
"1"(a.hi));
return result;
}
Run Code Online (Sandbox Code Playgroud)
然后它将非常有效地内联,但有一个缺陷.返回值通过通用寄存器的"接口"完成,值为0或1.这会增加两个或三个不必要的额外指令,并减少比较操作,否则将完全优化.生成的代码看起来像这样:
mov r10, [r14]
mov r11, [r14+8]
cmp r10, [r15]
sbb r11, [r15+8]
setc al
movzx eax, al
test eax, eax
jnz is_lessthan
Run Code Online (Sandbox Code Playgroud)
如果我使用带有"bo"返回值的"sbb%0,%0"而不是带有"bool"返回值的"setc%0",那么还有两个额外的指令:
mov r10, [r14]
mov r11, [r14+8]
cmp r10, [r15] …Run Code Online (Sandbox Code Playgroud) 我想要做的是,使用assembly,创建一个类实例,调用其中一个方法,然后释放实例.
我知道我错过了一些非常重要的东西,可能很简单,但我不知道是什么.
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TSomeClass = class(TObject)
private
FCreateDateTime: string;
public
constructor Create;
procedure SayYeah;
end;
constructor TSomeClass.Create;
begin
FCreateDateTime := DateTimeToStr(Now);
end;
procedure TSomeClass.SayYeah;
begin
Writeln('yeah @ ' + FCreateDateTime);
end;
procedure Doit;
asm
CALL TSomeClass.Create; // <= Access Violation
CALL TSomeClass.SayYeah;
CALL TSomeClass.Free;
end;
begin
try
Doit;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
Run Code Online (Sandbox Code Playgroud)
仅供参考:我想了解如何在低水平实现这一目标,而不是另一种方式.
更新:
感谢Andreas Rejbrand,我找到了罪魁祸首:
Update2:
感谢Arnaud使用EBX而不是PUSH/POP EAX来发现缺陷
var
TSomeClass_TypeInfo: Pointer;
procedure Doit; …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用内联汇编将一堆结构成员(Particle是指向此类结构的指针)加载到某些寄存器中。这是我最初的解决方案:
asm("mov %1(%0), %%edx\n"
"fld %2(%0)\n"
"fld %3(%0)\n"
"fld %4(%0)\n"
"fld %5(%0)\n"
"movups %6(%0), %%xmm1\n"
"movups %7(%0), %%xmm2\n"
"movups %8(%0), %%xmm3\n"
"movups %9(%0), %%xmm4\n"
:
: "r" (Particle),
"n" (offsetof(ptcParticle, Active)),
"n" (offsetof(ptcParticle, Size)),
"n" (offsetof(ptcParticle, Rotation)),
"n" (offsetof(ptcParticle, Time)),
"n" (offsetof(ptcParticle, TimeScale)),
"n" (offsetof(ptcParticle, Colour)),
"n" (offsetof(ptcParticle, Location)),
"n" (offsetof(ptcParticle, Velocity)),
"n" (offsetof(ptcParticle, Accel))
: "%edx", "%st", "%st(1)", "%st(2)", "%st(3)", "%xmm1", "%xmm2",
"%xmm3", "%xmm4"
);
Run Code Online (Sandbox Code Playgroud)
但它不起作用,因为 GCC 将这些偏移量输出为立即数字文字,如下所示:
mov $0(%eax), %edx
fld $44(%eax)
fld $40(%eax)
fld $8(%eax) …Run Code Online (Sandbox Code Playgroud) 我正在使用一个专有的MCU,它有一个内置的金属库(掩模ROM).我正在使用的编译器是clang,它使用类似GCC的内联ASM.我遇到的问题是调用库,因为库没有一致的调用约定.虽然我找到了一个解决方案,但我发现在某些情况下,编译器会在调用之前立即对clobber进行优化,我认为我的工作方式有问题.这是我正在使用的代码:
int EchoByte()
{
register int asmHex __asm__ ("R1") = Hex;
asm volatile("//Assert Input to R1 for MASKROM_EchoByte"
:
:"r"(asmHex)
:"%R1");
((volatile void (*)(void))(MASKROM_EchoByte))(); //MASKROM_EchoByte is a 16-bit integer with the memory location of the function
}
Run Code Online (Sandbox Code Playgroud)
现在这有一个明显的问题,即当变量"asmHex"被声明为寄存器R1时,实际调用不使用它,因此编译器"不知道"在调用时保留R1.我使用以下代码来消除这种情况:
int EchoByte()
{
register int asmHex __asm__ ("R1") = Hex;
asm volatile("//Assert Input to R1 for MASKROM_EchoByte"
:
:"r"(asmHex)
:"%R1");
((volatile void (*)(void))(MASKROM_EchoByte))();
asm volatile("//Assert Input to R1 for MASKROM_EchoByte"
:
:"r"(asmHex)
:"%R1");
}
Run Code Online (Sandbox Code Playgroud)
这对我来说真的很难看,而且应该有更好的方法.另外我担心编译器可能会在两者之间做一些废话,因为调用本身并没有表明它需要asmHex变量.不幸的是,((volatile void(*)(int))(MASKROM_EchoByte))(asmHex)不起作用,因为它将遵循C-convention,它将参数放入R2 +(R1保留用于刮擦)
请注意,遗憾的是,更改Mask ROM库是不可能的,并且有太多常用的例程在C/C++中重新创建它们.
干杯,谢谢.
编辑:我应该注意,虽然我可以调用ASM块中的函数,但编译器对无调用函数进行了优化,并且通过调用汇编看起来没有调用.如果有某种方式指示内联ASM包含函数调用,我可以使用此路由,但否则返回地址可能会被破坏.在任何情况下我都无法找到办法.
以下 16 字节原子操作是否正确实现?还有更好的选择吗?
typedef struct {
uintptr_t low;
uintptr_t high;
} uint128_atomic;
uint128_atomic load_relaxed(uint128_atomic const *atomic)
{
uint128_atomic ret;
asm volatile("xor %%eax, %%eax\n"
"xor %%ebx, %%ebx\n"
"xor %%ecx, %%ecx\n"
"xor %%edx, %%edx\n"
"lock; cmpxchg16b %1"
: "=A"(ret)
: "m"(*atomic)
: "cc", "rbx", "rcx");
return ret;
}
bool cmpexch_weak_relaxed(
uint128_atomic *atomic,
uint128_atomic *expected,
uint128_atomic desired)
{
bool matched;
uint128_atomic e = *expected;
asm volatile("lock; cmpxchg16b %1\n"
"setz %0"
: "=q"(matched), "+m"(atomic->ui)
: "a"(e.low), "d"(e.high), "b"(desired.low), "c"(desired.high)
: "cc");
return matched;
} …Run Code Online (Sandbox Code Playgroud) 我试图理解atomic_forced_read定义的目的,它经常出现在malloc.c的GNU libc实现中。
我不太擅长内联汇编,但看起来这会返回完全相同的值,并且类型与输入值相同。我在这里缺少什么?
原子强制读取定义在atomic.h中
523 #ifndef atomic_forced_read
524 # define atomic_forced_read(x) \
525 ({ __typeof (x) __x; __asm ("" : "=r" (__x) : "0" (x)); __x; })
526 #endif
Run Code Online (Sandbox Code Playgroud)
链接到atomic.h
https://code.woboq.org/userspace/glibc/include/atomic.h.html
main为什么我不能在基本 asm 内联中使用局部变量?它只允许在扩展汇编中使用,但为什么会这样呢?
(我知道局部变量在返回地址之后位于堆栈上(因此一旦函数返回就不能使用),但这不应成为不使用它们的原因)
以及基本汇编的示例:
int a = 10; //global a
int b = 20; //global b
int result;
int main() {
asm ( "pusha\n\t"
"movl a, %eax\n\t"
"movl b, %ebx\n\t"
"imull %ebx, %eax\n\t"
"movl %eax, result\n\t"
"popa");
printf("the answer is %d\n", result);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
扩展的例子:
int main (void) {
int data1 = 10; //local var - could be used in extended
int data2 = 20;
int result;
asm ( "imull %%edx, %%ecx\n\t"
"movl %%ecx, %%eax"
: "=a"(result) …Run Code Online (Sandbox Code Playgroud) 如何asm()在cython中调用C语言的内联汇编函数?我尝试了一个简单的asm("mov $eax, 0x1") or __asm__(). 它 cythonizes 很好,直到asm-call,然后给我以下错误:
NameError:名称“asm”未定义
我将我的代码编译为python setup.py build_ext --inplace && python runids.py
我试图准确理解谷歌的DoNotOptimize()运作方式。
为了完整起见,以下是它的定义(对于 clang 和非常量数据):
template <class Tp>
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) {
asm volatile("" : "+r,m"(value) : : "memory");
}
Run Code Online (Sandbox Code Playgroud)
据我了解,我们可以在如下代码中使用它:
start_time = time();
bench_output = run_bench(bench_inputs);
result = time() - start_time;
Run Code Online (Sandbox Code Playgroud)
为了确保基准保持在关键部分:
start_time = time();
DoNotOptimize(bench_inputs);
bench_output = run_bench(bench_inputs);
DoNotOptimise(bench_output);
result = time() - start_time;
Run Code Online (Sandbox Code Playgroud)
具体来说,我不明白的是为什么这保证(是吗?)run_bench()不会移到上面start_time = time()。
(有人在这个评论中问过这个问题,但我不明白答案)。
据我了解,上面DoNotOptimze()做了几件事:
value进入堆栈,因为它是通过 C++ 引用传递的。您不能有指向寄存器的指针,因此它必须位于内存中。value现在位于堆栈上,因此随后破坏内存(如在 asm 约束中完成的那样)将迫使编译器假设value通过调用DoNotOptimize(value).+r,m …benchmarking inline-assembly compiler-optimization google-benchmark instruction-reordering