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