001/* 002 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.lir.amd64.phases; 024 025import static com.oracle.graal.lir.phases.LIRPhase.Options.*; 026 027import java.util.*; 028 029import jdk.internal.jvmci.code.*; 030import com.oracle.graal.debug.*; 031import jdk.internal.jvmci.meta.*; 032import jdk.internal.jvmci.options.*; 033 034import com.oracle.graal.compiler.common.cfg.*; 035import com.oracle.graal.lir.*; 036import com.oracle.graal.lir.amd64.AMD64Move.AMD64MultiStackMove; 037import com.oracle.graal.lir.amd64.AMD64Move.AMD64StackMove; 038import com.oracle.graal.lir.gen.*; 039import com.oracle.graal.lir.phases.*; 040 041/** 042 * Replaces sequential {@link AMD64StackMove}s of the same type with a single 043 * {@link AMD64MultiStackMove} to avoid storing/restoring the scratch register multiple times. 044 * 045 * Note: this phase must be inserted <b>after</b> {@link RedundantMoveElimination} phase because 046 * {@link AMD64MultiStackMove} are not probably detected. 047 */ 048public class StackMoveOptimizationPhase extends PostAllocationOptimizationPhase { 049 public static class Options { 050 // @formatter:off 051 @Option(help = "", type = OptionType.Debug) 052 public static final NestedBooleanOptionValue LIROptStackMoveOptimizer = new NestedBooleanOptionValue(LIROptimization, true); 053 // @formatter:on 054 } 055 056 private static final DebugMetric eliminatedBackup = Debug.metric("StackMoveOptimizer[EliminatedScratchBackupRestore]"); 057 058 @Override 059 protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, 060 BenchmarkCounterFactory counterFactory) { 061 LIR lir = lirGenRes.getLIR(); 062 for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) { 063 List<LIRInstruction> instructions = lir.getLIRforBlock(block); 064 new Closure().process(instructions); 065 } 066 } 067 068 private static class Closure { 069 private static final int NONE = -1; 070 071 private int begin = NONE; 072 private Register reg = null; 073 private List<AllocatableValue> dst; 074 private List<Value> src; 075 private StackSlotValue slot; 076 private boolean removed = false; 077 078 public void process(List<LIRInstruction> instructions) { 079 for (int i = 0; i < instructions.size(); i++) { 080 LIRInstruction inst = instructions.get(i); 081 082 if (isStackMove(inst)) { 083 AMD64StackMove move = asStackMove(inst); 084 085 if (reg != null && !reg.equals(move.getScratchRegister())) { 086 // end of trace & start of new 087 replaceStackMoves(instructions); 088 } 089 090 // lazy initialize 091 if (dst == null) { 092 assert src == null; 093 dst = new ArrayList<>(); 094 src = new ArrayList<>(); 095 } 096 097 dst.add(move.getResult()); 098 src.add(move.getInput()); 099 100 if (begin == NONE) { 101 // trace begin 102 begin = i; 103 reg = move.getScratchRegister(); 104 slot = move.getBackupSlot(); 105 } 106 107 } else if (begin != NONE) { 108 // end of trace 109 replaceStackMoves(instructions); 110 } 111 } 112 // remove instructions 113 if (removed) { 114 instructions.removeAll(Collections.singleton(null)); 115 } 116 117 } 118 119 private void replaceStackMoves(List<LIRInstruction> instructions) { 120 int size = dst.size(); 121 if (size > 1) { 122 AMD64MultiStackMove multiMove = new AMD64MultiStackMove(dst.toArray(new AllocatableValue[size]), src.toArray(new AllocatableValue[size]), reg, slot); 123 // replace first instruction 124 instructions.set(begin, multiMove); 125 // and null out others 126 Collections.fill(instructions.subList(begin + 1, begin + size), null); 127 // removed 128 removed = true; 129 eliminatedBackup.add(size - 1); 130 } 131 // reset 132 dst.clear(); 133 src.clear(); 134 begin = NONE; 135 reg = null; 136 slot = null; 137 } 138 } 139 140 private static AMD64StackMove asStackMove(LIRInstruction inst) { 141 assert isStackMove(inst); 142 return (AMD64StackMove) inst; 143 } 144 145 private static boolean isStackMove(LIRInstruction inst) { 146 return inst instanceof AMD64StackMove; 147 } 148 149}