001/* 002 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.lir.sparc; 024 025import static com.oracle.graal.asm.sparc.SPARCAssembler.Annul.*; 026import static com.oracle.graal.asm.sparc.SPARCAssembler.BranchPredict.*; 027import static com.oracle.graal.asm.sparc.SPARCAssembler.CC.*; 028import static com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag.*; 029import static com.oracle.graal.asm.sparc.SPARCAssembler.RCondition.*; 030import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; 031import static jdk.internal.jvmci.code.ValueUtil.*; 032import static jdk.internal.jvmci.common.UnsafeAccess.*; 033import static jdk.internal.jvmci.sparc.SPARC.*; 034import static jdk.internal.jvmci.sparc.SPARC.CPUFeature.*; 035 036import java.lang.reflect.*; 037 038import jdk.internal.jvmci.code.*; 039import jdk.internal.jvmci.meta.*; 040import jdk.internal.jvmci.sparc.SPARC.CPUFeature; 041 042import com.oracle.graal.asm.*; 043import com.oracle.graal.asm.sparc.*; 044import com.oracle.graal.asm.sparc.SPARCAssembler.CC; 045import com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag; 046import com.oracle.graal.lir.*; 047import com.oracle.graal.lir.asm.*; 048import com.oracle.graal.lir.gen.*; 049 050/** 051 * Emits code which compares two arrays of the same length. 052 */ 053@Opcode("ARRAY_EQUALS") 054public final class SPARCArrayEqualsOp extends SPARCLIRInstruction { 055 public static final LIRInstructionClass<SPARCArrayEqualsOp> TYPE = LIRInstructionClass.create(SPARCArrayEqualsOp.class); 056 public static final SizeEstimate SIZE = SizeEstimate.create(32); 057 058 private final Kind kind; 059 private final int arrayBaseOffset; 060 private final int arrayIndexScale; 061 062 @Def({REG}) protected Value resultValue; 063 @Alive({REG}) protected Value array1Value; 064 @Alive({REG}) protected Value array2Value; 065 @Alive({REG}) protected Value lengthValue; 066 @Temp({REG}) protected Value temp1; 067 @Temp({REG}) protected Value temp2; 068 @Temp({REG}) protected Value temp3; 069 @Temp({REG}) protected Value temp4; 070 @Temp({REG}) protected Value temp5; 071 072 public SPARCArrayEqualsOp(LIRGeneratorTool tool, Kind kind, Value result, Value array1, Value array2, Value length) { 073 super(TYPE, SIZE); 074 this.kind = kind; 075 076 Class<?> arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass(); 077 this.arrayBaseOffset = unsafe.arrayBaseOffset(arrayClass); 078 this.arrayIndexScale = unsafe.arrayIndexScale(arrayClass); 079 080 this.resultValue = result; 081 this.array1Value = array1; 082 this.array2Value = array2; 083 this.lengthValue = length; 084 085 // Allocate some temporaries. 086 this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().wordKind)); 087 this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().wordKind)); 088 this.temp3 = tool.newVariable(LIRKind.value(tool.target().wordKind)); 089 this.temp4 = tool.newVariable(LIRKind.value(tool.target().wordKind)); 090 this.temp5 = tool.newVariable(LIRKind.value(tool.target().wordKind)); 091 } 092 093 @Override 094 public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { 095 Register result = asRegister(resultValue); 096 Register array1 = asRegister(temp1); 097 Register array2 = asRegister(temp2); 098 Register length = asRegister(temp3); 099 100 Label trueLabel = new Label(); 101 Label falseLabel = new Label(); 102 Label done = new Label(); 103 104 // Load array base addresses. 105 masm.add(asObjectReg(array1Value), arrayBaseOffset, array1); 106 masm.add(asObjectReg(array2Value), arrayBaseOffset, array2); 107 108 // Get array length in bytes. 109 masm.mulx(asIntReg(lengthValue), arrayIndexScale, length); 110 masm.mov(length, result); // copy 111 112 emit8ByteCompare(masm, result, array1, array2, length, trueLabel, falseLabel); 113 emitTailCompares(masm, result, array1, array2, trueLabel, falseLabel); 114 115 // Return true 116 masm.bind(trueLabel); 117 masm.mov(1, result); 118 masm.bicc(Always, ANNUL, done); 119 masm.nop(); 120 121 // Return false 122 masm.bind(falseLabel); 123 masm.mov(g0, result); 124 125 // That's it 126 masm.bind(done); 127 } 128 129 /** 130 * Vector size used in {@link #emit8ByteCompare}. 131 */ 132 private static final int VECTOR_SIZE = 8; 133 134 /** 135 * Emits code that uses 8-byte vector compares. 136 */ 137 private void emit8ByteCompare(SPARCMacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { 138 assert lengthValue.getPlatformKind().equals(Kind.Int); 139 Label loop = new Label(); 140 Label compareTail = new Label(); 141 Label compareTailCorrectVectorEnd = new Label(); 142 143 Register tempReg1 = asRegister(temp4); 144 Register tempReg2 = asRegister(temp5); 145 146 boolean hasCBcond = masm.hasFeature(CPUFeature.CBCOND); 147 148 masm.sra(length, 0, length); 149 masm.and(result, VECTOR_SIZE - 1, result); // tail count (in bytes) 150 masm.andcc(length, ~(VECTOR_SIZE - 1), length); // vector count (in bytes) 151 masm.bpcc(ConditionFlag.Equal, NOT_ANNUL, compareTail, CC.Xcc, PREDICT_NOT_TAKEN); 152 153 masm.sub(length, VECTOR_SIZE, length); // Delay slot 154 masm.add(array1, length, array1); 155 masm.add(array2, length, array2); 156 masm.sub(g0, length, length); 157 158 // Compare the last element first 159 masm.ldx(new SPARCAddress(array1, 0), tempReg1); 160 masm.ldx(new SPARCAddress(array2, 0), tempReg2); 161 if (hasCBcond) { 162 masm.cbcondx(NotEqual, tempReg1, tempReg2, falseLabel); 163 masm.cbcondx(Equal, length, 0, compareTailCorrectVectorEnd); 164 } else { 165 masm.cmp(tempReg1, tempReg2); 166 masm.bpcc(NotEqual, NOT_ANNUL, falseLabel, Xcc, PREDICT_NOT_TAKEN); 167 masm.nop(); 168 masm.bpr(Rc_z, NOT_ANNUL, compareTailCorrectVectorEnd, PREDICT_NOT_TAKEN, length); 169 masm.nop(); 170 } 171 172 // Load the first value from array 1 (Later done in back branch delay-slot) 173 masm.ldx(new SPARCAddress(array1, length), tempReg1); 174 masm.bind(loop); 175 masm.ldx(new SPARCAddress(array2, length), tempReg2); 176 masm.cmp(tempReg1, tempReg2); 177 masm.bpcc(NotEqual, NOT_ANNUL, falseLabel, Xcc, PREDICT_NOT_TAKEN); 178 // Delay slot, not annul, add for next iteration 179 masm.addcc(length, VECTOR_SIZE, length); 180 // Annul, to prevent access past the array 181 masm.bpcc(NotEqual, ANNUL, loop, Xcc, PREDICT_TAKEN); 182 masm.ldx(new SPARCAddress(array1, length), tempReg1); // Load in delay slot 183 184 // Tail count zero, therefore we can go to the end 185 if (hasCBcond) { 186 masm.cbcondx(Equal, result, 0, trueLabel); 187 } else { 188 masm.bpr(Rc_z, NOT_ANNUL, trueLabel, PREDICT_TAKEN, result); 189 masm.nop(); 190 } 191 192 masm.bind(compareTailCorrectVectorEnd); 193 // Correct the array pointers 194 masm.add(array1, VECTOR_SIZE, array1); 195 masm.add(array2, VECTOR_SIZE, array2); 196 197 masm.bind(compareTail); 198 } 199 200 /** 201 * Emits code to compare the remaining 1 to 4 bytes. 202 */ 203 private void emitTailCompares(SPARCMacroAssembler masm, Register result, Register array1, Register array2, Label trueLabel, Label falseLabel) { 204 Label compare2Bytes = new Label(); 205 Label compare1Byte = new Label(); 206 207 Register tempReg1 = asRegister(temp3); 208 Register tempReg2 = asRegister(temp4); 209 boolean hasCBcond = masm.hasFeature(CBCOND); 210 211 if (kind.getByteCount() <= 4) { 212 // Compare trailing 4 bytes, if any. 213 if (hasCBcond) { 214 masm.cbcondx(Less, result, 4, compare2Bytes); 215 } else { 216 masm.cmp(result, 4); 217 masm.bpcc(Less, NOT_ANNUL, compare2Bytes, Xcc, PREDICT_NOT_TAKEN); 218 masm.nop(); 219 } 220 221 masm.lduw(new SPARCAddress(array1, 0), tempReg1); 222 masm.lduw(new SPARCAddress(array2, 0), tempReg2); 223 224 if (hasCBcond) { 225 masm.cbcondx(NotEqual, tempReg1, tempReg2, falseLabel); 226 } else { 227 masm.cmp(tempReg1, tempReg2); 228 masm.bpcc(NotEqual, NOT_ANNUL, falseLabel, Xcc, PREDICT_NOT_TAKEN); 229 masm.nop(); 230 } 231 232 if (kind.getByteCount() <= 2) { 233 // Move array pointers forward. 234 masm.add(array1, 4, array1); 235 masm.add(array2, 4, array2); 236 masm.sub(result, 4, result); 237 238 // Compare trailing 2 bytes, if any. 239 masm.bind(compare2Bytes); 240 241 if (hasCBcond) { 242 masm.cbcondx(Less, result, 2, compare1Byte); 243 } else { 244 masm.cmp(result, 2); 245 masm.bpcc(Less, NOT_ANNUL, compare1Byte, Xcc, PREDICT_TAKEN); 246 masm.nop(); 247 } 248 249 masm.lduh(new SPARCAddress(array1, 0), tempReg1); 250 masm.lduh(new SPARCAddress(array2, 0), tempReg2); 251 252 if (hasCBcond) { 253 masm.cbcondx(NotEqual, tempReg1, tempReg2, falseLabel); 254 } else { 255 masm.cmp(tempReg1, tempReg2); 256 masm.bpcc(NotEqual, NOT_ANNUL, falseLabel, Xcc, PREDICT_TAKEN); 257 masm.nop(); 258 } 259 260 // The one-byte tail compare is only required for boolean and byte arrays. 261 if (kind.getByteCount() <= 1) { 262 // Move array pointers forward before we compare the last trailing byte. 263 masm.add(array1, 2, array1); 264 masm.add(array2, 2, array2); 265 masm.sub(result, 2, result); 266 267 // Compare trailing byte, if any. 268 masm.bind(compare1Byte); 269 if (hasCBcond) { 270 masm.cbcondx(NotEqual, result, 1, trueLabel); 271 } else { 272 masm.cmp(result, 1); 273 masm.bpcc(NotEqual, NOT_ANNUL, trueLabel, Xcc, PREDICT_TAKEN); 274 masm.nop(); 275 } 276 masm.ldub(new SPARCAddress(array1, 0), tempReg1); 277 masm.ldub(new SPARCAddress(array2, 0), tempReg2); 278 if (hasCBcond) { 279 masm.cbcondx(NotEqual, tempReg1, tempReg2, falseLabel); 280 } else { 281 masm.cmp(tempReg1, tempReg2); 282 masm.bpcc(NotEqual, NOT_ANNUL, falseLabel, Xcc, PREDICT_TAKEN); 283 masm.nop(); 284 } 285 } else { 286 masm.bind(compare1Byte); 287 } 288 } else { 289 masm.bind(compare2Bytes); 290 } 291 } 292 } 293}