ARM: Add atomic sequences using ldrexd/strexd
Andrew Haley
aph at redhat.com
Tue Dec 20 07:39:19 PST 2011
Generate proper atomic code for volatile longs; much the same as
the code yesterday, but this time for the JIT.
Andrew.
2011-12-20 Andrew Haley <aph at redhat.com>
* openjdk/hotspot/src/cpu/zero/vm/thumb2.cpp (T_LDREXD, T_STREXD):
New instructions.
(ldrexd, strexd): Likewise.
(Thumb2_load_long, Thumb2_store_long): New functions.
(Thumb2_codegen): Use Thumb2_load_long and Thumb2_store_long for
all long field accesses.
diff -r 293b2d68ce5f -r c4c8d17de1e2 arm_port/hotspot/src/cpu/zero/vm/thumb2.cpp
--- a/arm_port/hotspot/src/cpu/zero/vm/thumb2.cpp Tue Dec 20 10:12:28 2011 -0500
+++ b/arm_port/hotspot/src/cpu/zero/vm/thumb2.cpp Tue Dec 20 15:36:52 2011 +0000
@@ -2086,6 +2086,9 @@
#define T_STREX(dst, src, base, off) (0xe8400000 | ((base) << 16) | \
((src) << 12) | ((dst) << 8) | ((off >> 2)))
+#define T_LDREXD(dst1, dst2, base) (0xe8d0007f | ((base) << 16) | ((dst1) << 12) | (dst2 << 8))
+#define T_STREXD(dst, src1, src2, base) (0xe8c00070 | ((base) << 16) | ((src1) << 12) | (src2 << 8) | dst)
+
#define T_STM8(base, regset) (0xc000 | ((base) << 8) | (regset))
#define T_STM16(base, regset, st, wb) (0xe8000000 | ((st) << 23) | ((wb) << 21) | \
((base) << 16) | (regset))
@@ -2391,6 +2394,22 @@
J_Unimplemented();
}
+int ldrexd(CodeBuf *codebuf, Reg dst0, Reg dst1, Reg base)
+{
+ if (Thumb2) {
+ return out_16x2(codebuf, T_LDREXD(dst0, dst1, base));
+ }
+ J_Unimplemented();
+}
+
+int strexd(CodeBuf *codebuf, Reg dst, Reg src0, Reg src1, Reg base)
+{
+ if (Thumb2) {
+ return out_16x2(codebuf, T_STREXD(dst, src0, src1, base));
+ }
+ J_Unimplemented();
+}
+
int str_imm(CodeBuf *codebuf, Reg src, Reg base, int offset, int pre, int wb)
{
unsigned uoff;
@@ -4872,6 +4891,69 @@
H_D2F,
};
+// Generate code for a load of a jlong. If the operand is volatile,
+// generate a sequence of the form
+//
+// .Lsrc:
+// ldrexd r0, r1 , [src]
+// strexd r2 , r0, r1, [src]
+// cmp r2, #0
+// bne .Lsrc
+
+void Thumb2_load_long(Thumb2_Info *jinfo, Reg r_lo, Reg r_hi, Reg base,
+ int field_offset,
+ bool is_volatile = false)
+{
+ CodeBuf *codebuf = jinfo->codebuf;
+ if (is_volatile) {
+ Reg r_addr = base;
+ Reg tmp = Thumb2_Tmp(jinfo, (1<<r_lo) | (1<<r_hi) | (1<<base));
+ if (field_offset) {
+ r_addr = Thumb2_Tmp(jinfo, (1<<r_lo) | (1<<r_hi) | (1<<base) | (1<<tmp));
+ add_imm(jinfo->codebuf, r_addr, base, field_offset);
+ }
+ int loc = out_loc(codebuf);
+ ldrexd(codebuf, r_lo, r_hi, r_addr);
+ strexd(codebuf, tmp, r_lo, r_hi, r_addr);
+ cmp_imm(codebuf, tmp, 0);
+ branch(codebuf, COND_NE, loc);
+ } else {
+ ldrd_imm(codebuf, r_lo, r_hi, base, field_offset, 1, 0);
+ }
+}
+
+// Generate code for a load of a jlong. If the operand is volatile,
+// generate a sequence of the form
+//
+// .Ldst
+// ldrexd r2, r3, [dst]
+// strexd r2, r0, r1, [dst]
+// cmp r2, #0
+// bne .Ldst
+
+void Thumb2_store_long(Thumb2_Info *jinfo, Reg r_lo, Reg r_hi, Reg base,
+ int field_offset,
+ bool is_volatile = false)
+{
+ CodeBuf *codebuf = jinfo->codebuf;
+ if (is_volatile) {
+ Reg r_addr = base;
+ Reg tmp1 = Thumb2_Tmp(jinfo, (1<<r_lo) | (1<<r_hi) | (1<<base));
+ Reg tmp2 = Thumb2_Tmp(jinfo, (1<<r_lo) | (1<<r_hi) | (1<<base) | (1<<tmp1));
+ if (field_offset) {
+ r_addr = Thumb2_Tmp(jinfo, (1<<r_lo) | (1<<r_hi) | (1<<base) | (1<<tmp1) | (1<<tmp2));
+ add_imm(jinfo->codebuf, r_addr, base, field_offset);
+ }
+ int loc = out_loc(codebuf);
+ ldrexd(codebuf, tmp1, tmp2, r_addr);
+ strexd(codebuf, tmp1, r_lo, r_hi, r_addr);
+ cmp_imm(codebuf, tmp1, 0);
+ branch(codebuf, COND_NE, loc);
+ } else {
+ strd_imm(codebuf, r_lo, r_hi, base, field_offset, 1, 0);
+ }
+}
+
#define OPCODE2HANDLER(opc) (handlers[opcode2handler[(opc)-opc_idiv]])
extern "C" void _ZN18InterpreterRuntime18register_finalizerEP10JavaThreadP7oopDesc(void);
@@ -5687,7 +5769,8 @@
Thumb2_Spill(jinfo, 2, 0);
r_hi = PUSH(jstack, JSTACK_REG(jstack));
r_lo = PUSH(jstack, JSTACK_REG(jstack));
- ldrd_imm(jinfo->codebuf, r_lo, r_hi, r_obj, field_offset, 1, 0);
+ Thumb2_load_long(jinfo, r_lo, r_hi, r_obj, field_offset,
+ cache->is_volatile());
} else {
Reg r;
@@ -5748,13 +5831,15 @@
int field_offset = cache->f2();
if (tos_type == ltos || tos_type == dtos) {
- Reg r_lo, r_hi;
+ Reg r_lo, r_hi, r_addr;
Thumb2_Spill(jinfo, 2, 0);
r_hi = PUSH(jstack, JSTACK_REG(jstack));
r_lo = PUSH(jstack, JSTACK_REG(jstack));
+ r_addr = Thumb2_Tmp(jinfo, (1<<r_hi) | (1<<r_lo));
ldr_imm(jinfo->codebuf, r_lo, Ristate, ISTATE_CONSTANTS, 1, 0);
- ldr_imm(jinfo->codebuf, r_lo, r_lo, CP_OFFSET + (index << 4) + 4, 1, 0);
- ldrd_imm(jinfo->codebuf, r_lo, r_hi, r_lo, field_offset, 1, 0);
+ ldr_imm(jinfo->codebuf, r_addr, r_lo, CP_OFFSET + (index << 4) + 4, 1, 0);
+ Thumb2_load_long(jinfo, r_lo, r_hi, r_addr, field_offset,
+ cache->is_volatile());
} else {
Reg r;
Thumb2_Spill(jinfo, 1, 0);
@@ -5820,7 +5905,7 @@
r_lo = POP(jstack);
r_hi = POP(jstack);
r_obj = POP(jstack);
- strd_imm(jinfo->codebuf, r_lo, r_hi, r_obj, field_offset, 1, 0);
+ Thumb2_store_long(jinfo, r_lo, r_hi, r_obj, field_offset, cache->is_volatile());
} else {
Reg r;
Thumb2_Fill(jinfo, 2);
@@ -5890,7 +5975,7 @@
JASSERT(r_obj != r_lo && r_obj != r_hi, "corruption in putstatic");
ldr_imm(jinfo->codebuf, r_obj, Ristate, ISTATE_CONSTANTS, 1, 0);
ldr_imm(jinfo->codebuf, r_obj, r_obj, CP_OFFSET + (index << 4) + 4, 1, 0);
- strd_imm(jinfo->codebuf, r_lo, r_hi, r_obj, field_offset, 1, 0);
+ Thumb2_store_long(jinfo, r_lo, r_hi, r_obj, field_offset, cache->is_volatile());
} else {
Reg r;
Thumb2_Fill(jinfo, 1);
More information about the distro-pkg-dev
mailing list