You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio 2024年12月版内联汇编报错:invalid operand for inline asm constraint 'i'

问题:内联汇编bfi指令编译报错:invalid operand for inline asm constraint 'i'

数年前编写的内联汇编函数曾可正常运行,但在2024年12月最新版本的Android Studio中编译时出现如下报错:

error: invalid operand for inline asm constraint 'i'

涉及的bfi内联函数代码如下:

static __attribute__((always_inline)) uint32_t bfi(uint32_t dst, uint32_t src, int lsb, int n)
{
    __asm (
    "bfi    %w[dst], %w[src], %[lsb], %[n]"
    : [dst]"+r"(dst)
    : [src]"r"(src), [lsb]"i"(lsb), [n]"i"(n)
    :
    );
    return dst;
}

调用时传入的是编译时常量,示例代码:

static __attribute__((always_inline)) uint16_t procPixel_ia(uint32_t p)
{
    p = bfi(p, p, 3, 16);
    p = bfi(p, p, 2, 11);
    p >>= 8;
    return (uint16_t) p;
}

更换旧版NDK也无法解决,需指出问题所在或相关变更。


问题原因与解决办法

核心问题

GCC/Clang对i约束的检查变得更严格:虽然调用时传入的是常量,但函数参数lsb和n的类型为int,编译器无法在函数定义层面确认它们是编译时常量,因此拒绝将其作为i约束的操作数(i约束要求操作数必须是立即数/编译期可确定的常量)。

解决办法

  1. 标记参数为编译期常量
    如果使用C++,可以将函数声明为constexpr,让编译器明确参数是编译期常量:

    static constexpr __attribute__((always_inline)) uint32_t bfi(uint32_t dst, uint32_t src, int lsb, int n)
    {
        __asm (
        "bfi    %w[dst], %w[src], %[lsb], %[n]"
        : [dst]"+r"(dst)
        : [src]"r"(src), [lsb]"i"(lsb), [n]"i"(n)
        :
        );
        return dst;
    }
    

    如果用C语言,可改用宏定义替代函数,直接在调用处展开常量:

    #define bfi(dst, src, lsb, n) ({ \
        uint32_t _d = (dst); \
        __asm__ ("bfi %w0, %w1, %2, %3" : "+r"(_d) : "r"(src), "i"(lsb), "i"(n)); \
        _d; \
    })
    
  2. 使用ARM架构特定约束
    ARM的bfi指令对lsb(0-31)和n(1-32)有固定范围限制,可改用ARM专属约束:lsb用I(匹配0-31立即数),n用J(匹配1-32立即数),编译器会接受符合范围的常量参数,无需显式标记参数为常量:

    static __attribute__((always_inline)) uint32_t bfi(uint32_t dst, uint32_t src, int lsb, int n)
    {
        __asm (
        "bfi    %w[dst], %w[src], %[lsb], %[n]"
        : [dst]"+r"(dst)
        : [src]"r"(src), [lsb]"I"(lsb), [n]"J"(n)
        :
        );
        return dst;
    }
    

相关变更背景

近年GCC和Clang版本更新中,对内联汇编约束的类型检查更加严格,尤其是针对i约束,不再允许编译器无法在函数定义阶段确认的常量参数。即使调用时传入的是常量,只要函数参数本身未被标记为常量类型,编译器会默认参数可能是变量,从而触发报错。

内容的提问来源于stack exchange,提问作者Jake 'Alquimista' LEE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 04:25:12