X86 xchgl和cmpxchgl指令替换案例分享

举报
onita@汪汪队 发表于 2020/02/10 11:34:49 2020/02/10
【摘要】 1 问题背景客户迁移过程中,编译自研代码时,有如果两个编译报错:Ø 不识别xchgl汇编指令{standard input}: Assembler messages:{standard input}:1222: Error: unknown mnemonic `xchgl' -- `xchgl x1,[x19,112]'{standard input}:1225: Error: unkno...

1 问题背景

客户迁移过程中,编译自研代码时,有如果两个编译报错:

Ø  不识别xchgl汇编指令

{standard input}: Assembler messages:

{standard input}:1222: Error: unknown mnemonic `xchgl' -- `xchgl x1,[x19,112]'

{standard input}:1225: Error: unknown mnemonic `xchgl' -- `xchgl x0,[x19,88]'

 

Ø  不识别cmpxchgl汇编指令

{standard input}: Assembler messages:

{standard input}:1222: Error: unknown mnemonic `cmpxchgl'

 

2 原因分析

 

spacer.gifxchgl cmpxchgl都是X86上的指令集,ARM64上不识别,需要进行替换。xchgl指令的作用是交换 (寄存器/内存变量)和 (寄存器) 的值。如果交换的两个变量中有内存变量,会对内存变量增加原子锁操作。详细见以下释义:

 

cmpxchgl指令的作用是比较并交换两数。详细见官网释义:

spacer.gif

 

 

 

3 解决方案

3.1 内存屏障选择

xchgl cmpxchgl这两个指令在ARM64上可以用GCC的原子操作接口进行替换。在使用GCC内置的原子操作函数__atomic_xxxx_n时,输出参数包含memory order(即通常我们所说的内存屏障)。GCC4.7前,__sync 同步原语中默认的内存模型为full barrier模型,__sync原语前后的读写操作均不可做指令重排。为提高流水线执行效率,GCC 4.7合入C++11的内存模型,通过__atomic 同步原语,由使用者控制需要的屏障级别。对多线程访问临界区的逻辑不清晰时,建议仍使用__ATOMIC_SEQ_CST屏障,避免由屏障使用不当带来一致性问题。下面是几种可选的屏障类型及其简要介绍:

 

Memory order

Instroduction

__ATOMIC_RELAXED

__ATOMIC_RELAXED

__ATOMIC_CONSUME

load操作,当前线程依赖该原子变量的访存操作不能reorder到该指令之前,对其他线程store操作(release)可见

__ATOMIC_ACQUIRE

load操作,当前线程所有访存操作不能reorder到该指令之前,对其他线程store操作(release)可见

__ATOMIC_RELEASE

store操作,当前线程所有访存操作不能reorder到该指令之后,对其他线程load操作(consume)可见

__ATOMIC_ACQ_REL

load/store操作,memory_order_acquire + memory_order_release

__ATOMIC_SEQ_CST

memory_order_acq_rel + 顺序一致性(sequential consisten)

 

3.2 xchgl替换方法

xchgl在交换两值时,其中有一个是内存变量,替换时要对内存变量加原子锁。arm上没有可以完全替换的汇编指令,可以使用GCC的原子操作接口__atomic_exchange_n进行替换。

X86实现样例:

inline int nBasicAtomicInt::fetchAndStoreOrdered(int newValue)

{

    /* 原子操作, _value的值和newValue

     * 交换, 且返回_value原来的值

     */

    asm volatile("xchgl %0,%1"

                 : "=r" (newValue), "+m" (m_value)

                 : "0" (newValue)

                 : "memory");

    return newValue;

}

 

TaiShan上可替换成:

inline int nBasicAtomicInt::fetchAndStoreOrdered(int newValue)

{

    /* 原子操作, _value的值和newValue

     * 交换, 且返回_value原来的值

     */

    return __atomic_exchange_n(&_q_value, newValue, __ATOMIC_SEQ_CST);

}

 

 

 

3.3 cmpxchgl替换方法

cmpxchgl可用GCC的原子操作接口__atomic_compare_exchange_n进行替换。与xchgl类似,GCC原子操作接口的参数, 使用者可以根据自身代码逻辑选择合适的参数。

X86实现样例:

inline bool nBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue)

{

    unsigned char ret;

    /* 原子操作, 原来m_value的值如果等于expectedValue,则把newValue

     * 载入m_value, 且返回ret=true; 如果不等于,m_value的值不变,且返回ret=false

     */

    asm volatile("lock\n"

                 "cmpxchgl %3,%2\n"

                 "sete %1\n"

                 : "=a" (newValue), "=qm" (ret), "+m" (m_value)

                 : "r" (newValue), "0" (expectedValue)

                 : "memory");

    return ret != 0;

}

TaiShan上可替换成:

inline bool nBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue)

{

    unsigned char ret;

    /* 原子操作, 原来m_value的值如果等于expectedValue,则把newValue载入_value, 且返回ret=true; 如果不等于,m_value的值不变,且返回ret=false */

    return __atomic_compare_exchange_n(&m_value, &expectedValue, newValue, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);

}

 

 

 

4 总结

客户自研代码迁移时,如果遇到汇编指令报错(编译日志中有“Assembler messages”关键字),而ARM64上没有功能完全匹配的汇编指令时,除了可以用汇编指令的组合替换之外,还可以尝试使用GCC的内置函数替换。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。