1/*
2 * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package org.graalvm.compiler.asm.sparc.test;
24
25import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
26import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPR;
27import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BR;
28import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CBCOND;
29import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL;
30import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN;
31import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc;
32import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.CarryClear;
33import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal;
34import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_z;
35import static jdk.vm.ci.sparc.SPARC.g0;
36
37import java.util.EnumSet;
38import java.util.function.Consumer;
39
40import jdk.vm.ci.code.Architecture;
41import jdk.vm.ci.code.BailoutException;
42import jdk.vm.ci.code.TargetDescription;
43import jdk.vm.ci.sparc.SPARC;
44
45import org.junit.Assert;
46import org.junit.Before;
47import org.junit.Test;
48
49import org.graalvm.compiler.asm.Label;
50import org.graalvm.compiler.asm.sparc.SPARCAssembler;
51import org.graalvm.compiler.asm.sparc.SPARCAssembler.ControlTransferOp;
52import org.graalvm.compiler.asm.sparc.SPARCAssembler.SPARCOp;
53import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
54import org.graalvm.compiler.test.GraalTest;
55
56public class SPARCAssemblerTest extends GraalTest {
57    private SPARCMacroAssembler masm;
58
59    private static EnumSet<SPARC.CPUFeature> computeFeatures() {
60        EnumSet<SPARC.CPUFeature> features = EnumSet.noneOf(SPARC.CPUFeature.class);
61        features.add(SPARC.CPUFeature.CBCOND);
62        return features;
63    }
64
65    private static TargetDescription createTarget() {
66        final int stackFrameAlignment = 16;
67        final int implicitNullCheckLimit = 4096;
68        final boolean inlineObjects = true;
69        Architecture arch = new SPARC(computeFeatures());
70        return new TargetDescription(arch, true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects);
71    }
72
73    @Before
74    public void setup() {
75        TargetDescription target = createTarget();
76        masm = new SPARCMacroAssembler(target);
77    }
78
79    @Test
80    public void testPatchCbcod() {
81        testControlTransferOp(l -> CBCOND.emit(masm, CarryClear, false, g0, 3, l), -512, 511);
82    }
83
84    @Test
85    public void testPatchBpcc() {
86        int maxDisp = 1 << 18;
87        testControlTransferOp(l -> BPCC.emit(masm, Xcc, Equal, ANNUL, PREDICT_NOT_TAKEN, l), -maxDisp,
88                        maxDisp - 1);
89    }
90
91    @Test
92    public void testPatchBpr() {
93        int maxDisp = 1 << 15;
94        testControlTransferOp(l -> BPR.emit(masm, Rc_z, ANNUL, PREDICT_NOT_TAKEN, g0, l), -maxDisp,
95                        maxDisp - 1);
96    }
97
98    @Test
99    public void testPatchBr() {
100        int maxDisp = 1 << 21;
101        testControlTransferOp(l -> BR.emit(masm, Equal, ANNUL, l), -maxDisp,
102                        maxDisp - 1);
103    }
104
105    @Test(expected = BailoutException.class)
106    public void testControlTransferInvalidDisp() {
107        int cbcondInstruction = 0x12f83f60;
108        CBCOND.setDisp(cbcondInstruction, 0x2ff);
109    }
110
111    public void testControlTransferOp(Consumer<Label> opCreator, int minDisp, int maxDisp) {
112        doTestControlTransferOp(opCreator, minDisp, maxDisp);
113        try {
114            doTestControlTransferOp(opCreator, minDisp - 1, maxDisp);
115            fail("minDisp out of bound must not assemble correctly");
116        } catch (BailoutException e) {
117            // ignored
118        }
119        try {
120            doTestControlTransferOp(opCreator, minDisp, maxDisp + 1);
121            fail("maxDisp out of bound must not assemble correctly");
122        } catch (BailoutException e) {
123            // ignored
124        }
125    }
126
127    /**
128     * Assembles the control transfer op and then verifies the expected disp value against the disp
129     * field provided by the disassembler.
130     */
131    public void doTestControlTransferOp(Consumer<Label> opCreator, int minDisp, int maxDisp) {
132        Label lBack = new Label();
133        Label lForward = new Label();
134        masm.bind(lBack);
135        for (int i = 0; i < -minDisp; i++) {
136            masm.nop();
137        }
138        int backPos = masm.position();
139        opCreator.accept(lBack);
140        masm.nop(); // Nop required to separate the two control transfer instructions
141        int forwardPos = masm.position();
142        opCreator.accept(lForward);
143        for (int i = 0; i < maxDisp - 1; i++) {
144            masm.nop();
145        }
146        masm.bind(lForward);
147
148        int condBack = masm.getInt(backPos);
149        SPARCOp backOp = SPARCAssembler.getSPARCOp(condBack);
150        int dispBack = ((ControlTransferOp) backOp).getDisp(condBack);
151        Assert.assertEquals(minDisp, dispBack);
152
153        int condFwd = masm.getInt(forwardPos);
154        SPARCOp fwdOp = SPARCAssembler.getSPARCOp(condFwd);
155        int dispFwd = ((ControlTransferOp) fwdOp).getDisp(condFwd);
156        Assert.assertEquals(maxDisp, dispFwd);
157    }
158}
159