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