1 /* 2 * Copyright (c) 2009, 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 */ 23 24 package org.graalvm.compiler.core.sparc; 25 26 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FMOVDCC; 27 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FMOVSCC; 28 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.MOVicc; 29 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0; 30 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc; 31 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmpd; 32 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmps; 33 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; 34 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; 35 import static jdk.vm.ci.sparc.SPARCKind.SINGLE; 36 import static jdk.vm.ci.sparc.SPARCKind.WORD; 37 import static jdk.vm.ci.sparc.SPARCKind.XWORD; 38 39 import org.graalvm.compiler.asm.sparc.SPARCAssembler; 40 import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC; 41 import org.graalvm.compiler.asm.sparc.SPARCAssembler.CMOV; 42 import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag; 43 import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s; 44 import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs; 45 import org.graalvm.compiler.core.common.LIRKind; 46 import org.graalvm.compiler.core.common.calc.Condition; 47 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 48 import org.graalvm.compiler.core.common.spi.LIRKindTool; 49 import org.graalvm.compiler.debug.GraalError; 50 import org.graalvm.compiler.lir.LIR; 51 import org.graalvm.compiler.lir.LIRFrameState; 52 import org.graalvm.compiler.lir.LIRValueUtil; 53 import org.graalvm.compiler.lir.LabelRef; 54 import org.graalvm.compiler.lir.StandardOp.NoOp; 55 import org.graalvm.compiler.lir.SwitchStrategy; 56 import org.graalvm.compiler.lir.Variable; 57 import org.graalvm.compiler.lir.gen.LIRGenerationResult; 58 import org.graalvm.compiler.lir.gen.LIRGenerator; 59 import org.graalvm.compiler.lir.sparc.SPARCAddressValue; 60 import org.graalvm.compiler.lir.sparc.SPARCArrayEqualsOp; 61 import org.graalvm.compiler.lir.sparc.SPARCByteSwapOp; 62 import org.graalvm.compiler.lir.sparc.SPARCCall; 63 import org.graalvm.compiler.lir.sparc.SPARCControlFlow; 64 import org.graalvm.compiler.lir.sparc.SPARCControlFlow.BranchOp; 65 import org.graalvm.compiler.lir.sparc.SPARCControlFlow.CondMoveOp; 66 import org.graalvm.compiler.lir.sparc.SPARCControlFlow.ReturnOp; 67 import org.graalvm.compiler.lir.sparc.SPARCControlFlow.StrategySwitchOp; 68 import org.graalvm.compiler.lir.sparc.SPARCControlFlow.TableSwitchOp; 69 import org.graalvm.compiler.lir.sparc.SPARCFloatCompareOp; 70 import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue; 71 import org.graalvm.compiler.lir.sparc.SPARCJumpOp; 72 import org.graalvm.compiler.lir.sparc.SPARCLoadConstantTableBaseOp; 73 import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp; 74 import org.graalvm.compiler.lir.sparc.SPARCMove.MembarOp; 75 import org.graalvm.compiler.lir.sparc.SPARCMove.NullCheckOp; 76 import org.graalvm.compiler.lir.sparc.SPARCMove.StackLoadAddressOp; 77 import org.graalvm.compiler.lir.sparc.SPARCOP3Op; 78 import org.graalvm.compiler.lir.sparc.SPARCPauseOp; 79 import org.graalvm.compiler.phases.util.Providers; 80 81 import jdk.vm.ci.meta.AllocatableValue; 82 import jdk.vm.ci.meta.Constant; 83 import jdk.vm.ci.meta.JavaConstant; 84 import jdk.vm.ci.meta.JavaKind; 85 import jdk.vm.ci.meta.PlatformKind; 86 import jdk.vm.ci.meta.Value; 87 import jdk.vm.ci.meta.ValueKind; 88 import jdk.vm.ci.sparc.SPARC; 89 import jdk.vm.ci.sparc.SPARCKind; 90 91 /** 92 * This class implements the SPARC specific portion of the LIR generator. 93 */ 94 public abstract class SPARCLIRGenerator extends LIRGenerator { 95 96 private SPARCLoadConstantTableBaseOp loadConstantTableBaseOp; 97 private final ConstantTableBaseProvider constantTableBaseProvider; 98 99 public static final class ConstantTableBaseProvider { 100 private Variable constantTableBase; 101 private boolean useConstantTableBase = false; 102 103 public Variable getConstantTableBase() { 104 useConstantTableBase = true; 105 return constantTableBase; 106 } 107 } 108 109 public SPARCLIRGenerator(LIRKindTool lirKindTool, SPARCArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes, 110 ConstantTableBaseProvider constantTableBaseProvider) { 111 super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes); 112 this.constantTableBaseProvider = constantTableBaseProvider; 113 } 114 115 @Override 116 protected JavaConstant zapValueForKind(PlatformKind kind) { 117 long dead = 0xDEADDEADDEADDEADL; 118 switch ((SPARCKind) kind) { 119 case BYTE: 120 return JavaConstant.forByte((byte) dead); 121 case HWORD: 122 return JavaConstant.forShort((short) dead); 123 case WORD: 124 return JavaConstant.forInt((int) dead); 125 case XWORD: 126 return JavaConstant.forLong(dead); 127 case SINGLE: 128 case V32_BYTE: 129 case V32_HWORD: 130 return JavaConstant.forFloat(Float.intBitsToFloat((int) dead)); 131 case DOUBLE: 132 case V64_BYTE: 133 case V64_HWORD: 134 case V64_WORD: 135 return JavaConstant.forDouble(Double.longBitsToDouble(dead)); 136 default: 137 throw new IllegalArgumentException(kind.toString()); 138 } 139 } 140 141 /** 142 * The SPARC backend only uses WORD and DWORD values in registers because except to the ld/st 143 * instructions no instruction deals either with 32 or 64 bits. This function converts small 144 * integer kinds to WORD. 145 */ 146 @Override 147 public <K extends ValueKind<K>> K toRegisterKind(K kind) { 148 switch ((SPARCKind) kind.getPlatformKind()) { 149 case BYTE: 150 case HWORD: 151 return kind.changeType(SPARCKind.WORD); 152 default: 153 return kind; 154 } 155 } 156 157 public SPARCAddressValue asAddressValue(Value address) { 158 if (address instanceof SPARCAddressValue) { 159 return (SPARCAddressValue) address; 160 } else { 161 ValueKind<?> kind = address.getValueKind(); 162 if (address instanceof JavaConstant) { 163 long displacement = ((JavaConstant) address).asLong(); 164 if (SPARCAssembler.isSimm13(displacement)) { 165 return new SPARCImmediateAddressValue(kind, SPARC.g0.asValue(kind), (int) displacement); 166 } 167 } 168 return new SPARCImmediateAddressValue(kind, asAllocatable(address), 0); 169 } 170 } 171 172 @Override 173 public Variable emitAddress(AllocatableValue stackslot) { 174 Variable result = newVariable(LIRKind.value(target().arch.getWordKind())); 175 append(new StackLoadAddressOp(result, stackslot)); 176 return result; 177 } 178 179 @Override 180 public void emitReturn(JavaKind javaKind, Value input) { 181 AllocatableValue operand = Value.ILLEGAL; 182 if (input != null) { 183 operand = resultOperandFor(javaKind, input.getValueKind()); 184 emitMove(operand, input); 185 } 186 append(new ReturnOp(operand)); 187 } 188 189 @Override 190 public void emitJump(LabelRef label) { 191 append(new SPARCJumpOp(label)); 192 } 193 194 @Override 195 public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, 196 double trueDestinationProbability) { 197 Value left; 198 Value right; 199 Condition actualCondition; 200 if (isJavaConstant(x)) { 201 left = load(y); 202 right = loadNonConst(x); 203 actualCondition = cond.mirror(); 204 } else { 205 left = load(x); 206 right = loadNonConst(y); 207 actualCondition = cond; 208 } 209 SPARCKind actualCmpKind = (SPARCKind) cmpKind; 210 if (actualCmpKind.isInteger()) { 211 assert actualCmpKind.equals(XWORD) || actualCmpKind.equals(WORD) : "SPARC does not support compare of: " + actualCmpKind; 212 append(new SPARCControlFlow.CompareBranchOp(left, right, actualCondition, trueDestination, falseDestination, actualCmpKind, unorderedIsTrue, trueDestinationProbability)); 213 } else if (actualCmpKind.isFloat()) { 214 emitFloatCompare(actualCmpKind, x, y, Fcc0); 215 ConditionFlag cf = SPARCControlFlow.fromCondition(false, cond, unorderedIsTrue); 216 append(new SPARCControlFlow.BranchOp(cf, trueDestination, falseDestination, actualCmpKind, trueDestinationProbability)); 217 } else { 218 throw GraalError.shouldNotReachHere(); 219 } 220 } 221 222 @Override 223 public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpLIRKind, double overflowProbability) { 224 SPARCKind cmpKind = (SPARCKind) cmpLIRKind.getPlatformKind(); 225 append(new BranchOp(ConditionFlag.OverflowSet, overflow, noOverflow, cmpKind, overflowProbability)); 226 } 227 228 @Override 229 public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { 230 emitIntegerTest(left, right); 231 append(new BranchOp(ConditionFlag.Equal, trueDestination, falseDestination, (SPARCKind) left.getPlatformKind(), trueDestinationProbability)); 232 } 233 234 private void emitIntegerTest(Value a, Value b) { 235 assert ((SPARCKind) a.getPlatformKind()).isInteger(); 236 if (LIRValueUtil.isVariable(b)) { 237 append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(b), loadNonConst(a))); 238 } else { 239 append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(a), loadNonConst(b))); 240 } 241 } 242 243 private Value loadSimm11(Value value) { 244 if (isJavaConstant(value)) { 245 JavaConstant c = asJavaConstant(value); 246 if (c.isNull() || SPARCAssembler.isSimm11(c)) { 247 return value; 248 } 249 } 250 return load(value); 251 } 252 253 @Override 254 public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) { 255 // Emit compare 256 SPARCKind cmpSPARCKind = (SPARCKind) cmpKind; 257 boolean mirrored = emitCompare(cmpSPARCKind, left, right); 258 259 // Emit move 260 Value actualTrueValue = trueValue; 261 Value actualFalseValue = falseValue; 262 SPARCKind valueKind = (SPARCKind) trueValue.getPlatformKind(); 263 CMOV cmove; 264 if (valueKind.isFloat()) { 265 actualTrueValue = load(trueValue); // Floats cannot be immediate at all 266 actualFalseValue = load(falseValue); 267 cmove = valueKind.equals(SINGLE) ? FMOVSCC : FMOVDCC; 268 } else if (valueKind.isInteger()) { 269 actualTrueValue = loadSimm11(trueValue); 270 actualFalseValue = loadSimm11(falseValue); 271 cmove = MOVicc; 272 } else { 273 throw GraalError.shouldNotReachHere(); 274 } 275 Variable result = newVariable(trueValue.getValueKind()); 276 ConditionFlag finalCondition = SPARCControlFlow.fromCondition(cmpSPARCKind.isInteger(), mirrored ? cond.mirror() : cond, unorderedIsTrue); 277 CC cc = CC.forKind(cmpSPARCKind); 278 append(new CondMoveOp(cmove, cc, finalCondition, actualTrueValue, actualFalseValue, result)); 279 return result; 280 } 281 282 /** 283 * This method emits the compare instruction, and may reorder the operands. It returns true if 284 * it did so. 285 * 286 * @param cmpKind Kind how a and b have to be compared 287 * @param a the left operand of the comparison 288 * @param b the right operand of the comparison 289 * @return true if the left and right operands were switched, false otherwise 290 */ 291 protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) { 292 boolean mirrored; 293 if (cmpKind.isInteger()) { // Integer case 294 mirrored = emitIntegerCompare(cmpKind, a, b); 295 } else if (cmpKind.isFloat()) { // Float case 296 mirrored = false; // No mirroring done on floats 297 emitFloatCompare(cmpKind, a, b, Fcc0); 298 } else { 299 throw GraalError.shouldNotReachHere(); 300 } 301 return mirrored; 302 } 303 304 private boolean emitIntegerCompare(SPARCKind cmpKind, Value a, Value b) { 305 boolean mirrored; 306 assert cmpKind.isInteger(); 307 Value left; 308 Value right; 309 if (LIRValueUtil.isVariable(b)) { 310 left = load(b); 311 right = loadNonConst(a); 312 mirrored = true; 313 } else { 314 left = load(a); 315 right = loadNonConst(b); 316 mirrored = false; 317 } 318 int compareBytes = cmpKind.getSizeInBytes(); 319 // SPARC compares 32 or 64 bits 320 if (compareBytes < left.getPlatformKind().getSizeInBytes()) { 321 left = arithmeticLIRGen.emitSignExtend(left, compareBytes * 8, XWORD.getSizeInBytes() * 8); 322 } 323 if (compareBytes < right.getPlatformKind().getSizeInBytes()) { 324 right = arithmeticLIRGen.emitSignExtend(right, compareBytes * 8, XWORD.getSizeInBytes() * 8); 325 } 326 append(SPARCOP3Op.newBinaryVoid(Subcc, left, right)); 327 return mirrored; 328 } 329 330 private void emitFloatCompare(SPARCKind cmpJavaKind, Value a, Value b, CC cc) { 331 Opfs floatCompareOpcode; 332 assert cmpJavaKind.isFloat(); 333 switch (cmpJavaKind) { 334 case DOUBLE: 335 floatCompareOpcode = Fcmpd; 336 break; 337 case SINGLE: 338 floatCompareOpcode = Fcmps; 339 break; 340 default: 341 throw GraalError.shouldNotReachHere(); 342 } 343 append(new SPARCFloatCompareOp(floatCompareOpcode, cc, load(a), load(b))); 344 } 345 346 @Override 347 public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) { 348 emitIntegerTest(left, right); 349 Variable result = newVariable(trueValue.getValueKind()); 350 ConditionFlag flag = SPARCControlFlow.fromCondition(true, Condition.EQ, false); 351 CC cc = CC.forKind(left.getPlatformKind()); 352 append(new CondMoveOp(MOVicc, cc, flag, loadSimm11(trueValue), loadSimm11(falseValue), result)); 353 return result; 354 } 355 356 @Override 357 protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { 358 long maxOffset = linkage.getMaxCallTargetOffset(); 359 if (SPARCAssembler.isWordDisp30(maxOffset)) { 360 append(new SPARCCall.DirectNearForeignCallOp(linkage, result, arguments, temps, info)); 361 } else { 362 append(new SPARCCall.DirectFarForeignCallOp(linkage, result, arguments, temps, info)); 363 } 364 } 365 366 @Override 367 public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { 368 AllocatableValue scratchValue = newVariable(key.getValueKind()); 369 AllocatableValue base = AllocatableValue.ILLEGAL; 370 for (Constant c : strategy.getKeyConstants()) { 371 if (!(c instanceof JavaConstant) || !getMoveFactory().canInlineConstant((JavaConstant) c)) { 372 base = constantTableBaseProvider.getConstantTableBase(); 373 break; 374 } 375 } 376 append(createStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue)); 377 } 378 379 protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue) { 380 return new StrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue); 381 } 382 383 @Override 384 protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) { 385 // Making a copy of the switch value is necessary because jump table destroys the input 386 // value 387 Variable tmp = newVariable(key.getValueKind()); 388 emitMove(tmp, key); 389 append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(LIRKind.value(target().arch.getWordKind())))); 390 } 391 392 protected SPARC getArchitecture() { 393 return (SPARC) target().arch; 394 } 395 396 @Override 397 public Variable emitByteSwap(Value input) { 398 Variable result = newVariable(LIRKind.combine(input)); 399 append(new SPARCByteSwapOp(this, result, input)); 400 return result; 401 } 402 403 @Override 404 public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) { 405 Variable result = newVariable(LIRKind.value(SPARCKind.WORD)); 406 append(new SPARCArrayEqualsOp(this, kind, result, load(array1), load(array2), asAllocatable(length))); 407 return result; 408 } 409 410 @Override 411 public void emitMembar(int barriers) { 412 int necessaryBarriers = target().arch.requiredBarriers(barriers); 413 if (target().isMP && necessaryBarriers != 0) { 414 append(new MembarOp(necessaryBarriers)); 415 } 416 } 417 418 @Override 419 public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) { 420 append(new ReturnOp(Value.ILLEGAL)); 421 } 422 423 public Value emitSignExtendLoad(LIRKind kind, LIRKind resultKind, Value address, LIRFrameState state) { 424 SPARCAddressValue loadAddress = asAddressValue(address); 425 Variable result = newVariable(resultKind); 426 append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state, true)); 427 return result; 428 } 429 430 public Value emitZeroExtendLoad(LIRKind kind, LIRKind resultKind, Value address, LIRFrameState state) { 431 SPARCAddressValue loadAddress = asAddressValue(address); 432 Variable result = newVariable(resultKind); 433 append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state)); 434 return result; 435 } 436 437 @Override 438 public void emitNullCheck(Value address, LIRFrameState state) { 439 PlatformKind kind = address.getPlatformKind(); 440 assert kind == XWORD : address + " - " + kind + " not an object!"; 441 append(new NullCheckOp(asAddressValue(address), state)); 442 } 443 444 public void emitLoadConstantTableBase() { 445 constantTableBaseProvider.constantTableBase = newVariable(LIRKind.value(XWORD)); 446 int nextPosition = getResult().getLIR().getLIRforBlock(getCurrentBlock()).size(); 447 NoOp placeHolder = append(new NoOp(getCurrentBlock(), nextPosition)); 448 loadConstantTableBaseOp = new SPARCLoadConstantTableBaseOp(constantTableBaseProvider.constantTableBase, placeHolder); 449 } 450 451 @Override 452 public void beforeRegisterAllocation() { 453 LIR lir = getResult().getLIR(); 454 loadConstantTableBaseOp.setAlive(lir, constantTableBaseProvider.useConstantTableBase); 455 } 456 457 @Override 458 public void emitPause() { 459 append(new SPARCPauseOp()); 460 } 461 }