thumb.pm 3.41 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/perl
##
##  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
##
##  Use of this source code is governed by a BSD-style license
##  that can be found in the LICENSE file in the root of the source
##  tree. An additional intellectual property rights grant can be found
##  in the file PATENTS.  All contributing project authors may
##  be found in the AUTHORS file in the root of the source tree.
##

package thumb;

14
sub FixThumbInstructions($$)
15
{
16
17
18
    my $short_branches = $_[1];
    my $branch_shift_offset = $short_branches ? 1 : 0;

19
20
21
22
23
24
25
26
    # Write additions with shifts, such as "add r10, r11, lsl #8",
    # in three operand form, "add r10, r10, r11, lsl #8".
    s/(add\s+)(r\d+),\s*(r\d+),\s*(lsl #\d+)/$1$2, $2, $3, $4/g;

    # Convert additions with a non-constant shift into a sequence
    # with left shift, addition and a right shift (to restore the
    # register to the original value). Currently the right shift
    # isn't necessary in the code base since the values in these
27
    # registers aren't used, but doing the shift for consistency.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    # This converts instructions such as "add r12, r12, r5, lsl r4"
    # into the sequence "lsl r5, r4", "add r12, r12, r5", "lsr r5, r4".
    s/^(\s*)(add)(\s+)(r\d+),\s*(r\d+),\s*(r\d+),\s*lsl (r\d+)/$1lsl$3$6, $7\n$1$2$3$4, $5, $6\n$1lsr$3$6, $7/g;

    # Convert loads with right shifts in the indexing into a
    # sequence of an add, load and sub. This converts
    # "ldrb r4, [r9, lr, asr #1]" into "add r9, r9, lr, asr #1",
    # "ldrb r9, [r9]", "sub r9, r9, lr, asr #1".
    s/^(\s*)(ldrb)(\s+)(r\d+),\s*\[(\w+),\s*(\w+),\s*(asr #\d+)\]/$1add $3$5, $5, $6, $7\n$1$2$3$4, [$5]\n$1sub $3$5, $5, $6, $7/g;

    # Convert register indexing with writeback into a separate add
    # instruction. This converts "ldrb r12, [r1, r2]!" into
    # "ldrb r12, [r1, r2]", "add r1, r1, r2".
    s/^(\s*)(ldrb)(\s+)(r\d+),\s*\[(\w+),\s*(\w+)\]!/$1$2$3$4, [$5, $6]\n$1add $3$5, $6/g;

    # Convert negative register indexing into separate sub/add instructions.
    # This converts "ldrne r4, [src, -pstep, lsl #1]" into
    # "subne src, src, pstep, lsl #1", "ldrne r4, [src]",
    # "addne src, src, pstep, lsl #1". In a couple of cases where
    # this is used, it's used for two subsequent load instructions,
    # where a hand-written version of it could merge two subsequent
    # add and sub instructions.
50
    s/^(\s*)((ldr|str|pld)(ne)?)(\s+)(r\d+,\s*)?\[(\w+), -([^\]]+)\]/$1sub$4$5$7, $7, $8\n$1$2$5$6\[$7\]\n$1add$4$5$7, $7, $8/g;
51
52
53
54
55
56
57
58

    # Convert register post indexing to a separate add instruction.
    # This converts "ldrneb r9, [r0], r2" into "ldrneb r9, [r0]",
    # "add r0, r2".
    s/^(\s*)((ldr|str)(ne)?[bhd]?)(\s+)(\w+),(\s*\w+,)?\s*\[(\w+)\],\s*(\w+)/$1$2$5$6,$7 [$8]\n$1add$4$5$8, $8, $9/g;

    # Convert a conditional addition to the pc register into a series of
    # instructions. This converts "addlt pc, pc, r3, lsl #2" into
59
60
61
    # "itttt lt", "movlt.n r12, pc", "addlt.w r12, #12",
    # "addlt.w r12, r12, r3, lsl #2", "movlt.n pc, r12".
    # This assumes that r12 is free at this point.
62
    s/^(\s*)addlt(\s+)pc,\s*pc,\s*(\w+),\s*lsl\s*#(\d+)/$1itttt$2lt\n$1movlt.n$2r12, pc\n$1addlt.w$2r12, #12\n$1addlt.w$2r12, r12, $3, lsl #($4-$branch_shift_offset)\n$1movlt.n$2pc, r12/g;
63
64
65
66
67
68
69
70

    # Convert "mov pc, lr" into "bx lr", since the former only works
    # for switching from arm to thumb (and only in armv7), but not
    # from thumb to arm.
    s/mov(\s*)pc\s*,\s*lr/bx$1lr/g;
}

1;