1/*
2 * Copyright (c) 2013, 2015, 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.core.test.backend;
24
25import java.util.HashSet;
26
27import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
28import org.graalvm.compiler.debug.DebugContext;
29import org.graalvm.compiler.lir.LIR;
30import org.graalvm.compiler.lir.LIRInstruction;
31import org.graalvm.compiler.lir.LIRValueUtil;
32import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
33import org.graalvm.compiler.lir.ValueProcedure;
34import org.graalvm.compiler.nodes.StructuredGraph;
35import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
36import org.junit.Assert;
37
38import jdk.vm.ci.code.Register;
39import jdk.vm.ci.code.ValueUtil;
40import jdk.vm.ci.meta.Value;
41
42public class AllocatorTest extends BackendTest {
43
44    @SuppressWarnings("try")
45    protected void testAllocation(String snippet, final int expectedRegisters, final int expectedRegRegMoves, final int expectedSpillMoves) {
46        final StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
47        DebugContext debug = graph.getDebug();
48        try (DebugContext.Scope s = debug.scope("AllocatorTest", graph, graph.method(), getCodeCache())) {
49            final RegisterStats stats = new RegisterStats(getLIRGenerationResult(graph).getLIR());
50            try (DebugContext.Scope s2 = debug.scope("Assertions", stats.lir)) {
51                Assert.assertEquals("register count", expectedRegisters, stats.registers.size());
52                Assert.assertEquals("reg-reg moves", expectedRegRegMoves, stats.regRegMoves);
53                Assert.assertEquals("spill moves", expectedSpillMoves, stats.spillMoves);
54            } catch (Throwable e) {
55                throw debug.handle(e);
56            }
57        } catch (Throwable e) {
58            throw debug.handle(e);
59        }
60    }
61
62    private class RegisterStats {
63
64        public final LIR lir;
65        public HashSet<Register> registers = new HashSet<>();
66        public int regRegMoves;
67        public int spillMoves;
68
69        RegisterStats(LIR lir) {
70            this.lir = lir;
71
72            for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
73                if (block == null) {
74                    continue;
75                }
76                for (LIRInstruction instr : lir.getLIRforBlock(block)) {
77                    collectStats(instr);
78                }
79            }
80        }
81
82        private ValueProcedure collectStatsProc = (value, mode, flags) -> {
83            if (ValueUtil.isRegister(value)) {
84                final Register reg = ValueUtil.asRegister(value);
85                registers.add(reg);
86            }
87            return value;
88        };
89
90        private void collectStats(final LIRInstruction instr) {
91            instr.forEachOutput(collectStatsProc);
92
93            if (ValueMoveOp.isValueMoveOp(instr)) {
94                ValueMoveOp move = ValueMoveOp.asValueMoveOp(instr);
95                Value def = move.getResult();
96                Value use = move.getInput();
97                if (ValueUtil.isRegister(def)) {
98                    if (ValueUtil.isRegister(use)) {
99                        regRegMoves++;
100                    }
101                } else if (LIRValueUtil.isStackSlotValue(def)) {
102                    spillMoves++;
103                }
104            }
105        }
106    }
107}
108