1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dexgen.dex.code.form;
18
19import com.android.dexgen.dex.code.DalvInsn;
20import com.android.dexgen.dex.code.HighRegisterPrefix;
21import com.android.dexgen.dex.code.InsnFormat;
22import com.android.dexgen.dex.code.SimpleInsn;
23import com.android.dexgen.rop.code.RegisterSpec;
24import com.android.dexgen.rop.code.RegisterSpecList;
25import com.android.dexgen.util.AnnotatedOutput;
26
27/**
28 * Instruction format {@code 12x}. See the instruction format spec
29 * for details.
30 */
31public final class Form12x extends InsnFormat {
32    /** {@code non-null;} unique instance of this class */
33    public static final InsnFormat THE_ONE = new Form12x();
34
35    /**
36     * Constructs an instance. This class is not publicly
37     * instantiable. Use {@link #THE_ONE}.
38     */
39    private Form12x() {
40        // This space intentionally left blank.
41    }
42
43    /** {@inheritDoc} */
44    @Override
45    public String insnArgString(DalvInsn insn) {
46        RegisterSpecList regs = insn.getRegisters();
47        int sz = regs.size();
48
49        /*
50         * The (sz - 2) and (sz - 1) below makes this code work for
51         * both the two- and three-register ops. (See "case 3" in
52         * isCompatible(), below.)
53         */
54
55        return regs.get(sz - 2).regString() + ", " +
56            regs.get(sz - 1).regString();
57    }
58
59    /** {@inheritDoc} */
60    @Override
61    public String insnCommentString(DalvInsn insn, boolean noteIndices) {
62        // This format has no comment.
63        return "";
64    }
65
66    /** {@inheritDoc} */
67    @Override
68    public int codeSize() {
69        return 1;
70    }
71
72    /** {@inheritDoc} */
73    @Override
74    public boolean isCompatible(DalvInsn insn) {
75        if (!(insn instanceof SimpleInsn)) {
76            return false;
77        }
78
79        RegisterSpecList regs = insn.getRegisters();
80        RegisterSpec rs1;
81        RegisterSpec rs2;
82
83        switch (regs.size()) {
84            case 2: {
85                rs1 = regs.get(0);
86                rs2 = regs.get(1);
87                break;
88            }
89            case 3: {
90                /*
91                 * This format is allowed for ops that are effectively
92                 * 3-arg but where the first two args are identical.
93                 */
94                rs1 = regs.get(1);
95                rs2 = regs.get(2);
96                if (rs1.getReg() != regs.get(0).getReg()) {
97                    return false;
98                }
99                break;
100            }
101            default: {
102                return false;
103            }
104        }
105
106        return unsignedFitsInNibble(rs1.getReg()) &&
107            unsignedFitsInNibble(rs2.getReg());
108    }
109
110    /** {@inheritDoc} */
111    @Override
112    public InsnFormat nextUp() {
113        return Form22x.THE_ONE;
114    }
115
116    /** {@inheritDoc} */
117    @Override
118    public void writeTo(AnnotatedOutput out, DalvInsn insn) {
119        RegisterSpecList regs = insn.getRegisters();
120        int sz = regs.size();
121
122        /*
123         * The (sz - 2) and (sz - 1) below makes this code work for
124         * both the two- and three-register ops. (See "case 3" in
125         * isCompatible(), above.)
126         */
127
128        write(out, opcodeUnit(insn,
129                              makeByte(regs.get(sz - 2).getReg(),
130                                       regs.get(sz - 1).getReg())));
131    }
132}
133