SPARCArithmetic.java revision 12651:6ef01bd40ce2
1184610Salfred/* 2184610Salfred * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. 3184610Salfred * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4184610Salfred * 5184610Salfred * This code is free software; you can redistribute it and/or modify it 6184610Salfred * under the terms of the GNU General Public License version 2 only, as 7184610Salfred * published by the Free Software Foundation. 8184610Salfred * 9184610Salfred * This code is distributed in the hope that it will be useful, but WITHOUT 10184610Salfred * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11184610Salfred * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12184610Salfred * version 2 for more details (a copy is included in the LICENSE file that 13184610Salfred * accompanied this code). 14184610Salfred * 15184610Salfred * You should have received a copy of the GNU General Public License version 16184610Salfred * 2 along with this work; if not, write to the Free Software Foundation, 17184610Salfred * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18184610Salfred * 19184610Salfred * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20184610Salfred * or visit www.oracle.com if you need additional information or have any 21184610Salfred * questions. 22184610Salfred */ 23184610Salfredpackage org.graalvm.compiler.lir.sparc; 24184610Salfred 25184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; 26184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_V_SHIFT; 27184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_XCC_SHIFT; 28184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.FBPCC; 29184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13; 30184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; 31184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; 32184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; 33184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0; 34184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; 35184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; 36184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Ordered; 37184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmpd; 38184610Salfredimport static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmps; 39184610Salfredimport static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; 40184610Salfredimport static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; 41184610Salfredimport static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; 42184610Salfredimport static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; 43184610Salfredimport static jdk.vm.ci.code.ValueUtil.asRegister; 44184610Salfredimport static jdk.vm.ci.code.ValueUtil.isRegister; 45184610Salfredimport static jdk.vm.ci.sparc.SPARC.g0; 46184610Salfredimport static jdk.vm.ci.sparc.SPARCKind.DOUBLE; 47184610Salfredimport static jdk.vm.ci.sparc.SPARCKind.SINGLE; 48184610Salfredimport static jdk.vm.ci.sparc.SPARCKind.WORD; 49184610Salfredimport static jdk.vm.ci.sparc.SPARCKind.XWORD; 50184610Salfred 51184610Salfredimport org.graalvm.compiler.asm.Label; 52184610Salfredimport org.graalvm.compiler.asm.sparc.SPARCAssembler; 53184610Salfredimport org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; 54184610Salfredimport org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; 55184610Salfredimport org.graalvm.compiler.core.common.LIRKind; 56184610Salfredimport org.graalvm.compiler.debug.GraalError; 57184610Salfredimport org.graalvm.compiler.lir.LIRFrameState; 58184610Salfredimport org.graalvm.compiler.lir.LIRInstructionClass; 59184610Salfredimport org.graalvm.compiler.lir.Opcode; 60184610Salfredimport org.graalvm.compiler.lir.asm.CompilationResultBuilder; 61184610Salfredimport org.graalvm.compiler.lir.gen.LIRGeneratorTool; 62184610Salfred 63184610Salfredimport jdk.vm.ci.code.Register; 64184610Salfredimport jdk.vm.ci.meta.AllocatableValue; 65184610Salfredimport jdk.vm.ci.meta.Value; 66184610Salfredimport jdk.vm.ci.sparc.SPARC; 67184610Salfred 68184610Salfredpublic class SPARCArithmetic { 69184610Salfred public static final class FloatConvertOp extends SPARCLIRInstruction { 70184610Salfred public static final LIRInstructionClass<FloatConvertOp> TYPE = LIRInstructionClass.create(FloatConvertOp.class); 71184610Salfred public static final SizeEstimate SIZE = SizeEstimate.create(5); 72184610Salfred 73184610Salfred @Opcode private final FloatConvert opcode; 74184610Salfred @Def({REG, HINT}) protected Value result; 75184610Salfred @Use({REG}) protected Value x; 76184610Salfred 77184610Salfred public enum FloatConvert { 78184610Salfred F2I, 79184610Salfred D2I, 80184610Salfred F2L, 81184610Salfred D2L 82184610Salfred } 83184610Salfred 84184610Salfred public FloatConvertOp(FloatConvert opcode, Value x, Value result) { 85184610Salfred super(TYPE, SIZE); 86184610Salfred this.opcode = opcode; 87184610Salfred this.x = x; 88184610Salfred this.result = result; 89184610Salfred } 90184610Salfred 91184610Salfred @Override 92184610Salfred protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 93184610Salfred Label notOrdered = new Label(); 94184610Salfred switch (opcode) { 95184610Salfred case F2L: 96184610Salfred masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE)); 97184610Salfred FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); 98184610Salfred masm.fstox(asRegister(x, SINGLE), asRegister(result, DOUBLE)); 99184610Salfred masm.fxtod(asRegister(result), asRegister(result)); 100184610Salfred masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE)); 101184610Salfred masm.bind(notOrdered); 102184610Salfred break; 103184610Salfred case F2I: 104184610Salfred masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE)); 105184610Salfred FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); 106184610Salfred masm.fstoi(asRegister(x, SINGLE), asRegister(result, SINGLE)); 107184610Salfred masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE)); 108184610Salfred masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE)); 109184610Salfred masm.bind(notOrdered); 110184610Salfred break; 111184610Salfred case D2L: 112184610Salfred masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE)); 113184610Salfred FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); 114184610Salfred masm.fdtox(asRegister(x, DOUBLE), asRegister(result, DOUBLE)); 115184610Salfred masm.fxtod(asRegister(result, DOUBLE), asRegister(result, DOUBLE)); 116184610Salfred masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE)); 117184610Salfred masm.bind(notOrdered); 118184610Salfred break; 119184610Salfred case D2I: 120184610Salfred masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE)); 121184610Salfred FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); 122184610Salfred masm.fdtoi(asRegister(x, DOUBLE), asRegister(result, SINGLE)); 123184610Salfred masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE)); 124184610Salfred masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE)); 125184610Salfred masm.bind(notOrdered); 126184610Salfred break; 127184610Salfred default: 128184610Salfred throw GraalError.shouldNotReachHere("missing: " + opcode); 129184610Salfred } 130184610Salfred } 131184610Salfred } 132184610Salfred 133184610Salfred /** 134184610Salfred * Special LIR instruction as it requires a bunch of scratch registers. 135184610Salfred */ 136184610Salfred public static final class RemOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { 137184610Salfred public static final LIRInstructionClass<RemOp> TYPE = LIRInstructionClass.create(RemOp.class); 138184610Salfred public static final SizeEstimate SIZE = SizeEstimate.create(4); 139184610Salfred 140184610Salfred @Opcode private final Rem opcode; 141184610Salfred @Def({REG}) protected Value result; 142184610Salfred @Alive({REG, CONST}) protected Value x; 143184610Salfred @Alive({REG, CONST}) protected Value y; 144184610Salfred @Temp({REG}) protected Value scratch1; 145184610Salfred @Temp({REG}) protected Value scratch2; 146184610Salfred @State protected LIRFrameState state; 147184610Salfred 148184610Salfred public enum Rem { 149184610Salfred IUREM, 150184610Salfred LUREM 151184610Salfred } 152184610Salfred 153184610Salfred public RemOp(Rem opcode, Value result, Value x, Value y, Value scratch1, Value scratch2, LIRFrameState state) { 154184610Salfred super(TYPE, SIZE); 155184610Salfred this.opcode = opcode; 156184610Salfred this.result = result; 157184610Salfred this.x = x; 158184610Salfred this.y = y; 159184610Salfred this.scratch1 = scratch1; 160184610Salfred this.scratch2 = scratch2; 161184610Salfred this.state = state; 162184610Salfred } 163184610Salfred 164184610Salfred @Override 165184610Salfred public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 166184610Salfred 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} 353