首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >我怎么才能让GCC把这个位变换指令优化成一个动作呢?

我怎么才能让GCC把这个位变换指令优化成一个动作呢?
EN

Stack Overflow用户
提问于 2020-03-07 17:55:51
回答 2查看 193关注 0票数 6

我试图使用以下代码来模拟软件中的16位半浮点:

代码语言:javascript
运行
复制
typedef struct half
{
    unsigned short mantissa:10;
    unsigned short exponent:5;
    unsigned short sign:1;
} half;

unsigned short from_half(half h)
{
    return h.mantissa | h.exponent << 10 | h.sign << 15;
}

half to_half(unsigned short s)
{
    half result = { s, s >> 10, s >> 15 };
    return result;
}

我将其设置为便于将其优化为移动指令,但瞧,在from_half中,GCC无论如何都会做位转换(甚至在-O3):

代码语言:javascript
运行
复制
from_half:
        mov     edx, edi
        mov     eax, edi
        and     di, 1023
        shr     dx, 15
        and     eax, 31744
        movzx   edx, dl
        sal     edx, 15
        or      eax, edx
        or      eax, edi
        ret

to_half被很好地优化时:

代码语言:javascript
运行
复制
to_half:
        mov     eax, edi
        ret

哥德波特

我尝试过不同的优化级别(-O1-O2-Os),但没有人将其优化到我所希望的程度。

即使在-O1,Clang也是这样做的

代码语言:javascript
运行
复制
from_half:                              # @from_half
        mov     eax, edi
        ret
to_half:                                # @to_half
        mov     eax, edi
        ret

哥德波特

我怎么才能让GCC把这个优化成一个动作呢?为什么还没有这样优化呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-03-07 20:03:44

除了布布的回答之外,您还可以尝试以下方法来回答您的问题

我怎么才能让GCC把这个优化成一个动作呢?

只将每个移位的位场表达式转换为unsigned short

代码语言:javascript
运行
复制
unsigned short from_half(half h)
{
    return (unsigned short)h.mantissa | (unsigned short)(h.exponent << 10) | (unsigned short)(h.sign << 15);
}

https://godbolt.org/z/CfZSgC

其结果是:

代码语言:javascript
运行
复制
from_half:
        mov     eax, edi
        ret

为什么还没有这样优化呢?

我不确定我对这个问题有一个确切的答案。显然,将位字段提升到int的中间过程混淆了优化器.但这只是猜测。

票数 6
EN

Stack Overflow用户

发布于 2020-03-07 18:20:06

我已经有一段时间没有用C编写代码了,但似乎union的使用应该是有效的:

代码语言:javascript
运行
复制
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>

static bool useUnion;

__attribute__ ((__constructor__)) // supported by gcc compiler
static void initUseUnion()
{
    union {
       uint16_t i;
       char c[2];
    } n = { 0x0001 };
    useUnion = n.c[0]; // little endian
}

typedef struct half
{
    unsigned short mantissa:10;
    unsigned short exponent:5;
    unsigned short sign:1;
} half;

typedef union half_short
{
    half h;
    uint16_t s;
} half_short;

unsigned short from_half(half h)
{
    if (useUnion) {
        half_short hs;
        hs.h = h;
        return hs.s;
    }
    else {
        return h.mantissa | h.exponent << 10 | h.sign << 15;
    }
}

half to_half(unsigned short s)
{
    if (useUnion) {
        half_short hs;
        hs.s = s;
        return hs.h;
    }
    else {
        half result = { s, s >> 10, s >> 15 };
        return result;
    }
}

int main(int argc, char* argv[])
{
    printf("%d\n", useUnion);
    return 0;
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60580591

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档