Support for 32bit CAS as an intrinsic.
Change-Id: Ib7f345a8c54a518c7ce5c0765287417bec5a9ef1
diff --git a/src/compiler/codegen/GenInvoke.cc b/src/compiler/codegen/GenInvoke.cc
index 29bd2a6..7190a8b 100644
--- a/src/compiler/codegen/GenInvoke.cc
+++ b/src/compiler/codegen/GenInvoke.cc
@@ -915,9 +915,70 @@
#endif
}
+bool genInlinedCas32(CompilationUnit* cUnit, CallInfo* info, bool need_write_barrier) {
+#if defined(TARGET_ARM)
+ // Unused - RegLocation rlSrcUnsafe = info->args[0];
+ RegLocation rlSrcObj= info->args[1]; // Object - known non-null
+ RegLocation rlSrcOffset= info->args[2]; // long low
+ rlSrcOffset.wide = 0; // ignore high half in info->args[3]
+ RegLocation rlSrcExpected= info->args[4]; // int or Object
+ RegLocation rlSrcNewValue= info->args[5]; // int or Object
+ RegLocation rlDest = inlineTarget(cUnit, info); // boolean place for result
+
+
+ // Release store semantics, get the barrier out of the way.
+ oatGenMemBarrier(cUnit, kSY);
+
+ RegLocation rlObject = loadValue(cUnit, rlSrcObj, kCoreReg);
+ RegLocation rlNewValue = loadValue(cUnit, rlSrcNewValue, kCoreReg);
+
+ if (need_write_barrier) {
+ // Mark card for object assuming new value is stored.
+ markGCCard(cUnit, rlNewValue.lowReg, rlObject.lowReg);
+ }
+
+ RegLocation rlOffset = loadValue(cUnit, rlSrcOffset, kCoreReg);
+
+ int rPtr = oatAllocTemp(cUnit);
+ opRegRegReg(cUnit, kOpAdd, rPtr, rlObject.lowReg, rlOffset.lowReg);
+
+ // Free now unneeded rlObject and rlOffset to give more temps.
+ oatClobberSReg(cUnit, rlObject.sRegLow);
+ oatFreeTemp(cUnit, rlObject.lowReg);
+ oatClobberSReg(cUnit, rlOffset.sRegLow);
+ oatFreeTemp(cUnit, rlOffset.lowReg);
+
+ int rOldValue = oatAllocTemp(cUnit);
+ newLIR3(cUnit, kThumb2Ldrex, rOldValue, rPtr, 0); // rOldValue := [rPtr]
+
+ RegLocation rlExpected = loadValue(cUnit, rlSrcExpected, kCoreReg);
+
+ // if (rOldValue == rExpected) {
+ // [rPtr] <- rNewValue && rResult := success ? 0 : 1
+ // rResult ^= 1
+ // } else {
+ // rResult := 0
+ // }
+ opRegReg(cUnit, kOpCmp, rOldValue, rlExpected.lowReg);
+ oatFreeTemp(cUnit, rOldValue); // Now unneeded.
+ RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
+ opIT(cUnit, kArmCondEq, "TE");
+ newLIR4(cUnit, kThumb2Strex, rlResult.lowReg, rlNewValue.lowReg, rPtr, 0);
+ oatFreeTemp(cUnit, rPtr); // Now unneeded.
+ opRegImm(cUnit, kOpXor, rlResult.lowReg, 1);
+ opRegReg(cUnit, kOpXor, rlResult.lowReg, rlResult.lowReg);
+
+ storeValue(cUnit, rlDest, rlResult);
+
+ return true;
+#else
+ return false;
+#endif
+}
+
bool genIntrinsic(CompilationUnit* cUnit, CallInfo* info)
{
- if ((info->optFlags & MIR_INLINED) || info->isRange) {
+ if (info->optFlags & MIR_INLINED) {
return false;
}
/*
@@ -931,48 +992,54 @@
* take advantage of/generate new useful dataflow info.
*/
std::string tgtMethod(PrettyMethod(info->index, *cUnit->dex_file));
- if (tgtMethod.compare("char java.lang.String.charAt(int)") == 0) {
+ if (tgtMethod == "char java.lang.String.charAt(int)") {
return genInlinedCharAt(cUnit, info);
}
- if (tgtMethod.compare("int java.lang.Math.min(int, int)") == 0) {
+ if (tgtMethod == "int java.lang.Math.min(int, int)") {
return genInlinedMinMaxInt(cUnit, info, true /* isMin */);
}
- if (tgtMethod.compare("int java.lang.Math.max(int, int)") == 0) {
+ if (tgtMethod == "int java.lang.Math.max(int, int)") {
return genInlinedMinMaxInt(cUnit, info, false /* isMin */);
}
- if (tgtMethod.compare("int java.lang.String.length()") == 0) {
+ if (tgtMethod == "int java.lang.String.length()") {
return genInlinedStringIsEmptyOrLength(cUnit, info, false /* isEmpty */);
}
- if (tgtMethod.compare("boolean java.lang.String.isEmpty()") == 0) {
+ if (tgtMethod == "boolean java.lang.String.isEmpty()") {
return genInlinedStringIsEmptyOrLength(cUnit, info, true /* isEmpty */);
}
- if (tgtMethod.compare("int java.lang.Math.abs(int)") == 0) {
+ if (tgtMethod == "int java.lang.Math.abs(int)") {
return genInlinedAbsInt(cUnit, info);
}
- if (tgtMethod.compare("long java.lang.Math.abs(long)") == 0) {
+ if (tgtMethod == "long java.lang.Math.abs(long)") {
return genInlinedAbsLong(cUnit, info);
}
- if (tgtMethod.compare("int java.lang.Float.floatToRawIntBits(float)") == 0) {
+ if (tgtMethod == "int java.lang.Float.floatToRawIntBits(float)") {
return genInlinedFloatCvt(cUnit, info);
}
- if (tgtMethod.compare("float java.lang.Float.intBitsToFloat(int)") == 0) {
+ if (tgtMethod == "float java.lang.Float.intBitsToFloat(int)") {
return genInlinedFloatCvt(cUnit, info);
}
- if (tgtMethod.compare("long java.lang.Double.doubleToRawLongBits(double)") == 0) {
+ if (tgtMethod == "long java.lang.Double.doubleToRawLongBits(double)") {
return genInlinedDoubleCvt(cUnit, info);
}
- if (tgtMethod.compare("double java.lang.Double.longBitsToDouble(long)") == 0) {
+ if (tgtMethod == "double java.lang.Double.longBitsToDouble(long)") {
return genInlinedDoubleCvt(cUnit, info);
}
- if (tgtMethod.compare("int java.lang.String.indexOf(int, int)") == 0) {
+ if (tgtMethod == "int java.lang.String.indexOf(int, int)") {
return genInlinedIndexOf(cUnit, info, false /* base 0 */);
}
- if (tgtMethod.compare("int java.lang.String.indexOf(int)") == 0) {
+ if (tgtMethod == "int java.lang.String.indexOf(int)") {
return genInlinedIndexOf(cUnit, info, true /* base 0 */);
}
- if (tgtMethod.compare("int java.lang.String.compareTo(java.lang.String)") == 0) {
+ if (tgtMethod == "int java.lang.String.compareTo(java.lang.String)") {
return genInlinedStringCompareTo(cUnit, info);
}
+ if (tgtMethod == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
+ return genInlinedCas32(cUnit, info, false);
+ }
+ if (tgtMethod == "boolean sun.misc.Unsafe.compareAndSwapObject(java.lang.Object, long, java.lang.Object, java.lang.Object)") {
+ return genInlinedCas32(cUnit, info, true);
+ }
return false;
}