CSE 431. Computer Architecture

Download Report

Transcript CSE 431. Computer Architecture

计算机组成与结构
第二章 计算机指令
张锦
1
2.1 概述
 控制计算机工作必须使用其能理解的“语言”
 机器语言的单词-指令,单词表-指令集
 指令集:一个给定的体系结构所能理解的命令
集合
 所有的机器语言都非常类似
 构成计算机的硬件技术基于相似的底层原理
 一些基本操作是所有计算机都必须提供的
 计算机设计者具有共同的目标:


以最低的成本得到最好的性能
设计一种使硬件设计和编译器构造更简洁的语言
2/90
2.1 概述
 “设备简单性”是应当着重考虑的问题

本章将描述一个遵循该思路的指令集,并展示
如何用硬件描述,以及其和高级语言的关系
 “存储程序”概念:指令和各种类型数据以数字
形式存储在存储器中。
 本书所描述的指令集是20世纪80年代以来设计
的指令集MIPS
 在实验课中,我们将学习另外一种指令集IA32,x86系列CPU使用的指令集
3/90
回顾:(von Neumann) Processor
Organization
CPU
Memory
Devices
Control
Input
Datapath
Output
Fetch
Exec
Decode
4/90
续:
 Control needs to
input instructions from Memory
 issue signals to control the information flow between
the Datapath components and to control what
operations they perform
 control instruction sequencing
 Datapath needs to have the
 components – the functional units and
storage (e.g., register file) needed to execute
instructions
 interconnects - components connected so that the
instructions can be accomplished and so that data can
be loaded from and stored to Memory

5/90
回顾:RISC - Reduced Instruction Set
Computer
 RISC philosophy




fixed instruction lengths
load-store instruction sets
limited addressing modes
limited operations
Design goals: speed, cost
(design, fabrication, test,
packaging), size, power
consumption, reliability,
memory space (embedded
systems)
 MIPS, Sun SPARC, HP PA-RISC, IBM PowerPC,
Intel (Compaq) Alpha, …
 Instruction sets are measured by how well compilers
use them as opposed to how well assembly language
programmers use them
6/90
回顾:MIPS R3000 Instruction Set
Architecture (ISA)
 Instruction Categories






Registers
Computational
Load/Store
Jump and Branch
Floating Point

coprocessor
Memory Management
Special
R0 - R31
PC
HI
LO
3 Instruction Formats: all 32 bits wide
OP
rs
rt
OP
rs
rt
OP
rd
sa
immediate
jump target
funct
R format
I format
J format
7/90
回顾: Unsigned Binary
Representation
Hex
Binary
Decimal
0x00000000
0…0000
0
0x00000001
0…0001
1
0x00000002
0…0010
2
0x00000003
0…0011
3
0x00000004
0…0100
4
0x00000005
0…0101
5
0x00000006
0…0110
6
0x00000007
0…0111
7
0x00000008
0…1000
8
0x00000009
0…1001
9
231 230 229
...
23 22 21
20
bit weight
31 30 29
...
3
0
bit position
1 1 1
...
1 1 1 1
bit
1 0 0 0
...
0 0 0 0
-
2
1
1
232 - 1
…
0xFFFFFFFC
1…1100
232 - 4
0xFFFFFFFD
1…1101
232 - 3
0xFFFFFFFE
1…1110
232 - 2
0xFFFFFFFF
1…1111
232 - 1
8/90
回顾:American Std Code for Info Interchange
(ASCII): 8-bit bytes representing characters
ASCII
Char
ASCII
Char
ASCII
Char
ASCII
Char
ASCII
Char
ASCII
Char
0
Null
32
space
48
0
64
@
96
`
112
p
1
33
!
49
1
65
A
97
a
113
q
2
34
“
50
2
66
B
98
b
114
r
3
35
#
51
3
67
C
99
c
115
s
36
$
52
4
68
D
100
d
116
t
37
%
53
5
69
E
101
e
117
u
38
&
54
6
70
F
102
f
118
v
39
‘
55
7
71
G
103
g
119
w
4
EOT
5
6
ACK
7
8
bksp
40
(
56
8
72
H
104
h
120
x
9
tab
41
)
57
9
73
I
105
i
121
y
10
LF
42
*
58
:
74
J
106
j
122
z
43
+
59
;
75
K
107
k
123
{
44
,
60
<
76
L
108
l
124
|
127
DEL
11
12
15
FF
47
/
63
?
79
O
111
o
9/90
2.2 计算机硬件的操作
 任何计算机都必须能完成算术运算指令
 第一条MIPS汇编语言指令:加法运算指令
 格式:add a, b, c
 每条MIPS运算指令仅仅执行一个操作,并只有
3个操作数
 下面指令序列完成了什么功能?




add a, b, c # The sum of b and c is placed in a.
add a, a, d
add a, a, e
#右边是注释,帮助理解程序
10/90
MIPS算术指令
 MIPS assembly language arithmetic statement
add $t0, $s1, $s2
sub $t0, $s1, $s2
 Each arithmetic instruction performs only one
operation
 Each arithmetic instruction fits in 32 bits and
specifies exactly three operands
destination  source1 op source2
 Operand order is fixed (destination first)
 Those operands are all contained in the datapath’s
register file ($t0,$s1,$s2) – indicated by $
11/90
MIPS算术指令
 上述要求符合硬件简单性的设计原则

操作数个数固定比不固定,所需硬件更简单
 硬件设计四个基本原则之一:
 简单源自规整
 两个例题:


1、将a=b+c 和 d=a-e 编译为MIPS汇编指令
2、将 f = (g+h)-(i+j)编译为MIPS汇编语言
指令
12/90
小结:
 到目前学到的MIPS汇编指令
MIPS汇编语言
示例
语义
类别
指令
注释
算术运算
加
add a,b,c a=b+c 总是三个操作数
减
sub a,b,c
a=b-c 总是三个操作数
13/90
2.3 计算机硬件的操作数
 MIPS的算术指令操作数必须直接取自寄存器
 寄存器是计算机构成的基本元素
 对程序员可见
 和高级语言的变量相比,寄存器数量有限
 MIPS中有32个32位寄存器
 个数有限,太多将延长时钟周期(电信号传输)
 硬件设计的第二个原则:越少越快
 在计算机中经常涉及的一个概念:字
 字所包含的二进制位数称为字长
 不同计算机系统中字长可能不同
 MIPS中字为32位
14/90
使用寄存器编译C语句
 MIPS中使用0到31表示相应的寄存器,约定:
用“$”符号后跟两个字符代表一个寄存器

$s0, …$s7:寄存器; $t0,…, $t7:临时寄存器
 翻译如下C语句:
 f=(g+h)-(i+j),其中:f、g、h、i和j分别用$s0、
$s1、 $s2、 $s3和$s4代替
 翻译后的代码:
 Add $t0, $s1, $s2
 Add $t1, $s3, $s4
 Sub $s0, $t0, $t1
15/90
MIPS Register File
 Holds thirty-two 32-bit registers


Two read ports and
One write port
Register File
32 bits
src1 addr
src2 addr
dst addr
write data
5
32 src1
data
5
5
32
32
locations
32 src2
data
write control
16/90
MIPS Register File
 Registers are
 Faster than main memory
 But register files with more locations
are slower (e.g., a 64 word file could be as much as 50%
slower than a 32 word file)
 Read/write port 增加了冲突
 Easier for a compiler to use
 e.g., (A*B) – (C*D) – (E*F) can do multiplies in any order
vs. stack
 Can hold variables so that
 code density improves (since register are named with fewer
bits than a memory location)
17/90
2.3.1 存储器操作
 寄存器个数有限,只能保留少量数据
 包含大量数据的数组、结构的数据结构,计算
机将数据存放在内存中
 MIPS的算术运算只作用于寄存器,因此,必须
有在存储器和寄存器之间传送数据的指令


这些指令称为“数据传送指令”
为了访问某个字,必
须给出其存储器“地址”,
这时可以将存储器看做
一个很大的一维数组
18/90
存字指令和取字指令
 取指令:把数据从存储器复制到寄存器的数据
传送指令

格式:lw $s1, 100($s2) # load word
 存指令:把数据从寄存器传送到存储器

格式:sw $s1, 100($s2) # store word
 数据传送指令中的常量叫“偏移量”offset
 存放基址的寄存器叫“基址寄存器” base register
19/90
例1:翻译如下C语句
 A是含100个字的数组,编译器将$s1、$s2分配
给g、h,基址寄存器分配为$s3
 翻译如下语句:

g = h +A [8]

MIPS指令
lw $t0, 8($s3)
Add $s1, $s2, $t0


20/90
例2:翻译如下C语句
 假设变量h放在$s2,数组A的基址放在$s3中,
翻译如下MIPS汇编代码
 A[12]=h+A[8]
 MIPS代码:
 lw $t0, 32($s3)
 Add $t0, $s2, $t0
 Sw $t0, 48($s3)
21/90
注意:
 编译器将:变量和寄存器对应起来;而将数组、
结构这样的数据结构分配到存储器中相应位置,
然后将其在M中的起始地址放入数据传送指令
中
 在程序中8位字节非常有用,很多系统按单个
字节编址。在MIPS中,一个字包括4个字节,
因此,连续字的地址相差4
 MIPS中字的起始地址必须是4的倍数,这称为
“对齐限制”

两种字节寻找方式:使用最左端(大端)字节的地
址作为字地址,或者相反;MIPS采用前者
22/90
字节寻址的影响
 字节寻址影响数组下标
 在例1中,加到基址寄存器$s3的偏移量必须是
4*8,否则将变为A[8/4]
23/90
2.3.2 常数或立即数操作数
 程序中常常要使用常量
 但目前的指令中,常数必须从R中取出,因此,
在这之前必须将常数从M放到R中
 为了避免这种方式,MIPS中提供了另外一种指
令:立即数加
 Addi $s3, $s3, 4
 立即数加说明了硬件设计的第三个原则:加速
执行常用操作
24/90
注意:
 程序中变量个数远多于R个数,因此,编译器尽量将最
常用的变量保存在R中,其他在M中

寄存器换出:将不常使用或稍后才使用的变量存放到存
储器中的过程
 硬件设计的原则:大小和速度快慢呈现反比关系(存
储器层次结构)。


数据在R中将比在M中访问速度更快
数据在R中效率更高。
 指令一次读2个R,并写入结果,传送指令每次只能读写
一个数
 因此,MIPS编译器必须有效地使用R
25/90
2.4 计算机中指令的表示
 机器如何表示数?
 我们习惯采用十进制,计算机常用二进制
 仅仅是数制不同而已,二、八、十、十六
 实际中在计算机里以高低电平表示0或1
 根据冯.诺依曼体系的特点,指令和数据一样存储在计
算机中
 指令也以一系列高低电平信号形式保存在计算机中,
并以数字形式表示


每条指令的各个部分可以看做单个数字,将其拼在一起
就形成了指令
所有的指令都使用到了R,必须规定R的名字如何对应R
的序号
26/90
例题:将MIPS汇编指令翻译为机器指令
 指令: add
$t0, $s1, $s2
 十进制表示:
0






17
18
8
0
32
指令的每一段称为一个字段(field)
第一个和最后一个字段组合说明该指令为加法
第二个字段表示第一个源操作数的R号(17=$s1)
第三个字段表示第二个源操作数的R号(18=$s2)
第四个字段表示存放目的操作数的R号(8=$t0)
第五个字段没有用到
27/90
例题:将MIPS汇编指令翻译为机器指令
 对应的二进制表示:
000000
10001
10010
01000
00000
100000
 上述形式称为机器语言:指令的数字形式;数字形式
的指令序列称为机器代码
 指令的这种设计称为指令格式
 指令为32位,和字长一致,遵循“简单源自规整”的原则
 但是直接二进制表示非常繁琐,出现了更简化一些的
表示,十六进制



本书约定,在数的右下角标注“ten、hex、two”区别各种
进制
在其他书中,有用 B、O、H分别表示二、十、十六
要熟悉进制转换,书中page 35的例题
28/90
MIPS字段
 为了使讨论更简洁,重命名了MIPS各字段
op






rs
op
6-bits
rs
5-bits
operand
rt
5-bits
operand
rd
5-bits
destination
shamt
5-bits
funct
6-bits
rt
rd
shamt
funct
opcode that specifies the operation
register file address of the first source
register file address of the second source
register file address of the result’s
shift amount (for shift instructions)
function code augmenting the opcode
29/90
MIPS字段
 问题:如果指令需要比上述字段长的字段时?
 取字指令包括2个R和一个常数
 位移量限制了转移的范围
 因此,在MIPS设计时,一方面要使所有指令长
度相同,另一方面要让每条指令格式刚好合适
 如何处理?遵循硬件设计的第四项原则:


优秀的设计需要适当的折中
折中方案:所有指令长度相同,但不同的指令
采用不同的指令格式。

存在不同的指令格式,如R型、I型、J型等
30/90
不同指令格式
 下面的指令格式称为R型
op
rs
rt
rd
shamt
funct
 I型指令格式如下:
Op, 5b


rs,5b
rt,5b
constant or address, 16bit
16位的偏移可以使得取字指令得到相对基址偏
移达到2^15范围的数据
注意,在这种指令格式下的MIPS汇编语言的字
段含义有所不同
31/90
I型取字指令
 Load/Store Instruction Format (I format)
lw
op
rs
$t0,
rt
($s2)
16 bit offset
Memory
2410 + $s2 =
. . . 0001 1000
+ . . . 1001 0100
. . . 1010 1100 =
0x120040ac
24
0xf f f f f f f f
0x120040ac
$t0
0x12004094
$s2
data
0x0000000c
0x00000008
0x00000004
0x00000000
word address (hex)
32/90
不同指令格式的区分
 多种指令格式使得硬件变得复杂
 在MIPS中,机器根据第一个字段区分不同的指
令格式



R型、I型等,其第一个字段均为5位
每种格式的第一个字段op被分配一套不同的值,
计算机可以据此确定指令后半部分是三字段还
是一字段
参考37页表2-6
33/90
例子:翻译如下C语句为MIPS汇编指令
 A[300]=h+A[300]
 假定:数组A的基址在$t1, h-$s2
 编译后的代码:
 Lw $t0, 1200($t1)
 Add $t0, $s2, $t0
 Sw $t0,1200($t1)


参考37页中十进制表示的机器语言指令以及二
进制的机器语言指令
参考38页,回顾已经学过的MIPS机器语言指令
34/90
重点:
 当前计算机构造基于2个关键性原则
 1、指令以数据形式表示
 2、和数据一样,程序存储在存储器
中,并可读写
 这两个原则导致了“存储程序”的概
念
 将指令当作数字使得程序被当作二
进制数字文件发行;在商业上,计
算机可以继承已有的与该指令集兼
容的软件,这使得工业界目前围绕
几个有限的指令体系构成不同的联
盟
35/90
2.5 逻辑运算指令
 对字里的特定几位进行操作也非常有用
 MIPS中加入了一些对某些位操作的指令,称为
逻辑操作
 图2-9中(p40)给出了对应的操作符以及对应
于MIPS的指令
 第一类:移位指令 sll和srl




Sll $t2, $s0, 4
Op
rs
rt
rd
shamt func
0
0
16
10
4
0
逻辑左移和右移相当于乘或者除操作
36/90
2.5 逻辑运算指令
 第二类指令:逻辑操作 and(andi)、or(ori)、nor
 And
$t0, $t1, $t2




Or
Nor


And运算可以用0来屏蔽某些位(0与任何都为0)
Andi是和常数相与
$t0, $t1, $t2
$t0, $t1, $t3 # ~( $t1| $t3)
NOT是取反操作,但是只需要一个操作数,为了保
持双操作数的指令格式不变,引入或非NOR替代之,
如果t3为0,则可以得到对t1取反的结果
参考p41页中图2-10的归纳
37/90
2.6 分支指令
 计算机的智能在于其可以根据不同情况选择合
适的指令执行
 在程序中实现使用的是分支语句,如:if、go
to、label等
 MIPS汇编语言中包括2条语句:
 Beq register1, register2, L1 #相等时转
 Bne register1, register2, L1 #不相等时转

称为条件分支指令
38/90
例子:将if-then-else编译为条件分支
指令
 If (i= =j) f=g+h; else f=g-h;
 设:f, …,j 分配到 $s0,…$s4
 MIPS指令序列:
 Bne $s3, $s4, Else
 Add $s0, $s1, $s2
 J Exit
 Else: sub $s0, $s1, $s2
 Exit:
 注意:编译器经常产生分支指令和标号,但高级语言中
并不出现。避免使用显式标号和分支,可以使得高级语
言的编码效率提高
39/90
例子:循环语句的编译
 While (save[i]= = k) i + =1;
 假设:i和k对应$s3和$s5, save基址存于$s6
 Loop:
sll
$t1, $s3, 2

Add $t1,
$t1, $s6

Lw
$t0, 0($t1)

Bne
$t0, $s5, Exit

Addi $s3, $s3, 1

J
Loop

Exit:
 以分支指令结束的指令序列对编译技术而言非常基础
(称为基本块)。而编译的最初阶段就是将程序分为
基本块。
 基本块:除了可能在序列结尾处,序列中没有分支指
令;除可能在序列开始处,序列中没有分支目标和分
支标号
40/90
变量大小判断的实现
 比较除了等于和不等于之外,也包括大小比较
 MIPS汇编指令:


slt $t0, $t3, $s4 # t3中的值小于t4中的将t0置1
Slti $t0, $s2, 10 #立即数比较版本
 为什么没有给出“小于时分支”指令?

遵循“设备简单性”的原则,这类指令过于复杂
 MIPS编译器使用slt、slti、beq、bnq等指令和
$zero中的定值0产生所有的比较条件:相等、
不等、小于、小于等于、大于、大于等于
41/90
分支语句:case/switch语句
 Case/switch功能:根据变量的不同取值,选择不同的
程序分支
 实现switch的一种方法:利用条件判断序列,将switch
语句转化为一些了if-then-else语句
 另一种方法:通过编码形成一个分支指令序列地址表
(转移地址表)。



程序查表获取目标地址,并跳转到相应的分支指令序列
转移地址表是一个字数组,数组中各元素对应代码中各
个标号的地址
MIPS中设计了一条无条件跳转指令jr支持上述实现
 在高级语言中,虽然有各种不同的分支判断和循环语
句,但实现他们的底层基础语句是条件分支
 回顾:p45中图2-12,已经学习过的MIPS指令
42/90
2.7 计算机硬件的过程支持
 过程或函数是结构化编程的有效工具
 过程:使用参数将过程与其他程序和数据分开,只允许传
值和返回结果
 降低问题复杂度、提高程序的可读性、可重用性
 在过程运行时,程序遵循如下六个步骤:
 将参数放在过程可以取到的位置
 向过程传递控制
 获得过程所需的存储资源
 执行需要的任务
 将结果的值放在调用程序可以获取到的地方
 将控制返回到初始点
43/90
2.7 计算机硬件的过程支持
 R的速度最快,因此,在编译时需要尽可能多使用R,
MIPS在对过程进行编译时使用R遵循如下规定:

$a0-$a3:传参数; $v0-$v1:返回值; $ra:返回起始点
 另外,MIPS汇编语言有一条专门的过程指令:跳转到某
个地址的同时将下一条指令的地址保存在寄存器$ra中
 跳转-链接指令 jal procedureAddress




链接指明调用位置的地址,存于$ra中
保存当前运行指令的地址寄存器:程序计数器PC
Jal指令将PC+4保存在$ra中
相应的,为了在过程调用结束时返回,MIPS设计了一返
回指令:jr $ra
44/90
2.7.1 使用更多R
 程序中经常需要将R的内容换出到M


如果要使用多于4个参数R或2个返回值R时
调用结束后恢复原数据
 理想的数据结构是栈stack



需要栈指针:指向最新分配的地址
两个操作:入栈push和出栈pop
MIPS中为栈分配了一个R:$sp
 惯例:栈增长实际中是存储器地址由高到低
45/90
例子:编译一个不调用其他过程的
C过程
 如p48中例题
 假设:参变量g,h,I,j对应$a0,-$a3, f对应$s0
 MIPS编译后的指令序列:














Leaf_example:
Addi
$sp, $sp, -12
Sw
$t1, 8($sp)
Sw
$t0, 4($sp)
Sw
$s0, 0($sp)
Add
$t0, $a0, $a1
Add
$t1, $a2, $a3
sub
$s0, $t0, $t1
Add
$v0, $s0, $zero
Lw
$s0, 0($sp)
Lw
$t0, 4($sp)
Lw
$t1, 8($sp)
Addi
$sp, $sp, 12
Jr
$ra
#过程从标号开始
# 保存3个R
#对应过程实体
# 放入返回值
#恢复3个旧值
$t0-$t9,10个R为临时R,
不需保存;$s0-$s7:8个
保留R,需要保存。这
个规定减少了R换出
# 返回
46/90
2.7.2 嵌套过程
 没有调用其他过程的过程称为叶过程
 叶过程很简单,但是程序中存在嵌套的情况,
甚至是自身递归,如:汉诺塔、计算n!等
 R有限导致可能存在R争用问题
 解决:将所有需要保存的R压栈。




调用者将所有调用后仍需要的参数R($ax)或临
时R($tx)压栈;
调用者将返回地址R $ra和被调用者使用的被保
存R($sx)压栈
栈指针sp随时调整计算栈中R的个数
返回时,R从M中恢复,栈指针重新调整
47/90
例子:计算阶乘
 P50的例子

 翻译如下:
 Fact:
 Addi
$sp, $sp, -8
 Sw
$ra, 4($sp)
 Sw
$a0, 0($sp)





Slti
Beq
Addi
$t0, $a0,1
$t0, $zero, L1
$sp, $sp, 8
$ra
L1: addi $a0, $a0,-1
Jal
fact

Lw
Lw
addi
Mul
$a0, 0($sp)
$ra, 4($sp)
$sp, $sp, 8
$v0, $a0, $v0

Jr
$ra


Addi
Jr


$v0, $zero, 1
48/90
对上述指令列的解释
 一个C的变量就是一个存储位置,对其解释需
要确定其类型和存储方式





两种存储方式:动态和静态。动态仅存在于过
程中
静态变量则进入和退出过程时一直存在
在过程之外和用static声明的变量都是静态
MIPS使用一个专门的R,全局指针$gp,用于简
化静态数据的访问
参考p51中图2-15中过程保留的不保留的对象
49/90
2.7.3 在栈中为新数据分配空间
 栈中保留数据的复杂性在于局部变量的存在
 栈中保留R和局部变量的段称为过程帧



在MIPS软件中使用一个专门的R,帧指针$fp,
指向过程帧的第一个字
帧指针提供了用于局部存储器引用的稳定基寄
存器
避免在过程中修改$sp来保护$fp
50/90
调用过程之前、中间和之后
51/90
2.7.4 在堆中为新数据分配空间
 内存中除了保留过程的动
态变量外,还需要存储静
态变量和动态数据结构
 MIPS对内存进行了约定:




内存低端地址受保护
之后是MIPS机器代码存储
区域,正文段(程序代码)
之上为静态数据段(常量和
静态变量)
剩下的:一段为链表以及
那些随程序运行而变化的
动态数据(与这类数据结
构对应的段习惯上称为
堆),另一端为栈。
C、Java通过函数调用在堆上
分配和释放空间,如:malloc、new等
注意:这只是软件的约定,而非MIPS的体系结构
52/90
MIPS中寄存器约定
Name
Register
Number
Usage
调用时
是否保护?
$zero
0
constant 0 (hardware)
n.a.
$at
1
reserved for assembler
n.a.
$v0 - $v1
2-3
returned values
no
$a0 - $a3
4-7
arguments
yes
$t0 - $t7
8-15
temporaries
no
$s0 - $s7
16-23
saved values
yes
$t8 - $t9
24-25
temporaries
no
$gp
28
global pointer
yes
$sp
29
stack pointer
yes
$fp
30
frame pointer
yes
$ra
31
return addr (hardware)
yes
53/90
Category
算术
(R & I
format)
数据传送
(I format)
条件分支
(I & R
format)
无条件分
支
(J
&R
format)
Instr
Op Code
Example
Meaning
add
0 and 32 add $s1, $s2, $s3
$s1 = $s2 + $s3
subtract
0 and 34 sub $s1, $s2, $s3
$s1 = $s2 - $s3
add immediate
8
addi $s1, $s2, 6
$s1 = $s2 + 6
or immediate
13
ori $s1, $s2, 6
$s1 = $s2 v 6
load word
35
lw $s1, 24($s2)
$s1 = Memory($s2+24)
store word
43
sw $s1, 24($s2)
Memory($s2+24) = $s1
load byte
32
lb
$s1, 25($s2)
$s1 = Memory($s2+25)
store byte
40
sb
$s1, 25($s2)
Memory($s2+25) = $s1
load upper imm
15
lui
$s1, 6
$s1 = 6 * 216
br on equal
4
beq $s1, $s2, L
if ($s1==$s2) go to L
br on not equal
5
bne $s1, $s2, L
if ($s1 !=$s2) go to L
set on less than
0 and 42 slt
$s1, $s2, $s3
if ($s2<$s3) $s1=1 else
$s1=0
set on less than
immediate
10
slti $s1, $s2, 6
if ($s2<6) $s1=1 else
$s1=0
jump
2
j
2500
go to 10000
jump register
0 and 8
jr
$t1
go to $t1
jump and link
3
jal 2500
go to 10000; $ra=PC+4
54/90
2.8 人机交互
 计算机虽然为了数字计算而被发明,但很快被
用于文字处理
 当前多数计算机使用一个字节8位表示字符,
遵循ASCII(American Standard Code for
Information Interchange)

P55中的图2-21
 相应的,MIPS中提供了字节转移指令



Lb:从内存中读取一个字节,放到R最右边8 位
Sb:将R最右边8位取出写入内存
Lb $t0, 0($sp)
sb $t0, 0($sp)
55/90
字符串的处理
 字符串中的字符数通常是变化的,如何表示字
符串的长度呢?



字符串的第一位置保留以给出字符串的长度
附加带有字符串长度的变量
字符串最后的位置用一个字符来标识
 C语言使用第三种方法,用值为0(ASCII中位
NULL)来结束字符串

字符串“abc”在C中是用4个字节表示
 Java使用Unicode ,用16位表示一个字符,java
包括一个字来给出字符串长度
56/90
例子:编译字符串复制程序
 P56 中例题
 假定:x-$a0, y-$a1, i-$s0
 MIPS汇编指令:
 Strcpy:

Lb $t2, 0($t1)


Add $t3, $s0, $a0
Sb $t2, 0($t3)
Addi $sp, $sp, -4
Sw $s0, 0($sp)

Beq $t2, $zero, L2

Addi $s0, $s0, 1
J L1



Add $s0, $zero, $zero


L1: add $t1, $s0, $a1



L2: lw $s0, 0($sp)
Addi $sp, $sp, 4
Jr $ra
57/90
半字处理指令
 MIPS具有外在指令读取和存储16位的半字
 Lh $t0, 0($sp)
 Sh $t0, 0($sp)
58/90
2.9 对32位立即数的MIPS编址和寻
址
 指令固定32位,OP等字段占去了部分位置,使
得数值部分能够使用的位数减少
 虽然16位表示数值能满足大多数应用需要,但
是也有大数需要表示,而且有时32位常量或地
址也更方便
 MIPS中专门指令给R中的常量设置高16位,并
允许后续指令设定常量的低16位
 Lui $t0, 255 # Load upper immediate
 编译器必须把大常数分开然后重组在一个R中;
汇编程序使用$at作为临时R产生长的整数值
59/90
例题:读取一个32位常数
 0000 0000 0011 1101 0000 1001 0000 0000
 Lui $s0, 61

0000 0000 0011 1101 0000 0000 0000 0000
 Ori $s0, $s0, 2304

0000 0000 0011 1101 0000 1001 0000 0000
60/90
2.9.2 分支和跳转中的寻址
 MIPS中跳转指令寻址最简单
 J型指令,op占6位,其余为地址字段
 分支指令必须指定2个操作数和分支地址,其
中16位用于分支的地址字段
 如果程序地址大于2^16,怎么办?




指定一个总是加上分支地址的R,则:
程序计数器=R+分支地址,可以达到2^32
使用哪一个R呢?
PC是一个理想的选择,称为PC相对寻址
这里的地址是字地址,而不是字节地址
61/90
例题:远距离分支如何处理?
 Beq $s0, $s1, L1
 通过一对提供大得多的分支转移距离指令代替
 Bne $s0, $s1, L2
J
L1
 L2:
62/90
2.9.3 MIPS寻址模式总结
 MIPS寻址模式如下:
 1、R寻址,操作数是R
 2、基址或偏移寻址,操作数在M中,地址为
指令中基址R和常数的和
 3、立即数寻址,操作数是指令中的常数
 4、PC相对寻址,地址是PC和指令中常数的和
 5、伪直接寻址,跳转地址是指令中26位和PC
计数器的高位相连而成
63/90
2.9.3 MIPS寻址模式总结
64/90
2.9.4 机器语言解码
 将机器语言恢复到汇编语言有时也是必须的
 例子:解码如下指令
 00af8020 hex
 二进制:
 0000 00101 01111 10000 00000 100000
 Op rs
rt
rd
shamt funct
 查p62页中表格,确定对应的指令
65/90
2.10 程序的自动翻译和启动运行
 如何将一个硬盘上的C语言转换成在计算机上
可运行的程序:4个阶段
66/90
2.10.1 编译器
 编译器:将C程序转换成一种机器能够理解的
符号形式的汇编语言程序


在1975年,Os都是由汇编语言编写,主要是由
于内存很昂贵,而且编译器效率不高
现在内存已经很便宜,而且优化编译器能够生
成和汇编专家编写一样优秀的汇编程序
 汇编器:将汇编语言汇编为机器语言的目标文
件,包括机器语言指令、数据和将指令放入正
确内存所需要的信息

汇编语言是高层软件的接口,汇编器能够处理
一些机器语言的常见变种
67/90
2.10.2 汇编器
 汇编器能够处理伪指令
 伪指令:MIPS体系中不存在的指令,其存在使
得MIPS拥有一个比已由硬件实现的更丰富的汇
编语言指令集
 汇编器能够接受不同基数的数字
 汇编器通过符号表匹配标记名和指令所在内存
字的地址
 UNIX系统中目标文件通常包含六个部分

目标文件首部;正文段;静态数据段;重定位
信息;符号表;调试信息
68/90
2.10.3 链接器
 对一个代码行的改动需要重新编译和汇编整个
程序,浪费计算资源,可以改进吗?
 可行方法:单独编译和汇编每个过程,使得某
一行代码的改变只需要编译和汇编一个过程
 这种方法需要一种新的系统程序:链接器
 链接器的工作包括3个步骤:



1、将代码和数据模块按符号特征放入内存
2、决定数据和指令标记的地址
3、修正内部和外部引用
69/90
2.10.3 链接器
 链接器使用每个目标模块的重定位信息和符号
表解析所有未定义标记
 链接器使得修正代码比重新编译和重新汇编要
快的多
 当已经解析完所有外部引用,链接器将决定每
个模块将占用的内存位置

当链接器将一个模块放入内存时,所有绝对引
用将被重定位以确定其在内存中的位置
 链接器将产生一个可执行文件
 例题:目标文件的链接,见p67
70/90
2.10.4 加载器
 可执行文件在磁盘中,需要将其读入内存并运行
 在UNIX系统中,这个过程依照如下步骤进行:
 1、读取可执行文件首部确定正文段和数据段大小
 2、为正文和数据创建一个足够大的地址空间
 3、把可执行文件中的指令和数据复制到相应内存
中;
 4、把主程序的参数(如果存在)复制到栈顶
 5、初始化机器寄存器,将栈指针指向第一个空单
元
 6、跳转到启动例程,它将参数复制到参数R并且
调用程序的主例程;当主例程返回时,启动例程
通过exit系统调用终止程序
71/90
2.10.5 动态链接库
 传统中程序运行前链接库例程的方法存在一些不足:
 库例程称为可执行代码的一部分,库的更新不会同步到程
序中
 不论是否使用库中所有部分,库都会全部被加载
 引出了动态链接库dll,如果程序运行库例程就不会被链
接加载




在dll最初版本中,加载器运行一个动态链接程序,使用文
件中的额外信息找到适当的库并更新所有外部引用
问题是:其仍然链接库中所有调用和可能调用的例程
产生了:DLL的延迟过程链接方案,每个例程只有在被调
用时才被链接
这个方案一定程度上依赖:间接寻址技术
72/90
 库例程第一次被调用时,程
序调用虚入口然后执行间接
跳转。这个跳转指向识别期
望的库例程的代码,通过输
入数值到R,然后跳转到动
态链接加载器;接着链接加
载器查找所需的例程、将其
重映射并改变简介跳转位置
的地址使其指向这个例程;
然后跳转到这个例程;这个
例程完成时,将返回到初始
调用点。因为已经得到例程
的地址,以后即可间接跳转
到该例程,而无需再执行额
外中间过程。


DLL需要额外的空间存储动
态链接的信息,但是不需
要复制或者链接整个库
即时在第一次例程调用时
付出了较多的开销,但是
此后只需要一个简单的间
接跳转
73/90
2.10.6 开始一个Java程序
 典型的转换和运行Java程序的步骤:



首先被编译为一个二进制版本的Java字节码形
式(已经可以在解释器,Java虚拟机,上运行)
在程序运行时,JVM链接java库中一些要调用的
函数;为了得到较好的性能,JVM调用即时编
译器(Just in time),在运行它的机器上有选择
的把一些方法编译成宿主机上的本地机器语言
解释器:一个用来模拟指令系统结构的程序


优势是可移植;缺点是性能较差(与C差了10倍)
Java下一阶段目标是设计程序运行是译码的编译器,
进而降低编译和解释之间的性能差异
74/90
75/90
2.11 编译器如何优化
 编译器会极大影响计算机的性能,因而,理解
编译技术是理解性能的关键
 下图说明了编译器结构
76/90
2.11.1 高层优化
 高层优化:在非常接近源码的层次上进行优化
 常用的变换:
 过程内联:用函数体代替函数调用,实参取代
形参
 通过循环变换减少循环开销
 改善存储器访问,有效使用硬件资源
77/90
2.11.2 局部和全局优化
 这个过程通常执行以下三类优化
 1、局部优化:用于单个基本块
 2、全局优化:作用于多个基本块
 3、全局R分配:分配代码区域的变量给R
 一些优化的例子
 P73中的公用子表达式消除
 上例中,如果优化跨越2个基本块,对应为全局
公用子表达式消除
 其他如:强度削弱:将复杂操作用几个简单操
作代替;常数传播和常数合并;复制传播;无
用内存写消除
78/90
注意:
 编译器必须保守。


编译器的首要工作是产生正确的代码;
其次是产生运行速度快的目标代码
 对于程序员而言,其可能更好的改进代码,因
为其掌握编译器所没有的信息。如:指针之间
是否存在冲突等
 问题是:程序员在使用指针试图提高性能时,
该指针和其他变量或数组存在别名冲突将阻止
编译器做进一步的优化
79/90
优化技术
 另外2种重要的全局优化,均为循环优化


代码移动:查找循环中不变的部分(代码的特
殊部分,在每次循环迭代中都会得到同样的值)
归纳变量消除:一系列变量的组合,包括减小
索引数组时的开销,本质上是用指针访问来替
换数组索引
 优化总结:参考p74中图2-32
80/90
2.12 编译器如何工作初探
 有关编译技术的内容将请马征老师在周三做一
个专题报告
 内容大体包括:



将概述编译技术的发展过程
编译技术的主要内容
常用编译优化技术概述
81/90
2.13 以一个C程序排序为例
 问题:将C程序翻译为MIPS汇编指令
 交换(swap)数组中的元素
 按照如下步骤进行:
 1、为程序中变量分配R;
 2、把过程体转化为汇编代码;
 3、保存跨过程调用的R。
 C代码:
 Void swap(int v[], int k)
 { int temp;
 Temp = v[k];
 V[k]= v[k+1];
 V[k+1]= temp;}
82/90
续:
 分配R
 传参使用$a0-$a3
 V - $a0; k - $a1; temp$t0
 过程体:
 Sll $t1,$a1,2
 Add $t1, $a0, $t1
 完整程序:
 Swap: Sll $t1,$a1,2
 Add $t1, $a0, $t1



Sw $t2, 0($t1)
Sw $t2, 4($t1)

Jr $ra





Lw $t0, 0($t1)
Lw $t2, 4($t1)
Lw $t0, 0($t1)
Lw $t2, 4($t1)
Sw $t2, 0($t1)
Sw $t2, 4($t1)
83/90
例子:sort过程









Void sort( int v[], int n)
{
Int I,j;
For(i=0; i<n; i+=1)
{
for (j=i-1; j>=0 && v[j]>v[j+1]; j-=1)
swap(v,j);
}
}
84/90
续:
 几个步骤:
 1、R分配
 2、sort过程体的代码
 3、sort的过程调用
 4、sort中的参数传递
 5、在sort中保存R
 具体参考p77
85/90
理解程序性能
 运行时间是唯一准确的性能度量标准

参考p81的图2-37
 编程语言和算法对排序程序性能的影响

参考p81的图2-38
86/90
2.15 数组与指针
 对比使用数组和数组下标的汇编码和使用指针的汇编




码,加深对指针的理解
例子:将内存中一个字序列清零
C程序:
Clear1 (int array[], int size)
{int I; For(i=0;i<size;i+=1) array[i]=0;}
 Clear2(int *array, int size)
 {int *p;
 For(p= &array[0]; p< &array[size]; p=p+1) *p=0;}
87/90
两个版本的clear
 Move $t0, $zero
 Move $t0, $a0
 Loop1: sll $t1, $t0, 2
 All
 add $t2, $a0, $t1

 sw $zero, 0($t2)

 addi $t0, $t0, 1

 slt $t3, $t0, $a1

$t1, $a1,2
Add $t2, $a0, $t1
Loop2: sw $zero, 0($t0)
Addi $t0, $t0, 4
Slt $t3, $t0, $t2
Bne $t3, $zero, loop2
 Bne $t3, $zero, loop1

 每次循环中重复执行的指令减少了;不需要“乘”;
 相当于编译器中实现的强度削弱(用移位代替乘法)和循环变量消除
(减少循环中数组地址的计算)。
 以前大家用指针来获得比数组更优化的性能,但目前,编译器可以为
数组生成同样优秀的代码。所以,可以将繁重的工作留给编译器,以
得到更优的性能
88/90
注意:
 谬误:功能更强大的指令集意味着更高的性能
 谬误:使用汇编语言来获得最高的性能
 谬误:忘记在字节寻址的机器中,连续的字地
址并不相差1
 谬误:在自动变量的定义过程体外使用指向该
变量的指针
 课下阅读2.16
89/90
2.18 结论
 存储程序计算机的两个原则:程序使用和数字
没有区别的指令 和 使用可改变内容的M
 设计机器的指令集需要全面平衡执行程序所需
的指令数目、指令需要的时钟周期数和时钟速
度
 有4条设计原则指导指令集设计者:

简单来自于规整;越少越快;加速执行常用操
作;优秀的设计需要适当折中
 MIPS指令集中各指令的功能
90/90
作业
 2.4;
 2.19;
 2.29;
 2.30;
 2.49
 2.51
91/90