1 /* 2 * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.lir.sparc; 26 27 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; 28 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_V_SHIFT; 29 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_XCC_SHIFT; 30 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FBPCC; 31 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13; 32 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; 33 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; 34 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; 35 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0; 36 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; 37 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; 38 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Ordered; 39 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmpd; 40 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmps; 41 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; 42 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; 43 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; 44 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; 45 import static jdk.vm.ci.code.ValueUtil.asRegister; 46 import static jdk.vm.ci.code.ValueUtil.isRegister; 47 import static jdk.vm.ci.sparc.SPARC.g0; 48 import static jdk.vm.ci.sparc.SPARCKind.DOUBLE; 49 import static jdk.vm.ci.sparc.SPARCKind.SINGLE; 50 import static jdk.vm.ci.sparc.SPARCKind.WORD; 51 import static jdk.vm.ci.sparc.SPARCKind.XWORD; 52 53 import org.graalvm.compiler.asm.Label; 54 import org.graalvm.compiler.asm.sparc.SPARCAssembler; 55 import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; 56 import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; 57 import org.graalvm.compiler.core.common.LIRKind; 58 import org.graalvm.compiler.debug.GraalError; 59 import org.graalvm.compiler.lir.LIRFrameState; 60 import org.graalvm.compiler.lir.LIRInstructionClass; 61 import org.graalvm.compiler.lir.Opcode; 62 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 63 import org.graalvm.compiler.lir.gen.LIRGeneratorTool; 64 65 import jdk.vm.ci.code.Register; 66 import jdk.vm.ci.meta.AllocatableValue; 67 import jdk.vm.ci.meta.Value; 68 import jdk.vm.ci.sparc.SPARC; 69 70 public class SPARCArithmetic { 71 public static final class FloatConvertOp extends SPARCLIRInstruction { 72 public static final LIRInstructionClass<FloatConvertOp> TYPE = LIRInstructionClass.create(FloatConvertOp.class); 73 public static final SizeEstimate SIZE = SizeEstimate.create(5); 74 75 @Opcode private final FloatConvert opcode; 76 @Def({REG, HINT}) protected AllocatableValue result; 77 @Use({REG}) protected Value x; 78 79 public enum FloatConvert { 80 F2I, 81 D2I, 82 F2L, 83 D2L 84 } 85 86 public FloatConvertOp(FloatConvert opcode, Value x, AllocatableValue result) { 87 super(TYPE, SIZE); 88 this.opcode = opcode; 89 this.x = x; 90 this.result = result; 91 } 92 93 @Override 94 protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 95 Label notOrdered = new Label(); 96 switch (opcode) { 97 case F2L: 98 masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE)); 99 FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); 100 masm.fstox(asRegister(x, SINGLE), asRegister(result, DOUBLE)); 101 masm.fxtod(asRegister(result), asRegister(result)); 102 masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE)); 103 masm.bind(notOrdered); 104 break; 105 case F2I: 106 masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE)); 107 FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); 108 masm.fstoi(asRegister(x, SINGLE), asRegister(result, SINGLE)); 109 masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE)); 110 masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE)); 111 masm.bind(notOrdered); 112 break; 113 case D2L: 114 masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE)); 115 FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); 116 masm.fdtox(asRegister(x, DOUBLE), asRegister(result, DOUBLE)); 117 masm.fxtod(asRegister(result, DOUBLE), asRegister(result, DOUBLE)); 118 masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE)); 119 masm.bind(notOrdered); 120 break; 121 case D2I: 122 masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE)); 123 FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); 124 masm.fdtoi(asRegister(x, DOUBLE), asRegister(result, SINGLE)); 125 masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE)); 126 masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE)); 127 masm.bind(notOrdered); 128 break; 129 default: 130 throw GraalError.shouldNotReachHere("missing: " + opcode); 131 } 132 } 133 } 134 135 /** 136 * Special LIR instruction as it requires a bunch of scratch registers. 137 */ 138 public static final class RemOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { 139 public static final LIRInstructionClass<RemOp> TYPE = LIRInstructionClass.create(RemOp.class); 140 public static final SizeEstimate SIZE = SizeEstimate.create(4); 141 142 @Opcode private final Rem opcode; 143 @Def({REG}) protected AllocatableValue result; 144 @Alive({REG, CONST}) protected Value x; 145 @Alive({REG, CONST}) protected Value y; 146 @Temp({REG}) protected AllocatableValue scratch1; 147 @Temp({REG}) protected AllocatableValue scratch2; 148 @State protected LIRFrameState state; 149 150 public enum Rem { 151 IUREM, 152 LUREM 153 } 154 155 public RemOp(Rem opcode, AllocatableValue result, Value x, Value y, AllocatableValue scratch1, AllocatableValue scratch2, LIRFrameState state) { 156 super(TYPE, SIZE); 157 this.opcode = opcode; 158 this.result = result; 159 this.x = x; 160 this.y = y; 161 this.scratch1 = scratch1; 162 this.scratch2 = scratch2; 163 this.state = state; 164 } 165 166 @Override 167 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 168 if (!isJavaConstant(x) && isJavaConstant(y)) { 169 assert isSimm13(crb.asIntConst(y)); 170 assert !x.equals(scratch1); 171 assert !x.equals(scratch2); 172 assert !y.equals(scratch1); 173 switch (opcode) { 174 case LUREM: 175 if (state != null) { 176 crb.recordImplicitException(masm.position(), state); 177 } 178 masm.udivx(asRegister(x, XWORD), crb.asIntConst(y), asRegister(scratch1, XWORD)); 179 masm.mulx(asRegister(scratch1, XWORD), crb.asIntConst(y), asRegister(scratch2, XWORD)); 180 getDelayedControlTransfer().emitControlTransfer(crb, masm); 181 masm.sub(asRegister(x, XWORD), asRegister(scratch2, XWORD), asRegister(result, XWORD)); 182 break; 183 case IUREM: 184 GraalError.unimplemented(); 185 break; 186 default: 187 throw GraalError.shouldNotReachHere(); 188 } 189 } else if (isRegister(x) && isRegister(y)) { 190 Value xLeft = x; 191 switch (opcode) { 192 case LUREM: 193 if (isJavaConstant(x)) { 194 masm.setx(crb.asLongConst(x), asRegister(scratch2, XWORD), false); 195 xLeft = scratch2; 196 } 197 assert !asRegister(xLeft, XWORD).equals(asRegister(scratch1, XWORD)); 198 assert !asRegister(y, XWORD).equals(asRegister(scratch1, XWORD)); 199 if (state != null) { 200 crb.recordImplicitException(masm.position(), state); 201 } 202 masm.udivx(asRegister(xLeft, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD)); 203 masm.mulx(asRegister(scratch1, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD)); 204 getDelayedControlTransfer().emitControlTransfer(crb, masm); 205 masm.sub(asRegister(xLeft, XWORD), asRegister(scratch1, XWORD), asRegister(result, XWORD)); 206 break; 207 case IUREM: 208 assert !asRegister(result, WORD).equals(asRegister(scratch1, WORD)); 209 assert !asRegister(result, WORD).equals(asRegister(scratch2, WORD)); 210 masm.srl(asRegister(x, WORD), 0, asRegister(scratch1, WORD)); 211 masm.srl(asRegister(y, WORD), 0, asRegister(result, WORD)); 212 if (state != null) { 213 crb.recordImplicitException(masm.position(), state); 214 } 215 masm.udivx(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(scratch2, WORD)); 216 masm.mulx(asRegister(scratch2, WORD), asRegister(result, WORD), asRegister(result, WORD)); 217 getDelayedControlTransfer().emitControlTransfer(crb, masm); 218 masm.sub(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(result, WORD)); 219 break; 220 default: 221 throw GraalError.shouldNotReachHere(); 222 } 223 } else { 224 throw GraalError.shouldNotReachHere(); 225 } 226 } 227 } 228 229 public static final class SPARCIMulccOp extends SPARCLIRInstruction { 230 public static final LIRInstructionClass<SPARCIMulccOp> TYPE = LIRInstructionClass.create(SPARCIMulccOp.class); 231 public static final SizeEstimate SIZE = SizeEstimate.create(10); 232 @Def({REG}) protected AllocatableValue result; 233 @Alive({REG}) protected AllocatableValue x; 234 @Alive({REG}) protected AllocatableValue y; 235 236 public SPARCIMulccOp(AllocatableValue result, AllocatableValue x, AllocatableValue y) { 237 super(TYPE, SIZE); 238 this.result = result; 239 this.x = x; 240 this.y = y; 241 } 242 243 @Override 244 protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 245 try (ScratchRegister tmpScratch = masm.getScratchRegister()) { 246 Register tmp = tmpScratch.getRegister(); 247 Register resultRegister = asRegister(result, WORD); 248 Register xRegister = asRegister(x, WORD); 249 Register yRegister = asRegister(y, WORD); 250 masm.sra(xRegister, 0, xRegister); 251 masm.sra(yRegister, 0, yRegister); 252 masm.mulx(xRegister, yRegister, resultRegister); 253 Label noOverflow = new Label(); 254 masm.sra(resultRegister, 0, tmp); 255 masm.compareBranch(tmp, resultRegister, Equal, Xcc, noOverflow, PREDICT_TAKEN, null); 256 masm.wrccr(SPARC.g0, 1 << (SPARCAssembler.CCR_ICC_SHIFT + SPARCAssembler.CCR_V_SHIFT)); 257 masm.bind(noOverflow); 258 } 259 } 260 } 261 262 /** 263 * Calculates the product and condition code for long multiplication of long values. 264 */ 265 public static final class SPARCLMulccOp extends SPARCLIRInstruction { 266 public static final LIRInstructionClass<SPARCLMulccOp> TYPE = LIRInstructionClass.create(SPARCLMulccOp.class); 267 public static final SizeEstimate SIZE = SizeEstimate.create(13); 268 269 @Def({REG}) protected AllocatableValue result; 270 @Alive({REG}) protected AllocatableValue x; 271 @Alive({REG}) protected AllocatableValue y; 272 @Temp({REG}) protected AllocatableValue scratch1; 273 @Temp({REG}) protected AllocatableValue scratch2; 274 275 public SPARCLMulccOp(AllocatableValue result, AllocatableValue x, AllocatableValue y, LIRGeneratorTool gen) { 276 super(TYPE, SIZE); 277 this.result = result; 278 this.x = x; 279 this.y = y; 280 this.scratch1 = gen.newVariable(LIRKind.combine(x, y)); 281 this.scratch2 = gen.newVariable(LIRKind.combine(x, y)); 282 } 283 284 @Override 285 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 286 Label noOverflow = new Label(); 287 masm.mulx(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(result, XWORD)); 288 289 // Calculate the upper 64 bit signed := (umulxhi product - (x{63}&y + y{63}&x)) 290 masm.umulxhi(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD)); 291 masm.srax(asRegister(x, XWORD), 63, asRegister(scratch2, XWORD)); 292 masm.and(asRegister(scratch2, XWORD), asRegister(y, XWORD), asRegister(scratch2, XWORD)); 293 masm.sub(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD), asRegister(scratch1, XWORD)); 294 295 masm.srax(asRegister(y, XWORD), 63, asRegister(scratch2, XWORD)); 296 masm.and(asRegister(scratch2, XWORD), asRegister(x, XWORD), asRegister(scratch2, XWORD)); 297 masm.sub(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD), asRegister(scratch1, XWORD)); 298 299 // Now construct the lower half and compare 300 masm.srax(asRegister(result, XWORD), 63, asRegister(scratch2, XWORD)); 301 masm.cmp(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD)); 302 BPCC.emit(masm, Xcc, Equal, NOT_ANNUL, PREDICT_TAKEN, noOverflow); 303 masm.nop(); 304 masm.wrccr(g0, 1 << (CCR_XCC_SHIFT + CCR_V_SHIFT)); 305 masm.bind(noOverflow); 306 } 307 } 308 309 public static final class MulHighOp extends SPARCLIRInstruction { 310 public static final LIRInstructionClass<MulHighOp> TYPE = LIRInstructionClass.create(MulHighOp.class); 311 public static final SizeEstimate SIZE = SizeEstimate.create(4); 312 313 @Opcode private final MulHigh opcode; 314 @Def({REG}) public AllocatableValue result; 315 @Alive({REG}) public AllocatableValue x; 316 @Alive({REG}) public AllocatableValue y; 317 @Temp({REG}) public AllocatableValue scratch; 318 319 public enum MulHigh { 320 IMUL, 321 LMUL 322 } 323 324 public MulHighOp(MulHigh opcode, AllocatableValue x, AllocatableValue y, AllocatableValue result, AllocatableValue scratch) { 325 super(TYPE, SIZE); 326 this.opcode = opcode; 327 this.x = x; 328 this.y = y; 329 this.scratch = scratch; 330 this.result = result; 331 } 332 333 @Override 334 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 335 assert isRegister(x) && isRegister(y) && isRegister(result) && isRegister(scratch); 336 switch (opcode) { 337 case IMUL: 338 masm.sra(asRegister(x), 0, asRegister(x)); 339 masm.sra(asRegister(y), 0, asRegister(y)); 340 masm.mulx(asRegister(x, WORD), asRegister(y, WORD), asRegister(result, WORD)); 341 masm.srax(asRegister(result, WORD), 32, asRegister(result, WORD)); 342 break; 343 case LMUL: 344 assert !asRegister(scratch, XWORD).equals(asRegister(result, XWORD)); 345 masm.umulxhi(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(result, XWORD)); 346 347 masm.srlx(asRegister(x, XWORD), 63, asRegister(scratch, XWORD)); 348 masm.mulx(asRegister(scratch, XWORD), asRegister(y, XWORD), asRegister(scratch, XWORD)); 349 masm.sub(asRegister(result, XWORD), asRegister(scratch, XWORD), asRegister(result, XWORD)); 350 351 masm.srlx(asRegister(y, XWORD), 63, asRegister(scratch, XWORD)); 352 masm.mulx(asRegister(scratch, XWORD), asRegister(x, XWORD), asRegister(scratch, XWORD)); 353 masm.sub(asRegister(result, XWORD), asRegister(scratch, XWORD), asRegister(result, XWORD)); 354 break; 355 default: 356 throw GraalError.shouldNotReachHere(); 357 } 358 } 359 } 360 }