aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--x86_64/emit.c15
-rw-r--r--x86_64/isel.c1
2 files changed, 15 insertions, 1 deletions
diff --git a/x86_64/emit.c b/x86_64/emit.c
index f5b63fa..77f421e 100644
--- a/x86_64/emit.c
+++ b/x86_64/emit.c
@@ -1044,7 +1044,20 @@ emitinstr(uchar **pcode, struct function *fn, struct block *blk, int curi, struc
mkoper(OMEM, .base = mkregoper(ins->l).reg, .index = NOINDEX, .disp = -intconval(ins->r)));
}
break;
- case Oshl: X = Xshl; goto ALU2;
+ case Oshl:
+ dst = reg2oper(ins->reg-1);
+ src = mkregoper(ins->l);
+ if (dst.reg == src.reg)
+ Xshl(pcode, cls, dst, mkimmdatregoper(ins->r));
+ else {
+ uint sh = ins->r.i;
+ assert(ins->r.t == RICON && sh <= 3);
+ if (sh == 1) /* shl x, 1 -> lea [x + x] */
+ Xlea(pcode, cls, dst, mkoper(OMEM, .base = src.reg, .index = src.reg));
+ else /* shl x, n -> lea [x*(1<<n)+0x0] */
+ Xlea(pcode, cls, dst, mkoper(OMEM, .base = NOBASE, .index = src.reg, .shift = sh));
+ }
+ break;
case Osar: X = Xsar; goto ALU2;
case Oslr: X = Xshr; goto ALU2;
case Oand:
diff --git a/x86_64/isel.c b/x86_64/isel.c
index 19692ed..2b087cd 100644
--- a/x86_64/isel.c
+++ b/x86_64/isel.c
@@ -507,6 +507,7 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
ALU:
if (!(op == Oadd && kisint(ins->cls))) /* 3-address add is lea */
if (!(op == Omul && kisint(ins->cls) && isimm32(ins->r))) /* for (I)MUL r,r/m,imm */
+ if (!(op == Oshl && ins->r.t == RICON && ins->r.i <= 3)) /* can be lea */
ins->inplace = 1;
if (iscon(ins->l)) {
fixarg(&ins->l, ins, blk, curi);