1 /*
   2  * Copyright (c) 2015, 2018, 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  */
  23 
  24 
  25 package org.graalvm.compiler.core.common.alloc;
  26 
  27 import jdk.internal.vm.compiler.collections.EconomicMap;
  28 import jdk.internal.vm.compiler.collections.Equivalence;
  29 import org.graalvm.compiler.core.common.GraalOptions;
  30 
  31 import jdk.vm.ci.code.Register;
  32 import jdk.vm.ci.code.Register.RegisterCategory;
  33 import jdk.vm.ci.code.RegisterArray;
  34 import jdk.vm.ci.code.RegisterConfig;
  35 import jdk.vm.ci.meta.PlatformKind;
  36 
  37 /**
  38  * Configuration for register allocation. This is different to {@link RegisterConfig} as it only
  39  * returns registers specified by {@link GraalOptions#RegisterPressure}.
  40  */
  41 public class RegisterAllocationConfig {
  42 
  43     public static final class AllocatableRegisters {
  44         public final Register[] allocatableRegisters;
  45         public final int minRegisterNumber;
  46         public final int maxRegisterNumber;
  47 
  48         public AllocatableRegisters(RegisterArray allocatableRegisters, int minRegisterNumber, int maxRegisterNumber) {
  49             this.allocatableRegisters = allocatableRegisters.toArray();
  50             this.minRegisterNumber = minRegisterNumber;
  51             this.maxRegisterNumber = maxRegisterNumber;
  52             assert verify(allocatableRegisters, minRegisterNumber, maxRegisterNumber);
  53         }
  54 
  55         private static boolean verify(RegisterArray allocatableRegisters, int minRegisterNumber, int maxRegisterNumber) {
  56             int min = Integer.MAX_VALUE;
  57             int max = Integer.MIN_VALUE;
  58             for (Register reg : allocatableRegisters) {
  59                 int number = reg.number;
  60                 if (number < min) {
  61                     min = number;
  62                 }
  63                 if (number > max) {
  64                     max = number;
  65                 }
  66             }
  67             assert minRegisterNumber == min;
  68             assert maxRegisterNumber == max;
  69             return true;
  70         }
  71     }
  72 
  73     public static final String ALL_REGISTERS = "<all>";
  74 
  75     private static Register findRegister(String name, RegisterArray all) {
  76         for (Register reg : all) {
  77             if (reg.name.equals(name)) {
  78                 return reg;
  79             }
  80         }
  81         throw new IllegalArgumentException("register " + name + " is not allocatable");
  82     }
  83 
  84     protected RegisterArray initAllocatable(RegisterArray registers) {
  85         if (allocationRestrictedTo != null) {
  86             Register[] regs = new Register[allocationRestrictedTo.length];
  87             for (int i = 0; i < allocationRestrictedTo.length; i++) {
  88                 regs[i] = findRegister(allocationRestrictedTo[i], registers);
  89             }
  90             return new RegisterArray(regs);
  91         }
  92 
  93         return registers;
  94     }
  95 
  96     protected final RegisterConfig registerConfig;
  97     private final EconomicMap<PlatformKind.Key, AllocatableRegisters> categorized = EconomicMap.create(Equivalence.DEFAULT);
  98     private final String[] allocationRestrictedTo;
  99     private RegisterArray cachedRegisters;
 100 
 101     /**
 102      * @param allocationRestrictedTo if not {@code null}, register allocation will be restricted to
 103      *            registers whose names appear in this array
 104      */
 105     public RegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo) {
 106         assert registerConfig != null;
 107         this.registerConfig = registerConfig;
 108         this.allocationRestrictedTo = allocationRestrictedTo;
 109     }
 110 
 111     /**
 112      * Gets the set of registers that can be used by the register allocator for a value of a
 113      * particular kind.
 114      */
 115     public AllocatableRegisters getAllocatableRegisters(PlatformKind kind) {
 116         PlatformKind.Key key = kind.getKey();
 117         if (categorized.containsKey(key)) {
 118             AllocatableRegisters val = categorized.get(key);
 119             return val;
 120         }
 121         AllocatableRegisters ret = createAllocatableRegisters(registerConfig.filterAllocatableRegisters(kind, getAllocatableRegisters()));
 122         categorized.put(key, ret);
 123         return ret;
 124     }
 125 
 126     /**
 127      * Gets the {@link RegisterCategory} for the given {@link PlatformKind}.
 128      */
 129     public RegisterCategory getRegisterCategory(PlatformKind kind) {
 130         return getAllocatableRegisters(kind).allocatableRegisters[0].getRegisterCategory();
 131     }
 132 
 133     protected AllocatableRegisters createAllocatableRegisters(RegisterArray registers) {
 134         int min = Integer.MAX_VALUE;
 135         int max = Integer.MIN_VALUE;
 136         for (Register reg : registers) {
 137             int number = reg.number;
 138             if (number < min) {
 139                 min = number;
 140             }
 141             if (number > max) {
 142                 max = number;
 143             }
 144         }
 145         assert min < max;
 146         return new AllocatableRegisters(registers, min, max);
 147 
 148     }
 149 
 150     /**
 151      * Gets the set of registers that can be used by the register allocator.
 152      */
 153     public RegisterArray getAllocatableRegisters() {
 154         if (cachedRegisters == null) {
 155             cachedRegisters = initAllocatable(registerConfig.getAllocatableRegisters());
 156         }
 157         assert cachedRegisters != null;
 158         return cachedRegisters;
 159     }
 160 
 161     public RegisterConfig getRegisterConfig() {
 162         return registerConfig;
 163     }
 164 
 165 }