mirror of
https://github.com/decompme/decomp.me.git
synced 2026-02-22 14:29:18 -06:00
Subrepo update (#564)
* git subrepo pull backend/asm_differ subrepo: subdir: "backend/asm_differ" merged: "aad7f7d" upstream: origin: "https://github.com/simonlindholm/asm-differ" branch: "main" commit: "aad7f7d" git-subrepo: version: "0.4.5" origin: "https://github.com/Homebrew/brew" commit: "fb52a1214" * git subrepo pull (merge) backend/m2c subrepo: subdir: "backend/m2c" merged: "9809df2" upstream: origin: "https://github.com/matt-kempster/mips_to_c" branch: "master" commit: "0927f17" git-subrepo: version: "0.4.5" origin: "https://github.com/Homebrew/brew" commit: "fb52a1214" * Attempt to fix download URL
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/simonlindholm/asm-differ
|
||||
branch = main
|
||||
commit = 516595687dd8d9b3dd409f263269a973c38b96ea
|
||||
parent = b026a2ef101e56137870e0ee91e527475f55db62
|
||||
commit = aad7f7d1517517f55817fda1ce4728d8a406d099
|
||||
parent = 822278a57bd2ab6ee8f8aa1f97d88aaa783e2b93
|
||||
method = merge
|
||||
cmdver = 0.4.3
|
||||
cmdver = 0.4.5
|
||||
|
||||
36
backend/asm_differ/diff.py
generated
36
backend/asm_differ/diff.py
generated
@@ -1591,6 +1591,10 @@ class AsmProcessorPPC(AsmProcessor):
|
||||
class AsmProcessorARM32(AsmProcessor):
|
||||
def process_reloc(self, row: str, prev: str) -> Tuple[str, Optional[str]]:
|
||||
arch = self.config.arch
|
||||
if "R_ARM_V4BX" in row:
|
||||
# R_ARM_V4BX converts "bx <reg>" to "mov pc,<reg>" for some targets.
|
||||
# Ignore for now.
|
||||
return prev, None
|
||||
if "R_ARM_ABS32" in row and not prev.startswith(".word"):
|
||||
# Don't crash on R_ARM_ABS32 relocations incorrectly applied to code.
|
||||
# (We may want to do something more fancy here that actually shows the
|
||||
@@ -1739,7 +1743,6 @@ class ArchSettings:
|
||||
re_reloc: Pattern[str]
|
||||
branch_instructions: Set[str]
|
||||
instructions_with_address_immediates: Set[str]
|
||||
jump_instructions: Set[str] = field(default_factory=set)
|
||||
forbidden: Set[str] = field(default_factory=lambda: set(string.ascii_letters + "_"))
|
||||
arch_flags: List[str] = field(default_factory=list)
|
||||
branch_likely_instructions: Set[str] = field(default_factory=set)
|
||||
@@ -1776,18 +1779,6 @@ MIPS_BRANCH_INSTRUCTIONS = MIPS_BRANCH_LIKELY_INSTRUCTIONS.union(
|
||||
}
|
||||
)
|
||||
|
||||
MIPS_JUMP_ADDR_INSTRUCTIONS = {
|
||||
"jal",
|
||||
"j",
|
||||
}
|
||||
MIPS_JUMP_REG_INSTRUCTIONS = {
|
||||
"jalr",
|
||||
"jr",
|
||||
}
|
||||
MIPS_JUMP_INSTRUCTIONS = set.union(
|
||||
MIPS_JUMP_ADDR_INSTRUCTIONS, MIPS_JUMP_REG_INSTRUCTIONS
|
||||
)
|
||||
|
||||
ARM32_PREFIXES = {"b", "bl"}
|
||||
ARM32_CONDS = {
|
||||
"",
|
||||
@@ -1946,16 +1937,15 @@ MIPS_SETTINGS = ArchSettings(
|
||||
re_reg=re.compile(r"\$?\b([astv][0-9]|at|f[astv]?[0-9]+f?|kt?[01]|fp|ra|zero)\b"),
|
||||
re_sprel=re.compile(r"(?<=,)([0-9]+|0x[0-9a-f]+)\(sp\)"),
|
||||
re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"),
|
||||
re_imm=re.compile(r"(\b|-)([0-9]+|0x[0-9a-fA-F]+)\b(?!\(sp)|%(lo|hi)\([^)]*\)"),
|
||||
re_imm=re.compile(
|
||||
r"(\b|-)([0-9]+|0x[0-9a-fA-F]+)\b(?!\(sp)|%(lo|hi|got|gp_rel|call16)\([^)]*\)"
|
||||
),
|
||||
re_reloc=re.compile(r"R_MIPS_"),
|
||||
arch_flags=["-m", "mips:4300"],
|
||||
branch_likely_instructions=MIPS_BRANCH_LIKELY_INSTRUCTIONS,
|
||||
branch_instructions=MIPS_BRANCH_INSTRUCTIONS,
|
||||
jump_instructions=MIPS_JUMP_INSTRUCTIONS,
|
||||
instructions_with_address_immediates=set.union(
|
||||
MIPS_BRANCH_INSTRUCTIONS, MIPS_JUMP_ADDR_INSTRUCTIONS
|
||||
),
|
||||
delay_slot_instructions=set.union(MIPS_BRANCH_INSTRUCTIONS, MIPS_JUMP_INSTRUCTIONS),
|
||||
instructions_with_address_immediates=MIPS_BRANCH_INSTRUCTIONS.union({"j", "jal"}),
|
||||
delay_slot_instructions=MIPS_BRANCH_INSTRUCTIONS.union({"j", "jal", "jr", "jalr"}),
|
||||
proc=AsmProcessorMIPS,
|
||||
)
|
||||
|
||||
@@ -2307,7 +2297,9 @@ def process(dump: str, config: Config) -> List[Line]:
|
||||
row = normalize_imms(row, arch)
|
||||
|
||||
branch_target = None
|
||||
if mnemonic in arch.branch_instructions or is_text_relative_j:
|
||||
if (
|
||||
mnemonic in arch.branch_instructions or is_text_relative_j
|
||||
) and symbol is None:
|
||||
x86_longjmp = re.search(r"\*(.*)\(", args)
|
||||
if x86_longjmp:
|
||||
capture = x86_longjmp.group(1)
|
||||
@@ -2501,8 +2493,8 @@ def diff_sameline(
|
||||
else:
|
||||
# If the last field has a parenthesis suffix, e.g. "0x38(r7)"
|
||||
# we split that part out to make it a separate field
|
||||
# however, we don't split if it has a proceeding %hi/%lo e.g."%lo(.data)" or "%hi(.rodata + 0x10)"
|
||||
re_paren = re.compile(r"(?<!%hi)(?<!%lo)\(")
|
||||
# however, we don't split if it has a proceeding % macro, e.g. "%lo(.data)"
|
||||
re_paren = re.compile(r"(?<!%hi)(?<!%lo)(?<!%got)(?<!%call16)(?<!%gp_rel)\(")
|
||||
oldfields = oldfields[:-1] + re_paren.split(oldfields[-1])
|
||||
newfields = newfields[:-1] + re_paren.split(newfields[-1])
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ def download_n64():
|
||||
print(f"ido{version} already exists, skipping")
|
||||
else:
|
||||
download_tar(
|
||||
url=f"https://github.com/ethteck/ido-static-recomp/releases/download/master/ido-{version}-recomp-{host_os.ido_os}-latest.tar.gz",
|
||||
url=f"https://github.com/ethteck/ido-static-recomp/releases/download/v0.0/ido-{version}-recomp-{host_os.ido_os}-latest.tar.gz",
|
||||
dest_name=f"ido{version}",
|
||||
)
|
||||
# SN
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/matt-kempster/mips_to_c
|
||||
branch = master
|
||||
commit = a2802673e58482940990f668fdd01cab20360974
|
||||
commit = 0927f17aac197848d4ebdf0c6bbad74b01f0851c
|
||||
parent = 79adcdac2f60b87a955788b461d7b32819668392
|
||||
method = merge
|
||||
cmdver = 0.4.3
|
||||
cmdver = 0.4.5
|
||||
|
||||
@@ -36,4 +36,8 @@ typedef s64 M2C_UNK64;
|
||||
/* Carry bit from partially-implemented instructions */
|
||||
#define M2C_CARRY 0
|
||||
|
||||
/* Memcpy patterns */
|
||||
#define M2C_MEMCPY_ALIGNED memcpy
|
||||
#define M2C_MEMCPY_UNALIGNED memcpy
|
||||
|
||||
#endif
|
||||
|
||||
224
backend/m2c/src/arch_mips.py
generated
224
backend/m2c/src/arch_mips.py
generated
@@ -12,6 +12,7 @@ from typing import (
|
||||
|
||||
from .error import DecompFailure
|
||||
from .options import Target
|
||||
from .asm_file import Label
|
||||
from .asm_instruction import (
|
||||
Argument,
|
||||
AsmAddressMode,
|
||||
@@ -32,6 +33,7 @@ from .asm_pattern import (
|
||||
AsmMatch,
|
||||
AsmMatcher,
|
||||
AsmPattern,
|
||||
Pattern,
|
||||
Replacement,
|
||||
SimpleAsmPattern,
|
||||
make_pattern,
|
||||
@@ -83,6 +85,7 @@ from .evaluate import (
|
||||
handle_conditional_move,
|
||||
handle_convert,
|
||||
handle_la,
|
||||
handle_lw,
|
||||
handle_load,
|
||||
handle_lwl,
|
||||
handle_lwr,
|
||||
@@ -469,6 +472,211 @@ class TrapuvPattern(SimpleAsmPattern):
|
||||
return Replacement([m.body[2], new_instr], len(m.body))
|
||||
|
||||
|
||||
class SetGpPattern(AsmPattern):
|
||||
"""Strip PIC .cpload pattern at the top of functions."""
|
||||
|
||||
pattern = make_pattern(
|
||||
"*",
|
||||
"addiu $gp, $gp, _",
|
||||
"addu $gp, $gp, $t9",
|
||||
)
|
||||
|
||||
def match(self, matcher: AsmMatcher) -> Optional[Replacement]:
|
||||
if matcher.index != 0:
|
||||
return None
|
||||
m = matcher.try_match(self.pattern)
|
||||
if m is None:
|
||||
return None
|
||||
nop = AsmInstruction("nop", [])
|
||||
return Replacement([nop], len(m.body))
|
||||
|
||||
|
||||
class MemcpyPatternBase(AsmPattern):
|
||||
"""IDO unrolled memcpy, used e.g. for struct copies. Slightly different patterns
|
||||
are used for -mips1 vs -mips2, and for >=4 vs <4 byte alignment."""
|
||||
|
||||
pattern_mips1: Pattern
|
||||
pattern_mips2: Pattern
|
||||
epilogue1: Pattern
|
||||
epilogue2: Pattern
|
||||
instruction_name: str
|
||||
|
||||
def match(self, matcher: AsmMatcher) -> Optional[Replacement]:
|
||||
for pattern in (self.pattern_mips1, self.pattern_mips2):
|
||||
m = matcher.try_match(pattern)
|
||||
if m:
|
||||
break
|
||||
else:
|
||||
return None
|
||||
|
||||
# Find length by searching backwards for an "addiu $e, $x, ..." where
|
||||
# $x = $i or there's a "move $i, $x".
|
||||
length: Optional[int] = None
|
||||
e_src: Optional[Instruction] = None
|
||||
i_src: Optional[Instruction] = None
|
||||
for i in range(matcher.index - 1, -1, -1):
|
||||
item = matcher.input[i]
|
||||
if isinstance(item, Label):
|
||||
break
|
||||
if not i_src and m.regs["i"] in item.outputs:
|
||||
i_src = item
|
||||
if not e_src and m.regs["e"] in item.outputs:
|
||||
e_src = item
|
||||
if e_src is None or e_src.mnemonic != "addiu":
|
||||
return None
|
||||
if e_src.args[1] != m.regs["i"] and (
|
||||
i_src is None or i_src.mnemonic != "move" or i_src.args[1] != e_src.args[1]
|
||||
):
|
||||
return None
|
||||
assert isinstance(e_src.args[2], AsmLiteral)
|
||||
length = e_src.args[2].value
|
||||
|
||||
# Extend the pattern to include additional bytes copied when the total size
|
||||
# isn't a multiple of three. (This doesn't really work well at the moment,
|
||||
# see the comment in AlignedMemcpyPattern...)
|
||||
added_length = length
|
||||
m2 = matcher.try_match(pattern + self.epilogue1)
|
||||
if m2:
|
||||
m = m2
|
||||
length += 4
|
||||
m3 = matcher.try_match(pattern + self.epilogue1 + self.epilogue2)
|
||||
if m3:
|
||||
m = m3
|
||||
length += 4
|
||||
|
||||
from_reg = Register("from")
|
||||
to_reg = Register("to")
|
||||
from_offset = AsmLiteral(m.literals["N"])
|
||||
to_offset = AsmLiteral(m.literals["M"])
|
||||
added_len_arg = AsmLiteral(added_length)
|
||||
len_arg = AsmLiteral(length)
|
||||
return Replacement(
|
||||
[
|
||||
m.body[0],
|
||||
AsmInstruction("addiu", [from_reg, m.regs["i"], from_offset]),
|
||||
AsmInstruction("addiu", [to_reg, m.regs["o"], to_offset]),
|
||||
AsmInstruction(self.instruction_name, [to_reg, from_reg, len_arg]),
|
||||
AsmInstruction("addiu", [m.regs["o"], m.regs["o"], added_len_arg]),
|
||||
AsmInstruction("addiu", [m.regs["i"], m.regs["i"], added_len_arg]),
|
||||
]
|
||||
+ list(m.wildcard_items)
|
||||
+ [AsmInstruction("nop", [])],
|
||||
len(m.body),
|
||||
)
|
||||
|
||||
|
||||
class AlignedMemcpyPattern(MemcpyPatternBase):
|
||||
pattern_mips1 = make_pattern(
|
||||
".loop:",
|
||||
"lw $a, N($i)",
|
||||
"addiu $i, $i, 12",
|
||||
"sw $a, M($o)",
|
||||
"lw $b, (N-8)($i)",
|
||||
"addiu $o, $o, 12",
|
||||
"sw $b, (M-8)($o)",
|
||||
"lw $c, (N-4)($i)",
|
||||
"bne $i, $e, .loop",
|
||||
"sw $c, (M-4)($o)",
|
||||
)
|
||||
pattern_mips2 = make_pattern(
|
||||
".loop:",
|
||||
"lw $a, N($i)",
|
||||
"addiu $i, $i, 12",
|
||||
"addiu $o, $o, 12",
|
||||
"sw $a, MM($o)",
|
||||
".eq M, MM+12",
|
||||
"lw $b, (N-8)($i)",
|
||||
"sw $b, (M-8)($o)",
|
||||
"lw $c, (N-4)($i)",
|
||||
"bne $i, $e, .loop",
|
||||
"sw $c, (M-4)($o)",
|
||||
)
|
||||
# TODO: the * should not be there on -mips2, and the very last instruction can be
|
||||
# reordered to be further down. (Luckily the effects of failing to capture this is
|
||||
# just an extra word copy after the memcpy.)
|
||||
epilogue1 = make_pattern(
|
||||
"lw $x, N($i)",
|
||||
"*",
|
||||
"sw $x, M($o)",
|
||||
)
|
||||
epilogue2 = make_pattern(
|
||||
"lw $y, (N+4)($i)",
|
||||
"*",
|
||||
"sw $y, (M+4)($o)",
|
||||
)
|
||||
instruction_name = "memcpy.aligned.fictive"
|
||||
|
||||
|
||||
class UnalignedMemcpyPattern(MemcpyPatternBase):
|
||||
pattern_mips1 = make_pattern(
|
||||
".loop:",
|
||||
"lwl $a, N($i)",
|
||||
"lwr $a, (N+3)($i)",
|
||||
"addiu $i, $i, 12",
|
||||
"swl $a, M($o)",
|
||||
"swr $a, (M+3)($o)",
|
||||
"lwl $b, (N-8)($i)",
|
||||
"lwr $b, (N-5)($i)",
|
||||
"addiu $o, $o, 12",
|
||||
"swl $b, (M-8)($o)",
|
||||
"swr $b, (M-5)($o)",
|
||||
"lwl $c, (N-4)($i)",
|
||||
"lwr $c, (N-1)($i)",
|
||||
"nop",
|
||||
"swl $c, (M-4)($o)",
|
||||
"bne $i, $e, .loop",
|
||||
"swr $c, (M-1)($o)",
|
||||
)
|
||||
pattern_mips2 = make_pattern(
|
||||
".loop:",
|
||||
"lwl $a, N($i)",
|
||||
"lwr $a, (N+3)($i)",
|
||||
"addiu $i, $i, 12",
|
||||
"addiu $o, $o, 12",
|
||||
"swl $a, MM($o)",
|
||||
".eq M, MM+12",
|
||||
"swr $a, (M-9)($o)",
|
||||
"lwl $b, (N-8)($i)",
|
||||
"lwr $b, (N-5)($i)",
|
||||
"swl $b, (M-8)($o)",
|
||||
"swr $b, (M-5)($o)",
|
||||
"lwl $c, (N-4)($i)",
|
||||
"lwr $c, (N-1)($i)",
|
||||
"swl $c, (M-4)($o)",
|
||||
"bne $i, $e, .loop",
|
||||
"swr $c, (M-1)($o)",
|
||||
)
|
||||
epilogue1 = make_pattern(
|
||||
"lwl $x, N($i)",
|
||||
"lwr $x, (N+3)($i)",
|
||||
"*",
|
||||
"swl $x, M($o)",
|
||||
"swr $x, (M+3)($o)",
|
||||
)
|
||||
epilogue2 = make_pattern(
|
||||
"lwl $y, (N+4)($i)",
|
||||
"lwr $y, (N+7)($i)",
|
||||
"*",
|
||||
"swl $y, (M+4)($o)",
|
||||
"swr $y, (M+7)($o)",
|
||||
)
|
||||
instruction_name = "memcpy.unaligned.fictive"
|
||||
|
||||
|
||||
class GpJumpPattern(SimpleAsmPattern):
|
||||
"""Remove additions of $gp used for position-independent jump tables. It's
|
||||
possible that this could be done for all additions of $gp, not just jumps,
|
||||
but we are conservative for now."""
|
||||
|
||||
pattern = make_pattern(
|
||||
"addu $x, $x, $gp",
|
||||
"jr $x",
|
||||
)
|
||||
|
||||
def replace(self, m: AsmMatch) -> Replacement:
|
||||
return Replacement([m.body[1]], len(m.body))
|
||||
|
||||
|
||||
class MipsArch(Arch):
|
||||
arch = Target.ArchEnum.MIPS
|
||||
|
||||
@@ -680,7 +888,7 @@ class MipsArch(Arch):
|
||||
clobbers: List[Location] = []
|
||||
outputs: List[Location] = []
|
||||
jump_target: Optional[Union[JumpTarget, Register]] = None
|
||||
function_target: Optional[Union[AsmGlobalSymbol, Register]] = None
|
||||
function_target: Optional[Argument] = None
|
||||
has_delay_slot = False
|
||||
is_branch_likely = False
|
||||
is_conditional = False
|
||||
@@ -732,7 +940,7 @@ class MipsArch(Arch):
|
||||
eval_fn = lambda s, a: s.set_switch_expr(a.reg(0))
|
||||
elif mnemonic == "jal" or mnemonic == "bal":
|
||||
# Function call to label
|
||||
assert len(args) == 1 and isinstance(args[0], AsmGlobalSymbol)
|
||||
assert len(args) == 1
|
||||
inputs = list(cls.argument_regs)
|
||||
outputs = list(cls.all_return_regs)
|
||||
clobbers = list(cls.temp_regs)
|
||||
@@ -1021,6 +1229,10 @@ class MipsArch(Arch):
|
||||
Mips1DoubleLoadStorePattern(),
|
||||
GccSqrtPattern(),
|
||||
TrapuvPattern(),
|
||||
SetGpPattern(),
|
||||
AlignedMemcpyPattern(),
|
||||
UnalignedMemcpyPattern(),
|
||||
GpJumpPattern(),
|
||||
]
|
||||
|
||||
instrs_ignore: Set[str] = {
|
||||
@@ -1099,6 +1311,12 @@ class MipsArch(Arch):
|
||||
),
|
||||
"sync": lambda a: void_fn_op("M2C_SYNC", []),
|
||||
"trapuv.fictive": lambda a: CommentStmt("code compiled with -trapuv"),
|
||||
"memcpy.aligned.fictive": lambda a: void_fn_op(
|
||||
"M2C_MEMCPY_ALIGNED", [a.reg(0), a.reg(1), a.imm(2)]
|
||||
),
|
||||
"memcpy.unaligned.fictive": lambda a: void_fn_op(
|
||||
"M2C_MEMCPY_UNALIGNED", [a.reg(0), a.reg(1), a.imm(2)]
|
||||
),
|
||||
}
|
||||
instrs_float_comp: InstrMap = {
|
||||
# Float comparisons that don't raise exception on nan
|
||||
@@ -1340,7 +1558,7 @@ class MipsArch(Arch):
|
||||
"lbu": lambda a: handle_load(a, type=Type.u8()),
|
||||
"lh": lambda a: handle_load(a, type=Type.s16()),
|
||||
"lhu": lambda a: handle_load(a, type=Type.u16()),
|
||||
"lw": lambda a: handle_load(a, type=Type.reg32(likely_float=False)),
|
||||
"lw": lambda a: handle_lw(a),
|
||||
"ld": lambda a: handle_load(a, type=Type.reg64(likely_float=False)),
|
||||
"lwu": lambda a: handle_load(a, type=Type.u32()),
|
||||
"lwc1": lambda a: handle_load(a, type=Type.reg32(likely_float=True)),
|
||||
|
||||
4
backend/m2c/src/arch_ppc.py
generated
4
backend/m2c/src/arch_ppc.py
generated
@@ -631,7 +631,7 @@ class PpcArch(Arch):
|
||||
clobbers: List[Location] = []
|
||||
outputs: List[Location] = []
|
||||
jump_target: Optional[Union[JumpTarget, Register]] = None
|
||||
function_target: Optional[Union[AsmGlobalSymbol, Register]] = None
|
||||
function_target: Optional[Argument] = None
|
||||
is_conditional = False
|
||||
is_return = False
|
||||
is_store = False
|
||||
@@ -711,7 +711,7 @@ class PpcArch(Arch):
|
||||
eval_fn = lambda s, a: s.set_switch_expr(a.regs[Register("ctr")])
|
||||
elif mnemonic == "bl":
|
||||
# Function call to label
|
||||
assert len(args) == 1 and isinstance(args[0], AsmGlobalSymbol)
|
||||
assert len(args) == 1
|
||||
inputs = list(cls.argument_regs)
|
||||
outputs = list(cls.all_return_regs)
|
||||
clobbers = list(cls.temp_regs)
|
||||
|
||||
4
backend/m2c/src/asm_instruction.py
generated
4
backend/m2c/src/asm_instruction.py
generated
@@ -281,7 +281,7 @@ def parse_arg_elems(
|
||||
assert value is None
|
||||
arg_elems.pop(0)
|
||||
word = parse_word(arg_elems)
|
||||
if word in ["data", "rodata", "bss", "text"]:
|
||||
if word in ["data", "rodata", "rdata", "bss", "sbss", "text"]:
|
||||
value = asm_section_global_symbol(word, 0)
|
||||
else:
|
||||
value = JumpTarget(word)
|
||||
@@ -290,7 +290,7 @@ def parse_arg_elems(
|
||||
assert value is None
|
||||
arg_elems.pop(0)
|
||||
macro_name = parse_word(arg_elems)
|
||||
assert macro_name in ("hi", "lo")
|
||||
assert macro_name in ("hi", "lo", "got", "gp_rel", "call16")
|
||||
expect("(")
|
||||
# Get the argument of the macro (which must exist).
|
||||
m = parse_arg_elems(
|
||||
|
||||
18
backend/m2c/src/asm_pattern.py
generated
18
backend/m2c/src/asm_pattern.py
generated
@@ -53,6 +53,7 @@ class Replacement:
|
||||
@dataclass
|
||||
class AsmMatch:
|
||||
body: List[BodyPart]
|
||||
wildcard_items: List[BodyPart]
|
||||
regs: Dict[str, Register]
|
||||
literals: Dict[str, int]
|
||||
|
||||
@@ -85,6 +86,7 @@ class TryMatchState:
|
||||
symbolic_registers: Dict[str, Register] = field(default_factory=dict)
|
||||
symbolic_labels: Dict[str, str] = field(default_factory=dict)
|
||||
symbolic_literals: Dict[str, int] = field(default_factory=dict)
|
||||
wildcard_items: List[BodyPart] = field(default_factory=list)
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
@@ -131,12 +133,14 @@ class TryMatchState:
|
||||
return isinstance(a, AsmLiteral) and self.match_var(
|
||||
self.symbolic_literals, e.symbol_name, a.value
|
||||
)
|
||||
elif e.symbol_name == "_":
|
||||
return True
|
||||
else:
|
||||
return isinstance(a, AsmGlobalSymbol) and a.symbol_name == e.symbol_name
|
||||
if isinstance(e, AsmAddressMode):
|
||||
return (
|
||||
isinstance(a, AsmAddressMode)
|
||||
and a.lhs == e.lhs
|
||||
and self.match_arg(a.lhs, e.lhs)
|
||||
and self.match_reg(a.rhs, e.rhs)
|
||||
)
|
||||
if isinstance(e, JumpTarget):
|
||||
@@ -149,6 +153,7 @@ class TryMatchState:
|
||||
|
||||
def match_one(self, actual: BodyPart, exp: PatternPart) -> bool:
|
||||
if exp is None:
|
||||
self.wildcard_items.append(actual)
|
||||
return True
|
||||
if isinstance(exp, Label):
|
||||
return isinstance(actual, Label) and self.match_var(
|
||||
@@ -167,6 +172,11 @@ class TryMatchState:
|
||||
return False
|
||||
return True
|
||||
|
||||
def match_meta(self, ins: AsmInstruction) -> bool:
|
||||
assert ins.mnemonic == ".eq"
|
||||
res = self.eval_math(ins.args[1])
|
||||
return self.match_arg(AsmLiteral(res), ins.args[0])
|
||||
|
||||
|
||||
@dataclass
|
||||
class AsmMatcher:
|
||||
@@ -179,12 +189,16 @@ class AsmMatcher:
|
||||
|
||||
start_index = index = self.index
|
||||
for (pat, optional) in pattern:
|
||||
if index < len(self.input) and state.match_one(self.input[index], pat):
|
||||
if isinstance(pat, AsmInstruction) and pat.mnemonic[0] == ".":
|
||||
if not state.match_meta(pat) and not optional:
|
||||
return None
|
||||
elif index < len(self.input) and state.match_one(self.input[index], pat):
|
||||
index += 1
|
||||
elif not optional:
|
||||
return None
|
||||
return AsmMatch(
|
||||
self.input[start_index:index],
|
||||
state.wildcard_items,
|
||||
state.symbolic_registers,
|
||||
state.symbolic_literals,
|
||||
)
|
||||
|
||||
26
backend/m2c/src/evaluate.py
generated
26
backend/m2c/src/evaluate.py
generated
@@ -194,8 +194,17 @@ def handle_la(args: InstrArgs) -> Expression:
|
||||
)
|
||||
)
|
||||
|
||||
var = stack_info.global_info.address_of_gsym(target.sym.symbol_name)
|
||||
return add_imm(output_reg, var, Literal(target.offset), args)
|
||||
sym = stack_info.global_info.address_of_gsym(target.sym.symbol_name)
|
||||
return add_imm(output_reg, sym, Literal(target.offset), args)
|
||||
|
||||
|
||||
def handle_lw(args: InstrArgs) -> Expression:
|
||||
ref = args.maybe_got_imm(1)
|
||||
if ref is not None:
|
||||
# Handle `lw $a, %got(x + offset)($gp)` as an address load rather than a load.
|
||||
sym = args.stack_info.global_info.address_of_gsym(ref.sym.symbol_name)
|
||||
return add_imm(args.reg_ref(0), sym, Literal(ref.offset), args)
|
||||
return handle_load(args, type=Type.reg32(likely_float=False))
|
||||
|
||||
|
||||
def handle_or(left: Expression, right: Expression) -> Expression:
|
||||
@@ -418,17 +427,22 @@ def handle_lwl(args: InstrArgs) -> Expression:
|
||||
|
||||
def handle_lwr(args: InstrArgs) -> Expression:
|
||||
# Unaligned load for the right part of a register. This lwr may merge with an
|
||||
# existing lwl, if it loads from the same target but with an offset that's +3.
|
||||
# existing lwl, if it loads from the same target but with an offset that's ±3.
|
||||
uw_old_value = early_unwrap(args.reg(0))
|
||||
ref = args.memory_ref(1)
|
||||
lwl_key: Tuple[int, object]
|
||||
delta = -3 if args.stack_info.global_info.target.is_big_endian() else 3
|
||||
if isinstance(ref, AddressMode):
|
||||
lwl_key = (ref.offset - 3, args.regs[ref.rhs])
|
||||
lwl_key = (ref.offset + delta, args.regs[ref.rhs])
|
||||
else:
|
||||
lwl_key = (ref.offset - 3, ref.sym)
|
||||
lwl_key = (ref.offset + delta, ref.sym)
|
||||
if isinstance(uw_old_value, Lwl) and uw_old_value.key[0] == lwl_key[0]:
|
||||
return UnalignedLoad(uw_old_value.load_expr)
|
||||
if ref.offset % 4 == 2:
|
||||
# IDO may copy 3 bytes between 4-byte-aligned addresses using lwr+swr, e.g. for
|
||||
# the purpose of array initializers. Little endian can use lwl+swl instead,
|
||||
# but other compilers don't seem to emit this pattern so we don't handle that
|
||||
# at the moment.
|
||||
if ref.offset % 4 == 2 and args.stack_info.global_info.target.is_big_endian():
|
||||
left_mem_ref = replace(ref, offset=ref.offset - 2)
|
||||
load_expr = deref_unaligned(left_mem_ref, args.regs, args.stack_info)
|
||||
return Load3Bytes(load_expr)
|
||||
|
||||
57
backend/m2c/src/flow_graph.py
generated
57
backend/m2c/src/flow_graph.py
generated
@@ -298,6 +298,8 @@ def normalize_likely_branches(function: Function, arch: ArchFlowGraph) -> Functi
|
||||
and before_target is next_item
|
||||
and item.mnemonic != "b"
|
||||
):
|
||||
# Handle the GCC pattern where the branch likely crosses just a single
|
||||
# instruction.
|
||||
mn_inverted = invert_branch_mnemonic(item.mnemonic[:-1])
|
||||
item = arch.parse(mn_inverted, item.args, item.meta.derived())
|
||||
new_nop = arch.parse("nop", [], item.meta.derived())
|
||||
@@ -311,8 +313,9 @@ def normalize_likely_branches(function: Function, arch: ArchFlowGraph) -> Functi
|
||||
and str(before_target) == str(next_item)
|
||||
and (item.mnemonic != "b" or next_item.mnemonic != "nop")
|
||||
):
|
||||
# Handle the IDO pattern.
|
||||
if id(before_target) not in label_before_instr:
|
||||
new_label = old_label + "_before"
|
||||
new_label = f"_m2c_{old_label}_before"
|
||||
label_before_instr[id(before_target)] = new_label
|
||||
insert_label_before[id(before_target)] = new_label
|
||||
new_target = JumpTarget(label_before_instr[id(before_target)])
|
||||
@@ -324,6 +327,7 @@ def normalize_likely_branches(function: Function, arch: ArchFlowGraph) -> Functi
|
||||
new_body.append((orig_item, item))
|
||||
new_body.append((orig_next_item, next_item))
|
||||
else:
|
||||
# Fall back to not transforming the branch likely at all.
|
||||
new_body.append((item, item))
|
||||
new_body.append((next_item, next_item))
|
||||
else:
|
||||
@@ -405,13 +409,9 @@ def build_blocks(
|
||||
|
||||
assert isinstance(next_item, Instruction), "Cannot have two labels in a row"
|
||||
|
||||
# Best-effort check for whether the instruction can be executed twice in a row.
|
||||
# TODO: This may be able to be improved to use the other fields in Instruction?
|
||||
r = next_item.args[0] if next_item.args else None
|
||||
if all(a != r for a in next_item.args[1:]):
|
||||
process_after.append(label)
|
||||
process_after.append(next_item.clone())
|
||||
else:
|
||||
if item.is_branch_likely or item.function_target is not None:
|
||||
# (we could handle these cases too with some care, they're just very
|
||||
# rare so we don't bother)
|
||||
msg = [
|
||||
f"Label {label.name} refers to a delay slot; this is currently not supported.",
|
||||
"Please modify the assembly to work around it (e.g. copy the instruction",
|
||||
@@ -426,6 +426,40 @@ def build_blocks(
|
||||
"execute its delay slot unconditionally.",
|
||||
]
|
||||
raise DecompFailure("\n".join(msg))
|
||||
elif (
|
||||
all(x not in next_item.inputs for x in next_item.outputs)
|
||||
and not next_item.is_store
|
||||
):
|
||||
# It should be okay to execute this instruction twice. This check isn't
|
||||
# technically required, but it avoids creating new blocks which could
|
||||
# throw if_statements off guard.
|
||||
process_after.append(label)
|
||||
process_after.append(next_item.clone())
|
||||
else:
|
||||
target = item.jump_target
|
||||
assert isinstance(target, JumpTarget), "has delay slot and isn't a call"
|
||||
temp_label = JumpTarget(f"_m2c_{label.name}_skip")
|
||||
meta = item.meta.derived()
|
||||
nop = arch.parse("nop", [], meta)
|
||||
block_builder.add_instruction(
|
||||
arch.parse(item.mnemonic, item.args[:-1] + [temp_label], item.meta)
|
||||
)
|
||||
block_builder.add_instruction(nop)
|
||||
block_builder.new_block()
|
||||
block_builder.add_instruction(
|
||||
arch.parse("b", [JumpTarget(label.name)], item.meta.derived())
|
||||
)
|
||||
block_builder.add_instruction(nop.clone())
|
||||
block_builder.new_block()
|
||||
block_builder.set_label(Label(temp_label.target))
|
||||
block_builder.add_instruction(
|
||||
arch.parse("b", [target], item.meta.derived())
|
||||
)
|
||||
block_builder.add_instruction(next_item.clone())
|
||||
block_builder.new_block()
|
||||
block_builder.set_label(label)
|
||||
block_builder.add_instruction(next_item)
|
||||
return
|
||||
|
||||
if next_item.has_delay_slot:
|
||||
raise DecompFailure(
|
||||
@@ -438,7 +472,7 @@ def build_blocks(
|
||||
branch_likely_counts[target.target] += 1
|
||||
index = branch_likely_counts[target.target]
|
||||
mn_inverted = invert_branch_mnemonic(item.mnemonic[:-1])
|
||||
temp_label = JumpTarget(f"{target.target}_branchlikelyskip_{index}")
|
||||
temp_label = JumpTarget(f"_m2c_{target.target}_branchlikelyskip_{index}")
|
||||
branch_not = arch.parse(
|
||||
mn_inverted, item.args[:-1] + [temp_label], item.meta.derived()
|
||||
)
|
||||
@@ -454,11 +488,10 @@ def build_blocks(
|
||||
block_builder.new_block()
|
||||
block_builder.set_label(Label(temp_label.target))
|
||||
block_builder.add_instruction(nop.clone())
|
||||
|
||||
elif item.function_target is not None:
|
||||
# Move the delay slot instruction to before the call so it
|
||||
# passes correct arguments.
|
||||
if next_item.args and next_item.args[0] == item.args[0]:
|
||||
if len(item.args) >= 2 and item.args[1] in next_item.outputs:
|
||||
raise DecompFailure(
|
||||
f"Instruction after {item.mnemonic} clobbers its source\n"
|
||||
"register, which is currently not supported.\n\n"
|
||||
@@ -488,7 +521,7 @@ def build_blocks(
|
||||
|
||||
if item.is_conditional and item.is_return:
|
||||
if cond_return_target is None:
|
||||
cond_return_target = JumpTarget(f"_conditionalreturn_")
|
||||
cond_return_target = JumpTarget(f"_m2c_conditionalreturn_")
|
||||
# Strip the "lr" off of the instruction
|
||||
assert item.mnemonic[-2:] == "lr"
|
||||
branch_instr = arch.parse(
|
||||
|
||||
2
backend/m2c/src/instruction.py
generated
2
backend/m2c/src/instruction.py
generated
@@ -123,7 +123,7 @@ class Instruction:
|
||||
eval_fn: Optional[Callable[..., object]]
|
||||
|
||||
jump_target: Optional[Union[JumpTarget, Register]] = None
|
||||
function_target: Optional[Union[AsmGlobalSymbol, Register]] = None
|
||||
function_target: Optional[Argument] = None
|
||||
is_conditional: bool = False
|
||||
is_return: bool = False
|
||||
is_store: bool = False
|
||||
|
||||
21
backend/m2c/src/main.py
generated
21
backend/m2c/src/main.py
generated
@@ -1,4 +1,5 @@
|
||||
import argparse
|
||||
import gc
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
@@ -453,7 +454,7 @@ def parse_flags(flags: List[str]) -> Options:
|
||||
type=Target.parse,
|
||||
default="mips-ido-c",
|
||||
help="Target architecture, compiler, and language triple. "
|
||||
"Supported triples: mips-ido-c, mips-gcc-c, ppc-mwcc-c++, ppc-mwcc-c. "
|
||||
"Supported triples: mips-ido-c, mips-gcc-c, mipsel-gcc-c, ppc-mwcc-c++, ppc-mwcc-c. "
|
||||
"Default is mips-ido-c, `ppc` is an alias for ppc-mwcc-c++. ",
|
||||
)
|
||||
group.add_argument(
|
||||
@@ -514,6 +515,12 @@ def parse_flags(flags: List[str]) -> Options:
|
||||
"See the README for more information on unknown inference."
|
||||
),
|
||||
)
|
||||
group.add_argument(
|
||||
"--heuristic-strings",
|
||||
dest="heuristic_strings",
|
||||
action="store_true",
|
||||
help="Heuristically detect strings in rodata even when not defined using .asci/.asciz.",
|
||||
)
|
||||
group.add_argument(
|
||||
"--reg-vars",
|
||||
metavar="REGISTERS",
|
||||
@@ -537,6 +544,13 @@ def parse_flags(flags: List[str]) -> Options:
|
||||
action="store_true",
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
group.add_argument(
|
||||
"--disable-gc",
|
||||
dest="disable_gc",
|
||||
action="store_true",
|
||||
help="Disable Python garbage collection. Can improve performance at "
|
||||
"the risk of running out of memory.",
|
||||
)
|
||||
|
||||
args = parser.parse_args(flags)
|
||||
reg_vars = args.reg_vars.split(",") if args.reg_vars else []
|
||||
@@ -578,6 +592,7 @@ def parse_flags(flags: List[str]) -> Options:
|
||||
andor_detection=args.andor_detection,
|
||||
skip_casts=args.skip_casts,
|
||||
zfill_constants=args.zfill_constants,
|
||||
heuristic_strings=args.heuristic_strings,
|
||||
reg_vars=reg_vars,
|
||||
goto_patterns=args.goto_patterns,
|
||||
stop_on_error=args.stop_on_error,
|
||||
@@ -598,6 +613,7 @@ def parse_flags(flags: List[str]) -> Options:
|
||||
passes=args.passes,
|
||||
incbin_dirs=args.incbin_dirs,
|
||||
deterministic_vars=args.deterministic_vars,
|
||||
disable_gc=args.disable_gc,
|
||||
)
|
||||
|
||||
|
||||
@@ -606,6 +622,9 @@ def main() -> None:
|
||||
# CPython default. Cap to INT_MAX to avoid an OverflowError, though.
|
||||
sys.setrecursionlimit(min(2**31 - 1, 10 * sys.getrecursionlimit()))
|
||||
options = parse_flags(sys.argv[1:])
|
||||
if options.disable_gc:
|
||||
gc.disable()
|
||||
gc.set_threshold(0)
|
||||
sys.exit(run(options))
|
||||
|
||||
|
||||
|
||||
20
backend/m2c/src/options.py
generated
20
backend/m2c/src/options.py
generated
@@ -36,6 +36,10 @@ class Target:
|
||||
MIPS = "mips"
|
||||
PPC = "ppc"
|
||||
|
||||
class EndianEnum(ChoicesEnum):
|
||||
LITTLE = "little"
|
||||
BIG = "big"
|
||||
|
||||
class CompilerEnum(ChoicesEnum):
|
||||
IDO = "ido"
|
||||
GCC = "gcc"
|
||||
@@ -46,9 +50,13 @@ class Target:
|
||||
CXX = "c++"
|
||||
|
||||
arch: ArchEnum
|
||||
endian: EndianEnum
|
||||
compiler: CompilerEnum
|
||||
language: LanguageEnum
|
||||
|
||||
def is_big_endian(self) -> bool:
|
||||
return self.endian == Target.EndianEnum.BIG
|
||||
|
||||
@staticmethod
|
||||
def parse(name: str) -> "Target":
|
||||
"""
|
||||
@@ -57,9 +65,14 @@ class Target:
|
||||
If `-compiler` is missing, use the default for the arch.
|
||||
(This makes `mips` an alias for `mips-ido-c`, etc.)
|
||||
"""
|
||||
endian = Target.EndianEnum.BIG
|
||||
terms = name.split("-")
|
||||
try:
|
||||
arch = Target.ArchEnum(terms[0])
|
||||
arch_name = terms[0]
|
||||
if arch_name.endswith("el"):
|
||||
arch_name = arch_name[:-2]
|
||||
endian = Target.EndianEnum.LITTLE
|
||||
arch = Target.ArchEnum(arch_name)
|
||||
if len(terms) >= 2:
|
||||
compiler = Target.CompilerEnum(terms[1])
|
||||
elif arch == Target.ArchEnum.PPC:
|
||||
@@ -78,6 +91,7 @@ class Target:
|
||||
|
||||
return Target(
|
||||
arch=arch,
|
||||
endian=endian,
|
||||
compiler=compiler,
|
||||
language=language,
|
||||
)
|
||||
@@ -103,6 +117,7 @@ class Options:
|
||||
andor_detection: bool
|
||||
skip_casts: bool
|
||||
zfill_constants: bool
|
||||
heuristic_strings: bool
|
||||
reg_vars: List[str]
|
||||
goto_patterns: List[str]
|
||||
stop_on_error: bool
|
||||
@@ -123,12 +138,14 @@ class Options:
|
||||
passes: int
|
||||
incbin_dirs: List[Path]
|
||||
deterministic_vars: bool
|
||||
disable_gc: bool
|
||||
|
||||
def formatter(self) -> "Formatter":
|
||||
return Formatter(
|
||||
self.coding_style,
|
||||
skip_casts=self.skip_casts,
|
||||
zfill_constants=self.zfill_constants,
|
||||
heuristic_strings=self.heuristic_strings,
|
||||
valid_syntax=self.valid_syntax,
|
||||
)
|
||||
|
||||
@@ -156,6 +173,7 @@ class Formatter:
|
||||
valid_syntax: bool = False
|
||||
line_length: int = 80
|
||||
zfill_constants: bool = False
|
||||
heuristic_strings: bool = False
|
||||
|
||||
def indent(self, line: str, indent: int = 0) -> str:
|
||||
return self.indent_step * max(indent + self.extra_indent, 0) + line
|
||||
|
||||
53
backend/m2c/src/translate.py
generated
53
backend/m2c/src/translate.py
generated
@@ -1467,6 +1467,9 @@ class StructAccess(Expression):
|
||||
if (
|
||||
isinstance(var, AddressOf)
|
||||
and not var.expr.type.is_array()
|
||||
and not (
|
||||
isinstance(var.expr, GlobalSymbol) and var.expr.is_string_constant(fmt)
|
||||
)
|
||||
and field_name.startswith("->")
|
||||
):
|
||||
var = var.expr
|
||||
@@ -1509,14 +1512,27 @@ class GlobalSymbol(Expression):
|
||||
def dependencies(self) -> List[Expression]:
|
||||
return []
|
||||
|
||||
def is_string_constant(self) -> bool:
|
||||
def is_likely_char(self, c: int) -> bool:
|
||||
return 0x20 <= c < 0x7F or c in (0, 7, 8, 9, 10, 13, 27)
|
||||
|
||||
def is_string_constant(self, fmt: Formatter) -> bool:
|
||||
ent = self.asm_data_entry
|
||||
if not ent or not ent.is_string:
|
||||
if not ent or len(ent.data) != 1 or not isinstance(ent.data[0], bytes):
|
||||
return False
|
||||
return len(ent.data) == 1 and isinstance(ent.data[0], bytes)
|
||||
if ent.is_string:
|
||||
return True
|
||||
if (
|
||||
fmt.heuristic_strings
|
||||
and ent.is_readonly
|
||||
and len(ent.data[0]) > 1
|
||||
and ent.data[0][0] != 0
|
||||
and all(self.is_likely_char(x) for x in ent.data[0])
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
def format_string_constant(self, fmt: Formatter) -> str:
|
||||
assert self.is_string_constant(), "checked by caller"
|
||||
assert self.is_string_constant(fmt), "checked by caller"
|
||||
assert self.asm_data_entry and isinstance(self.asm_data_entry.data[0], bytes)
|
||||
|
||||
has_trailing_null = False
|
||||
@@ -1633,7 +1649,7 @@ class AddressOf(Expression):
|
||||
|
||||
def format(self, fmt: Formatter) -> str:
|
||||
if isinstance(self.expr, GlobalSymbol):
|
||||
if self.expr.is_string_constant():
|
||||
if self.expr.is_string_constant(fmt):
|
||||
return self.expr.format_string_constant(fmt)
|
||||
if self.expr.type.is_array():
|
||||
return f"{self.expr.format(fmt)}"
|
||||
@@ -2366,16 +2382,35 @@ class InstrArgs:
|
||||
raise DecompFailure(f"Invalid macro argument {arg.argument}")
|
||||
return ref
|
||||
|
||||
def maybe_got_imm(self, index: int) -> Optional[RawSymbolRef]:
|
||||
arg = self.raw_arg(index)
|
||||
if not isinstance(arg, AsmAddressMode) or arg.rhs != Register("gp"):
|
||||
return None
|
||||
val = arg.lhs
|
||||
if not isinstance(val, Macro) or val.macro_name not in (
|
||||
"got",
|
||||
"gp_rel",
|
||||
"call16",
|
||||
):
|
||||
return None
|
||||
ref = parse_symbol_ref(val.argument)
|
||||
if ref is None:
|
||||
raise DecompFailure(f"Invalid macro argument {val.argument}")
|
||||
return ref
|
||||
|
||||
def shifted_imm(self, index: int) -> Expression:
|
||||
# TODO: Should this be part of hi_imm? Do we need to handle @ha?
|
||||
raw_imm = self.unsigned_imm(index)
|
||||
assert isinstance(raw_imm, Literal)
|
||||
return Literal(raw_imm.value << 16)
|
||||
|
||||
def sym_imm(self, index: int) -> AddressOf:
|
||||
def sym_imm(self, index: int) -> Expression:
|
||||
arg = self.raw_arg(index)
|
||||
assert isinstance(arg, AsmGlobalSymbol)
|
||||
return self.stack_info.global_info.address_of_gsym(arg.symbol_name)
|
||||
if isinstance(arg, AsmGlobalSymbol):
|
||||
return self.stack_info.global_info.address_of_gsym(arg.symbol_name)
|
||||
if isinstance(arg, AsmLiteral):
|
||||
return self.full_imm(index)
|
||||
raise DecompFailure(f"Bad function call operand {arg}")
|
||||
|
||||
def memory_ref(self, index: int) -> Union[AddressMode, RawSymbolRef]:
|
||||
ret = strip_macros(self.raw_arg(index))
|
||||
@@ -4091,7 +4126,7 @@ class GlobalInfo:
|
||||
comments.append("const")
|
||||
|
||||
# Float & string constants are almost always inlined and can be omitted
|
||||
if sym.is_string_constant():
|
||||
if sym.is_string_constant(fmt):
|
||||
continue
|
||||
if array_dim is None and sym.type.is_likely_float():
|
||||
continue
|
||||
|
||||
56
backend/m2c/tests/add_test.py
generated
56
backend/m2c/tests/add_test.py
generated
@@ -26,6 +26,7 @@ class PathsToBinaries:
|
||||
IDO_CC: Optional[Path]
|
||||
SM64_TOOLS: Optional[Path]
|
||||
MWCC_CC: Optional[Path]
|
||||
WINE: Optional[Path]
|
||||
|
||||
|
||||
def get_environment_variables() -> PathsToBinaries:
|
||||
@@ -54,7 +55,11 @@ def get_environment_variables() -> PathsToBinaries:
|
||||
MWCC_CC = load(
|
||||
"MWCC_CC", "env variable MWCC_CC should point to a PPC cc binary (mwcceppc.exe)"
|
||||
)
|
||||
return PathsToBinaries(IDO_CC=IDO_CC, SM64_TOOLS=SM64_TOOLS, MWCC_CC=MWCC_CC)
|
||||
if MWCC_CC and sys.platform.startswith("linux"):
|
||||
WINE = load("WINE", "env variable WINE should point to wine or wibo binary")
|
||||
return PathsToBinaries(
|
||||
IDO_CC=IDO_CC, SM64_TOOLS=SM64_TOOLS, MWCC_CC=MWCC_CC, WINE=WINE
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -66,8 +71,7 @@ class Compiler:
|
||||
return replace(self, cc_command=self.cc_command + flags)
|
||||
|
||||
|
||||
def get_compilers(paths: PathsToBinaries) -> List[Tuple[str, Compiler]]:
|
||||
compilers: List[Tuple[str, Compiler]] = []
|
||||
def get_ido_compilers(paths: PathsToBinaries) -> List[Tuple[str, Compiler]]:
|
||||
if paths.IDO_CC is not None and paths.SM64_TOOLS is not None:
|
||||
ido = Compiler(
|
||||
name="ido",
|
||||
@@ -86,13 +90,17 @@ def get_compilers(paths: PathsToBinaries) -> List[Tuple[str, Compiler]]:
|
||||
"-signed",
|
||||
],
|
||||
)
|
||||
compilers.append(("irix-g", ido.with_cc_flags(["-g", "-mips2"])))
|
||||
compilers.append(("irix-o2", ido.with_cc_flags(["-O2", "-mips2"])))
|
||||
# compilers.append(("irix-g-mips1", ido.with_cc_flags(["-O2", "-mips1"])))
|
||||
# compilers.append(("irix-o2-mips1", ido.with_cc_flags(["-O2", "-mips1"])))
|
||||
else:
|
||||
logger.warning("IDO tools not found; skipping MIPS compilers")
|
||||
return [
|
||||
("irix-g", ido.with_cc_flags(["-g", "-mips2"])),
|
||||
("irix-o2", ido.with_cc_flags(["-O2", "-mips2"])),
|
||||
# ("irix-g-mips1", ido.with_cc_flags(["-O2", "-mips1"]))
|
||||
# ("irix-o2-mips1", ido.with_cc_flags(["-O2", "-mips1"]))
|
||||
]
|
||||
logger.warning("IDO tools not found; skipping MIPS compilers")
|
||||
return []
|
||||
|
||||
|
||||
def get_mwcc_compilers(paths: PathsToBinaries) -> List[Tuple[str, Compiler]]:
|
||||
if paths.MWCC_CC is not None:
|
||||
cc_command = [
|
||||
str(paths.MWCC_CC),
|
||||
@@ -107,17 +115,29 @@ def get_compilers(paths: PathsToBinaries) -> List[Tuple[str, Compiler]]:
|
||||
"int",
|
||||
"-nodefaults",
|
||||
]
|
||||
ok = True
|
||||
if paths.MWCC_CC.suffix == ".exe" and sys.platform.startswith("linux"):
|
||||
cc_command.insert(0, "/usr/bin/wine")
|
||||
mwcc = Compiler(
|
||||
name="mwcc",
|
||||
cc_command=cc_command,
|
||||
)
|
||||
compilers.append(("mwcc-o4p", mwcc.with_cc_flags(["-O4,p"])))
|
||||
# compilers.append(("mwcc-o4p-s0", mwcc.with_cc_flags(["-O4,p", "-sdata", "0", "-sdata2", "0"])))
|
||||
else:
|
||||
logger.warning("MWCC tools not found; skipping PPC compilers")
|
||||
if paths.WINE:
|
||||
cc_command.insert(0, str(paths.WINE))
|
||||
else:
|
||||
ok = False
|
||||
if ok:
|
||||
mwcc = Compiler(
|
||||
name="mwcc",
|
||||
cc_command=cc_command,
|
||||
)
|
||||
return [
|
||||
("mwcc-o4p", mwcc.with_cc_flags(["-O4,p"])),
|
||||
# ("mwcc-o4p-s0", mwcc.with_cc_flags(["-O4,p", "-sdata", "0", "-sdata2", "0"]))
|
||||
]
|
||||
logger.warning("MWCC tools not found; skipping PPC compilers")
|
||||
return []
|
||||
|
||||
|
||||
def get_compilers(paths: PathsToBinaries) -> List[Tuple[str, Compiler]]:
|
||||
compilers: List[Tuple[str, Compiler]] = []
|
||||
compilers.extend(get_ido_compilers(paths))
|
||||
compilers.extend(get_mwcc_compilers(paths))
|
||||
return compilers
|
||||
|
||||
|
||||
|
||||
13
backend/m2c/tests/end_to_end/delay-slot-branch/manual-out.c
generated
Normal file
13
backend/m2c/tests/end_to_end/delay-slot-branch/manual-out.c
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
s32 test(s32 arg0, s32 arg1) {
|
||||
s32 var_a0;
|
||||
|
||||
var_a0 = arg0;
|
||||
if (arg1 != 0) {
|
||||
do {
|
||||
var_a0 -= 1;
|
||||
} while (var_a0 != 0);
|
||||
} else {
|
||||
var_a0 -= 1;
|
||||
}
|
||||
return var_a0;
|
||||
}
|
||||
9
backend/m2c/tests/end_to_end/delay-slot-branch/manual.s
generated
Normal file
9
backend/m2c/tests/end_to_end/delay-slot-branch/manual.s
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
glabel test
|
||||
beqz $a1, .skip
|
||||
.loop:
|
||||
addiu $a0, $a0, -1
|
||||
bnez $a0, .loop
|
||||
nop
|
||||
.skip:
|
||||
jr $ra
|
||||
move $v0, $a0
|
||||
20
backend/m2c/tests/end_to_end/got/manual-out.c
generated
Normal file
20
backend/m2c/tests/end_to_end/got/manual-out.c
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
? func(); /* extern */
|
||||
extern ? global_sym;
|
||||
extern ? local_sym;
|
||||
|
||||
void test(u32 arg0) {
|
||||
s32 var_t2;
|
||||
|
||||
var_t2 = 0;
|
||||
switch (arg0) {
|
||||
case 0:
|
||||
var_t2 = 1;
|
||||
break;
|
||||
case 1:
|
||||
var_t2 = 2;
|
||||
break;
|
||||
}
|
||||
local_sym.unk8 = var_t2;
|
||||
global_sym.unk8 = 0;
|
||||
func();
|
||||
}
|
||||
41
backend/m2c/tests/end_to_end/got/manual.s
generated
Normal file
41
backend/m2c/tests/end_to_end/got/manual.s
generated
Normal file
@@ -0,0 +1,41 @@
|
||||
glabel test
|
||||
|
||||
li $t2, 0
|
||||
sltiu $at, $a0, 2
|
||||
beqz $at, .skip
|
||||
lw $at, %got(jtbl_1)($gp)
|
||||
sll $a0, $a0, 2
|
||||
addu $at, $at, $a0
|
||||
lw $a0, %lo(jtbl_1)($at)
|
||||
addu $a0, $a0, $gp
|
||||
jr $a0
|
||||
nop
|
||||
|
||||
.case0:
|
||||
b .skip
|
||||
li $t2, 1
|
||||
|
||||
.case1:
|
||||
b .skip
|
||||
li $t2, 2
|
||||
|
||||
.skip:
|
||||
|
||||
lw $t1, %got(local_sym)($gp)
|
||||
addiu $t1, $t1, %lo(local_sym)
|
||||
sw $t2, 8($t1)
|
||||
|
||||
lw $t1, %got(global_sym)($gp)
|
||||
sw $zero, 8($t1)
|
||||
|
||||
lw $t9, %got(func)($gp)
|
||||
jalr $t9
|
||||
nop
|
||||
|
||||
jr $ra
|
||||
nop
|
||||
|
||||
.section .rodata
|
||||
jtbl_1:
|
||||
.word .case0
|
||||
.word .case1
|
||||
4
backend/m2c/tests/end_to_end/lwl/orig.c
generated
4
backend/m2c/tests/end_to_end/lwl/orig.c
generated
@@ -17,9 +17,9 @@ void test(void) {
|
||||
// The last 3 bytes are loaded using lwr, then stored using swr
|
||||
char str[7] = "abcdef";
|
||||
foo(str);
|
||||
// 4 bytes being loaded using lwl+lwr, then stored using swl/swr
|
||||
// 4 bytes being loaded using lwl+lwr, then stored using swl+swr
|
||||
a1.data = a2.data;
|
||||
// 5 bytes being loaded using lwl+lwr+lbu, then stored using sw+sb
|
||||
// 5 bytes being loaded using lw+lbu, then stored using swl+swr+sb
|
||||
a3[0] = a1;
|
||||
// 4 bytes being loaded using lwl+lwr, then stored using sw
|
||||
strcpy(buf, "ghi");
|
||||
|
||||
9
backend/m2c/tests/end_to_end/struct-copy/irix-o2-mips1-out.c
generated
Normal file
9
backend/m2c/tests/end_to_end/struct-copy/irix-o2-mips1-out.c
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
extern ? D_410160;
|
||||
extern ? D_4102F0;
|
||||
|
||||
void test(s32 arg0, s32 arg1) {
|
||||
M2C_MEMCPY_ALIGNED(&D_410160, &D_4102F0, 0x18C);
|
||||
*(&D_410160 + 0x18C) = *(&D_4102F0 + 0x18C);
|
||||
M2C_MEMCPY_UNALIGNED(arg0, arg1, 0x60);
|
||||
*(arg0 + 0x60) = (unaligned s32) *(arg1 + 0x60);
|
||||
}
|
||||
52
backend/m2c/tests/end_to_end/struct-copy/irix-o2-mips1.s
generated
Normal file
52
backend/m2c/tests/end_to_end/struct-copy/irix-o2-mips1.s
generated
Normal file
@@ -0,0 +1,52 @@
|
||||
.set noat # allow manual use of $at
|
||||
.set noreorder # don't insert nops after branches
|
||||
|
||||
|
||||
glabel test
|
||||
/* 0000B0 004000B0 3C0F0041 */ lui $t7, %hi(D_4102F0)
|
||||
/* 0000B4 004000B4 25EF02F0 */ addiu $t7, $t7, %lo(D_4102F0)
|
||||
/* 0000B8 004000B8 3C0E0041 */ lui $t6, %hi(D_410160)
|
||||
/* 0000BC 004000BC 25CE0160 */ addiu $t6, $t6, %lo(D_410160)
|
||||
/* 0000C0 004000C0 25E8018C */ addiu $t0, $t7, 0x18c
|
||||
.L004000C4:
|
||||
/* 0000C4 004000C4 8DE10000 */ lw $at, ($t7)
|
||||
/* 0000C8 004000C8 25EF000C */ addiu $t7, $t7, 0xc
|
||||
/* 0000CC 004000CC ADC10000 */ sw $at, ($t6)
|
||||
/* 0000D0 004000D0 8DE1FFF8 */ lw $at, -8($t7)
|
||||
/* 0000D4 004000D4 25CE000C */ addiu $t6, $t6, 0xc
|
||||
/* 0000D8 004000D8 ADC1FFF8 */ sw $at, -8($t6)
|
||||
/* 0000DC 004000DC 8DE1FFFC */ lw $at, -4($t7)
|
||||
/* 0000E0 004000E0 15E8FFF8 */ bne $t7, $t0, .L004000C4
|
||||
/* 0000E4 004000E4 ADC1FFFC */ sw $at, -4($t6)
|
||||
/* 0000E8 004000E8 8DE10000 */ lw $at, ($t7)
|
||||
/* 0000EC 004000EC 00A06025 */ move $t4, $a1
|
||||
/* 0000F0 004000F0 00806825 */ move $t5, $a0
|
||||
/* 0000F4 004000F4 24AB0060 */ addiu $t3, $a1, 0x60
|
||||
/* 0000F8 004000F8 ADC10000 */ sw $at, ($t6)
|
||||
.L004000FC:
|
||||
/* 0000FC 004000FC 89810000 */ lwl $at, ($t4)
|
||||
/* 000100 00400100 99810003 */ lwr $at, 3($t4)
|
||||
/* 000104 00400104 258C000C */ addiu $t4, $t4, 0xc
|
||||
/* 000108 00400108 A9A10000 */ swl $at, ($t5)
|
||||
/* 00010C 0040010C B9A10003 */ swr $at, 3($t5)
|
||||
/* 000110 00400110 8981FFF8 */ lwl $at, -8($t4)
|
||||
/* 000114 00400114 9981FFFB */ lwr $at, -5($t4)
|
||||
/* 000118 00400118 25AD000C */ addiu $t5, $t5, 0xc
|
||||
/* 00011C 0040011C A9A1FFF8 */ swl $at, -8($t5)
|
||||
/* 000120 00400120 B9A1FFFB */ swr $at, -5($t5)
|
||||
/* 000124 00400124 8981FFFC */ lwl $at, -4($t4)
|
||||
/* 000128 00400128 9981FFFF */ lwr $at, -1($t4)
|
||||
/* 00012C 0040012C 00000000 */ nop
|
||||
/* 000130 00400130 A9A1FFFC */ swl $at, -4($t5)
|
||||
/* 000134 00400134 158BFFF1 */ bne $t4, $t3, .L004000FC
|
||||
/* 000138 00400138 B9A1FFFF */ swr $at, -1($t5)
|
||||
/* 00013C 0040013C 89810000 */ lwl $at, ($t4)
|
||||
/* 000140 00400140 99810003 */ lwr $at, 3($t4)
|
||||
/* 000144 00400144 00000000 */ nop
|
||||
/* 000148 00400148 A9A10000 */ swl $at, ($t5)
|
||||
/* 00014C 0040014C 03E00008 */ jr $ra
|
||||
/* 000150 00400150 B9A10003 */ swr $at, 3($t5)
|
||||
|
||||
/* 000154 00400154 00000000 */ nop
|
||||
/* 000158 00400158 00000000 */ nop
|
||||
/* 00015C 0040015C 00000000 */ nop
|
||||
9
backend/m2c/tests/end_to_end/struct-copy/irix-o2-out.c
generated
Normal file
9
backend/m2c/tests/end_to_end/struct-copy/irix-o2-out.c
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
extern ? D_410150;
|
||||
extern ? D_4102E0;
|
||||
|
||||
void test(s32 arg0, s32 arg1) {
|
||||
M2C_MEMCPY_ALIGNED(&D_410150, &D_4102E0, 0x18C);
|
||||
*(&D_410150 + 0x18C) = *(&D_4102E0 + 0x18C);
|
||||
M2C_MEMCPY_UNALIGNED(arg0, arg1, 0x60);
|
||||
*(arg0 + 0x60) = (unaligned s32) *(arg1 + 0x60);
|
||||
}
|
||||
48
backend/m2c/tests/end_to_end/struct-copy/irix-o2.s
generated
Normal file
48
backend/m2c/tests/end_to_end/struct-copy/irix-o2.s
generated
Normal file
@@ -0,0 +1,48 @@
|
||||
.set noat # allow manual use of $at
|
||||
.set noreorder # don't insert nops after branches
|
||||
|
||||
|
||||
glabel test
|
||||
/* 0000B0 004000B0 3C0F0041 */ lui $t7, %hi(D_4102E0)
|
||||
/* 0000B4 004000B4 25EF02E0 */ addiu $t7, $t7, %lo(D_4102E0)
|
||||
/* 0000B8 004000B8 3C0E0041 */ lui $t6, %hi(D_410150)
|
||||
/* 0000BC 004000BC 25CE0150 */ addiu $t6, $t6, %lo(D_410150)
|
||||
/* 0000C0 004000C0 25E8018C */ addiu $t0, $t7, 0x18c
|
||||
.L004000C4:
|
||||
/* 0000C4 004000C4 8DE10000 */ lw $at, ($t7)
|
||||
/* 0000C8 004000C8 25EF000C */ addiu $t7, $t7, 0xc
|
||||
/* 0000CC 004000CC 25CE000C */ addiu $t6, $t6, 0xc
|
||||
/* 0000D0 004000D0 ADC1FFF4 */ sw $at, -0xc($t6)
|
||||
/* 0000D4 004000D4 8DE1FFF8 */ lw $at, -8($t7)
|
||||
/* 0000D8 004000D8 ADC1FFF8 */ sw $at, -8($t6)
|
||||
/* 0000DC 004000DC 8DE1FFFC */ lw $at, -4($t7)
|
||||
/* 0000E0 004000E0 15E8FFF8 */ bne $t7, $t0, .L004000C4
|
||||
/* 0000E4 004000E4 ADC1FFFC */ sw $at, -4($t6)
|
||||
/* 0000E8 004000E8 8DE10000 */ lw $at, ($t7)
|
||||
/* 0000EC 004000EC 00A06025 */ move $t4, $a1
|
||||
/* 0000F0 004000F0 00806825 */ move $t5, $a0
|
||||
/* 0000F4 004000F4 24AB0060 */ addiu $t3, $a1, 0x60
|
||||
/* 0000F8 004000F8 ADC10000 */ sw $at, ($t6)
|
||||
.L004000FC:
|
||||
/* 0000FC 004000FC 89810000 */ lwl $at, ($t4)
|
||||
/* 000100 00400100 99810003 */ lwr $at, 3($t4)
|
||||
/* 000104 00400104 258C000C */ addiu $t4, $t4, 0xc
|
||||
/* 000108 00400108 25AD000C */ addiu $t5, $t5, 0xc
|
||||
/* 00010C 0040010C A9A1FFF4 */ swl $at, -0xc($t5)
|
||||
/* 000110 00400110 B9A1FFF7 */ swr $at, -9($t5)
|
||||
/* 000114 00400114 8981FFF8 */ lwl $at, -8($t4)
|
||||
/* 000118 00400118 9981FFFB */ lwr $at, -5($t4)
|
||||
/* 00011C 0040011C A9A1FFF8 */ swl $at, -8($t5)
|
||||
/* 000120 00400120 B9A1FFFB */ swr $at, -5($t5)
|
||||
/* 000124 00400124 8981FFFC */ lwl $at, -4($t4)
|
||||
/* 000128 00400128 9981FFFF */ lwr $at, -1($t4)
|
||||
/* 00012C 0040012C A9A1FFFC */ swl $at, -4($t5)
|
||||
/* 000130 00400130 158BFFF2 */ bne $t4, $t3, .L004000FC
|
||||
/* 000134 00400134 B9A1FFFF */ swr $at, -1($t5)
|
||||
/* 000138 00400138 89810000 */ lwl $at, ($t4)
|
||||
/* 00013C 0040013C 99810003 */ lwr $at, 3($t4)
|
||||
/* 000140 00400140 A9A10000 */ swl $at, ($t5)
|
||||
/* 000144 00400144 03E00008 */ jr $ra
|
||||
/* 000148 00400148 B9A10003 */ swr $at, 3($t5)
|
||||
|
||||
/* 00014C 0040014C 00000000 */ nop
|
||||
1
backend/m2c/tests/end_to_end/struct-copy/mwcc-o4p-flags.txt
generated
Normal file
1
backend/m2c/tests/end_to_end/struct-copy/mwcc-o4p-flags.txt
generated
Normal file
@@ -0,0 +1 @@
|
||||
--target ppc-mwcc-c
|
||||
41
backend/m2c/tests/end_to_end/struct-copy/mwcc-o4p-out.c
generated
Normal file
41
backend/m2c/tests/end_to_end/struct-copy/mwcc-o4p-out.c
generated
Normal file
@@ -0,0 +1,41 @@
|
||||
static ? a;
|
||||
static ? b;
|
||||
|
||||
void test(s32 arg0, s32 arg1) {
|
||||
s32 temp_r0;
|
||||
s32 temp_r0_2;
|
||||
s32 temp_r3;
|
||||
s32 temp_r5;
|
||||
s32 var_ctr;
|
||||
s32 var_ctr_2;
|
||||
void *var_r4;
|
||||
void *var_r5;
|
||||
void *var_r6;
|
||||
void *var_r7;
|
||||
|
||||
var_r7 = &a - 4;
|
||||
var_r6 = &b - 4;
|
||||
var_ctr = 0x32;
|
||||
do {
|
||||
temp_r5 = var_r6->unk4;
|
||||
temp_r0 = var_r6->unk8;
|
||||
var_r6 += 8;
|
||||
var_r7->unk4 = temp_r5;
|
||||
var_r7 += 8;
|
||||
var_r7->unk8 = temp_r0;
|
||||
var_ctr -= 1;
|
||||
} while (var_ctr != 0);
|
||||
var_r5 = arg0 - 4;
|
||||
var_r4 = arg1 - 4;
|
||||
var_ctr_2 = 0xC;
|
||||
do {
|
||||
temp_r3 = var_r4->unk4;
|
||||
temp_r0_2 = var_r4->unk8;
|
||||
var_r4 += 8;
|
||||
var_r5->unk4 = temp_r3;
|
||||
var_r5 += 8;
|
||||
var_r5->unk8 = temp_r0_2;
|
||||
var_ctr_2 -= 1;
|
||||
} while (var_ctr_2 != 0);
|
||||
var_r5->unk4 = (s32) var_r4->unk4;
|
||||
}
|
||||
242
backend/m2c/tests/end_to_end/struct-copy/mwcc-o4p.s
generated
Normal file
242
backend/m2c/tests/end_to_end/struct-copy/mwcc-o4p.s
generated
Normal file
@@ -0,0 +1,242 @@
|
||||
.include "macros.inc"
|
||||
|
||||
.section .text # 0x0 - 0x64
|
||||
|
||||
.global test
|
||||
test:
|
||||
/* 00000000 00000000 3C C0 00 00 */ lis r6, a@ha
|
||||
/* 00000004 00000004 3C A0 00 00 */ lis r5, b@ha
|
||||
/* 00000008 00000008 38 C6 00 00 */ addi r6, r6, a@l
|
||||
/* 0000000C 0000000C 38 00 00 32 */ li r0, 0x32
|
||||
/* 00000010 00000010 38 A5 00 00 */ addi r5, r5, b@l
|
||||
/* 00000014 00000014 38 E6 FF FC */ addi r7, r6, -4
|
||||
/* 00000018 00000018 38 C5 FF FC */ addi r6, r5, -4
|
||||
/* 0000001C 0000001C 7C 09 03 A6 */ mtctr r0
|
||||
.L00000020:
|
||||
/* 00000020 00000020 80 A6 00 04 */ lwz r5, 4(r6)
|
||||
/* 00000024 00000024 84 06 00 08 */ lwzu r0, 8(r6)
|
||||
/* 00000028 00000028 90 A7 00 04 */ stw r5, 4(r7)
|
||||
/* 0000002C 0000002C 94 07 00 08 */ stwu r0, 8(r7)
|
||||
/* 00000030 00000030 42 00 FF F0 */ bdnz .L00000020
|
||||
/* 00000034 00000034 38 00 00 0C */ li r0, 0xc
|
||||
/* 00000038 00000038 38 A3 FF FC */ addi r5, r3, -4
|
||||
/* 0000003C 0000003C 38 84 FF FC */ addi r4, r4, -4
|
||||
/* 00000040 00000040 7C 09 03 A6 */ mtctr r0
|
||||
.L00000044:
|
||||
/* 00000044 00000044 80 64 00 04 */ lwz r3, 4(r4)
|
||||
/* 00000048 00000048 84 04 00 08 */ lwzu r0, 8(r4)
|
||||
/* 0000004C 0000004C 90 65 00 04 */ stw r3, 4(r5)
|
||||
/* 00000050 00000050 94 05 00 08 */ stwu r0, 8(r5)
|
||||
/* 00000054 00000054 42 00 FF F0 */ bdnz .L00000044
|
||||
/* 00000058 00000058 80 04 00 04 */ lwz r0, 4(r4)
|
||||
/* 0000005C 0000005C 90 05 00 04 */ stw r0, 4(r5)
|
||||
/* 00000060 00000060 4E 80 00 20 */ blr
|
||||
|
||||
.section .bss # 0x0 - 0x320
|
||||
|
||||
.global a
|
||||
a:
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
|
||||
.global b
|
||||
b:
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
|
||||
10
backend/m2c/tests/end_to_end/struct-copy/orig.c
generated
Normal file
10
backend/m2c/tests/end_to_end/struct-copy/orig.c
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
struct A {
|
||||
int buf[100];
|
||||
} a, b;
|
||||
struct B {
|
||||
char buf[100];
|
||||
};
|
||||
void test(struct B *c, struct B *d) {
|
||||
a = b;
|
||||
*c = *d;
|
||||
}
|
||||
2
backend/m2c/website.py
generated
2
backend/m2c/website.py
generated
@@ -59,6 +59,7 @@ if "source" in form:
|
||||
"ppc-mwcc-c++",
|
||||
"mips-ido-c",
|
||||
"mips-gcc-c",
|
||||
"mipsel-gcc-c",
|
||||
):
|
||||
cmd.extend(["--target", value])
|
||||
if "nounkinference" in form:
|
||||
@@ -236,6 +237,7 @@ label {
|
||||
<select name="target">
|
||||
<option value="mips-ido-c">MIPS, IDO, C</option>
|
||||
<option value="mips-gcc-c">MIPS, GCC, C</option>
|
||||
<option value="mipsel-gcc-c">MIPSEL, GCC, C</option>
|
||||
<option value="ppc-mwcc-c++">PPC, MWCC, C++</option>
|
||||
<option value="ppc-mwcc-c">PPC, MWCC, C</option>
|
||||
</select>
|
||||
|
||||
Reference in New Issue
Block a user