【MIPS】经典指令块集锦
Directives声明变量值存储
容易将数据段地址和地址上的内容搞混
.data
fibs: .space 48 # allocate 12 * 4 = 48 Byte memory, store first address in label "fibs"
size: .word 12 # allocate 1 Byte(a word) for 12, store address in label "size"
.text # want to load the value of "size" (12) to $t5
la $t5, size # 1. load the address of "size" to $t5, for we could only use the label
lw $t5, 0($t5) # 2. load the value of "size" to $t5
需厘清:寄存器编号(地址);寄存器值;内存地址;内存段值
程序操纵寄存器,寄存器操纵内存地址
表示地址:1.立即数(+标签) 2.寄存器取值
二维数组使用
标准
Arr: .space 800
.macro getindex(%ans, %i, %j, %rank) # for Arr[][rank]
mult %i, %rank
mflo %ans
add %ans, %ans, %j
sll %ans, %ans, 2
.end_macro
.text
li $t0, 4
li $t1, 0
li $t2, 8
getindex($t3, $t0, $t1, $t2)
lw $s0, Arr($t3) # load Arr[4][0] to $s0
sw $s0, Arr($t3) # store $s0 to Arr[4][0]
一些存储带来的简化
.data
Arr: .space 800 # Arr[25][8]: 25 * 8 * 4Byte
# cols最好用2的幂,方便sll操作,不用mult
.macro getindex_8(%ans, %i, %j) # calculate (i*8+j)*4
sll %ans, %i, 3 # i << 3
add %ans, %ans, %j
sll %ansm %ans, 2
.end_macro
# never manipulate the value of %i, %j , which prevent the risk of mischanging other registers when using the macro
# thus "getindex($t0, $t1, $t1)" is safe to both the result and $t1
# 模块化维护某些规范,便无需在其他地方多虑。寄存器使用惯例、函数栈的意义在此。
这里将标签的首地址立即数直接作为offset,将感觉上的偏移作为base,效果不错。
不过是不是还得小心位数,address:32bit 而 offset:16bit ?是只传了低 16bit 吗
循环
for循环 for(int i=0;i<n;++i)
li $t0, 0 # int i=0 ($s0 store the value of n)
for_i_begin:
slt $t1, $t0, $s0 # i < n ? 1 : 0 can be changed to other comparing instruction
beqz $t1, for_i_end # ATTENTION: please match the comparing instruction , easy to mix up
# other instruction
addi $t0, $t0, 1 # ++i
j for_i_begin # continue loop
for_i_end:
函数调用
约定,类似
$t0
、$t1
等寄存器记作$t
所谓$t
由父函数维护,$s
由子函数维护。
($s
为正当的“存储寄存器”,因而当前父函数中不应操心,由其内部子函数维护该寄存器存储的效果;$t
为正当的“临时寄存器”,本不应该存储数据,因而子函数不应操心可以随便用,若想要存储则应由当前父函数自己操心)
- 预处理
.data
栈空间申请$sp
指向栈顶
- 父函数调用子函数
- 若有需要维护的变量,应事先在函数头处分为该父函数分配栈帧
- 传出参数: 在
$a0
、$a1
等寄存器(称为$a
,后同)处加载需传出的数据 - 维护变量-前: 考虑该父函数中需要保留的
$t
、$ra
等寄存器,逐条载入栈帧中 - 调用函数:
jal function
- 维护变量-后: 将之前于栈帧中存好的数据逐条载回
$ra
、$t
等寄存器 - 接收返回值: 从
$v
中取回传回的数据
- 子函数被调用
- 根据函数所需,为该子函数分配栈帧
- 维护变量-前: 考虑需要用到的
$s
寄存器,逐条载入栈帧中 - 取出传入参数: 将
$a
中传入的参数存到自己需要的地方 - 子函数内容
- 传回返回值: 将返回值载入
$v
- 维护变量-后: 将之前于栈帧中存好的数据逐条载回
$t
寄存器
示例:调用int son_function(int i,int j){}
.data
stack: .space 300
.text
la $sp, stack
addiu $sp, $sp, 300
# ......
father_function:
addiu $sp, $sp, -12
# using registers for operation
# registers $s0, $s1 are used to store partial variables
# registers $t0, $t1 are still not used up
move $a0, $t2
move $a1, $t3
sw $t1, 8($sp)
sw $t0, 4($sp)
sw $ra, 0($sp) # not necessary, depending on son_function
jal son_funtion
lw $ra, 0($sp)
lw $t0, 4($sp)
lw $t1, 8($sp)
addiu $sp, $sp, 12
jr $ra
# in son_function,
son_function:
addiu $sp, $sp, -8
sw $s1, 4
sw $s0, 0
move $t0, $a0
move $t1, $a1
# using registers for operation
# finally get return_value in $s1
# suppose no other function calling -- leaf function.
# (needn't have saved $ra in father function, just lazy to delete)
move $v0, $s1
lw $s0, 0
lw $s1, 4
addiu $sp, $sp, 8
jr $ra
跳转条件判断
比较跳转指令
bgt $t0, $t1, label
/bgt $t0, 100, label
均可,第二个可为reg、16位imm、32位imm
指令 | 跳转条件 | 拆分 |
---|---|---|
bgt |
> | slt +bne |
bge |
>= | slt +beq |
blt |
< | |
ble |
<= | |
beq |
== | / |
bne |
!= | / |
指令后加z
便是将$t1
变为0
跳转条件书写
if(exp)
1.顺逻辑
slt
sle
sgt
sge
判断exp
真值;beqz
bnez
根据真值是否为零决定跳转。
跳转伪指令(pseudo instruction)多半会按这种形式拆分成基础指令,标准的逻辑思路。注意sle
sge
一般会转化为slt
+ori
+subu
之类的,指令效率低,建议换
2.反逻辑
直接使用bgt
bge
blt
ble
判断!exp
真值,真了就跳转。
清爽很多,虽然指令效率和上面一样。同样少用bge
和ble
,通过反向来消除等号
复合条件
就是短路逻辑,感觉复杂了也挺繁琐的。
增添set_1:
set_0:
标签来完成短路跳转好像还不错。
具体规律遇到再说。
常见Pseudo Instruction分解
【MIPS】经典指令块集锦的更多相关文章
- July-程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大经典原创系列集锦与总结
程序员面试.算法研究.编程艺术.红黑树.数据挖掘5大经典原创系列集锦与总结 http://blog.csdn.net/v_july_v/article/details/6543438
- 计算机系统6-> 计组与体系结构3 | MIPS指令集(中)| MIPS汇编指令与机器表示
上一篇计算机系统5-> 计组与体系结构2 | MIPS指令集(上)| 指令系统从顶层讲解了一个指令集 / 指令系统应当具备哪些特征和工作原理.这一篇就聚焦MIPS指令集(MIPS32),看看其汇 ...
- Nginx 的 Location 配置指令块
最近一段时间在学习 Nginx ,以前一直对 Nginx 的 Location 配置很头大,最近终于弄出点眉目.总结如下:nginx 配置文件,自下到上分为三种层次分明的结构: | http b ...
- 面试经典算法题集锦——《剑指 offer》小结
从今年 3 月份开始准备找实习,到现在校招结束,申请的工作均为机器学习/数据挖掘算法相关职位,也拿到了几个 sp offer.经历这半年的洗礼,自己的综合能力和素质都得到了一个质的提升. 实话说对于未 ...
- 关于MVC4中EFCoderFirst 数据迁移的三句经典指令
首先输入这句指令 enable-migrations -contexttypename SchoolContext ---------(SchoolContext为你设置的数据库名)它会自动 ...
- [札记]IL经典指令解析之方法调度
call.callvirt和calli指令用于完成方法调用,有何区别呢? 1)call使用静态调度,也就是根据引用类型的静态类型来调度方法.call指令根据引用变量的类型来调用方法,因此通常用于调用非 ...
- MIPS 汇编指令学习
MIPS 寄存器 MIPS comes with 32 general purpose registers named $0. . . $31Registers also have symbolic ...
- Angular.js实现折叠按钮的经典指令.
var expanderModule=angular.module('expanderModule',[]) expanderModule.directive('expander',function( ...
- SqlServer教程:经典SQL语句集锦
SQL分类: DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE) DML—数据操纵语言(SELECT,DELETE,UPDATE,INSERT) DCL—数据控制语言(GRAN ...
- 经典SQL语句集锦
下列语句部分是MsSql语句,不可以在access中使用. SQL分类: DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE) DML—数据操纵语言(SELECT,DELET ...
随机推荐
- 关于Java的UUID
UUID或者UNID或者UID,是一个统一唯一标识,可以用来标记文档.数据或其它需要唯一标识的东西.Java 5.0内置UUID的实现,见java.util.UUID. 下面代码是找到的2种实现方式, ...
- win10家庭版升级到专业版密钥
J7QT3-3GCPG-9GVWT-CH2XR-GMRJM
- Java Function 接口用法
Java 8 中 Function 接口的介绍 Java 8 中提供了一个函数式接口 Function,这个接口表示对一个参数做一些操作然后返回操作之后的值.这个接口的有一个抽象方法 apply,这个 ...
- Unity 3D简单使用C#脚本,脚本的执行顺序
Unity3D脚本间执行顺序 Unity3D中一个场景有时候需要多个脚本,可以挂在同一物体上执行,也可以挂在不同物体上执行 那么执行顺序是怎样的?我们来测试下 在上个项目基础上,再建一个Test2脚本 ...
- composer [ErrorException] Undefined index: process
执行了升级composer self-update导致了 降级处理 composer self-update --1 composer install
- 使用postgis数据库进行多边形裁切线
背景:有一份polyline的基础数据,有一个多边形,求出多边形内的所有polyline PostGIS参考手册: http://postgis.net/docs/reference.html 1.p ...
- AQS源码深度剖析,大厂面试必看!
AQS(AbstractQueuedSynchronizer)是Java众多锁以及并发工具的基础类,底层采用乐观锁,大量采用CAS操作保证其原子性,并且在并发冲突时,采用自旋方法重试.实现了轻量高效的 ...
- 多方安全计算(3):MPC万能钥匙-混淆电路
学习&转载文章:多方安全计算(3):MPC万能钥匙-混淆电路 前言 我们在讲解不经意传输(Oblivious Transfer,OT)的文章(安全多方计算(1):不经意传输协议)中提到,利用n ...
- stdio.h的缓冲机制解析
1. 令人迷惑的printf() 在C语言中,由于stdio.h中的缓冲机制,printf的输出通常会受到缓冲区的影响. 这种影响可能非常微妙,并常常令人疑惑,比如我们来看下面这段代码 #includ ...
- 【异步编程实战】如何实现超时功能(以CompletableFuture为例)
[异步编程实战]如何实现超时功能(以CompletableFuture为例) 由于网络波动或者连接节点下线等种种问题,对于大多数网络异步任务的执行通常会进行超时限制,在异步编程中是一个常见的问题.本文 ...