ARM 汇编cosf_neon返回值的问题

yiyidhuang 2018-03-20 03:44:45
我在移植math enon library的时候,调用cosf_neon 函数时,返回值与调用sinf_neon函数的返回值相同。二者参数传值是一样的。从理论上讲,二者角度函数返回值不会相同,这部分还没想通为什么会出现这种情况。如下附上cosf_neon函数的代码,还请大神指教为何会出现这种情况:

float cosf_neon_sfp(float x)
{
#ifdef __MATH_NEON
asm volatile ("vdup.f32 d0, r0 \n\t");
cosf_neon_hfp(x);
asm volatile ("vmov.f32 r0, s0 \n\t");
#else
return cosf_c(x);
#endif
}
...全文
936 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
printf("cos of math is %f\n", cosf_neon_hfp(0.366519));
  • 打赏
  • 举报
回复
你调试看一下参数x是不是在r0中
yiyidhuang 2018-03-22
  • 打赏
  • 举报
回复
这样算的结果还是不对。今天都在看cos的汇编,进行中,暂时没什么方向。
  • 打赏
  • 举报
回复
我认为: float cosf_neon_sfp(float x) { #ifdef __MATH_NEON return cosf_neon_hfp(x); #else return cosf_c(x); #endif } 就可以,不需要画蛇添足。
yiyidhuang 2018-03-21
  • 打赏
  • 举报
回复
改成如下,结果还是一样,我换了一个平台,依然是arm的,结果跟第一个平台一致。
float cosf_neon_hfp(float x)
{    
    asm volatile (        
            "vdup.f32       d0, r0                  \n\t"   
            "vld1.f32       d3, [%0]                \n\t"   //d3 = {invrange, range}
            "vdup.f32       d0, d0[0]               \n\t"   //d0 = {x, x}
            "vabs.f32       d1, d0                  \n\t"   //d1 = {ax, ax}
            
            "vmul.f32       d2, d1, d3[0]           \n\t"   //d2 = d1 * d3[0] 
            "vcvt.u32.f32   d2, d2                  \n\t"   //d2 = (int) d2
            "vmov.i32       d5, #1                  \n\t"   //d5 = 1    
            "vcvt.f32.u32   d4, d2                  \n\t"   //d4 = (float) d2   
            "vshr.u32       d7, d2, #1              \n\t"   //d7 = d2 >> 1
            "vmls.f32       d1, d4, d3[1]           \n\t"   //d1 = d1 - d4 * d3[1]
            
            "vand.i32       d5, d2, d5              \n\t"   //d5 = d2 & d5
            "vclt.f32       d18, d0, #0             \n\t"   //d18 = (d0 < 0.0)
            "vcvt.f32.u32   d6, d5                  \n\t"   //d6 = (float) d5
            "vmls.f32       d1, d6, d3[1]           \n\t"   //d1 = d1 - d6 * d3[1]
            "veor.i32       d5, d5, d7              \n\t"   //d5 = d5 ^ d7  
            "vmul.f32       d2, d1, d1              \n\t"   //d2 = d1*d1 = {x^2, x^2}   
            
            "vld1.32        {d16, d17}, [%1]        \n\t"   //q8 = {p7, p3, p5, p1}
            "veor.i32       d5, d5, d18             \n\t"   //d5 = d5 ^ d18 
            "vshl.i32       d5, d5, #31             \n\t"   //d5 = d5 << 31
            "veor.i32       d1, d1, d5              \n\t"   //d1 = d1 ^ d5
            
            "vmul.f32       d3, d2, d2              \n\t"   //d3 = d2*d2 = {x^4, x^4}       
            "vmul.f32       q0, q8, d1[0]           \n\t"   //q0 = q8 * d1[0] = {p7x, p3x, p5x, p1x}
            "vmla.f32       d1, d0, d2[0]           \n\t"   //d1 = d1 + d0*d2 = {p5x + p7x^3, p1x + p3x^3}      
            "vmla.f32       d1, d3, d1[0]           \n\t"   //d1 = d1 + d3*d0 = {...., p1x + p3x^3 + p5x^5 + p7x^7}     
        
            //"vmov.f32       s0, s3                  \n\t"   //s0 = s3
            "vmov.f32       r0, s3                  \n\t"
            : 
            : "r"(__cosf_rng), "r"(__cosf_lut) 
            : "q0", "q1", "q2", "q3", "q8", "q9"
            );
}

float cosf_neon_sfp(float x)
{
    float xx = x + M_PI_2;     
    cosf_neon_hfp(xx);
    //asm volatile("vmov.f32 r0, s0         \n\t");
}
  • 打赏
  • 举报
回复
这行: "vdup.f32 d0, r0 \n\t" 没加到最开始
yiyidhuang 2018-03-21
  • 打赏
  • 举报
回复
csdn不能编辑自己的帖子,上一贴有一个地方没写对, x = x + M_PI_2; cosf_neon_hfp(x); 改为, float xx = x + M_PI_2; cosf_neon_hfp(xx); 不过结果还是一样,得到的值不正确。
yiyidhuang 2018-03-21
  • 打赏
  • 举报
回复
还是有问题,奇怪。以下是完整的测试code。
#include <stdio.h>
#include <math.h>

#define M_PI		3.14159265358979323846	/* pi */
#define M_PI_2		1.57079632679489661923	/* pi/2 */

#ifdef GCC
#define ALIGN(A) __attribute__ ((aligned (A))
#else
#define ALIGN(A)
#endif

static const float __cosf_rng[2] = {
	2.0 / M_PI,
	M_PI / 2.0
} ALIGN(16);

static const float __cosf_lut[4] = {
	-0.00018365f,	//p7
	-0.16664831f,	//p3
	+0.00830636f,	//p5
	+0.99999661f,	//p1
} ALIGN(16);

float cosf_neon_hfp(float x)
{
    
    asm volatile (        
            "vld1.f32       d3, [%0]                \n\t"   //d3 = {invrange, range}
            "vdup.f32       d0, d0[0]               \n\t"   //d0 = {x, x}
            "vabs.f32       d1, d0                  \n\t"   //d1 = {ax, ax}
            
            "vmul.f32       d2, d1, d3[0]           \n\t"   //d2 = d1 * d3[0] 
            "vcvt.u32.f32   d2, d2                  \n\t"   //d2 = (int) d2
            "vmov.i32       d5, #1                  \n\t"   //d5 = 1    
            "vcvt.f32.u32   d4, d2                  \n\t"   //d4 = (float) d2   
            "vshr.u32       d7, d2, #1              \n\t"   //d7 = d2 >> 1
            "vmls.f32       d1, d4, d3[1]           \n\t"   //d1 = d1 - d4 * d3[1]
            
            "vand.i32       d5, d2, d5              \n\t"   //d5 = d2 & d5
            "vclt.f32       d18, d0, #0             \n\t"   //d18 = (d0 < 0.0)
            "vcvt.f32.u32   d6, d5                  \n\t"   //d6 = (float) d5
            "vmls.f32       d1, d6, d3[1]           \n\t"   //d1 = d1 - d6 * d3[1]
            "veor.i32       d5, d5, d7              \n\t"   //d5 = d5 ^ d7  
            "vmul.f32       d2, d1, d1              \n\t"   //d2 = d1*d1 = {x^2, x^2}   
            
            "vld1.32        {d16, d17}, [%1]        \n\t"   //q8 = {p7, p3, p5, p1}
            "veor.i32       d5, d5, d18             \n\t"   //d5 = d5 ^ d18 
            "vshl.i32       d5, d5, #31             \n\t"   //d5 = d5 << 31
            "veor.i32       d1, d1, d5              \n\t"   //d1 = d1 ^ d5
            
            "vmul.f32       d3, d2, d2              \n\t"   //d3 = d2*d2 = {x^4, x^4}       
            "vmul.f32       q0, q8, d1[0]           \n\t"   //q0 = q8 * d1[0] = {p7x, p3x, p5x, p1x}
            "vmla.f32       d1, d0, d2[0]           \n\t"   //d1 = d1 + d0*d2 = {p5x + p7x^3, p1x + p3x^3}      
            "vmla.f32       d1, d3, d1[0]           \n\t"   //d1 = d1 + d3*d0 = {...., p1x + p3x^3 + p5x^5 + p7x^7}     
        
            //"vmov.f32       s0, s3                  \n\t"   //s0 = s3
            "vmov.f32       r0, s3                  \n\t"
            : 
            : "r"(__cosf_rng), "r"(__cosf_lut) 
            : "q0", "q1", "q2", "q3", "q8", "q9"
            );
}

float cosf_neon_sfp(float x)
{
    asm volatile("vdup.f32 d0, r0         \n\t");
    x = x + M_PI_2;
    cosf_neon_hfp(x);
    //asm volatile("vmov.f32 r0, s0         \n\t");
}

int main(char **argv, int argc)
{
    float cosf_val = 0;

    cosf_val = cosf_neon_sfp(0.366519);

    printf("------------------------------------------------------\n");
    printf("cosf_neon value is %f(the correct is 0.933580)\n", cosf_val);
    printf("cos of math is %f\n", cos(0.366519));
    printf("--------------------------END-------------------------\n");

    return 0;
}
  • 打赏
  • 举报
回复
这行: "vmov.f32 s0, s3 \n\t" 直接换成: "vmov.f32 r0, s3 \n\t" 后面的: asm volatile ("vmov.f32 r0, s0 \n\t");注释掉
yiyidhuang 2018-03-21
  • 打赏
  • 举报
回复
float xx = x + M_PI_2; 这一行刚才忘记去掉,去掉之后问题依然。
yiyidhuang 2018-03-21
  • 打赏
  • 举报
回复
回来了,继续。 按照如下的想法,看上去问题还是依旧,即:得到的cos还是等于sin。对ARM汇编不熟悉,刚才也找了一下ARM的汇编的资料,还没看个所以然出来。
float cosf_neon_sfp(float x)
{
#ifdef __MATH_NEON    
    float xx = x + M_PI_2;

	asm volatile ("vdup.f32 d0, r0 		\n\t");      
    asm volatile (        
            "vld1.f32       d3, [%0]                \n\t"   //d3 = {invrange, range}
            "vdup.f32       d0, d0[0]               \n\t"   //d0 = {x, x}
            "vabs.f32       d1, d0                  \n\t"   //d1 = {ax, ax}
            
            "vmul.f32       d2, d1, d3[0]           \n\t"   //d2 = d1 * d3[0] 
            "vcvt.u32.f32   d2, d2                  \n\t"   //d2 = (int) d2
            "vmov.i32       d5, #1                  \n\t"   //d5 = 1    
            "vcvt.f32.u32   d4, d2                  \n\t"   //d4 = (float) d2   
            "vshr.u32       d7, d2, #1              \n\t"   //d7 = d2 >> 1
            "vmls.f32       d1, d4, d3[1]           \n\t"   //d1 = d1 - d4 * d3[1]
            
            "vand.i32       d5, d2, d5              \n\t"   //d5 = d2 & d5
            "vclt.f32       d18, d0, #0             \n\t"   //d18 = (d0 < 0.0)
            "vcvt.f32.u32   d6, d5                  \n\t"   //d6 = (float) d5
            "vmls.f32       d1, d6, d3[1]           \n\t"   //d1 = d1 - d6 * d3[1]
            "veor.i32       d5, d5, d7              \n\t"   //d5 = d5 ^ d7  
            "vmul.f32       d2, d1, d1              \n\t"   //d2 = d1*d1 = {x^2, x^2}   
            
            "vld1.32        {d16, d17}, [%1]        \n\t"   //q8 = {p7, p3, p5, p1}
            "veor.i32       d5, d5, d18             \n\t"   //d5 = d5 ^ d18 
            "vshl.i32       d5, d5, #31             \n\t"   //d5 = d5 << 31
            "veor.i32       d1, d1, d5              \n\t"   //d1 = d1 ^ d5
            
            "vmul.f32       d3, d2, d2              \n\t"   //d3 = d2*d2 = {x^4, x^4}       
            "vmul.f32       q0, q8, d1[0]           \n\t"   //q0 = q8 * d1[0] = {p7x, p3x, p5x, p1x}
            "vmla.f32       d1, d0, d2[0]           \n\t"   //d1 = d1 + d0*d2 = {p5x + p7x^3, p1x + p3x^3}      
            "vmla.f32       d1, d3, d1[0]           \n\t"   //d1 = d1 + d3*d0 = {...., p1x + p3x^3 + p5x^5 + p7x^7}     
        
            "vmov.f32       s0, s3                  \n\t"   //s0 = s3
            : 
            : "r"(__cosf_rng), "r"(__cosf_lut) 
            : "q0", "q1", "q2", "q3", "q8", "q9"
            );
	asm volatile ("vmov.f32 r0, s0 		\n\t");
#else
	return cosf_c(x);
#endif
}
  • 打赏
  • 举报
回复
也许可以 "vdup.f32 d0, r0 \n\t" 复制cosf_neon_hfp的汇编代码到这里 "vmov.f32 r0, s0 \n\t"
yiyidhuang 2018-03-21
  • 打赏
  • 举报
回复
我有直接如下调用:cosf_neon_sfp(0.366519+M_PI_2) 或者 sinf_neon_sfp(0.366519+M_PI_2), 其中M_PI_2 = PI/2,得到的值就是正确的,即:0.933580。 从表面上看的现象是,如下的xx=x+M_PI_2没有执行到。
float cosf_neon_hfp(float x)
{
#ifdef __MATH_NEON
	float xx = x + M_PI_2;
	return sinf_neon_hfp(xx);
#endif
}
yiyidhuang 2018-03-21
  • 打赏
  • 举报
回复
bl cosf_neon_hfp -> 执行这个时,程序没有继续运行,一直卡住了。
  • 打赏
  • 举报
回复
那你直接用汇编调用呢: float cosf_neon_sfp(float x) { #ifdef __MATH_NEON asm volatile ( "vdup.f32 d0, r0 \n\t" "bl cosf_neon_hfp \n\t" "vmov.f32 r0, s0 \n\t" ); #else return cosf_c(x); #endif }
yiyidhuang 2018-03-21
  • 打赏
  • 举报
回复
再补充一下 sinf_neon_sfp:
float sinf_neon_sfp(float x)
{
#ifdef __MATH_NEON
	asm volatile ("vdup.f32 d0, r0 		\n\t");
	sinf_neon_hfp(x);
	asm volatile ("vmov.f32 r0, s0 		\n\t");
#else
	return sinf_c(x);
#endif
  
}
yiyidhuang 2018-03-21
  • 打赏
  • 举报
回复
如果直接调用cosf_neon_hfp(x),假设参数依旧是:0.366519,得到的值1.937315,这个值与在去掉cosf_neon_sfp中的那两条汇编得到的结果一致。 另外,我把其中所调用的sinf_neon_hfp函数也贴出来,都是直接用arm asm 写的。
float sinf_neon_hfp(float x)
{
#ifdef __MATH_NEON
	asm volatile (
	
	"vld1.32 		        d3, [%0]                           \n\t"  //d3 = {invrange, range}
	"vdup.f32 		d0, d0[0]				\n\t"	//d0 = {x, x}
	"vabs.f32 		d1, d0			        \n\t"	//d1 = {ax, ax}
	
	"vmul.f32 		d2, d1, d3[0]			\n\t"	//d2 = d1 * d3[0] 
	"vcvt.u32.f32 	        d2, d2				\n\t"	//d2 = (int) d2
	"vmov.i32	 	        d5, #1				\n\t"	//d5 = 1	
	"vcvt.f32.u32 	        d4, d2				\n\t"	//d4 = (float) d2	
	"vshr.u32 		d7, d2, #1			\n\t"	//d7 = d2 >> 1
	"vmls.f32 		d1, d4, d3[1]			\n\t"	//d1 = d1 - d4 * d3[1]
	
	"vand.i32 		d5, d2, d5			\n\t"	//d5 = d2 & d5
	"vclt.f32 		        d18, d0, #0			\n\t"	//d18 = (d0 < 0.0)
	"vcvt.f32.u32 	        d6, d5				\n\t"	//d6 = (float) d5
	"vmls.f32 		d1, d6, d3[1]			\n\t"	//d1 = d1 - d6 * d3[1]
	"veor.i32 		        d5, d5, d7			\n\t"	//d5 = d5 ^ d7	
	"vmul.f32 		d2, d1, d1			\n\t"	//d2 = d1*d1 = {x^2, x^2}	
	
	"vld1.32 		        {d16, d17}, [%1]		\n\t"	//q8 = {p7, p3, p5, p1}
	"veor.i32 		        d5, d5, d18			\n\t"	//d5 = d5 ^ d18	
	"vshl.i32 		        d5, d5, #31			\n\t"	//d5 = d5 << 31
	"veor.i32 		        d1, d1, d5			\n\t"	//d1 = d1 ^ d5
	
	"vmul.f32 		d3, d2, d2			\n\t"	//d3 = d2*d2 = {x^4, x^4}		
	"vmul.f32 		q0, q8, d1[0]			\n\t"	//q0 = q8 * d1[0] = {p7x, p3x, p5x, p1x}
	"vmla.f32 		d1, d0, d2[0]			\n\t"	//d1 = d1 + d0*d2 = {p5x + p7x^3, p1x + p3x^3}		
	"vmla.f32 		d1, d3, d1[0]			\n\t"	//d1 = d1 + d3*d0 = {...., p1x + p3x^3 + p5x^5 + p7x^7}		

	"vmov.f32 		s0, s3				\n\t"	//s0 = s3
	: 
	: "r"(__sinf_rng), "r"(__sinf_lut) 
        : "q0", "q1", "q2", "q3", "q8", "q9"
	);
#endif
}
  • 打赏
  • 举报
回复
那你单独调用cosf_neon_hfp(x);结果正确吗
yiyidhuang 2018-03-21
  • 打赏
  • 举报
回复
非常感谢回复。 首先这是从开源库摘录出来的代码片段。楼上大神所说的改法,我也尝试,有变化,但计算得到的值不正确。 假设参数值为:0.366519,如此,cos(0.366519)=0.933580,sin(0.366519)=0.358368。但是用1楼贴出来的代码,计算得到的值sinf_neon与cosf_neon 都是0.358367。看上去cosf_neon 并没有加PI/2,这一点我一直没搞懂。

21,459

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧