为什么 MIPS 汇编程序将 subi 转换为 2 条指令?
Why does a MIPS assembler convert subi into 2 instructions?
我正在使用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
用于开发 match/translation table。因此,并非所有翻译 [即使是简单的翻译] 都是可能的。
来自该文件:
# Copyright (c) 2003-2010, Pete Sanderson and Kenneth Vollmar
#
# Developed by Pete Sanderson (psanderson@otterbein.edu)
# and Kenneth Vollmar (kenvollmar@missouristate.edu)
#
# 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 ,,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() 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 [=10=] and , 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
# is used in the template specification, ($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, [=10=] #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 , VHL3 ori , , VL3U add RG1, RG2, #ADDition : set $t1 to ($t2 plus 32-bit immediate)
addu $t1,$t2,100000 lui , VHL3 ori , , VL3U addu RG1, RG2, #ADDition Unsigned : set $t1 to ($t2 plus 32-bit immediate), no overflow
addi $t1,$t2,100000 lui , VHL3 ori , , VL3U add RG1, RG2, #ADDition Immediate : set $t1 to ($t2 plus 32-bit immediate)
addiu $t1,$t2,100000 lui , VHL3 ori , , VL3U addu RG1, RG2, #ADDition Immediate Unsigned: set $t1 to ($t2 plus 32-bit immediate), no overflow
sub $t1,$t2,-100 addi , [=10=], VL3 sub RG1, RG2, #SUBtraction : set $t1 to ($t2 minus 16-bit immediate)
sub $t1,$t2,100000 lui , VHL3 ori , , VL3U sub RG1, RG2, #SUBtraction : set $t1 to ($t2 minus 32-bit immediate)
subu $t1,$t2,100000 lui , VHL3 ori , , VL3U subu RG1, RG2, #SUBtraction Unsigned : set $t1 to ($t2 minus 32-bit immediate), no overflow
subi $t1,$t2,-100 addi , [=10=], VL3 sub RG1, RG2, #SUBtraction Immediate : set $t1 to ($t2 minus 16-bit immediate)
subi $t1,$t2,100000 lui , VHL3 ori , , VL3U sub RG1, RG2, #SUBtraction Immediate : set $t1 to ($t2 minus 32-bit immediate)
subiu $t1,$t2,100000 lui , VHL3 ori , , VL3U subu RG1, RG2, #SUBtraction Immediate Unsigned : set $t1 to ($t2 minus 32-bit immediate), no overflow
# feel free to add more convenience arithmetic pseduo-ops.
文件中没有更多与 add/sub
相关的条目。
旁注: 当 adding/subtracting 地址时,应该使用 unsigned 版本来防止溢出(是可能用于特殊的$sp
值)
我正在使用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
用于开发 match/translation table。因此,并非所有翻译 [即使是简单的翻译] 都是可能的。
来自该文件:
# Copyright (c) 2003-2010, Pete Sanderson and Kenneth Vollmar
#
# Developed by Pete Sanderson (psanderson@otterbein.edu)
# and Kenneth Vollmar (kenvollmar@missouristate.edu)
#
# 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 ,,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() 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 [=10=] and , 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
# is used in the template specification, ($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, [=10=] #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 , VHL3 ori , , VL3U add RG1, RG2, #ADDition : set $t1 to ($t2 plus 32-bit immediate)
addu $t1,$t2,100000 lui , VHL3 ori , , VL3U addu RG1, RG2, #ADDition Unsigned : set $t1 to ($t2 plus 32-bit immediate), no overflow
addi $t1,$t2,100000 lui , VHL3 ori , , VL3U add RG1, RG2, #ADDition Immediate : set $t1 to ($t2 plus 32-bit immediate)
addiu $t1,$t2,100000 lui , VHL3 ori , , VL3U addu RG1, RG2, #ADDition Immediate Unsigned: set $t1 to ($t2 plus 32-bit immediate), no overflow
sub $t1,$t2,-100 addi , [=10=], VL3 sub RG1, RG2, #SUBtraction : set $t1 to ($t2 minus 16-bit immediate)
sub $t1,$t2,100000 lui , VHL3 ori , , VL3U sub RG1, RG2, #SUBtraction : set $t1 to ($t2 minus 32-bit immediate)
subu $t1,$t2,100000 lui , VHL3 ori , , VL3U subu RG1, RG2, #SUBtraction Unsigned : set $t1 to ($t2 minus 32-bit immediate), no overflow
subi $t1,$t2,-100 addi , [=10=], VL3 sub RG1, RG2, #SUBtraction Immediate : set $t1 to ($t2 minus 16-bit immediate)
subi $t1,$t2,100000 lui , VHL3 ori , , VL3U sub RG1, RG2, #SUBtraction Immediate : set $t1 to ($t2 minus 32-bit immediate)
subiu $t1,$t2,100000 lui , VHL3 ori , , VL3U subu RG1, RG2, #SUBtraction Immediate Unsigned : set $t1 to ($t2 minus 32-bit immediate), no overflow
# feel free to add more convenience arithmetic pseduo-ops.
文件中没有更多与 add/sub
相关的条目。
旁注: 当 adding/subtracting 地址时,应该使用 unsigned 版本来防止溢出(是可能用于特殊的$sp
值)