| // 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}, |
| [AUNDEF]= {Break}, |
| [AUSEFIELD]= {OK}, |
| [ACHECKNIL]= {LeftRead}, |
| [AVARDEF]= {Pseudo | RightWrite}, |
| [AVARKILL]= {Pseudo | RightWrite}, |
| |
| // 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}, |
| // In addtion, duffzero reads R0,R1 and writes R1. This fact is |
| // encoded in peep.c |
| [ADUFFZERO]= {Call}, |
| // In addtion, duffcopy reads R1,R2 and writes R0,R1,R2. This fact is |
| // encoded in peep.c |
| [ADUFFCOPY]= {Call}, |
| |
| // 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 | Break}, |
| [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(p->from.type == D_CONST && p->from.sym != nil && (info->flags & LeftRead)) { |
| info->flags &= ~LeftRead; |
| info->flags |= LeftAddr; |
| } |
| |
| 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; |
| } |