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