assembly - 为什么 MIPS 汇编器将 subi 转换为 2 条指令?

标签 assembly mips mars-simulator

我正在使用MARS (MIPS Assembly and Runtime Simulator) 4.5 ,它取代了伪指令

subi $sp, $sp, 4

具有两个指令序列:

addi $at, $zero, 0x00000004
sub $sp, $sp, $at

为什么不把它当作

addi $sp, $sp, -4

哪条指令是单条指令?

递减堆栈指针是一种常见的操作,很难相信汇编器的作者没有注意到这种低效率。

最佳答案

好吧,spim 没有 subi [您使用 sub 伪操作]。

mars 可以做得更好。也许应该提交错误报告?

但是,它的伪操作由一个文本文件控制:PseudoOps.txt,用于开发匹配/翻译表。因此,并非所有翻译(即使是简单的翻译)都是可能的。

来自该文件:

# Copyright (c) 2003-2010,  Pete Sanderson and Kenneth Vollmar
#
# Developed by Pete Sanderson (<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="dbaba8bab5bfbea9a8b4b59bb4afafbea9b9beb2b5f5bebfae" rel="noreferrer noopener nofollow">[email protected]</a>)
# and Kenneth Vollmar (<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="046f616a726b686869657644696d77776b71766d77706570612a616071" rel="noreferrer noopener nofollow">[email protected]</a>)
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject
# to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# (MIT license, http://www.opensource.org/licenses/mit-license.html)

# File containing definitions of MIPS pseudo-ops

# File format:
#   Each line contains specification for one pseudo-op, including optional description.
#   First item is source statement syntax, specified in same "example" parser format used for regular instructions.
#   Source statement specification ends with a tab.  It is followed by a tab-separated list of basic instruction
#   templates to complete and substitute for the pseudo-op.
#   Format for specifying syntax of templates is different from specifying syntax of source statement:
#      (n=0,1,2,3,...) is token position in source statement (operator is token 0, parentheses are tokens but commas aren't)
#      RGn means substitute register found in n'th token of source statement
#      NRn means substitute next higher register than the one in n'th token of source code
#      OPn means substitute n'th token of source code as is
#      LLn means substitute low order 16-bits from label address in source token n.
#      LLnU means substitute low order 16-bits (unsigned) from label address in source token n.
#      LLnPm (m=1,2,3,4) means substitute low order 16-bits from label address in source token n, after adding m.
#      LHn means substitute high order 16-bits from label address in source token n. Must add 1 if address bit 15 is 1.
#      LHnPm (m=1,2,3,4) means substitute high order 16-bits from label address in source token n, after adding m. Must then add 1 if bit 15 is 1.
#      VLn means substitute low order 16-bits from 32-bit value in source token n.
#      VLnU means substitute low order 16-bits (unsigned) from 32-bit value in source token n.
#      VLnPm (m=1,2,3,4) means substitute low order 16-bits from 32-bit value in source token n, after adding m to value.
#      VLnPmU (m=1,2,3,4) means substitute low order 16-bits(unsigned) from 32-bit value in source token n, after adding m to value.
#      VHLn means substitute high order 16-bits from 32-bit value in source token n.  Use this if later combined with low order 16-bits using "ori $1,$1,VLnU". See logical and branch operations.
#      VHn means substitute high order 16-bits from 32-bit value in source token n, then add 1 if value's bit 15 is 1.  Use this only if later instruction uses VLn($1) to calculate 32-bit address.  See loads and stores.
#      VHLnPm (m=1,2,3,4) means substitute high order 16-bits from 32-bit value in source token n, after adding m.  See VHLn.
#      VHnPm (m=1,2,3,4) means substitute high order 16-bits from 32-bit value in source token n, after adding m. Must then add 1 if bit 15 is 1. See VHn.
#      LLP is similar to LLn, but is needed for "label+100000" address offset. Immediate is added before taking low order 16.
#      LLPU is similar to LLn, but is needed for "label+100000" address offset. Immediate is added before taking low order 16 (unsigned).
#      LLPPm (m=1,2,3,4) is similar to LLP except m is added along with immediate before taking low order 16.
#      LHPA is similar to LHn, but is needed for "label+100000" address offset. Immediate is added before taking high order 16.
#      LHPN is similar to LHPA, used only by "la" instruction. Address resolved by "ori" so do not add 1 if bit 15 is 1.
#      LHPAPm (m=1,2,3,4) is similar to LHPA except value m is added along with immediate before taking high order 16.
#      LHL means substitute high order 16-bits from label address in token 2 of "la" (load address) source statement.
#      LAB means substitute textual label from last token of source statement.  Used for various branches.
#      S32 means substitute the result of subtracting the constant value in last token from 32.  Used by "ror", "rol".
#      DBNOP means Delayed Branching NOP - generate a "nop" instruction but only if delayed branching is enabled.  Added in 3.4.1 release.
#      BROFFnm means substitute n if delayed branching is NOT enabled otherwise substitute m.  n and m are single digit numbers indicating constant branch offset (in words).  Added in 3.4.1 release.
#      COMPACT is a marker to separate the default template from a second template optimized for 16-bit addresses.  See loads and stores having (data) label operands.
#   Everything else is copied as is into the generated statement (you must use register numbers not mnemonics)
#   The list of basic instruction templates is optionally followed a description of the instruction for help purposes.
#   To add optional description, append a tab then the '#' character followed immediately (no spaces) by the description.
#
#  See documentation for ExtendedInstruction.makeTemplateSubstitutions() for more details.
#
#  Matching for a given instruction mnemonic is first-fit not best-fit.  If an instruction has both 16 and 32-bit
#  immediate operand options, they should be listed in that order (16-bit version first).  Otherwise the 16-bit
#  version will never be matched since the 32-bit version fits small immediate values first.
#
#  The pseudo-op specification must start in the first column.  If first column is blank, the line will be skipped!
#
#  When specifying the example instruction (first item on line), the conventions I follow are:
#  - for a register operand, specify a numbered register (e.g. $t1 or $f1) to represent any register in the set.
#    The numerical value is not significant.  This is NOT the case when writing the templates that follow!
#    In the templates, numbered registers are parsed as is (use only $0 and $1, which are $zero and $at).
#  - for an immediate operand, specify a positive value indicative of the expected range.  I use 10 to represent
#    a 5 bit value, 100 to represent a 16-bit value, and 100000 to represent a 32-bit value.
#  - for a label operand, I use the string "label" (without the quotes).
#  The idea is to give the parser an example that will be parsed into the desired token sequence.  Syntax checking
#  is done by comparing the source token sequence to list of token sequences generated from the examples.
#  IMPORTANT NOTE:  The use of $t1,$t2, etc in the instruction sample means that any CPU register reference
#                   can be used in that position.  It is simply a placeholder.  By contrast, when
#                   $1 is used in the template specification, $1 ($at) is literally placed into the generated
#                   instruction!  If you want the generated code to echo the source register, use RG1,RG2, etc.

#######################  arithmetic and branch pseudo-ops #####################

not $t1,$t2 nor RG1, RG2, $0    #Bitwise NOT (bit inversion)

# Here are some "convenience" arithmetic pseduo-ops.  But do they encourage sloppy programming?
add $t1,$t2,-100    addi RG1, RG2, VL3  #ADDition : set $t1 to ($t2 plus 16-bit immediate)
add $t1,$t2,100000  lui $1, VHL3    ori $1, $1, VL3U    add RG1, RG2, $1    #ADDition : set $t1 to ($t2 plus 32-bit immediate)
addu $t1,$t2,100000 lui $1, VHL3    ori $1, $1, VL3U    addu RG1, RG2, $1   #ADDition Unsigned : set $t1 to ($t2 plus 32-bit immediate), no overflow
addi $t1,$t2,100000 lui $1, VHL3    ori $1, $1, VL3U    add RG1, RG2, $1    #ADDition Immediate : set $t1 to ($t2 plus 32-bit immediate)
addiu $t1,$t2,100000    lui $1, VHL3    ori $1, $1, VL3U    addu RG1, RG2, $1   #ADDition Immediate Unsigned: set $t1 to ($t2 plus 32-bit immediate), no overflow
sub $t1,$t2,-100        addi $1, $0, VL3    sub RG1, RG2, $1    #SUBtraction : set $t1 to ($t2 minus 16-bit immediate)
sub $t1,$t2,100000  lui $1, VHL3    ori $1, $1, VL3U    sub RG1, RG2, $1    #SUBtraction : set $t1 to ($t2 minus 32-bit immediate)
subu $t1,$t2,100000 lui $1, VHL3    ori $1, $1, VL3U    subu RG1, RG2, $1   #SUBtraction Unsigned : set $t1 to ($t2 minus 32-bit immediate), no overflow
subi $t1,$t2,-100       addi $1, $0, VL3    sub RG1, RG2, $1    #SUBtraction Immediate : set $t1 to ($t2 minus 16-bit immediate)
subi $t1,$t2,100000 lui $1, VHL3    ori $1, $1, VL3U    sub RG1, RG2, $1    #SUBtraction Immediate : set $t1 to ($t2 minus 32-bit immediate)
subiu $t1,$t2,100000    lui $1, VHL3    ori $1, $1, VL3U    subu RG1, RG2, $1   #SUBtraction Immediate Unsigned : set $t1 to ($t2 minus 32-bit immediate), no overflow
# feel free to add more convenience arithmetic pseduo-ops.

文件中不再有与 add/sub 相关的条目。

附注:在添加/减去地址时,应使用无符号版本来防止溢出(对于特殊可能) >$sp 值)

关于assembly - 为什么 MIPS 汇编器将 subi 转换为 2 条指令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40823152/

相关文章:

assembly - 如何计算跳转目标地址和分支目标地址?

assembly - MIPS "la"伪指令

assembly - MIPS I 如何在不停止的情况下处理上一条 ALU 指令的分支?

c - 是否严格要求汇编才能使 "lowest"成为操作系统的一部分?

assembly - 在 MIPS 中编写带有全局变量的函数?

MIPS:带分支的无限循环

assembly - 无效的程序计数器值 : 0

linux - 为什么我无法在 NASM 程序集中打印用户输入的数据?

assembly - 最佳解决方案: add or addu

loops - while 循环对汇编代码有 2 个条件