1 /* 2 * Copyright (c) 2009, 2017, 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.Op3s.Add; 29 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Addcc; 30 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.And; 31 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Mulx; 32 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sdivx; 33 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sllx; 34 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sra; 35 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srax; 36 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srl; 37 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sub; 38 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc; 39 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Udivx; 40 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xnor; 41 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Faddd; 42 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fadds; 43 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtos; 44 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitod; 45 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitos; 46 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuld; 47 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuls; 48 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegd; 49 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegs; 50 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstod; 51 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fxtod; 52 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.UMulxhi; 53 import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_DREM; 54 import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_FREM; 55 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; 56 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; 57 import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.BSF; 58 import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.IBSR; 59 import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.LBSR; 60 import static jdk.vm.ci.code.CodeUtil.mask; 61 import static jdk.vm.ci.meta.JavaConstant.forLong; 62 import static jdk.vm.ci.sparc.SPARC.g0; 63 import static jdk.vm.ci.sparc.SPARCKind.DOUBLE; 64 import static jdk.vm.ci.sparc.SPARCKind.SINGLE; 65 import static jdk.vm.ci.sparc.SPARCKind.WORD; 66 import static jdk.vm.ci.sparc.SPARCKind.XWORD; 67 68 import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s; 69 import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs; 70 import org.graalvm.compiler.core.common.LIRKind; 71 import org.graalvm.compiler.core.common.calc.FloatConvert; 72 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 73 import org.graalvm.compiler.debug.GraalError; 74 import org.graalvm.compiler.lir.ConstantValue; 75 import org.graalvm.compiler.lir.LIRFrameState; 76 import org.graalvm.compiler.lir.Variable; 77 import org.graalvm.compiler.lir.VirtualStackSlot; 78 import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator; 79 import org.graalvm.compiler.lir.sparc.SPARCAddressValue; 80 import org.graalvm.compiler.lir.sparc.SPARCArithmetic; 81 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.FloatConvertOp; 82 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp; 83 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp.MulHigh; 84 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp; 85 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp.Rem; 86 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCIMulccOp; 87 import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCLMulccOp; 88 import org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp; 89 import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp; 90 import org.graalvm.compiler.lir.sparc.SPARCMove.MoveFpGp; 91 import org.graalvm.compiler.lir.sparc.SPARCMove.StoreConstantOp; 92 import org.graalvm.compiler.lir.sparc.SPARCMove.StoreOp; 93 import org.graalvm.compiler.lir.sparc.SPARCOP3Op; 94 import org.graalvm.compiler.lir.sparc.SPARCOPFOp; 95 96 import jdk.vm.ci.meta.AllocatableValue; 97 import jdk.vm.ci.meta.JavaConstant; 98 import jdk.vm.ci.meta.PlatformKind; 99 import jdk.vm.ci.meta.Value; 100 import jdk.vm.ci.meta.ValueKind; 101 import jdk.vm.ci.sparc.SPARC; 102 import jdk.vm.ci.sparc.SPARC.CPUFeature; 103 import jdk.vm.ci.sparc.SPARCKind; 104 105 /** 106 * This class implements the SPARC specific portion of the LIR generator. 107 */ 108 public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator { 109 110 @Override 111 public SPARCLIRGenerator getLIRGen() { 112 return (SPARCLIRGenerator) super.getLIRGen(); 113 } 114 115 @Override 116 public Variable emitBitCount(Value operand) { 117 Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD)); 118 AllocatableValue usedOperand = asAllocatable(emitZeroExtend(operand)); 119 getLIRGen().append(new SPARCOP3Op(Op3s.Popc, g0.asValue(), usedOperand, result)); 120 return result; 121 } 122 123 @Override 124 public Variable emitBitScanForward(Value operand) { 125 Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD)); 126 getLIRGen().append(new SPARCBitManipulationOp(BSF, result, asAllocatable(operand), getLIRGen())); 127 return result; 128 } 129 130 @Override 131 public Variable emitBitScanReverse(Value operand) { 132 Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD)); 133 if (operand.getPlatformKind() == SPARCKind.XWORD) { 134 getLIRGen().append(new SPARCBitManipulationOp(LBSR, result, asAllocatable(operand), getLIRGen())); 135 } else { 136 getLIRGen().append(new SPARCBitManipulationOp(IBSR, result, asAllocatable(operand), getLIRGen())); 137 } 138 return result; 139 } 140 141 @Override 142 public Value emitMathAbs(Value inputValue) { 143 Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue)); 144 SPARCKind kind = (SPARCKind) inputValue.getPlatformKind(); 145 Opfs opf; 146 switch (kind) { 147 case SINGLE: 148 opf = Opfs.Fabss; 149 break; 150 case DOUBLE: 151 opf = Opfs.Fabsd; 152 break; 153 default: 154 throw GraalError.shouldNotReachHere("Input kind: " + kind); 155 } 156 getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), asAllocatable(inputValue), result)); 157 return result; 158 } 159 160 @Override 161 public Value emitMathSqrt(Value inputValue) { 162 Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue)); 163 SPARCKind kind = (SPARCKind) inputValue.getPlatformKind(); 164 Opfs opf; 165 switch (kind) { 166 case SINGLE: 167 opf = Opfs.Fsqrts; 168 break; 169 case DOUBLE: 170 opf = Opfs.Fsqrtd; 171 break; 172 default: 173 throw GraalError.shouldNotReachHere("Input kind: " + kind); 174 } 175 getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), asAllocatable(inputValue), result)); 176 return result; 177 } 178 179 @Override 180 public Value emitNegate(Value input) { 181 PlatformKind inputKind = input.getPlatformKind(); 182 if (isNumericInteger(inputKind)) { 183 return emitUnary(Sub, input); 184 } else { 185 return emitUnary(inputKind.equals(DOUBLE) ? Fnegd : Fnegs, input); 186 } 187 } 188 189 @Override 190 public Value emitNot(Value input) { 191 return emitUnary(Xnor, input); 192 } 193 194 private Variable emitUnary(Opfs opf, Value inputValue) { 195 Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue)); 196 getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), asAllocatable(inputValue), result)); 197 return result; 198 } 199 200 private Variable emitUnary(Op3s op3, Value input) { 201 Variable result = getLIRGen().newVariable(LIRKind.combine(input)); 202 getLIRGen().append(SPARCOP3Op.newUnary(op3, getLIRGen().loadSimm13(input), result)); 203 return result; 204 } 205 206 private Variable emitBinary(ValueKind<?> resultKind, Opfs opf, Value a, Value b) { 207 return emitBinary(resultKind, opf, a, b, null); 208 } 209 210 private Variable emitBinary(ValueKind<?> resultKind, Opfs opf, Value a, Value b, LIRFrameState state) { 211 Variable result = getLIRGen().newVariable(resultKind); 212 getLIRGen().append(new SPARCOPFOp(opf, asAllocatable(a), asAllocatable(b), result, state)); 213 return result; 214 } 215 216 private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, int b) { 217 return emitBinary(resultKind, op3, a, new ConstantValue(LIRKind.value(WORD), JavaConstant.forInt(b))); 218 } 219 220 private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, Value b) { 221 return emitBinary(resultKind, op3, a, b, null); 222 } 223 224 private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, Value b, LIRFrameState state) { 225 Variable result = getLIRGen().newVariable(resultKind); 226 if (op3.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) { 227 getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(b), getLIRGen().loadSimm13(a), result, state)); 228 } else { 229 getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(a), getLIRGen().loadSimm13(b), result, state)); 230 } 231 return result; 232 } 233 234 @Override 235 protected boolean isNumericInteger(PlatformKind kind) { 236 return ((SPARCKind) kind).isInteger(); 237 } 238 239 @Override 240 public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) { 241 if (isNumericInteger(a.getPlatformKind())) { 242 return emitBinary(resultKind, setFlags ? Addcc : Add, a, b); 243 } else { 244 boolean isDouble = a.getPlatformKind().equals(DOUBLE); 245 return emitBinary(resultKind, isDouble ? Faddd : Fadds, a, b); 246 } 247 } 248 249 @Override 250 public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) { 251 if (isNumericInteger(a.getPlatformKind())) { 252 return emitBinary(resultKind, setFlags ? Subcc : Sub, a, b); 253 } else { 254 boolean isDouble = a.getPlatformKind().equals(DOUBLE); 255 return emitBinary(resultKind, isDouble ? Opfs.Fsubd : Opfs.Fsubs, a, b); 256 } 257 } 258 259 @Override 260 public Variable emitMul(Value a, Value b, boolean setFlags) { 261 LIRKind resultKind = LIRKind.combine(a, b); 262 PlatformKind aKind = a.getPlatformKind(); 263 if (isNumericInteger(aKind)) { 264 if (setFlags) { 265 Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); 266 if (aKind == XWORD) { 267 getLIRGen().append(new SPARCLMulccOp(result, getLIRGen().load(a), getLIRGen().load(b), getLIRGen())); 268 } else if (aKind == WORD) { 269 getLIRGen().append(new SPARCIMulccOp(result, getLIRGen().load(a), getLIRGen().load(b))); 270 } else { 271 throw GraalError.shouldNotReachHere(); 272 } 273 return result; 274 } else { 275 return emitBinary(resultKind, Op3s.Mulx, a, b); 276 } 277 } else { 278 boolean isDouble = a.getPlatformKind().equals(DOUBLE); 279 return emitBinary(resultKind, isDouble ? Fmuld : Fmuls, a, b); 280 } 281 } 282 283 @Override 284 public Value emitMulHigh(Value a, Value b) { 285 MulHigh opcode; 286 switch (((SPARCKind) a.getPlatformKind())) { 287 case WORD: 288 opcode = MulHigh.IMUL; 289 break; 290 case XWORD: 291 opcode = MulHigh.LMUL; 292 break; 293 default: 294 throw GraalError.shouldNotReachHere(); 295 } 296 return emitMulHigh(opcode, a, b); 297 } 298 299 @Override 300 public Value emitUMulHigh(Value a, Value b) { 301 switch (((SPARCKind) a.getPlatformKind())) { 302 case WORD: 303 Value result = emitBinary(LIRKind.combine(a, b), Mulx, emitZeroExtend(a), emitZeroExtend(b)); 304 return emitBinary(LIRKind.combine(a, b), Srax, result, WORD.getSizeInBits()); 305 case XWORD: 306 return emitBinary(LIRKind.combine(a, b), UMulxhi, a, b); 307 default: 308 throw GraalError.shouldNotReachHere(); 309 } 310 } 311 312 private Value emitMulHigh(MulHigh opcode, Value a, Value b) { 313 Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); 314 MulHighOp mulHigh = new MulHighOp(opcode, getLIRGen().load(a), getLIRGen().load(b), result, getLIRGen().newVariable(LIRKind.combine(a, b))); 315 getLIRGen().append(mulHigh); 316 return result; 317 } 318 319 @Override 320 public Value emitDiv(Value a, Value b, LIRFrameState state) { 321 LIRKind resultKind = LIRKind.combine(a, b); 322 if (isJavaConstant(b) && asJavaConstant(b).isDefaultForKind()) { // Div by zero 323 Value zero = SPARC.g0.asValue(LIRKind.value(SPARCKind.WORD)); 324 return emitBinary(resultKind, Op3s.Sdivx, zero, zero, state); 325 } else if (isNumericInteger(a.getPlatformKind())) { 326 return emitBinary(resultKind, Op3s.Sdivx, emitSignExtend(a), emitSignExtend(b), state); 327 } else { 328 boolean isDouble = a.getPlatformKind() == DOUBLE; 329 return emitBinary(resultKind, isDouble ? Opfs.Fdivd : Opfs.Fdivs, a, b, state); 330 } 331 } 332 333 @Override 334 public Value emitRem(Value a, Value b, LIRFrameState state) { 335 Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); 336 Variable q1; // Intermediate values 337 Variable q2; 338 switch ((SPARCKind) a.getPlatformKind()) { 339 case WORD: 340 // Sign extend a and b 341 Value as = emitSignExtend(a); 342 Value bs = emitSignExtend(b); 343 q1 = emitBinary(as.getValueKind(), Sdivx, as, bs, state); 344 q2 = emitBinary(as.getValueKind(), Mulx, q1, bs); 345 result = emitSub(as, q2, false); 346 break; 347 case XWORD: 348 q1 = emitBinary(result.getValueKind(), Sdivx, a, b, state); 349 q2 = emitBinary(result.getValueKind(), Mulx, q1, b); 350 result = emitSub(a, q2, false); 351 break; 352 case SINGLE: 353 ForeignCallLinkage fremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_FREM); 354 result = getLIRGen().emitForeignCall(fremCall, state, a, b); 355 break; 356 case DOUBLE: 357 ForeignCallLinkage dremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_DREM); 358 result = getLIRGen().emitForeignCall(dremCall, state, a, b); 359 break; 360 default: 361 throw GraalError.shouldNotReachHere("missing: " + a.getPlatformKind()); 362 } 363 return result; 364 } 365 366 @Override 367 public Value emitURem(Value a, Value b, LIRFrameState state) { 368 Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); 369 Variable scratch1 = getLIRGen().newVariable(LIRKind.combine(a, b)); 370 Variable scratch2 = getLIRGen().newVariable(LIRKind.combine(a, b)); 371 Rem opcode; 372 switch (((SPARCKind) a.getPlatformKind())) { 373 case WORD: 374 opcode = Rem.IUREM; 375 break; 376 case XWORD: 377 opcode = Rem.LUREM; 378 break; 379 default: 380 throw GraalError.shouldNotReachHere(); 381 } 382 getLIRGen().append(new RemOp(opcode, result, asAllocatable(a), asAllocatable(b), scratch1, scratch2, state)); 383 return result; 384 385 } 386 387 @Override 388 public Value emitUDiv(Value a, Value b, LIRFrameState state) { 389 return emitBinary(LIRKind.combine(a, b), Udivx, emitZeroExtend(a), emitZeroExtend(b), state); 390 } 391 392 @Override 393 public Variable emitAnd(Value a, Value b) { 394 LIRKind resultKind = LIRKind.combine(a, b); 395 return emitBinary(resultKind, Op3s.And, a, b); 396 } 397 398 @Override 399 public Variable emitOr(Value a, Value b) { 400 LIRKind resultKind = LIRKind.combine(a, b); 401 return emitBinary(resultKind, Op3s.Or, a, b); 402 } 403 404 @Override 405 public Variable emitXor(Value a, Value b) { 406 LIRKind resultKind = LIRKind.combine(a, b); 407 return emitBinary(resultKind, Op3s.Xor, a, b); 408 } 409 410 @Override 411 public Variable emitShl(Value a, Value b) { 412 SPARCKind aKind = (SPARCKind) a.getPlatformKind(); 413 LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind); 414 Op3s op; 415 switch (aKind) { 416 case WORD: 417 op = Op3s.Sll; 418 break; 419 case XWORD: 420 op = Op3s.Sllx; 421 break; 422 default: 423 throw GraalError.shouldNotReachHere(String.format("Unsupported kind %s", aKind)); 424 } 425 return emitBinary(resultKind, op, a, b); 426 } 427 428 @Override 429 public Variable emitShr(Value a, Value b) { 430 SPARCKind aKind = (SPARCKind) a.getPlatformKind(); 431 LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind); 432 Op3s op; 433 switch (aKind) { 434 case WORD: 435 op = Op3s.Sra; 436 break; 437 case XWORD: 438 op = Op3s.Srax; 439 break; 440 default: 441 throw GraalError.shouldNotReachHere(); 442 } 443 return emitBinary(resultKind, op, a, b); 444 } 445 446 @Override 447 public Variable emitUShr(Value a, Value b) { 448 SPARCKind aKind = (SPARCKind) a.getPlatformKind(); 449 LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind); 450 Op3s op; 451 switch (aKind) { 452 case WORD: 453 op = Op3s.Srl; 454 break; 455 case XWORD: 456 op = Op3s.Srlx; 457 break; 458 default: 459 throw GraalError.shouldNotReachHere(); 460 } 461 return emitBinary(resultKind, op, a, b); 462 } 463 464 private AllocatableValue emitConvertMove(LIRKind kind, AllocatableValue input) { 465 Variable result = getLIRGen().newVariable(kind); 466 getLIRGen().emitMove(result, input); 467 return result; 468 } 469 470 @Override 471 public Value emitFloatConvert(FloatConvert op, Value inputValue) { 472 AllocatableValue inputAllocatable = asAllocatable(inputValue); 473 AllocatableValue result; 474 switch (op) { 475 case D2F: 476 result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(SINGLE)); 477 getLIRGen().append(new SPARCOPFOp(Fdtos, inputAllocatable, result)); 478 break; 479 case F2D: 480 result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(DOUBLE)); 481 getLIRGen().append(new SPARCOPFOp(Fstod, inputAllocatable, result)); 482 break; 483 case I2F: { 484 AllocatableValue intEncodedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); 485 result = getLIRGen().newVariable(intEncodedFloatReg.getValueKind()); 486 moveBetweenFpGp(intEncodedFloatReg, inputAllocatable); 487 getLIRGen().append(new SPARCOPFOp(Fitos, intEncodedFloatReg, result)); 488 break; 489 } 490 case I2D: { 491 // Unfortunately we must do int -> float -> double because fitod has float 492 // and double encoding in one instruction 493 AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); 494 result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); 495 moveBetweenFpGp(convertedFloatReg, inputAllocatable); 496 getLIRGen().append(new SPARCOPFOp(Fitod, convertedFloatReg, result)); 497 break; 498 } 499 case L2D: { 500 AllocatableValue longEncodedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); 501 moveBetweenFpGp(longEncodedDoubleReg, inputAllocatable); 502 AllocatableValue convertedDoubleReg = getLIRGen().newVariable(longEncodedDoubleReg.getValueKind()); 503 getLIRGen().append(new SPARCOPFOp(Fxtod, longEncodedDoubleReg, convertedDoubleReg)); 504 result = convertedDoubleReg; 505 break; 506 } 507 case D2I: { 508 AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); 509 getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2I, inputAllocatable, convertedFloatReg)); 510 AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD)); 511 moveBetweenFpGp(convertedIntReg, convertedFloatReg); 512 result = convertedIntReg; 513 break; 514 } 515 case F2L: { 516 AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); 517 getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2L, inputAllocatable, convertedDoubleReg)); 518 AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD)); 519 moveBetweenFpGp(convertedLongReg, convertedDoubleReg); 520 result = convertedLongReg; 521 break; 522 } 523 case F2I: { 524 AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); 525 getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2I, inputAllocatable, convertedFloatReg)); 526 AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD)); 527 moveBetweenFpGp(convertedIntReg, convertedFloatReg); 528 result = convertedIntReg; 529 break; 530 } 531 case D2L: { 532 AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); 533 getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2L, inputAllocatable, convertedDoubleReg)); 534 AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD)); 535 moveBetweenFpGp(convertedLongReg, convertedDoubleReg); 536 result = convertedLongReg; 537 break; 538 } 539 case L2F: { 540 AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); 541 result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); 542 moveBetweenFpGp(convertedDoubleReg, inputAllocatable); 543 getLIRGen().append(new SPARCOPFOp(Opfs.Fxtos, convertedDoubleReg, result)); 544 break; 545 } 546 default: 547 throw GraalError.shouldNotReachHere(); 548 } 549 return result; 550 } 551 552 protected VirtualStackSlot getTempSlot(LIRKind kind) { 553 return getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(kind); 554 } 555 556 private void moveBetweenFpGp(AllocatableValue dst, AllocatableValue src) { 557 AllocatableValue tempSlot; 558 PlatformKind dstKind = dst.getPlatformKind(); 559 PlatformKind srcKind = src.getPlatformKind(); 560 if (getLIRGen().getArchitecture().getFeatures().contains(CPUFeature.VIS3) && !(srcKind == WORD && dstKind == SINGLE) && !(srcKind == SINGLE && dstKind == WORD)) { 561 tempSlot = AllocatableValue.ILLEGAL; 562 } else { 563 tempSlot = getTempSlot(LIRKind.value(XWORD)); 564 } 565 getLIRGen().append(new MoveFpGp(dst, src, tempSlot)); 566 } 567 568 @Override 569 public Value emitNarrow(Value inputVal, int bits) { 570 if (inputVal.getPlatformKind() == XWORD && bits <= 32) { 571 LIRKind resultKind = LIRKind.combine(inputVal).changeType(WORD); 572 Variable result = getLIRGen().newVariable(resultKind); 573 getLIRGen().emitMove(result, inputVal); 574 return result; 575 } else { 576 return inputVal; 577 } 578 } 579 580 private Value emitSignExtend(Value inputValue) { 581 int inputBits = inputValue.getPlatformKind().getSizeInBytes() * 8; 582 return emitNarrow(emitSignExtend(inputValue, inputBits, XWORD.getSizeInBits()), inputBits); 583 } 584 585 @Override 586 public Value emitSignExtend(Value inputVal, int fromBits, int toBits) { 587 assert fromBits <= toBits && toBits <= XWORD.getSizeInBits(); 588 LIRKind shiftKind = LIRKind.value(WORD); 589 LIRKind resultKind = LIRKind.combine(inputVal).changeType(toBits > 32 ? XWORD : WORD); 590 int shiftCount = XWORD.getSizeInBits() - fromBits; 591 if (fromBits == toBits) { 592 return inputVal; 593 } else if (isJavaConstant(inputVal)) { 594 JavaConstant javaConstant = asJavaConstant(inputVal); 595 long constant; 596 if (javaConstant.isNull()) { 597 constant = 0; 598 } else { 599 constant = javaConstant.asLong(); 600 } 601 return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount)); 602 } else { 603 AllocatableValue inputAllocatable = asAllocatable(inputVal); 604 Variable result = getLIRGen().newVariable(resultKind); 605 if (fromBits == WORD.getSizeInBits() && toBits == XWORD.getSizeInBits()) { 606 getLIRGen().append(new SPARCOP3Op(Sra, inputAllocatable, g0.asValue(LIRKind.value(WORD)), result)); 607 } else { 608 Variable tmp = getLIRGen().newVariable(resultKind.changeType(XWORD)); 609 getLIRGen().append(new SPARCOP3Op(Sllx, inputAllocatable, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), tmp)); 610 getLIRGen().append(new SPARCOP3Op(Srax, tmp, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), result)); 611 } 612 return result; 613 } 614 } 615 616 private Value emitZeroExtend(Value inputValue) { 617 int inputBits = inputValue.getPlatformKind().getSizeInBytes() * 8; 618 return emitNarrow(emitZeroExtend(inputValue, inputBits, XWORD.getSizeInBits()), inputBits); 619 } 620 621 @Override 622 public Value emitZeroExtend(Value inputValue, int fromBits, int toBits) { 623 assert fromBits <= toBits && toBits <= 64; 624 if (fromBits == toBits) { 625 return inputValue; 626 } 627 Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(toBits > WORD.getSizeInBits() ? XWORD : WORD)); 628 AllocatableValue inputAllocatable = asAllocatable(inputValue); 629 if (fromBits == 32) { 630 getLIRGen().append(new SPARCOP3Op(Srl, inputAllocatable, g0.asValue(), result)); 631 } else { 632 Value mask = getLIRGen().emitConstant(LIRKind.value(XWORD), forLong(mask(fromBits))); 633 getLIRGen().append(new SPARCOP3Op(And, inputAllocatable, mask, result)); 634 } 635 return result; 636 } 637 638 @Override 639 public AllocatableValue emitReinterpret(LIRKind to, Value inputVal) { 640 SPARCKind fromKind = (SPARCKind) inputVal.getPlatformKind(); 641 SPARCKind toKind = (SPARCKind) to.getPlatformKind(); 642 AllocatableValue input = asAllocatable(inputVal); 643 Variable result = getLIRGen().newVariable(to); 644 // These cases require a move between CPU and FPU registers: 645 if (fromKind.isFloat() != toKind.isFloat()) { 646 moveBetweenFpGp(result, input); 647 return result; 648 } else { 649 // Otherwise, just emit an ordinary move instruction. 650 // Instructions that move or generate 32-bit register values also set the upper 32 651 // bits of the register to zero. 652 // Consequently, there is no need for a special zero-extension move. 653 return emitConvertMove(to, input); 654 } 655 } 656 657 @Override 658 public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { 659 SPARCAddressValue loadAddress = getLIRGen().asAddressValue(address); 660 Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind)); 661 getLIRGen().append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state)); 662 return result; 663 } 664 665 @Override 666 public void emitStore(ValueKind<?> kind, Value address, Value inputVal, LIRFrameState state) { 667 SPARCAddressValue storeAddress = getLIRGen().asAddressValue(address); 668 if (isJavaConstant(inputVal)) { 669 JavaConstant c = asJavaConstant(inputVal); 670 if (c.isDefaultForKind()) { 671 getLIRGen().append(new StoreConstantOp(kind.getPlatformKind(), storeAddress, c, state)); 672 return; 673 } 674 } 675 Variable input = getLIRGen().load(inputVal); 676 getLIRGen().append(new StoreOp(kind.getPlatformKind(), storeAddress, input, state)); 677 } 678 }