1 /* 2 * Copyright (c) 2011, 2019, 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.lir.gen; 26 27 import java.util.BitSet; 28 import java.util.List; 29 30 import org.graalvm.compiler.core.common.CompressEncoding; 31 import org.graalvm.compiler.core.common.LIRKind; 32 import org.graalvm.compiler.core.common.calc.Condition; 33 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; 34 import org.graalvm.compiler.core.common.spi.CodeGenProviders; 35 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 36 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; 37 import org.graalvm.compiler.core.common.type.Stamp; 38 import org.graalvm.compiler.debug.GraalError; 39 import org.graalvm.compiler.graph.NodeSourcePosition; 40 import org.graalvm.compiler.lir.LIRFrameState; 41 import org.graalvm.compiler.lir.LIRInstruction; 42 import org.graalvm.compiler.lir.LabelRef; 43 import org.graalvm.compiler.lir.SwitchStrategy; 44 import org.graalvm.compiler.lir.Variable; 45 import org.graalvm.compiler.lir.VirtualStackSlot; 46 47 import jdk.vm.ci.code.CodeCacheProvider; 48 import jdk.vm.ci.code.Register; 49 import jdk.vm.ci.code.RegisterAttributes; 50 import jdk.vm.ci.code.RegisterConfig; 51 import jdk.vm.ci.code.StackSlot; 52 import jdk.vm.ci.code.TargetDescription; 53 import jdk.vm.ci.code.ValueKindFactory; 54 import jdk.vm.ci.meta.AllocatableValue; 55 import jdk.vm.ci.meta.Constant; 56 import jdk.vm.ci.meta.JavaConstant; 57 import jdk.vm.ci.meta.JavaKind; 58 import jdk.vm.ci.meta.MetaAccessProvider; 59 import jdk.vm.ci.meta.PlatformKind; 60 import jdk.vm.ci.meta.Value; 61 import jdk.vm.ci.meta.ValueKind; 62 63 public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindFactory<LIRKind> { 64 65 /** 66 * Factory for creating moves. 67 */ 68 interface MoveFactory { 69 70 /** 71 * Checks whether the supplied constant can be used without loading it into a register for 72 * most operations, i.e., for commonly used arithmetic, logical, and comparison operations. 73 * 74 * @param c The constant to check. 75 * @return True if the constant can be used directly, false if the constant needs to be in a 76 * register. 77 */ 78 boolean canInlineConstant(Constant c); 79 80 /** 81 * @param constant The constant that might be moved to a stack slot. 82 * @return {@code true} if constant to stack moves are supported for this constant. 83 */ 84 boolean allowConstantToStackMove(Constant constant); 85 86 LIRInstruction createMove(AllocatableValue result, Value input); 87 88 LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input); 89 90 LIRInstruction createLoad(AllocatableValue result, Constant input); 91 92 LIRInstruction createStackLoad(AllocatableValue result, Constant input); 93 } 94 95 abstract class BlockScope implements AutoCloseable { 96 97 public abstract AbstractBlockBase<?> getCurrentBlock(); 98 99 @Override 100 public abstract void close(); 101 102 } 103 104 ArithmeticLIRGeneratorTool getArithmetic(); 105 106 CodeGenProviders getProviders(); 107 108 TargetDescription target(); 109 110 MetaAccessProvider getMetaAccess(); 111 112 CodeCacheProvider getCodeCache(); 113 114 ForeignCallsProvider getForeignCalls(); 115 116 AbstractBlockBase<?> getCurrentBlock(); 117 118 LIRGenerationResult getResult(); 119 120 RegisterConfig getRegisterConfig(); 121 122 boolean hasBlockEnd(AbstractBlockBase<?> block); 123 124 MoveFactory getMoveFactory(); 125 126 /** 127 * Get a special {@link MoveFactory} for spill moves. 128 * 129 * The instructions returned by this factory must only depend on the input values. References to 130 * values that require interaction with register allocation are strictly forbidden. 131 */ 132 MoveFactory getSpillMoveFactory(); 133 134 BlockScope getBlockScope(AbstractBlockBase<?> block); 135 136 Value emitConstant(LIRKind kind, Constant constant); 137 138 Value emitJavaConstant(JavaConstant constant); 139 140 /** 141 * Some backends need to convert sub-word kinds to a larger kind in 142 * {@link ArithmeticLIRGeneratorTool#emitLoad} and {@link #emitLoadConstant} because sub-word 143 * registers can't be accessed. This method converts the {@link LIRKind} of a memory location or 144 * constant to the {@link LIRKind} that will be used when it is loaded into a register. 145 */ 146 <K extends ValueKind<K>> K toRegisterKind(K kind); 147 148 AllocatableValue emitLoadConstant(ValueKind<?> kind, Constant constant); 149 150 void emitNullCheck(Value address, LIRFrameState state); 151 152 Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue); 153 154 Value emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue); 155 156 /** 157 * Emit an atomic read-and-add instruction. 158 * 159 * @param address address of the value to be read and written 160 * @param valueKind the access kind for the value to be written 161 * @param delta the value to be added 162 */ 163 default Value emitAtomicReadAndAdd(Value address, ValueKind<?> valueKind, Value delta) { 164 throw GraalError.unimplemented(); 165 } 166 167 /** 168 * Emit an atomic read-and-write instruction. 169 * 170 * @param address address of the value to be read and written 171 * @param valueKind the access kind for the value to be written 172 * @param newValue the new value to be written 173 */ 174 default Value emitAtomicReadAndWrite(Value address, ValueKind<?> valueKind, Value newValue) { 175 throw GraalError.unimplemented(); 176 } 177 178 void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state); 179 180 Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args); 181 182 RegisterAttributes attributes(Register register); 183 184 /** 185 * Create a new {@link Variable}. 186 * 187 * @param kind The type of the value that will be stored in this {@link Variable}. See 188 * {@link LIRKind} for documentation on what to pass here. Note that in most cases, 189 * simply passing {@link Value#getValueKind()} is wrong. 190 * @return A new {@link Variable}. 191 */ 192 Variable newVariable(ValueKind<?> kind); 193 194 Variable emitMove(Value input); 195 196 void emitMove(AllocatableValue dst, Value src); 197 198 void emitMoveConstant(AllocatableValue dst, Constant src); 199 200 Variable emitAddress(AllocatableValue stackslot); 201 202 void emitMembar(int barriers); 203 204 void emitUnwind(Value operand); 205 206 /** 207 * Called just before register allocation is performed on the LIR owned by this generator. 208 * Overriding implementations of this method must call the overridden method. 209 */ 210 void beforeRegisterAllocation(); 211 212 void emitIncomingValues(Value[] params); 213 214 /** 215 * Emits a return instruction. Implementations need to insert a move if the input is not in the 216 * correct location. 217 */ 218 void emitReturn(JavaKind javaKind, Value input); 219 220 AllocatableValue asAllocatable(Value value); 221 222 Variable load(Value value); 223 224 Value loadNonConst(Value value); 225 226 /** 227 * Determines if only oop maps are required for the code generated from the LIR. 228 */ 229 boolean needOnlyOopMaps(); 230 231 /** 232 * Gets the ABI specific operand used to return a value of a given kind from a method. 233 * 234 * @param javaKind the {@link JavaKind} of value being returned 235 * @param valueKind the backend type of the value being returned 236 * @return the operand representing the ABI defined location used return a value of kind 237 * {@code kind} 238 */ 239 AllocatableValue resultOperandFor(JavaKind javaKind, ValueKind<?> valueKind); 240 241 <I extends LIRInstruction> I append(I op); 242 243 void setSourcePosition(NodeSourcePosition position); 244 245 void emitJump(LabelRef label); 246 247 void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, 248 double trueDestinationProbability); 249 250 void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability); 251 252 void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability); 253 254 Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue); 255 256 Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue); 257 258 void emitStrategySwitch(JavaConstant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value); 259 260 void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget); 261 262 Variable emitByteSwap(Value operand); 263 264 @SuppressWarnings("unused") 265 default Variable emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2) { 266 throw GraalError.unimplemented("String.compareTo substitution is not implemented on this architecture"); 267 } 268 269 Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length, int constantLength, boolean directPointers); 270 271 @SuppressWarnings("unused") 272 default ForeignCallLinkage lookupArrayEqualsStub(JavaKind kind, int constantLength) { 273 return null; 274 } 275 276 @SuppressWarnings("unused") 277 default Variable emitArrayEquals(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length, int constantLength, boolean directPointers) { 278 throw GraalError.unimplemented("Array.equals with different types substitution is not implemented on this architecture"); 279 } 280 281 @SuppressWarnings("unused") 282 default Variable emitArrayIndexOf(JavaKind kind, boolean findTwoConsecutive, Value sourcePointer, Value sourceCount, Value... searchValues) { 283 throw GraalError.unimplemented("String.indexOf substitution is not implemented on this architecture"); 284 } 285 286 /* 287 * The routines emitStringLatin1Inflate/3 and emitStringUTF16Compress/3 models a simplified 288 * version of 289 * 290 * emitStringLatin1Inflate(Value src, Value src_ndx, Value dst, Value dst_ndx, Value len) and 291 * emitStringUTF16Compress(Value src, Value src_ndx, Value dst, Value dst_ndx, Value len) 292 * 293 * respectively, where we have hoisted the offset address computations in a method replacement 294 * snippet. 295 */ 296 @SuppressWarnings("unused") 297 default void emitStringLatin1Inflate(Value src, Value dst, Value len) { 298 throw GraalError.unimplemented("StringLatin1.inflate substitution is not implemented on this architecture"); 299 } 300 301 @SuppressWarnings("unused") 302 default Variable emitStringUTF16Compress(Value src, Value dst, Value len) { 303 throw GraalError.unimplemented("StringUTF16.compress substitution is not implemented on this architecture"); 304 } 305 306 void emitBlackhole(Value operand); 307 308 LIRKind getLIRKind(Stamp stamp); 309 310 void emitPause(); 311 312 void emitPrefetchAllocate(Value address); 313 314 Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull); 315 316 Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull); 317 318 default void emitConvertNullToZero(AllocatableValue result, Value input) { 319 emitMove(result, input); 320 } 321 322 default void emitConvertZeroToNull(AllocatableValue result, Value input) { 323 emitMove(result, input); 324 } 325 326 /** 327 * Emits an instruction that prevents speculative execution from proceeding: no instruction 328 * after this fence will execute until all previous instructions have retired. 329 */ 330 void emitSpeculationFence(); 331 332 default VirtualStackSlot allocateStackSlots(int slots, BitSet objects, List<VirtualStackSlot> outObjectStackSlots) { 333 return getResult().getFrameMapBuilder().allocateStackSlots(slots, objects, outObjectStackSlots); 334 } 335 336 default Value emitReadCallerStackPointer(Stamp wordStamp) { 337 /* 338 * We do not know the frame size yet. So we load the address of the first spill slot 339 * relative to the beginning of the frame, which is equivalent to the stack pointer of the 340 * caller. 341 */ 342 return emitAddress(StackSlot.get(getLIRKind(wordStamp), 0, true)); 343 } 344 345 default Value emitReadReturnAddress(Stamp wordStamp, int returnAddressSize) { 346 return emitMove(StackSlot.get(getLIRKind(wordStamp), -returnAddressSize, true)); 347 } 348 }