summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2014-11-24 11:40:36 -0500
committerAustin Clements <austin@google.com>2014-11-24 11:40:36 -0500
commit3cd4b0d0305ab817e9ae0a6a7c7e9c44fecbb510 (patch)
tree040b65142d1564bf6453953e6d033c061b368757
parentda15dedfd028d08bb842c990d1195ff901d8b014 (diff)
downloadgo-3cd4b0d0305ab817e9ae0a6a7c7e9c44fecbb510.tar.gz
[dev.cc] 9g: fill progtable for CC, V, and VCC instruction variants
This adds some utilities for converting between the CC, V, and VCC variants of operations and uses these to derive the ProgInfo entries for these variants (which are identical to the ProgInfo for the base operations). The 9g peephole optimizer will also use these conversion utilities. LGTM=minux, rsc R=rsc, dave, minux CC=golang-codereviews https://codereview.appspot.com/180110044
-rw-r--r--src/cmd/9g/opt.h10
-rw-r--r--src/cmd/9g/prog.c162
2 files changed, 172 insertions, 0 deletions
diff --git a/src/cmd/9g/opt.h b/src/cmd/9g/opt.h
index 7f15b5a69..6a07b268f 100644
--- a/src/cmd/9g/opt.h
+++ b/src/cmd/9g/opt.h
@@ -225,6 +225,16 @@ enum
void proginfo(ProgInfo*, Prog*);
+// Many Power ISA arithmetic and logical instructions come in four
+// standard variants. These bits let us map between variants.
+enum {
+ V_CC = 1<<0, // xCC (affect CR field 0 flags)
+ V_V = 1<<1, // xV (affect SO and OV flags)
+};
+
+int as2variant(int);
+int variant2as(int, int);
+
// To allow use of AJMP, ACALL, ARET in ../gc/popt.c.
enum
{
diff --git a/src/cmd/9g/prog.c b/src/cmd/9g/prog.c
index 51c132d18..7c0f0c795 100644
--- a/src/cmd/9g/prog.c
+++ b/src/cmd/9g/prog.c
@@ -101,9 +101,36 @@ static ProgInfo progtable[ALAST] = {
[ADUFFCOPY]= {Call},
};
+static void
+initproginfo(void)
+{
+ static int initialized;
+ int addvariant[] = {V_CC, V_V, V_CC|V_V};
+ int as, as2, i, variant;
+
+ if(initialized)
+ return;
+ initialized = 1;
+
+ // Perform one-time expansion of instructions in progtable to
+ // their CC, V, and VCC variants
+ for(as=0; as<nelem(progtable); as++) {
+ if(progtable[as].flags == 0)
+ continue;
+ variant = as2variant(as);
+ for(i=0; i<nelem(addvariant); i++) {
+ as2 = variant2as(as, variant | addvariant[i]);
+ if(as2 != 0 && progtable[as2].flags == 0)
+ progtable[as2] = progtable[as];
+ }
+ }
+}
+
void
proginfo(ProgInfo *info, Prog *p)
{
+ initproginfo();
+
*info = progtable[p->as];
if(info->flags == 0) {
*info = progtable[AADD];
@@ -143,3 +170,138 @@ proginfo(ProgInfo *info, Prog *p)
info->regset |= RtoB(3) | RtoB(4);
}
}
+
+// Instruction variants table. Initially this contains entries only
+// for the "base" form of each instruction. On the first call to
+// as2variant or variant2as, we'll add the variants to the table.
+static int varianttable[ALAST][4] = {
+ [AADD]= {AADD, AADDCC, AADDV, AADDVCC},
+ [AADDC]= {AADDC, AADDCCC, AADDCV, AADDCVCC},
+ [AADDE]= {AADDE, AADDECC, AADDEV, AADDEVCC},
+ [AADDME]= {AADDME, AADDMECC, AADDMEV, AADDMEVCC},
+ [AADDZE]= {AADDZE, AADDZECC, AADDZEV, AADDZEVCC},
+ [AAND]= {AAND, AANDCC, 0, 0},
+ [AANDN]= {AANDN, AANDNCC, 0, 0},
+ [ACNTLZD]= {ACNTLZD, ACNTLZDCC, 0, 0},
+ [ACNTLZW]= {ACNTLZW, ACNTLZWCC, 0, 0},
+ [ADIVD]= {ADIVD, ADIVDCC, ADIVDV, ADIVDVCC},
+ [ADIVDU]= {ADIVDU, ADIVDUCC, ADIVDUV, ADIVDUVCC},
+ [ADIVW]= {ADIVW, ADIVWCC, ADIVWV, ADIVWVCC},
+ [ADIVWU]= {ADIVWU, ADIVWUCC, ADIVWUV, ADIVWUVCC},
+ [AEQV]= {AEQV, AEQVCC, 0, 0},
+ [AEXTSB]= {AEXTSB, AEXTSBCC, 0, 0},
+ [AEXTSH]= {AEXTSH, AEXTSHCC, 0, 0},
+ [AEXTSW]= {AEXTSW, AEXTSWCC, 0, 0},
+ [AFABS]= {AFABS, AFABSCC, 0, 0},
+ [AFADD]= {AFADD, AFADDCC, 0, 0},
+ [AFADDS]= {AFADDS, AFADDSCC, 0, 0},
+ [AFCFID]= {AFCFID, AFCFIDCC, 0, 0},
+ [AFCTID]= {AFCTID, AFCTIDCC, 0, 0},
+ [AFCTIDZ]= {AFCTIDZ, AFCTIDZCC, 0, 0},
+ [AFCTIW]= {AFCTIW, AFCTIWCC, 0, 0},
+ [AFCTIWZ]= {AFCTIWZ, AFCTIWZCC, 0, 0},
+ [AFDIV]= {AFDIV, AFDIVCC, 0, 0},
+ [AFDIVS]= {AFDIVS, AFDIVSCC, 0, 0},
+ [AFMADD]= {AFMADD, AFMADDCC, 0, 0},
+ [AFMADDS]= {AFMADDS, AFMADDSCC, 0, 0},
+ [AFMOVD]= {AFMOVD, AFMOVDCC, 0, 0},
+ [AFMSUB]= {AFMSUB, AFMSUBCC, 0, 0},
+ [AFMSUBS]= {AFMSUBS, AFMSUBSCC, 0, 0},
+ [AFMUL]= {AFMUL, AFMULCC, 0, 0},
+ [AFMULS]= {AFMULS, AFMULSCC, 0, 0},
+ [AFNABS]= {AFNABS, AFNABSCC, 0, 0},
+ [AFNEG]= {AFNEG, AFNEGCC, 0, 0},
+ [AFNMADD]= {AFNMADD, AFNMADDCC, 0, 0},
+ [AFNMADDS]= {AFNMADDS, AFNMADDSCC, 0, 0},
+ [AFNMSUB]= {AFNMSUB, AFNMSUBCC, 0, 0},
+ [AFNMSUBS]= {AFNMSUBS, AFNMSUBSCC, 0, 0},
+ [AFRES]= {AFRES, AFRESCC, 0, 0},
+ [AFRSP]= {AFRSP, AFRSPCC, 0, 0},
+ [AFRSQRTE]= {AFRSQRTE, AFRSQRTECC, 0, 0},
+ [AFSEL]= {AFSEL, AFSELCC, 0, 0},
+ [AFSQRT]= {AFSQRT, AFSQRTCC, 0, 0},
+ [AFSQRTS]= {AFSQRTS, AFSQRTSCC, 0, 0},
+ [AFSUB]= {AFSUB, AFSUBCC, 0, 0},
+ [AFSUBS]= {AFSUBS, AFSUBSCC, 0, 0},
+ [AMTFSB0]= {AMTFSB0, AMTFSB0CC, 0, 0},
+ [AMTFSB1]= {AMTFSB1, AMTFSB1CC, 0, 0},
+ [AMULHD]= {AMULHD, AMULHDCC, 0, 0},
+ [AMULHDU]= {AMULHDU, AMULHDUCC, 0, 0},
+ [AMULHW]= {AMULHW, AMULHWCC, 0, 0},
+ [AMULHWU]= {AMULHWU, AMULHWUCC, 0, 0},
+ [AMULLD]= {AMULLD, AMULLDCC, AMULLDV, AMULLDVCC},
+ [AMULLW]= {AMULLW, AMULLWCC, AMULLWV, AMULLWVCC},
+ [ANAND]= {ANAND, ANANDCC, 0, 0},
+ [ANEG]= {ANEG, ANEGCC, ANEGV, ANEGVCC},
+ [ANOR]= {ANOR, ANORCC, 0, 0},
+ [AOR]= {AOR, AORCC, 0, 0},
+ [AORN]= {AORN, AORNCC, 0, 0},
+ [AREM]= {AREM, AREMCC, AREMV, AREMVCC},
+ [AREMD]= {AREMD, AREMDCC, AREMDV, AREMDVCC},
+ [AREMDU]= {AREMDU, AREMDUCC, AREMDUV, AREMDUVCC},
+ [AREMU]= {AREMU, AREMUCC, AREMUV, AREMUVCC},
+ [ARLDC]= {ARLDC, ARLDCCC, 0, 0},
+ [ARLDCL]= {ARLDCL, ARLDCLCC, 0, 0},
+ [ARLDCR]= {ARLDCR, ARLDCRCC, 0, 0},
+ [ARLDMI]= {ARLDMI, ARLDMICC, 0, 0},
+ [ARLWMI]= {ARLWMI, ARLWMICC, 0, 0},
+ [ARLWNM]= {ARLWNM, ARLWNMCC, 0, 0},
+ [ASLD]= {ASLD, ASLDCC, 0, 0},
+ [ASLW]= {ASLW, ASLWCC, 0, 0},
+ [ASRAD]= {ASRAD, ASRADCC, 0, 0},
+ [ASRAW]= {ASRAW, ASRAWCC, 0, 0},
+ [ASRD]= {ASRD, ASRDCC, 0, 0},
+ [ASRW]= {ASRW, ASRWCC, 0, 0},
+ [ASUB]= {ASUB, ASUBCC, ASUBV, ASUBVCC},
+ [ASUBC]= {ASUBC, ASUBCCC, ASUBCV, ASUBCVCC},
+ [ASUBE]= {ASUBE, ASUBECC, ASUBEV, ASUBEVCC},
+ [ASUBME]= {ASUBME, ASUBMECC, ASUBMEV, ASUBMEVCC},
+ [ASUBZE]= {ASUBZE, ASUBZECC, ASUBZEV, ASUBZEVCC},
+ [AXOR]= {AXOR, AXORCC, 0, 0},
+};
+
+static void
+initvariants(void)
+{
+ static int initialized;
+ int i, j;
+
+ if(initialized)
+ return;
+ initialized = 1;
+
+ for(i=0; i<nelem(varianttable); i++) {
+ if(varianttable[i][0] == 0) {
+ // Instruction has no variants
+ varianttable[i][0] = i;
+ continue;
+ }
+ // Copy base form to other variants
+ if(varianttable[i][0] == i) {
+ for(j=0; j<nelem(varianttable[i]); j++)
+ memmove(&varianttable[varianttable[i][j]], &varianttable[i], sizeof(varianttable[i]));
+ }
+ }
+}
+
+// as2variant returns the variant (V_*) flags of instruction as.
+int
+as2variant(int as)
+{
+ int i;
+ initvariants();
+ for(i=0; i<nelem(varianttable[as]); i++)
+ if(varianttable[as][i] == as)
+ return i;
+ fatal("as2variant: instruction %A is not a variant of itself", as);
+ return 0;
+}
+
+// variant2as returns the instruction as with the given variant (V_*) flags.
+// If no such variant exists, this returns 0.
+int
+variant2as(int as, int flags)
+{
+ initvariants();
+ return varianttable[as][flags];
+}