ref:http://kmittal82.wordpress.com/2012/02/17/armthumbthumb-2/

A few months ago I gave a presentation titled “Introduction to the ARM architecture”. One of the most well received sections of that was a bit where I explained the difference between the various types of instruction sets that can be run on the ARM architecture, i.e. ARM (32 bit), Thumb (16 bit) and Thumb-2 (16/32 bit). I will try and explain the difference between the three in this post.

Before we begin, let’s look at a very simple test case which we will build for all three architectures (Thanks for my friend and colleague Stephen Wade for coming up with this test case)

typedef unsigned char uint8;
typedef unsigned short uint16;
/* r0 = x , r1 = a, r2 = b, r3 = c */
uint8 foo(uint8 x, uint8 a, uint16 b, uint16 c)
{
    if (a==2)
    {
        x += (b >> 8);
    }
    else
    {
        x += (c >> 8);
    }
    return x;
}

According to the ARM procedure call standard, the arguments to the function would be passed in registers r0-r3, with the return value passed in r0.

ARM

Each instruction in the ARM instruction set is 32 bits in size. At the same time, the ARM instructions have access to other useful features such as conditional instructions and in-line barrel shifter. Without access to conditional instructions, code needs to be handled by branching, which is more expensive. The in-line barrel shifter gives the instruction the ability to shift bits within the registers as part of the instruction itself, which eliminates the need for having separate instructions for shifting. Using RVCT, I compiled this for ARM state, and dumped the code with fromelf

1
2
3
4
5
0x00000000:    e3510002    ..Q.    CMP      r1,#2
0x00000004:    10800423    #...    ADDNE    r0,r0,r3,LSR #8
0x00000008:    00800422    "...    ADDEQ    r0,r0,r2,LSR #8
0x0000000c:    e20000ff    ....    AND      r0,r0,#0xff
0x00000010:    e12fff1e    ../.    BX       lr

First thing we notice here is that each instruction is 32 bits (or 4 bytes) wide based on the instruction encoding (second column from the left). Given that we have 5 such instructions, we have a code size of 20 bytes

Now, in the first line, r1 is compared to the integer value 2, which is the first thing that our function foo() does. Simple so far. The more interesting thing is the second and third instruction, which demonstrates conditional execution of instructions as well as the in-line barrel shifter.

The second instruction, in effect says “If the result of the previous comparison was a NE (not equal), then shift r3 by 8 bits to the right, add it to r0 and store the result back in r0″. This corresponds to the “else” part of the loop in our function. Not only did we manage to avoid a branch, we were also able to shift the bits and do the addition, all in one simple instruction. The third instruction is exactly the same, but deals with the “if” part of the loop.

The fourth instruction is again interesting. Since the return value of the function is of type unsigned char, only the bottom 8 bits are significant. So, we do an AND of the return value (stored in r0) with #0xff, which effectively zeros the top 24bits (by ANDing with 0), and now our return value is ready in r0.

The fifth and final instruction simply returns back to the caller.

Thumb

In Thumb state, each instruction is 16 bits in size, and very few instructions are conditional. Also, there is no access to the in-line barrel shifter, so separate instructions are needed for shifting bits. What this means in practice is that Thumb code would generally be slower to execute than ARM code (since more Thumb instructions might be needed to do the job than the number of ARM instructions), but it can help save code size. Building our example with “RVCT” and dumping using “fromelf”, we see the following code sequence#

1
2
3
4
5
6
7
8
9
10
_Z3foohhtt
    0x00000000:    2902        .)      CMP      r1,#2
    0x00000002:    d101        ..      BNE      {pc}+0x6 ; 0x8
    0x00000004:    0a11        ..      LSRS     r1,r2,#8
    0x00000006:    e000        ..      B        {pc}+0x4 ; 0xa
    0x00000008:    0a19        ..      LSRS     r1,r3,#8
    0x0000000a:    1808        ..      ADDS     r0,r1,r0
    0x0000000c:    0600        ..      LSLS     r0,r0,#24
    0x0000000e:    0e00        ..      LSRS     r0,r0,#24
    0x00000010:    4770        pG      BX       lr

Immediately, the first thing we notice is that all the instructions are 16 bits in size, as indicated by the instruction encodings (second column from the left). This here gives us a total code size of 9 x 2 = 18 bytes

When we start analysing the generated code, the drawback of Thumb state here is immediately apparent. Thumb only has access to conditional branches, so the generated code is done through branches. The second instruction branches to address 0×8 if the comparison in the first step was not equal (i.e. we enter the “else” part of our C++ code). At address 0×8, we notice the second drawback of the Thumb state, the lack of an in-line barrel shifter. A separate LSRS instruction shifts the bits in r3 by 8, and stores it in r1. Following that, this value is r1 is added to r0. Our return value is nearly ready, but we need to zero the top 24bits. The Thumb instruction set does not have access to AND, so it performs two shifts on r0, first shifting r0 by 24bits to the left (zeroing the bottom 8 bits), then shifting this further by 24 bits to the right (zeroing the top 24 bits). Similar code is generated for the “if” part of the code as well.

Thumb-2

Thumb-2 offers a “best of both worlds” compromise between ARM and Thumb, and aims to deliver the performance of ARM state code with the code density of Thumb state code. Thumb-2 has access to both 16 and 32 bit instructions, and even has support for conditional execution, albeit in the form of “If-then” (IT) constructs. Thumb-2 was first introduced as part of ARMv6-T2, and has subsequently been made the default thumb implementation for ARMv7.

So, lets build our example for Thumb-2 and analyse it as before. Note, I have built this by using the “-Otime” optimization in order to generate the IT constructs.

1
2
3
4
5
6
7
_Z3foohhtt
    0x00000000:    2902        .)      CMP      r1,#2
    0x00000002:    bf14        ..      ITE      NE
    0x00000004:    eb002013    ...     ADDNE    r0,r0,r3,LSR #8
    0x00000008:    eb002012    ...     ADDEQ    r0,r0,r2,LSR #8
    0x0000000c:    b2c0        ..      UXTB     r0,r0
    0x0000000e:    4770        pG      BX       lr

First thing we notice here is there is a mix of 32 bit and 16 bit instructions, as apparent by the instruction encodings (second column from the left). We see here that instead of all instructions being the same width, we have 4 instructions which are 16 bit, and 2 instructions which are 32 bits, giving us a code size of 16 bytes.

As seen, the second instruction is an ITE NE construct. This is not an instruction per se, but more of a heads up to the processor, instructing it that some conditional instructions need to be executed, and the first one of this will be based on the NE condition. What follows in instructions 3 and 4 is identical to what happened in ARM state code. Finally, the UXTB instruction is an instruction which extends (unsigned) the byte to a word, which in this case effectively zeros out the top 24 bits.

Remember

  • ARM instructions are all 32 bits in size, and have access to an in-line barrel shifter, as well as most instructions are conditional. This is best suited for performance sensitive code, where the code size does not matter
  • Thumb instructions are all 16 bits in size, and do not have access to an in-line barrel shifter, and neither are the instructions conditional. This is best suite for situation where code footprint needs to be minimised, albeit at the expense of performance (Having said that, Thumb code might give better performance results depending on the size of the cache and other factors)
  • Thumb-2 instructions offer a “best of both worlds” approach, and it utilizes both 16 and 32 bit instructions. Conditional execution of instructions is possible through IT constructs, although there a limit to the number of conditions which can be conditionally executed within the IT block.

[转]ARM/Thumb/Thumb-2的更多相关文章

  1. ARM 的Thumb状态测试

    作为一个使用ARM的学习者,有必要全面了解你的处理器内核.尽管有些内容可能在实际应用中用不到,但是“了解”还是很必要的.Thumb状态,是ARM的一个特色,但是你知道Thumb状态与ARM状态最大的区 ...

  2. 对于Android NDK编译器ARM和Thumb模式的理解

    编译NDK项目时,编译器无法识别arm汇编,设置LOCAL_ARM_MODE := arm后问题解决, NDK文档上对LOCAL_ARM_MODE的说明如下: LOCAL_ARM_MODE By de ...

  3. ARM处理器的寄存器,ARM与Thumb状态,7中运行模式

     ** ARM处理器的寄存器,ARM与Thumb状态,7中运行模式  分类: 嵌入式 ARM处理器工作模式一共有 7 种 : USR  模式    正常用户模式,程序正常执行模式 FIQ模式(Fast ...

  4. ARM处理器的寄存器,ARM与Thumb状态,7中运行模式 【转】

    转自:http://blog.chinaunix.net/uid-28458801-id-3494646.html ARM处理器工作模式一共有 7 种 : USR  模式    正常用户模式,程序正常 ...

  5. ARM ® and Thumb ®-2 指令系统

    指令表关键词        Rm {, <opsh>} 寄存器移位方式,将寄存器的移位结果作为操作数而Rm值保持不变       <Operand2> 灵活的使用第二个操作数. ...

  6. ARM状态和THUMB状态

    ARM处理器的工作状态 在ARM的体系结构中,可以工作在三种不同的状态,一是ARM状态,二是Thumb状态及Thumb-2状态,三是调试状态. <嵌入式系统开发与应用教程(第2版)>上介绍 ...

  7. 13 ARM指令集与Thumb指令集

    指令格式 ARM基本格式 <opcode>{<cond>}{S}{.W|.N}<Rd>,<Rn>{,<operand2>} opecode: ...

  8. iOS程序破解——ARM汇编基础

    原文在此:http://www.cnblogs.com/mddblog/p/4951650.html 一.Thumb指令与ARM指令 Thumb指令为16位,因此存储代码的密度高,节省存储空间.但是功 ...

  9. 原子操作--ARM架构

    说明:内核版本号为3.10.101 一.ARM架构中的原子操作实现 在原子操作(一)中我们已经提到,各个架构组织为“复仇者”联盟,统一了基本的原子变量操作,这里我们就拿atomic_dec(v)来看看 ...

随机推荐

  1. Jquery动态插入table行

    想在一个<table id="table1"></table>标签中动态的插入行,在jquery中可以这样做: $("#table1") ...

  2. Codeforces 10C Digital Root 法冠军

    主题链接:点击打开链接 #include<stdio.h> #include<iostream> #include<string.h> #include<se ...

  3. jquery中DOM的操作方法

    先介绍几个比较简单的方法,不经常用到,做个记录 1. filter() 方法 顾名思义,filter是一个过滤器,如果给定表示 DOM 元素集合的 jQuery 对象,.filter() 方法会用匹配 ...

  4. Tomcat剖析(四):Tomcat默认连接器(1)

    Tomcat剖析(四):Tomcat默认连接器(1) 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三): ...

  5. 几款web版整合(QQ、msn、icq、yahoo通、Gtalk等)即时聊天http://hi.baidu.com/ejie/blog/item/e89794ef9a9431efce1b3ebd.html

        直到近期为止,我们经常使用的即时聊天工具(QQ.msn等)了Web版,大家不用下载庞大软件,直接打开网页就能够与自己的好友聊天,很方便.在此将时汇总,便于大家查找,节约大家一点时间. 此都是官 ...

  6. js调用wcf 的SOA

    jquery 调用wcf 的SOA架构,将三层架构运用到SOA的架构中来 经过前面3天的学习,我想大家应该对SOA的架构有了初步的了解,其实 SOA与三层架构并不冲突,而是三层架构的升级版. 来看下传 ...

  7. ENode 2.0

    ENode 2.0 - 介绍一下关于ENode中对Command的调度设计 摘要: CQRS架构,C端的职责是处理从上层发送过来的command.对于单台机器来说,我们如何尽快的处理command呢? ...

  8. 找呀志_通过开源框架引AsyncHttpClient处理get/post要求

    一个.开源参考架构的方法. 方法一 找到下载的文件的源代码,Com中的src文件夹下 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhb3lhemhp ...

  9. 打印Ibatis最后,SQL声明

    做项目时,满足这一需求.我们希望最终打印出在数据库运行SQL声明,这些都普遍遇到了一些一般性问题.我会去Appfuse,结果这次没有成功.它是有相关的配置,可是好像没实用.我也就没有深查下去.我想这种 ...

  10. Kafka spring 集成

    下载配置kafka参考该链接:http://www.cnblogs.com/super-d2/p/4534323.html pom.xml: <dependency> <groupI ...