int32 FtoB(int);
int BtoR(int32);
int BtoF(int32);
+
+/*
+ * prog.c
+ */
+typedef struct ProgInfo ProgInfo;
+struct ProgInfo
+{
+ uint32 flags; // the bits below
+};
+
+enum
+{
+ // Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
+ Pseudo = 1<<1,
+
+ // There's nothing to say about the instruction,
+ // but it's still okay to see.
+ OK = 1<<2,
+
+ // Size of right-side write, or right-side read if no write.
+ SizeB = 1<<3,
+ SizeW = 1<<4,
+ SizeL = 1<<5,
+ SizeQ = 1<<6,
+ SizeF = 1<<7, // float aka float32
+ SizeD = 1<<8, // double aka float64
+
+ // Left side: address taken, read, write.
+ LeftAddr = 1<<9,
+ LeftRead = 1<<10,
+ LeftWrite = 1<<11,
+
+ // Register in middle; never written.
+ RegRead = 1<<12,
+ CanRegRead = 1<<13,
+
+ // Right side: address taken, read, write.
+ RightAddr = 1<<14,
+ RightRead = 1<<15,
+ RightWrite = 1<<16,
+
+ // Instruction kinds
+ Move = 1<<17, // straight move
+ Conv = 1<<18, // size conversion
+ Cjmp = 1<<19, // conditional jump
+ Break = 1<<20, // breaks control flow (no fallthrough)
+ Call = 1<<21, // function call
+ Jump = 1<<22, // jump
+ Skip = 1<<23, // data instruction
+};
+
+void proginfo(ProgInfo*, Prog*);
--- /dev/null
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+
+enum
+{
+ RightRdwr = RightRead | RightWrite,
+};
+
+// This table gives the basic information about instruction
+// generated by the compiler and processed in the optimizer.
+// See opt.h for bit definitions.
+//
+// Instructions not generated need not be listed.
+// As an exception to that rule, we typically write down all the
+// size variants of an operation even if we just use a subset.
+//
+// The table is formatted for 8-space tabs.
+static ProgInfo progtable[ALAST] = {
+ [ATYPE]= {Pseudo | Skip},
+ [ATEXT]= {Pseudo},
+ [AFUNCDATA]= {Pseudo},
+ [APCDATA]= {Pseudo},
+
+ // NOP is an internal no-op that also stands
+ // for USED and SET annotations, not the Intel opcode.
+ [ANOP]= {LeftRead | RightWrite},
+
+ // Integer.
+ [AADC]= {SizeL | LeftRead | RegRead | RightWrite},
+ [AADD]= {SizeL | LeftRead | RegRead | RightWrite},
+ [AAND]= {SizeL | LeftRead | RegRead | RightWrite},
+ [ABIC]= {SizeL | LeftRead | RegRead | RightWrite},
+ [ACMN]= {SizeL | LeftRead | RightRead},
+ [ACMP]= {SizeL | LeftRead | RightRead},
+ [ADIVU]= {SizeL | LeftRead | RegRead | RightWrite},
+ [ADIV]= {SizeL | LeftRead | RegRead | RightWrite},
+ [AEOR]= {SizeL | LeftRead | RegRead | RightWrite},
+ [AMODU]= {SizeL | LeftRead | RegRead | RightWrite},
+ [AMOD]= {SizeL | LeftRead | RegRead | RightWrite},
+ [AMULALU]= {SizeL | LeftRead | RegRead | RightRdwr},
+ [AMULAL]= {SizeL | LeftRead | RegRead | RightRdwr},
+ [AMULA]= {SizeL | LeftRead | RegRead | RightRdwr},
+ [AMULU]= {SizeL | LeftRead | RegRead | RightWrite},
+ [AMUL]= {SizeL | LeftRead | RegRead | RightWrite},
+ [AMULL]= {SizeL | LeftRead | RegRead | RightWrite},
+ [AMULLU]= {SizeL | LeftRead | RegRead | RightWrite},
+ [AMVN]= {SizeL | LeftRead | RightWrite},
+ [AORR]= {SizeL | LeftRead | RegRead | RightWrite},
+ [ARSB]= {SizeL | LeftRead | RegRead | RightWrite},
+ [ARSC]= {SizeL | LeftRead | RegRead | RightWrite},
+ [ASBC]= {SizeL | LeftRead | RegRead | RightWrite},
+ [ASLL]= {SizeL | LeftRead | RegRead | RightWrite},
+ [ASRA]= {SizeL | LeftRead | RegRead | RightWrite},
+ [ASRL]= {SizeL | LeftRead | RegRead | RightWrite},
+ [ASUB]= {SizeL | LeftRead | RegRead | RightWrite},
+ [ATEQ]= {SizeL | LeftRead | RightRead},
+ [ATST]= {SizeL | LeftRead | RightRead},
+
+ // Floating point.
+ [AADDD]= {SizeD | LeftRead | RightRdwr},
+ [AADDF]= {SizeF | LeftRead | RightRdwr},
+ [ACMPD]= {SizeD | LeftRead | RightRead},
+ [ACMPF]= {SizeF | LeftRead | RightRead},
+ [ADIVD]= {SizeD | LeftRead | RightRdwr},
+ [ADIVF]= {SizeF | LeftRead | RightRdwr},
+ [AMULD]= {SizeD | LeftRead | RightRdwr},
+ [AMULF]= {SizeF | LeftRead | RightRdwr},
+ [ASUBD]= {SizeD | LeftRead | RightRdwr},
+ [ASUBF]= {SizeF | LeftRead | RightRdwr},
+
+ // Conversions.
+ [AMOVWD]= {SizeD | LeftRead | RightWrite | Conv},
+ [AMOVWF]= {SizeF | LeftRead | RightWrite | Conv},
+ [AMOVDF]= {SizeF | LeftRead | RightWrite | Conv},
+ [AMOVDW]= {SizeL | LeftRead | RightWrite | Conv},
+ [AMOVFD]= {SizeD | LeftRead | RightWrite | Conv},
+ [AMOVFW]= {SizeL | LeftRead | RightWrite | Conv},
+
+ // Moves.
+ [AMOVB]= {SizeB | LeftRead | RightWrite | Move},
+ [AMOVD]= {SizeD | LeftRead | RightWrite | Move},
+ [AMOVF]= {SizeF | LeftRead | RightWrite | Move},
+ [AMOVH]= {SizeW | LeftRead | RightWrite | Move},
+ [AMOVW]= {SizeL | LeftRead | RightWrite | Move},
+
+ // These should be split into the two different conversions instead
+ // of overloading the one.
+ [AMOVBS]= {SizeB | LeftRead | RightWrite | Conv},
+ [AMOVBU]= {SizeB | LeftRead | RightWrite | Conv},
+ [AMOVHS]= {SizeW | LeftRead | RightWrite | Conv},
+ [AMOVHU]= {SizeW | LeftRead | RightWrite | Conv},
+
+ // Jumps.
+ [AB]= {Jump},
+ [ABL]= {Call},
+ [ABEQ]= {Cjmp},
+ [ABNE]= {Cjmp},
+ [ABCS]= {Cjmp},
+ [ABHS]= {Cjmp},
+ [ABCC]= {Cjmp},
+ [ABLO]= {Cjmp},
+ [ABMI]= {Cjmp},
+ [ABPL]= {Cjmp},
+ [ABVS]= {Cjmp},
+ [ABVC]= {Cjmp},
+ [ABHI]= {Cjmp},
+ [ABLS]= {Cjmp},
+ [ABGE]= {Cjmp},
+ [ABLT]= {Cjmp},
+ [ABGT]= {Cjmp},
+ [ABLE]= {Cjmp},
+ [ARET]= {Break},
+};
+
+void
+proginfo(ProgInfo *info, Prog *p)
+{
+ *info = progtable[p->as];
+ if(info->flags == 0)
+ fatal("unknown instruction %P", p);
+
+ if((info->flags & RegRead) && p->reg == NREG) {
+ info->flags &= ~RegRead;
+ info->flags |= CanRegRead | RightRead;
+ }
+
+ if(((p->scond & C_SCOND) != C_SCOND_NONE) && (info->flags & RightWrite))
+ info->flags |= RightRead;
+}
int i, z, nr;
uint32 vreg;
Bits bit;
-
+ ProgInfo info, info2;
+
if(first == 0) {
fmtinstall('Q', Qconv);
}
*/
nr = 0;
for(p=firstp; p != P; p = p->link) {
- switch(p->as) {
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- case ATYPE:
+ proginfo(&info, p);
+ if(info.flags & Skip)
continue;
- }
+
r = rega();
nr++;
if(firstr == R) {
r1 = r->p1;
if(r1 != R) {
- switch(r1->prog->as) {
- case ARET:
- case AB:
- case ARFE:
+ proginfo(&info2, r1->prog);
+ if(info2.flags & Break) {
r->p1 = R;
r1->s1 = R;
}
if(p->as == ABL && p->to.type == D_EXTERN)
continue;
- /*
- * left side always read
- */
- bit = mkvar(r, &p->from);
- for(z=0; z<BITS; z++)
- r->use1.b[z] |= bit.b[z];
-
- /*
- * middle always read when present
- */
- if(p->reg != NREG) {
+ if(info.flags & LeftRead) {
+ bit = mkvar(r, &p->from);
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+ }
+
+ if(info.flags & RegRead) {
if(p->from.type != D_FREG)
r->use1.b[0] |= RtoB(p->reg);
else
r->use1.b[0] |= FtoB(p->reg);
}
- /*
- * right side depends on opcode
- */
- bit = mkvar(r, &p->to);
- if(bany(&bit))
- switch(p->as) {
- default:
- yyerror("reg: unknown op: %A", p->as);
- break;
-
- /*
- * right side read
- */
- case ATST:
- case ATEQ:
- case ACMP:
- case ACMN:
- case ACMPD:
- case ACMPF:
- rightread:
- for(z=0; z<BITS; z++)
- r->use2.b[z] |= bit.b[z];
- break;
-
- /*
- * right side read or read+write, depending on middle
- * ADD x, z => z += x
- * ADD x, y, z => z = x + y
- */
- case AADD:
- case AAND:
- case AEOR:
- case ASUB:
- case ARSB:
- case AADC:
- case ASBC:
- case ARSC:
- case AORR:
- case ABIC:
- case ASLL:
- case ASRL:
- case ASRA:
- case AMUL:
- case AMULU:
- case ADIV:
- case AMOD:
- case AMODU:
- case ADIVU:
- if(p->reg != NREG)
- goto rightread;
- // fall through
-
- /*
- * right side read+write
- */
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- case AMULA:
- case AMULAL:
- case AMULALU:
- for(z=0; z<BITS; z++) {
- r->use2.b[z] |= bit.b[z];
- r->set.b[z] |= bit.b[z];
- }
- break;
-
- /*
- * right side write
- */
- case ANOP:
- case AMOVB:
- case AMOVBS:
- case AMOVBU:
- case AMOVD:
- case AMOVDF:
- case AMOVDW:
- case AMOVF:
- case AMOVFW:
- case AMOVH:
- case AMOVHS:
- case AMOVHU:
- case AMOVW:
- case AMOVWD:
- case AMOVWF:
- case AMVN:
- case AMULL:
- case AMULLU:
- if((p->scond & C_SCOND) != C_SCOND_NONE)
+ if(info.flags & (RightAddr | RightRead | RightWrite)) {
+ bit = mkvar(r, &p->to);
+ if(info.flags & RightAddr)
+ setaddrs(bit);
+ if(info.flags & RightRead)
for(z=0; z<BITS; z++)
r->use2.b[z] |= bit.b[z];
- for(z=0; z<BITS; z++)
- r->set.b[z] |= bit.b[z];
- break;
-
- /*
- * funny
- */
- case ABL:
- setaddrs(bit);
- break;
- }
-
- if(p->as == AMOVM) {
- z = p->to.offset;
- if(p->from.type == D_CONST)
- z = p->from.offset;
- for(i=0; z; i++) {
- if(z&1)
- regbits |= RtoB(i);
- z >>= 1;
- }
+ if(info.flags & RightWrite)
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
}
}
if(firstr == R)