[M3commit] CVS Update: cm3
Jay Krell
jkrell at elego.de
Fri Feb 12 13:43:15 CET 2010
CVSROOT: /usr/cvs
Changes by: jkrell at birch. 10/02/12 13:43:15
Modified files:
cm3/m3-sys/m3back/src/: Codex86.i3 Codex86.m3 M3x86.m3
Log message:
use inc/dec for atomic add/sub of 1 or -1
before:
lea esi,[_MM_Main+38h]
mov ebx, 1
lock inc dword ptr [esi], ebx
mov dword ptr [_MM_Main+9Ch],esi
after:
lea esi,[_MM_Main+38h]
lock inc dword ptr [esi]
mov dword ptr [_MM_Main+9Ch],esi
ideal:
lock inc dword ptr [_MM_Main+38h]
aha but I think I know why, will try for ideal
I thought this was only going to save one byte:
add foo,1
vs.
inc foo
but we were loading 1 into a register as well
(we could have gotten to add foo,1, but no point now)
the unop changes not actually used here
no unop is atomic, inc/dec are implemented separately
I tried using the table based stuff but it is confusing
diff:
Index: Codex86.i3
===================================================================
RCS file: /usr/cvs/cm3/m3-sys/m3back/src/Codex86.i3,v
retrieving revision 1.18
diff -u -r1.18 Codex86.i3
--- Codex86.i3 11 Feb 2010 14:59:51 -0000 1.18
+++ Codex86.i3 12 Feb 2010 12:41:14 -0000
@@ -60,8 +60,9 @@
lock_compare_exchange (READONLY dest, src: Operand);
pushOp (READONLY src: Operand);
popOp (READONLY dest: Operand);
- decOp (READONLY op: Operand);
- unOp (op: Op; READONLY dest: Operand);
+ decOp (READONLY op: Operand; locked := FALSE);
+ incOp (READONLY op: Operand; locked := FALSE);
+ unOp (op: Op; READONLY dest: Operand; locked := FALSE);
mulOp (READONLY src: Operand);
imulOp (READONLY dest, src: Operand);
imulImm (READONLY dest, src: Operand; imm, imsize: INTEGER);
Index: Codex86.m3
===================================================================
RCS file: /usr/cvs/cm3/m3-sys/m3back/src/Codex86.m3,v
retrieving revision 1.55
diff -u -r1.55 Codex86.m3
--- Codex86.m3 12 Feb 2010 11:19:26 -0000 1.55
+++ Codex86.m3 12 Feb 2010 12:41:14 -0000
@@ -92,6 +92,7 @@
pushOp := pushOp;
popOp := popOp;
decOp := decOp;
+ incOp := incOp;
unOp := unOp;
mulOp := mulOp;
imulOp := imulOp;
@@ -1019,26 +1020,49 @@
END;
END popOp;
-PROCEDURE decOp (t: T; READONLY op: Operand) =
+
+PROCEDURE incOrDecOp (t: T; READONLY op: Operand; locked: BOOLEAN; incOrDec: [0..1]) =
VAR ins: Instruction;
+ name := ARRAY [0..1] OF TEXT{"INC", "DEC"}[incOrDec];
BEGIN
- Mn(t, "DEC"); MnOp(t, op);
+ ins.lock := locked;
+ Mn(t, name); MnOp(t, op);
+
<* ASSERT op.loc = OLoc.mem OR op.loc = OLoc.register *>
- IF op.loc = OLoc.register THEN
- ins.opcode := 16_48 + op.reg[0];
+
+ IF locked THEN
+ ins.mrmpres := TRUE;
+ ins.disp := 0;
+ ins.dsize := 0;
+ ins.modrm := 8 * incOrDec + op.reg[0];
+ ins.opcode := 16_FF;
+ writecode(t, ins);
+ ELSIF op.loc = OLoc.register THEN
+ ins.opcode := 16_40 + 8 * incOrDec + op.reg[0];
writecode(t, ins);
ELSE
<* ASSERT op.loc = OLoc.mem AND CG_Bytes[op.mvar.mvar_type] = 4 *>
- build_modrm(t, op, t.opcode[1], ins);
+ build_modrm(t, op, t.opcode[incOrDec], ins);
ins.opcode := 16_FF;
writecode(t, ins);
log_global_var(t, op.mvar, -4);
END
+ END incOrDecOp;
+
+PROCEDURE incOp (t: T; READONLY op: Operand; locked := FALSE) =
+ BEGIN
+ incOrDecOp(t, op, locked, 0);
+ END incOp;
+
+PROCEDURE decOp (t: T; READONLY op: Operand; locked := FALSE) =
+ BEGIN
+ incOrDecOp(t, op, locked, 1);
END decOp;
-PROCEDURE unOp1 (t: T; op: Op; READONLY dest: Operand) =
+PROCEDURE unOp1 (t: T; op: Op; READONLY dest: Operand; locked := FALSE) =
VAR ins: Instruction;
BEGIN
+ ins.lock := locked;
ins.opcode := opcode[op].imm32;
IF dest.loc = OLoc.mem THEN
get_op_size(dest.mvar.mvar_type, ins);
@@ -1057,11 +1081,14 @@
END
END unOp1;
-PROCEDURE unOp (t: T; op: Op; READONLY dest: Operand) =
+PROCEDURE unOp (t: T; op: Op; READONLY dest: Operand; locked := FALSE) =
VAR destA: ARRAY OperandPart OF Operand;
destSize := SplitOperand(dest, destA);
BEGIN
+ (* future: we could use cmpxchg loop *)
+ <* ASSERT (destSize = 1) OR (NOT locked) *>
+
IF destSize = 2 AND (op IN SET OF Op{Op.oNEG, Op.oNOT}) THEN
CASE op OF
| Op.oNOT =>
@@ -1079,7 +1106,7 @@
<* ASSERT NOT Is64(destA[destSize - 1].optype) *>
FOR i := 0 TO destSize - 1 DO
- unOp1(t, op, destA[i]);
+ unOp1(t, op, destA[i], locked);
END;
END;
END unOp;
Index: M3x86.m3
===================================================================
RCS file: /usr/cvs/cm3/m3-sys/m3back/src/M3x86.m3,v
retrieving revision 1.110
diff -u -r1.110 M3x86.m3
--- M3x86.m3 12 Feb 2010 11:11:15 -0000 1.110
+++ M3x86.m3 12 Feb 2010 12:41:15 -0000
@@ -3004,7 +3004,8 @@
u.vstack.newdest(u.cg.reg[EDI]);
ELSE
- WITH stack0 = u.vstack.pos(0, "zero"), stop0 = u.vstack.op(stack0) DO
+ WITH stack0 = u.vstack.pos(0, "zero"),
+ stop0 = u.vstack.op(stack0) DO
u.vstack.find(stack0, Force.anyreg, RegSet {}, TRUE);
FOR i := 0 TO n - 1 DO
u.cg.store_ind(Operand { loc := OLoc.imm, imm := TZero, optype := t },
@@ -4297,15 +4298,16 @@
CONST AtomicOpToOp = ARRAY AtomicOp OF Op { Op.oADD, Op.oSUB, Op.oOR, Op.oAND, Op.oXOR };
CONST AtomicOpName = ARRAY AtomicOp OF TEXT { "add", "sub", "or", "and", "xor" };
-PROCEDURE fetch_and_op (x: U; op: AtomicOp; t: MType; z: ZType;
+PROCEDURE fetch_and_op (x: U; atomic_op: AtomicOp; t: MType; z: ZType;
<*UNUSED*>order: MemoryOrder) =
(* tmp := Mem [s1.A].t;
Mem [s1.A].t := tmp op s0.u;
s1.u := tmp op s0.u; pop *)
+ VAR op := AtomicOpToOp[atomic_op];
BEGIN
IF x.debug THEN
x.wr.Cmd ("fetch_and_op");
- x.wr.OutT (AtomicOpName[op]);
+ x.wr.OutT (AtomicOpName[atomic_op]);
x.wr.TName (t);
x.wr.TName (z);
x.wr.NL ();
@@ -4318,7 +4320,35 @@
RETURN;
END;
- EVAL x.vstack.dobin(AtomicOpToOp[op], (*symmetric*) op # AtomicOp.Sub, (*overwritesdest*) TRUE, t, locked := TRUE);
+ (* optimize add 1 => inc, add -1 => dec, sub 1 => dec, sub -1 => inc
+ * to save a byte encoding the immediate value.
+ * NOTE: We should do this for reg where t.reguse[reg].last_imm = 1 or -1 also.
+ *)
+
+ WITH stack0 = x.vstack.pos(0, "fetch_and_op"),
+ stack1 = x.vstack.pos(1, "fetch_and_op"),
+ stop0 = x.vstack.op(stack0) DO
+ IF op IN SET OF Op{Op.oADD, Op.oSUB} THEN
+ IF stop0.loc = OLoc.imm THEN
+ WITH imm = stop0.imm DO
+ IF (TInt.EQ(imm, TInt.One) OR TInt.EQ(imm, TInt.MOne)) THEN
+ x.vstack.unlock();
+ x.vstack.find(stack1, Force.anyreg);
+ IF (op = Op.oADD) = TInt.EQ(imm, TInt.One) THEN
+ x.cg.incOp(x.vstack.op(stack1), locked := TRUE);
+ ELSE
+ x.cg.decOp(x.vstack.op(stack1), locked := TRUE);
+ END;
+ x.vstack.newdest(x.vstack.op(stack1));
+ x.vstack.discard(1);
+ RETURN;
+ END;
+ END;
+ END;
+ END;
+ END;
+
+ EVAL x.vstack.dobin(op, (*symmetric*) (*op # AtomicOp.Sub*) FALSE, (*overwritesdest*) TRUE, t, locked := TRUE);
END fetch_and_op;
More information about the M3commit
mailing list