func gcmp(as int, lhs *gc.Node, rhs *gc.Node) *obj.Prog { if lhs.Op != gc.OREGISTER { gc.Fatalf("bad operands to gcmp: %v %v", gc.Oconv(int(lhs.Op), 0), gc.Oconv(int(rhs.Op), 0)) } p := rawgins(as, rhs, nil) raddr(lhs, p) return p }
/* * insert n into reg slot of p */ func raddr(n *gc.Node, p *obj.Prog) { var a obj.Addr gc.Naddr(&a, n) if a.Type != obj.TYPE_REG { if n != nil { gc.Fatal("bad in raddr: %v", gc.Oconv(int(n.Op), 0)) } else { gc.Fatal("bad in raddr: <null>") } p.Reg = 0 } else { p.Reg = a.Reg } }
// jmptoset returns ASETxx for AJxx. func jmptoset(jmp int) int { switch jmp { case x86.AJEQ: return x86.ASETEQ case x86.AJNE: return x86.ASETNE case x86.AJLT: return x86.ASETLT case x86.AJCS: return x86.ASETCS case x86.AJLE: return x86.ASETLE case x86.AJLS: return x86.ASETLS case x86.AJGT: return x86.ASETGT case x86.AJHI: return x86.ASETHI case x86.AJGE: return x86.ASETGE case x86.AJCC: return x86.ASETCC case x86.AJMI: return x86.ASETMI case x86.AJOC: return x86.ASETOC case x86.AJOS: return x86.ASETOS case x86.AJPC: return x86.ASETPC case x86.AJPL: return x86.ASETPL case x86.AJPS: return x86.ASETPS } gc.Fatal("jmptoset: no entry for %v", gc.Oconv(jmp, 0)) panic("unreachable") }
/* * return Axxx for Oxxx on type t. */ func optoas(op int, t *gc.Type) int { if t == nil { gc.Fatalf("optoas: t is nil") } a := int(obj.AXXX) switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { default: gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t) case gc.OEQ<<16 | gc.TBOOL, gc.OEQ<<16 | gc.TINT8, gc.OEQ<<16 | gc.TUINT8, gc.OEQ<<16 | gc.TINT16, gc.OEQ<<16 | gc.TUINT16, gc.OEQ<<16 | gc.TINT32, gc.OEQ<<16 | gc.TUINT32, gc.OEQ<<16 | gc.TINT64, gc.OEQ<<16 | gc.TUINT64, gc.OEQ<<16 | gc.TPTR32, gc.OEQ<<16 | gc.TPTR64, gc.OEQ<<16 | gc.TFLOAT32, gc.OEQ<<16 | gc.TFLOAT64: a = ppc64.ABEQ case gc.ONE<<16 | gc.TBOOL, gc.ONE<<16 | gc.TINT8, gc.ONE<<16 | gc.TUINT8, gc.ONE<<16 | gc.TINT16, gc.ONE<<16 | gc.TUINT16, gc.ONE<<16 | gc.TINT32, gc.ONE<<16 | gc.TUINT32, gc.ONE<<16 | gc.TINT64, gc.ONE<<16 | gc.TUINT64, gc.ONE<<16 | gc.TPTR32, gc.ONE<<16 | gc.TPTR64, gc.ONE<<16 | gc.TFLOAT32, gc.ONE<<16 | gc.TFLOAT64: a = ppc64.ABNE case gc.OLT<<16 | gc.TINT8, // ACMP gc.OLT<<16 | gc.TINT16, gc.OLT<<16 | gc.TINT32, gc.OLT<<16 | gc.TINT64, gc.OLT<<16 | gc.TUINT8, // ACMPU gc.OLT<<16 | gc.TUINT16, gc.OLT<<16 | gc.TUINT32, gc.OLT<<16 | gc.TUINT64, gc.OLT<<16 | gc.TFLOAT32, // AFCMPU gc.OLT<<16 | gc.TFLOAT64: a = ppc64.ABLT case gc.OLE<<16 | gc.TINT8, // ACMP gc.OLE<<16 | gc.TINT16, gc.OLE<<16 | gc.TINT32, gc.OLE<<16 | gc.TINT64, gc.OLE<<16 | gc.TUINT8, // ACMPU gc.OLE<<16 | gc.TUINT16, gc.OLE<<16 | gc.TUINT32, gc.OLE<<16 | gc.TUINT64: // No OLE for floats, because it mishandles NaN. // Front end must reverse comparison or use OLT and OEQ together. a = ppc64.ABLE case gc.OGT<<16 | gc.TINT8, gc.OGT<<16 | gc.TINT16, gc.OGT<<16 | gc.TINT32, gc.OGT<<16 | gc.TINT64, gc.OGT<<16 | gc.TUINT8, gc.OGT<<16 | gc.TUINT16, gc.OGT<<16 | gc.TUINT32, gc.OGT<<16 | gc.TUINT64, gc.OGT<<16 | gc.TFLOAT32, gc.OGT<<16 | gc.TFLOAT64: a = ppc64.ABGT case gc.OGE<<16 | gc.TINT8, gc.OGE<<16 | gc.TINT16, gc.OGE<<16 | gc.TINT32, gc.OGE<<16 | gc.TINT64, gc.OGE<<16 | gc.TUINT8, gc.OGE<<16 | gc.TUINT16, gc.OGE<<16 | gc.TUINT32, gc.OGE<<16 | gc.TUINT64: // No OGE for floats, because it mishandles NaN. // Front end must reverse comparison or use OLT and OEQ together. a = ppc64.ABGE case gc.OCMP<<16 | gc.TBOOL, gc.OCMP<<16 | gc.TINT8, gc.OCMP<<16 | gc.TINT16, gc.OCMP<<16 | gc.TINT32, gc.OCMP<<16 | gc.TPTR32, gc.OCMP<<16 | gc.TINT64: a = ppc64.ACMP case gc.OCMP<<16 | gc.TUINT8, gc.OCMP<<16 | gc.TUINT16, gc.OCMP<<16 | gc.TUINT32, gc.OCMP<<16 | gc.TUINT64, gc.OCMP<<16 | gc.TPTR64: a = ppc64.ACMPU case gc.OCMP<<16 | gc.TFLOAT32, gc.OCMP<<16 | gc.TFLOAT64: a = ppc64.AFCMPU case gc.OAS<<16 | gc.TBOOL, gc.OAS<<16 | gc.TINT8: a = ppc64.AMOVB case gc.OAS<<16 | gc.TUINT8: a = ppc64.AMOVBZ case gc.OAS<<16 | gc.TINT16: a = ppc64.AMOVH case gc.OAS<<16 | gc.TUINT16: a = ppc64.AMOVHZ case gc.OAS<<16 | gc.TINT32: a = ppc64.AMOVW case gc.OAS<<16 | gc.TUINT32, gc.OAS<<16 | gc.TPTR32: a = ppc64.AMOVWZ case gc.OAS<<16 | gc.TINT64, gc.OAS<<16 | gc.TUINT64, gc.OAS<<16 | gc.TPTR64: a = ppc64.AMOVD case gc.OAS<<16 | gc.TFLOAT32: a = ppc64.AFMOVS case gc.OAS<<16 | gc.TFLOAT64: a = ppc64.AFMOVD case gc.OADD<<16 | gc.TINT8, gc.OADD<<16 | gc.TUINT8, gc.OADD<<16 | gc.TINT16, gc.OADD<<16 | gc.TUINT16, gc.OADD<<16 | gc.TINT32, gc.OADD<<16 | gc.TUINT32, gc.OADD<<16 | gc.TPTR32, gc.OADD<<16 | gc.TINT64, gc.OADD<<16 | gc.TUINT64, gc.OADD<<16 | gc.TPTR64: a = ppc64.AADD case gc.OADD<<16 | gc.TFLOAT32: a = ppc64.AFADDS case gc.OADD<<16 | gc.TFLOAT64: a = ppc64.AFADD case gc.OSUB<<16 | gc.TINT8, gc.OSUB<<16 | gc.TUINT8, gc.OSUB<<16 | gc.TINT16, gc.OSUB<<16 | gc.TUINT16, gc.OSUB<<16 | gc.TINT32, gc.OSUB<<16 | gc.TUINT32, gc.OSUB<<16 | gc.TPTR32, gc.OSUB<<16 | gc.TINT64, gc.OSUB<<16 | gc.TUINT64, gc.OSUB<<16 | gc.TPTR64: a = ppc64.ASUB case gc.OSUB<<16 | gc.TFLOAT32: a = ppc64.AFSUBS case gc.OSUB<<16 | gc.TFLOAT64: a = ppc64.AFSUB case gc.OMINUS<<16 | gc.TINT8, gc.OMINUS<<16 | gc.TUINT8, gc.OMINUS<<16 | gc.TINT16, gc.OMINUS<<16 | gc.TUINT16, gc.OMINUS<<16 | gc.TINT32, gc.OMINUS<<16 | gc.TUINT32, gc.OMINUS<<16 | gc.TPTR32, gc.OMINUS<<16 | gc.TINT64, gc.OMINUS<<16 | gc.TUINT64, gc.OMINUS<<16 | gc.TPTR64: a = ppc64.ANEG case gc.OAND<<16 | gc.TINT8, gc.OAND<<16 | gc.TUINT8, gc.OAND<<16 | gc.TINT16, gc.OAND<<16 | gc.TUINT16, gc.OAND<<16 | gc.TINT32, gc.OAND<<16 | gc.TUINT32, gc.OAND<<16 | gc.TPTR32, gc.OAND<<16 | gc.TINT64, gc.OAND<<16 | gc.TUINT64, gc.OAND<<16 | gc.TPTR64: a = ppc64.AAND case gc.OOR<<16 | gc.TINT8, gc.OOR<<16 | gc.TUINT8, gc.OOR<<16 | gc.TINT16, gc.OOR<<16 | gc.TUINT16, gc.OOR<<16 | gc.TINT32, gc.OOR<<16 | gc.TUINT32, gc.OOR<<16 | gc.TPTR32, gc.OOR<<16 | gc.TINT64, gc.OOR<<16 | gc.TUINT64, gc.OOR<<16 | gc.TPTR64: a = ppc64.AOR case gc.OXOR<<16 | gc.TINT8, gc.OXOR<<16 | gc.TUINT8, gc.OXOR<<16 | gc.TINT16, gc.OXOR<<16 | gc.TUINT16, gc.OXOR<<16 | gc.TINT32, gc.OXOR<<16 | gc.TUINT32, gc.OXOR<<16 | gc.TPTR32, gc.OXOR<<16 | gc.TINT64, gc.OXOR<<16 | gc.TUINT64, gc.OXOR<<16 | gc.TPTR64: a = ppc64.AXOR // TODO(minux): handle rotates //case CASE(OLROT, TINT8): //case CASE(OLROT, TUINT8): //case CASE(OLROT, TINT16): //case CASE(OLROT, TUINT16): //case CASE(OLROT, TINT32): //case CASE(OLROT, TUINT32): //case CASE(OLROT, TPTR32): //case CASE(OLROT, TINT64): //case CASE(OLROT, TUINT64): //case CASE(OLROT, TPTR64): // a = 0//???; RLDC? // break; case gc.OLSH<<16 | gc.TINT8, gc.OLSH<<16 | gc.TUINT8, gc.OLSH<<16 | gc.TINT16, gc.OLSH<<16 | gc.TUINT16, gc.OLSH<<16 | gc.TINT32, gc.OLSH<<16 | gc.TUINT32, gc.OLSH<<16 | gc.TPTR32, gc.OLSH<<16 | gc.TINT64, gc.OLSH<<16 | gc.TUINT64, gc.OLSH<<16 | gc.TPTR64: a = ppc64.ASLD case gc.ORSH<<16 | gc.TUINT8, gc.ORSH<<16 | gc.TUINT16, gc.ORSH<<16 | gc.TUINT32, gc.ORSH<<16 | gc.TPTR32, gc.ORSH<<16 | gc.TUINT64, gc.ORSH<<16 | gc.TPTR64: a = ppc64.ASRD case gc.ORSH<<16 | gc.TINT8, gc.ORSH<<16 | gc.TINT16, gc.ORSH<<16 | gc.TINT32, gc.ORSH<<16 | gc.TINT64: a = ppc64.ASRAD // TODO(minux): handle rotates //case CASE(ORROTC, TINT8): //case CASE(ORROTC, TUINT8): //case CASE(ORROTC, TINT16): //case CASE(ORROTC, TUINT16): //case CASE(ORROTC, TINT32): //case CASE(ORROTC, TUINT32): //case CASE(ORROTC, TINT64): //case CASE(ORROTC, TUINT64): // a = 0//??? RLDC?? // break; case gc.OHMUL<<16 | gc.TINT64: a = ppc64.AMULHD case gc.OHMUL<<16 | gc.TUINT64, gc.OHMUL<<16 | gc.TPTR64: a = ppc64.AMULHDU case gc.OMUL<<16 | gc.TINT8, gc.OMUL<<16 | gc.TINT16, gc.OMUL<<16 | gc.TINT32, gc.OMUL<<16 | gc.TINT64: a = ppc64.AMULLD case gc.OMUL<<16 | gc.TUINT8, gc.OMUL<<16 | gc.TUINT16, gc.OMUL<<16 | gc.TUINT32, gc.OMUL<<16 | gc.TPTR32, // don't use word multiply, the high 32-bit are undefined. gc.OMUL<<16 | gc.TUINT64, gc.OMUL<<16 | gc.TPTR64: // for 64-bit multiplies, signedness doesn't matter. a = ppc64.AMULLD case gc.OMUL<<16 | gc.TFLOAT32: a = ppc64.AFMULS case gc.OMUL<<16 | gc.TFLOAT64: a = ppc64.AFMUL case gc.ODIV<<16 | gc.TINT8, gc.ODIV<<16 | gc.TINT16, gc.ODIV<<16 | gc.TINT32, gc.ODIV<<16 | gc.TINT64: a = ppc64.ADIVD case gc.ODIV<<16 | gc.TUINT8, gc.ODIV<<16 | gc.TUINT16, gc.ODIV<<16 | gc.TUINT32, gc.ODIV<<16 | gc.TPTR32, gc.ODIV<<16 | gc.TUINT64, gc.ODIV<<16 | gc.TPTR64: a = ppc64.ADIVDU case gc.ODIV<<16 | gc.TFLOAT32: a = ppc64.AFDIVS case gc.ODIV<<16 | gc.TFLOAT64: a = ppc64.AFDIV } return a }
/* * return Axxx for Oxxx on type t. */ func optoas(op gc.Op, t *gc.Type) int { if t == nil { gc.Fatalf("optoas: t is nil") } // avoid constant conversions in switches below const ( OMINUS_ = uint32(gc.OMINUS) << 16 OLSH_ = uint32(gc.OLSH) << 16 ORSH_ = uint32(gc.ORSH) << 16 OADD_ = uint32(gc.OADD) << 16 OSUB_ = uint32(gc.OSUB) << 16 OMUL_ = uint32(gc.OMUL) << 16 ODIV_ = uint32(gc.ODIV) << 16 OMOD_ = uint32(gc.OMOD) << 16 OOR_ = uint32(gc.OOR) << 16 OAND_ = uint32(gc.OAND) << 16 OXOR_ = uint32(gc.OXOR) << 16 OEQ_ = uint32(gc.OEQ) << 16 ONE_ = uint32(gc.ONE) << 16 OLT_ = uint32(gc.OLT) << 16 OLE_ = uint32(gc.OLE) << 16 OGE_ = uint32(gc.OGE) << 16 OGT_ = uint32(gc.OGT) << 16 OCMP_ = uint32(gc.OCMP) << 16 OAS_ = uint32(gc.OAS) << 16 OHMUL_ = uint32(gc.OHMUL) << 16 OADDR_ = uint32(gc.OADDR) << 16 OINC_ = uint32(gc.OINC) << 16 ODEC_ = uint32(gc.ODEC) << 16 OLROT_ = uint32(gc.OLROT) << 16 OEXTEND_ = uint32(gc.OEXTEND) << 16 OCOM_ = uint32(gc.OCOM) << 16 ) a := obj.AXXX switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { default: gc.Fatalf("optoas: no entry %v-%v", gc.Oconv(int(op), 0), t) case OADDR_ | gc.TPTR32: a = x86.ALEAL case OEQ_ | gc.TBOOL, OEQ_ | gc.TINT8, OEQ_ | gc.TUINT8, OEQ_ | gc.TINT16, OEQ_ | gc.TUINT16, OEQ_ | gc.TINT32, OEQ_ | gc.TUINT32, OEQ_ | gc.TINT64, OEQ_ | gc.TUINT64, OEQ_ | gc.TPTR32, OEQ_ | gc.TPTR64, OEQ_ | gc.TFLOAT32, OEQ_ | gc.TFLOAT64: a = x86.AJEQ case ONE_ | gc.TBOOL, ONE_ | gc.TINT8, ONE_ | gc.TUINT8, ONE_ | gc.TINT16, ONE_ | gc.TUINT16, ONE_ | gc.TINT32, ONE_ | gc.TUINT32, ONE_ | gc.TINT64, ONE_ | gc.TUINT64, ONE_ | gc.TPTR32, ONE_ | gc.TPTR64, ONE_ | gc.TFLOAT32, ONE_ | gc.TFLOAT64: a = x86.AJNE case OLT_ | gc.TINT8, OLT_ | gc.TINT16, OLT_ | gc.TINT32, OLT_ | gc.TINT64: a = x86.AJLT case OLT_ | gc.TUINT8, OLT_ | gc.TUINT16, OLT_ | gc.TUINT32, OLT_ | gc.TUINT64: a = x86.AJCS case OLE_ | gc.TINT8, OLE_ | gc.TINT16, OLE_ | gc.TINT32, OLE_ | gc.TINT64: a = x86.AJLE case OLE_ | gc.TUINT8, OLE_ | gc.TUINT16, OLE_ | gc.TUINT32, OLE_ | gc.TUINT64: a = x86.AJLS case OGT_ | gc.TINT8, OGT_ | gc.TINT16, OGT_ | gc.TINT32, OGT_ | gc.TINT64: a = x86.AJGT case OGT_ | gc.TUINT8, OGT_ | gc.TUINT16, OGT_ | gc.TUINT32, OGT_ | gc.TUINT64, OLT_ | gc.TFLOAT32, OLT_ | gc.TFLOAT64: a = x86.AJHI case OGE_ | gc.TINT8, OGE_ | gc.TINT16, OGE_ | gc.TINT32, OGE_ | gc.TINT64: a = x86.AJGE case OGE_ | gc.TUINT8, OGE_ | gc.TUINT16, OGE_ | gc.TUINT32, OGE_ | gc.TUINT64, OLE_ | gc.TFLOAT32, OLE_ | gc.TFLOAT64: a = x86.AJCC case OCMP_ | gc.TBOOL, OCMP_ | gc.TINT8, OCMP_ | gc.TUINT8: a = x86.ACMPB case OCMP_ | gc.TINT16, OCMP_ | gc.TUINT16: a = x86.ACMPW case OCMP_ | gc.TINT32, OCMP_ | gc.TUINT32, OCMP_ | gc.TPTR32: a = x86.ACMPL case OAS_ | gc.TBOOL, OAS_ | gc.TINT8, OAS_ | gc.TUINT8: a = x86.AMOVB case OAS_ | gc.TINT16, OAS_ | gc.TUINT16: a = x86.AMOVW case OAS_ | gc.TINT32, OAS_ | gc.TUINT32, OAS_ | gc.TPTR32: a = x86.AMOVL case OAS_ | gc.TFLOAT32: a = x86.AMOVSS case OAS_ | gc.TFLOAT64: a = x86.AMOVSD case OADD_ | gc.TINT8, OADD_ | gc.TUINT8: a = x86.AADDB case OADD_ | gc.TINT16, OADD_ | gc.TUINT16: a = x86.AADDW case OADD_ | gc.TINT32, OADD_ | gc.TUINT32, OADD_ | gc.TPTR32: a = x86.AADDL case OSUB_ | gc.TINT8, OSUB_ | gc.TUINT8: a = x86.ASUBB case OSUB_ | gc.TINT16, OSUB_ | gc.TUINT16: a = x86.ASUBW case OSUB_ | gc.TINT32, OSUB_ | gc.TUINT32, OSUB_ | gc.TPTR32: a = x86.ASUBL case OINC_ | gc.TINT8, OINC_ | gc.TUINT8: a = x86.AINCB case OINC_ | gc.TINT16, OINC_ | gc.TUINT16: a = x86.AINCW case OINC_ | gc.TINT32, OINC_ | gc.TUINT32, OINC_ | gc.TPTR32: a = x86.AINCL case ODEC_ | gc.TINT8, ODEC_ | gc.TUINT8: a = x86.ADECB case ODEC_ | gc.TINT16, ODEC_ | gc.TUINT16: a = x86.ADECW case ODEC_ | gc.TINT32, ODEC_ | gc.TUINT32, ODEC_ | gc.TPTR32: a = x86.ADECL case OCOM_ | gc.TINT8, OCOM_ | gc.TUINT8: a = x86.ANOTB case OCOM_ | gc.TINT16, OCOM_ | gc.TUINT16: a = x86.ANOTW case OCOM_ | gc.TINT32, OCOM_ | gc.TUINT32, OCOM_ | gc.TPTR32: a = x86.ANOTL case OMINUS_ | gc.TINT8, OMINUS_ | gc.TUINT8: a = x86.ANEGB case OMINUS_ | gc.TINT16, OMINUS_ | gc.TUINT16: a = x86.ANEGW case OMINUS_ | gc.TINT32, OMINUS_ | gc.TUINT32, OMINUS_ | gc.TPTR32: a = x86.ANEGL case OAND_ | gc.TINT8, OAND_ | gc.TUINT8: a = x86.AANDB case OAND_ | gc.TINT16, OAND_ | gc.TUINT16: a = x86.AANDW case OAND_ | gc.TINT32, OAND_ | gc.TUINT32, OAND_ | gc.TPTR32: a = x86.AANDL case OOR_ | gc.TINT8, OOR_ | gc.TUINT8: a = x86.AORB case OOR_ | gc.TINT16, OOR_ | gc.TUINT16: a = x86.AORW case OOR_ | gc.TINT32, OOR_ | gc.TUINT32, OOR_ | gc.TPTR32: a = x86.AORL case OXOR_ | gc.TINT8, OXOR_ | gc.TUINT8: a = x86.AXORB case OXOR_ | gc.TINT16, OXOR_ | gc.TUINT16: a = x86.AXORW case OXOR_ | gc.TINT32, OXOR_ | gc.TUINT32, OXOR_ | gc.TPTR32: a = x86.AXORL case OLROT_ | gc.TINT8, OLROT_ | gc.TUINT8: a = x86.AROLB case OLROT_ | gc.TINT16, OLROT_ | gc.TUINT16: a = x86.AROLW case OLROT_ | gc.TINT32, OLROT_ | gc.TUINT32, OLROT_ | gc.TPTR32: a = x86.AROLL case OLSH_ | gc.TINT8, OLSH_ | gc.TUINT8: a = x86.ASHLB case OLSH_ | gc.TINT16, OLSH_ | gc.TUINT16: a = x86.ASHLW case OLSH_ | gc.TINT32, OLSH_ | gc.TUINT32, OLSH_ | gc.TPTR32: a = x86.ASHLL case ORSH_ | gc.TUINT8: a = x86.ASHRB case ORSH_ | gc.TUINT16: a = x86.ASHRW case ORSH_ | gc.TUINT32, ORSH_ | gc.TPTR32: a = x86.ASHRL case ORSH_ | gc.TINT8: a = x86.ASARB case ORSH_ | gc.TINT16: a = x86.ASARW case ORSH_ | gc.TINT32: a = x86.ASARL case OHMUL_ | gc.TINT8, OMUL_ | gc.TINT8, OMUL_ | gc.TUINT8: a = x86.AIMULB case OHMUL_ | gc.TINT16, OMUL_ | gc.TINT16, OMUL_ | gc.TUINT16: a = x86.AIMULW case OHMUL_ | gc.TINT32, OMUL_ | gc.TINT32, OMUL_ | gc.TUINT32, OMUL_ | gc.TPTR32: a = x86.AIMULL case OHMUL_ | gc.TUINT8: a = x86.AMULB case OHMUL_ | gc.TUINT16: a = x86.AMULW case OHMUL_ | gc.TUINT32, OHMUL_ | gc.TPTR32: a = x86.AMULL case ODIV_ | gc.TINT8, OMOD_ | gc.TINT8: a = x86.AIDIVB case ODIV_ | gc.TUINT8, OMOD_ | gc.TUINT8: a = x86.ADIVB case ODIV_ | gc.TINT16, OMOD_ | gc.TINT16: a = x86.AIDIVW case ODIV_ | gc.TUINT16, OMOD_ | gc.TUINT16: a = x86.ADIVW case ODIV_ | gc.TINT32, OMOD_ | gc.TINT32: a = x86.AIDIVL case ODIV_ | gc.TUINT32, ODIV_ | gc.TPTR32, OMOD_ | gc.TUINT32, OMOD_ | gc.TPTR32: a = x86.ADIVL case OEXTEND_ | gc.TINT16: a = x86.ACWD case OEXTEND_ | gc.TINT32: a = x86.ACDQ } return a }
func foptoas(op gc.Op, t *gc.Type, flg int) int { a := obj.AXXX et := gc.Simtype[t.Etype] // avoid constant conversions in switches below const ( OCMP_ = uint32(gc.OCMP) << 16 OAS_ = uint32(gc.OAS) << 16 OADD_ = uint32(gc.OADD) << 16 OSUB_ = uint32(gc.OSUB) << 16 OMUL_ = uint32(gc.OMUL) << 16 ODIV_ = uint32(gc.ODIV) << 16 OMINUS_ = uint32(gc.OMINUS) << 16 ) if !gc.Thearch.Use387 { switch uint32(op)<<16 | uint32(et) { default: gc.Fatalf("foptoas-sse: no entry %v-%v", gc.Oconv(int(op), 0), t) case OCMP_ | gc.TFLOAT32: a = x86.AUCOMISS case OCMP_ | gc.TFLOAT64: a = x86.AUCOMISD case OAS_ | gc.TFLOAT32: a = x86.AMOVSS case OAS_ | gc.TFLOAT64: a = x86.AMOVSD case OADD_ | gc.TFLOAT32: a = x86.AADDSS case OADD_ | gc.TFLOAT64: a = x86.AADDSD case OSUB_ | gc.TFLOAT32: a = x86.ASUBSS case OSUB_ | gc.TFLOAT64: a = x86.ASUBSD case OMUL_ | gc.TFLOAT32: a = x86.AMULSS case OMUL_ | gc.TFLOAT64: a = x86.AMULSD case ODIV_ | gc.TFLOAT32: a = x86.ADIVSS case ODIV_ | gc.TFLOAT64: a = x86.ADIVSD } return a } // If we need Fpop, it means we're working on // two different floating-point registers, not memory. // There the instruction only has a float64 form. if flg&Fpop != 0 { et = gc.TFLOAT64 } // clear Frev if unneeded switch op { case gc.OADD, gc.OMUL: flg &^= Frev } switch uint32(op)<<16 | (uint32(et)<<8 | uint32(flg)) { case OADD_ | (gc.TFLOAT32<<8 | 0): return x86.AFADDF case OADD_ | (gc.TFLOAT64<<8 | 0): return x86.AFADDD case OADD_ | (gc.TFLOAT64<<8 | Fpop): return x86.AFADDDP case OSUB_ | (gc.TFLOAT32<<8 | 0): return x86.AFSUBF case OSUB_ | (gc.TFLOAT32<<8 | Frev): return x86.AFSUBRF case OSUB_ | (gc.TFLOAT64<<8 | 0): return x86.AFSUBD case OSUB_ | (gc.TFLOAT64<<8 | Frev): return x86.AFSUBRD case OSUB_ | (gc.TFLOAT64<<8 | Fpop): return x86.AFSUBDP case OSUB_ | (gc.TFLOAT64<<8 | (Fpop | Frev)): return x86.AFSUBRDP case OMUL_ | (gc.TFLOAT32<<8 | 0): return x86.AFMULF case OMUL_ | (gc.TFLOAT64<<8 | 0): return x86.AFMULD case OMUL_ | (gc.TFLOAT64<<8 | Fpop): return x86.AFMULDP case ODIV_ | (gc.TFLOAT32<<8 | 0): return x86.AFDIVF case ODIV_ | (gc.TFLOAT32<<8 | Frev): return x86.AFDIVRF case ODIV_ | (gc.TFLOAT64<<8 | 0): return x86.AFDIVD case ODIV_ | (gc.TFLOAT64<<8 | Frev): return x86.AFDIVRD case ODIV_ | (gc.TFLOAT64<<8 | Fpop): return x86.AFDIVDP case ODIV_ | (gc.TFLOAT64<<8 | (Fpop | Frev)): return x86.AFDIVRDP case OCMP_ | (gc.TFLOAT32<<8 | 0): return x86.AFCOMF case OCMP_ | (gc.TFLOAT32<<8 | Fpop): return x86.AFCOMFP case OCMP_ | (gc.TFLOAT64<<8 | 0): return x86.AFCOMD case OCMP_ | (gc.TFLOAT64<<8 | Fpop): return x86.AFCOMDP case OCMP_ | (gc.TFLOAT64<<8 | Fpop2): return x86.AFCOMDPP case OMINUS_ | (gc.TFLOAT32<<8 | 0): return x86.AFCHS case OMINUS_ | (gc.TFLOAT64<<8 | 0): return x86.AFCHS } gc.Fatalf("foptoas %v %v %#x", gc.Oconv(int(op), 0), t, flg) return 0 }
/* * return Axxx for Oxxx on type t. */ func optoas(op gc.Op, t *gc.Type) int { if t == nil { gc.Fatalf("optoas: t is nil") } // avoid constant conversions in switches below const ( OMINUS_ = uint32(gc.OMINUS) << 16 OLSH_ = uint32(gc.OLSH) << 16 ORSH_ = uint32(gc.ORSH) << 16 OADD_ = uint32(gc.OADD) << 16 OSUB_ = uint32(gc.OSUB) << 16 OMUL_ = uint32(gc.OMUL) << 16 ODIV_ = uint32(gc.ODIV) << 16 OOR_ = uint32(gc.OOR) << 16 OAND_ = uint32(gc.OAND) << 16 OXOR_ = uint32(gc.OXOR) << 16 OEQ_ = uint32(gc.OEQ) << 16 ONE_ = uint32(gc.ONE) << 16 OLT_ = uint32(gc.OLT) << 16 OLE_ = uint32(gc.OLE) << 16 OGE_ = uint32(gc.OGE) << 16 OGT_ = uint32(gc.OGT) << 16 OCMP_ = uint32(gc.OCMP) << 16 OAS_ = uint32(gc.OAS) << 16 OHMUL_ = uint32(gc.OHMUL) << 16 ) a := int(obj.AXXX) switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { default: gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t) case OEQ_ | gc.TBOOL, OEQ_ | gc.TINT8, OEQ_ | gc.TUINT8, OEQ_ | gc.TINT16, OEQ_ | gc.TUINT16, OEQ_ | gc.TINT32, OEQ_ | gc.TUINT32, OEQ_ | gc.TINT64, OEQ_ | gc.TUINT64, OEQ_ | gc.TPTR32, OEQ_ | gc.TPTR64, OEQ_ | gc.TFLOAT32, OEQ_ | gc.TFLOAT64: a = ppc64.ABEQ case ONE_ | gc.TBOOL, ONE_ | gc.TINT8, ONE_ | gc.TUINT8, ONE_ | gc.TINT16, ONE_ | gc.TUINT16, ONE_ | gc.TINT32, ONE_ | gc.TUINT32, ONE_ | gc.TINT64, ONE_ | gc.TUINT64, ONE_ | gc.TPTR32, ONE_ | gc.TPTR64, ONE_ | gc.TFLOAT32, ONE_ | gc.TFLOAT64: a = ppc64.ABNE case OLT_ | gc.TINT8, // ACMP OLT_ | gc.TINT16, OLT_ | gc.TINT32, OLT_ | gc.TINT64, OLT_ | gc.TUINT8, // ACMPU OLT_ | gc.TUINT16, OLT_ | gc.TUINT32, OLT_ | gc.TUINT64, OLT_ | gc.TFLOAT32, // AFCMPU OLT_ | gc.TFLOAT64: a = ppc64.ABLT case OLE_ | gc.TINT8, // ACMP OLE_ | gc.TINT16, OLE_ | gc.TINT32, OLE_ | gc.TINT64, OLE_ | gc.TUINT8, // ACMPU OLE_ | gc.TUINT16, OLE_ | gc.TUINT32, OLE_ | gc.TUINT64: // No OLE for floats, because it mishandles NaN. // Front end must reverse comparison or use OLT and OEQ together. a = ppc64.ABLE case OGT_ | gc.TINT8, OGT_ | gc.TINT16, OGT_ | gc.TINT32, OGT_ | gc.TINT64, OGT_ | gc.TUINT8, OGT_ | gc.TUINT16, OGT_ | gc.TUINT32, OGT_ | gc.TUINT64, OGT_ | gc.TFLOAT32, OGT_ | gc.TFLOAT64: a = ppc64.ABGT case OGE_ | gc.TINT8, OGE_ | gc.TINT16, OGE_ | gc.TINT32, OGE_ | gc.TINT64, OGE_ | gc.TUINT8, OGE_ | gc.TUINT16, OGE_ | gc.TUINT32, OGE_ | gc.TUINT64: // No OGE for floats, because it mishandles NaN. // Front end must reverse comparison or use OLT and OEQ together. a = ppc64.ABGE case OCMP_ | gc.TBOOL, OCMP_ | gc.TINT8, OCMP_ | gc.TINT16, OCMP_ | gc.TINT32, OCMP_ | gc.TPTR32, OCMP_ | gc.TINT64: a = ppc64.ACMP case OCMP_ | gc.TUINT8, OCMP_ | gc.TUINT16, OCMP_ | gc.TUINT32, OCMP_ | gc.TUINT64, OCMP_ | gc.TPTR64: a = ppc64.ACMPU case OCMP_ | gc.TFLOAT32, OCMP_ | gc.TFLOAT64: a = ppc64.AFCMPU case OAS_ | gc.TBOOL, OAS_ | gc.TINT8: a = ppc64.AMOVB case OAS_ | gc.TUINT8: a = ppc64.AMOVBZ case OAS_ | gc.TINT16: a = ppc64.AMOVH case OAS_ | gc.TUINT16: a = ppc64.AMOVHZ case OAS_ | gc.TINT32: a = ppc64.AMOVW case OAS_ | gc.TUINT32, OAS_ | gc.TPTR32: a = ppc64.AMOVWZ case OAS_ | gc.TINT64, OAS_ | gc.TUINT64, OAS_ | gc.TPTR64: a = ppc64.AMOVD case OAS_ | gc.TFLOAT32: a = ppc64.AFMOVS case OAS_ | gc.TFLOAT64: a = ppc64.AFMOVD case OADD_ | gc.TINT8, OADD_ | gc.TUINT8, OADD_ | gc.TINT16, OADD_ | gc.TUINT16, OADD_ | gc.TINT32, OADD_ | gc.TUINT32, OADD_ | gc.TPTR32, OADD_ | gc.TINT64, OADD_ | gc.TUINT64, OADD_ | gc.TPTR64: a = ppc64.AADD case OADD_ | gc.TFLOAT32: a = ppc64.AFADDS case OADD_ | gc.TFLOAT64: a = ppc64.AFADD case OSUB_ | gc.TINT8, OSUB_ | gc.TUINT8, OSUB_ | gc.TINT16, OSUB_ | gc.TUINT16, OSUB_ | gc.TINT32, OSUB_ | gc.TUINT32, OSUB_ | gc.TPTR32, OSUB_ | gc.TINT64, OSUB_ | gc.TUINT64, OSUB_ | gc.TPTR64: a = ppc64.ASUB case OSUB_ | gc.TFLOAT32: a = ppc64.AFSUBS case OSUB_ | gc.TFLOAT64: a = ppc64.AFSUB case OMINUS_ | gc.TINT8, OMINUS_ | gc.TUINT8, OMINUS_ | gc.TINT16, OMINUS_ | gc.TUINT16, OMINUS_ | gc.TINT32, OMINUS_ | gc.TUINT32, OMINUS_ | gc.TPTR32, OMINUS_ | gc.TINT64, OMINUS_ | gc.TUINT64, OMINUS_ | gc.TPTR64: a = ppc64.ANEG case OAND_ | gc.TINT8, OAND_ | gc.TUINT8, OAND_ | gc.TINT16, OAND_ | gc.TUINT16, OAND_ | gc.TINT32, OAND_ | gc.TUINT32, OAND_ | gc.TPTR32, OAND_ | gc.TINT64, OAND_ | gc.TUINT64, OAND_ | gc.TPTR64: a = ppc64.AAND case OOR_ | gc.TINT8, OOR_ | gc.TUINT8, OOR_ | gc.TINT16, OOR_ | gc.TUINT16, OOR_ | gc.TINT32, OOR_ | gc.TUINT32, OOR_ | gc.TPTR32, OOR_ | gc.TINT64, OOR_ | gc.TUINT64, OOR_ | gc.TPTR64: a = ppc64.AOR case OXOR_ | gc.TINT8, OXOR_ | gc.TUINT8, OXOR_ | gc.TINT16, OXOR_ | gc.TUINT16, OXOR_ | gc.TINT32, OXOR_ | gc.TUINT32, OXOR_ | gc.TPTR32, OXOR_ | gc.TINT64, OXOR_ | gc.TUINT64, OXOR_ | gc.TPTR64: a = ppc64.AXOR // TODO(minux): handle rotates //case CASE(OLROT, TINT8): //case CASE(OLROT, TUINT8): //case CASE(OLROT, TINT16): //case CASE(OLROT, TUINT16): //case CASE(OLROT, TINT32): //case CASE(OLROT, TUINT32): //case CASE(OLROT, TPTR32): //case CASE(OLROT, TINT64): //case CASE(OLROT, TUINT64): //case CASE(OLROT, TPTR64): // a = 0//???; RLDC? // break; case OLSH_ | gc.TINT8, OLSH_ | gc.TUINT8, OLSH_ | gc.TINT16, OLSH_ | gc.TUINT16, OLSH_ | gc.TINT32, OLSH_ | gc.TUINT32, OLSH_ | gc.TPTR32, OLSH_ | gc.TINT64, OLSH_ | gc.TUINT64, OLSH_ | gc.TPTR64: a = ppc64.ASLD case ORSH_ | gc.TUINT8, ORSH_ | gc.TUINT16, ORSH_ | gc.TUINT32, ORSH_ | gc.TPTR32, ORSH_ | gc.TUINT64, ORSH_ | gc.TPTR64: a = ppc64.ASRD case ORSH_ | gc.TINT8, ORSH_ | gc.TINT16, ORSH_ | gc.TINT32, ORSH_ | gc.TINT64: a = ppc64.ASRAD // TODO(minux): handle rotates //case CASE(ORROTC, TINT8): //case CASE(ORROTC, TUINT8): //case CASE(ORROTC, TINT16): //case CASE(ORROTC, TUINT16): //case CASE(ORROTC, TINT32): //case CASE(ORROTC, TUINT32): //case CASE(ORROTC, TINT64): //case CASE(ORROTC, TUINT64): // a = 0//??? RLDC?? // break; case OHMUL_ | gc.TINT64: a = ppc64.AMULHD case OHMUL_ | gc.TUINT64, OHMUL_ | gc.TPTR64: a = ppc64.AMULHDU case OMUL_ | gc.TINT8, OMUL_ | gc.TINT16, OMUL_ | gc.TINT32, OMUL_ | gc.TINT64: a = ppc64.AMULLD case OMUL_ | gc.TUINT8, OMUL_ | gc.TUINT16, OMUL_ | gc.TUINT32, OMUL_ | gc.TPTR32, // don't use word multiply, the high 32-bit are undefined. OMUL_ | gc.TUINT64, OMUL_ | gc.TPTR64: // for 64-bit multiplies, signedness doesn't matter. a = ppc64.AMULLD case OMUL_ | gc.TFLOAT32: a = ppc64.AFMULS case OMUL_ | gc.TFLOAT64: a = ppc64.AFMUL case ODIV_ | gc.TINT8, ODIV_ | gc.TINT16, ODIV_ | gc.TINT32, ODIV_ | gc.TINT64: a = ppc64.ADIVD case ODIV_ | gc.TUINT8, ODIV_ | gc.TUINT16, ODIV_ | gc.TUINT32, ODIV_ | gc.TPTR32, ODIV_ | gc.TUINT64, ODIV_ | gc.TPTR64: a = ppc64.ADIVDU case ODIV_ | gc.TFLOAT32: a = ppc64.AFDIVS case ODIV_ | gc.TFLOAT64: a = ppc64.AFDIV } return a }
func cgen_floatsse(n *gc.Node, res *gc.Node) { var a obj.As nl := n.Left nr := n.Right switch n.Op { default: gc.Dump("cgen_floatsse", n) gc.Fatalf("cgen_floatsse %v", gc.Oconv(n.Op, 0)) return case gc.OMINUS, gc.OCOM: nr = gc.Nodintconst(-1) gc.Convlit(&nr, n.Type) a = foptoas(gc.OMUL, nl.Type, 0) goto sbop // symmetric binary case gc.OADD, gc.OMUL: a = foptoas(n.Op, nl.Type, 0) goto sbop // asymmetric binary case gc.OSUB, gc.OMOD, gc.ODIV: a = foptoas(n.Op, nl.Type, 0) goto abop } sbop: // symmetric binary if nl.Ullman < nr.Ullman || nl.Op == gc.OLITERAL { nl, nr = nr, nl } abop: // asymmetric binary if nl.Ullman >= nr.Ullman { var nt gc.Node gc.Tempname(&nt, nl.Type) gc.Cgen(nl, &nt) var n2 gc.Node gc.Mgen(nr, &n2, nil) var n1 gc.Node gc.Regalloc(&n1, nl.Type, res) gmove(&nt, &n1) gins(a, &n2, &n1) gmove(&n1, res) gc.Regfree(&n1) gc.Mfree(&n2) } else { var n2 gc.Node gc.Regalloc(&n2, nr.Type, res) gc.Cgen(nr, &n2) var n1 gc.Node gc.Regalloc(&n1, nl.Type, nil) gc.Cgen(nl, &n1) gins(a, &n2, &n1) gc.Regfree(&n2) gmove(&n1, res) gc.Regfree(&n1) } return }
/* * return Axxx for Oxxx on type t. */ func optoas(op gc.Op, t *gc.Type) int { if t == nil { gc.Fatalf("optoas: t is nil") } // avoid constant conversions in switches below const ( OMINUS_ = uint32(gc.OMINUS) << 16 OLSH_ = uint32(gc.OLSH) << 16 ORSH_ = uint32(gc.ORSH) << 16 OADD_ = uint32(gc.OADD) << 16 OSUB_ = uint32(gc.OSUB) << 16 OMUL_ = uint32(gc.OMUL) << 16 ODIV_ = uint32(gc.ODIV) << 16 OOR_ = uint32(gc.OOR) << 16 OAND_ = uint32(gc.OAND) << 16 OXOR_ = uint32(gc.OXOR) << 16 OEQ_ = uint32(gc.OEQ) << 16 ONE_ = uint32(gc.ONE) << 16 OLT_ = uint32(gc.OLT) << 16 OLE_ = uint32(gc.OLE) << 16 OGE_ = uint32(gc.OGE) << 16 OGT_ = uint32(gc.OGT) << 16 OCMP_ = uint32(gc.OCMP) << 16 OAS_ = uint32(gc.OAS) << 16 OHMUL_ = uint32(gc.OHMUL) << 16 OSQRT_ = uint32(gc.OSQRT) << 16 ) a := int(obj.AXXX) switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { default: gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t) case OEQ_ | gc.TBOOL, OEQ_ | gc.TINT8, OEQ_ | gc.TUINT8, OEQ_ | gc.TINT16, OEQ_ | gc.TUINT16, OEQ_ | gc.TINT32, OEQ_ | gc.TUINT32, OEQ_ | gc.TINT64, OEQ_ | gc.TUINT64, OEQ_ | gc.TPTR32, OEQ_ | gc.TPTR64, OEQ_ | gc.TFLOAT32, OEQ_ | gc.TFLOAT64: a = arm64.ABEQ case ONE_ | gc.TBOOL, ONE_ | gc.TINT8, ONE_ | gc.TUINT8, ONE_ | gc.TINT16, ONE_ | gc.TUINT16, ONE_ | gc.TINT32, ONE_ | gc.TUINT32, ONE_ | gc.TINT64, ONE_ | gc.TUINT64, ONE_ | gc.TPTR32, ONE_ | gc.TPTR64, ONE_ | gc.TFLOAT32, ONE_ | gc.TFLOAT64: a = arm64.ABNE case OLT_ | gc.TINT8, OLT_ | gc.TINT16, OLT_ | gc.TINT32, OLT_ | gc.TINT64: a = arm64.ABLT case OLT_ | gc.TUINT8, OLT_ | gc.TUINT16, OLT_ | gc.TUINT32, OLT_ | gc.TUINT64, OLT_ | gc.TFLOAT32, OLT_ | gc.TFLOAT64: a = arm64.ABLO case OLE_ | gc.TINT8, OLE_ | gc.TINT16, OLE_ | gc.TINT32, OLE_ | gc.TINT64: a = arm64.ABLE case OLE_ | gc.TUINT8, OLE_ | gc.TUINT16, OLE_ | gc.TUINT32, OLE_ | gc.TUINT64, OLE_ | gc.TFLOAT32, OLE_ | gc.TFLOAT64: a = arm64.ABLS case OGT_ | gc.TINT8, OGT_ | gc.TINT16, OGT_ | gc.TINT32, OGT_ | gc.TINT64, OGT_ | gc.TFLOAT32, OGT_ | gc.TFLOAT64: a = arm64.ABGT case OGT_ | gc.TUINT8, OGT_ | gc.TUINT16, OGT_ | gc.TUINT32, OGT_ | gc.TUINT64: a = arm64.ABHI case OGE_ | gc.TINT8, OGE_ | gc.TINT16, OGE_ | gc.TINT32, OGE_ | gc.TINT64, OGE_ | gc.TFLOAT32, OGE_ | gc.TFLOAT64: a = arm64.ABGE case OGE_ | gc.TUINT8, OGE_ | gc.TUINT16, OGE_ | gc.TUINT32, OGE_ | gc.TUINT64: a = arm64.ABHS case OCMP_ | gc.TBOOL, OCMP_ | gc.TINT8, OCMP_ | gc.TINT16, OCMP_ | gc.TINT32, OCMP_ | gc.TPTR32, OCMP_ | gc.TINT64, OCMP_ | gc.TUINT8, OCMP_ | gc.TUINT16, OCMP_ | gc.TUINT32, OCMP_ | gc.TUINT64, OCMP_ | gc.TPTR64: a = arm64.ACMP case OCMP_ | gc.TFLOAT32: a = arm64.AFCMPS case OCMP_ | gc.TFLOAT64: a = arm64.AFCMPD case OAS_ | gc.TBOOL, OAS_ | gc.TINT8: a = arm64.AMOVB case OAS_ | gc.TUINT8: a = arm64.AMOVBU case OAS_ | gc.TINT16: a = arm64.AMOVH case OAS_ | gc.TUINT16: a = arm64.AMOVHU case OAS_ | gc.TINT32: a = arm64.AMOVW case OAS_ | gc.TUINT32, OAS_ | gc.TPTR32: a = arm64.AMOVWU case OAS_ | gc.TINT64, OAS_ | gc.TUINT64, OAS_ | gc.TPTR64: a = arm64.AMOVD case OAS_ | gc.TFLOAT32: a = arm64.AFMOVS case OAS_ | gc.TFLOAT64: a = arm64.AFMOVD case OADD_ | gc.TINT8, OADD_ | gc.TUINT8, OADD_ | gc.TINT16, OADD_ | gc.TUINT16, OADD_ | gc.TINT32, OADD_ | gc.TUINT32, OADD_ | gc.TPTR32, OADD_ | gc.TINT64, OADD_ | gc.TUINT64, OADD_ | gc.TPTR64: a = arm64.AADD case OADD_ | gc.TFLOAT32: a = arm64.AFADDS case OADD_ | gc.TFLOAT64: a = arm64.AFADDD case OSUB_ | gc.TINT8, OSUB_ | gc.TUINT8, OSUB_ | gc.TINT16, OSUB_ | gc.TUINT16, OSUB_ | gc.TINT32, OSUB_ | gc.TUINT32, OSUB_ | gc.TPTR32, OSUB_ | gc.TINT64, OSUB_ | gc.TUINT64, OSUB_ | gc.TPTR64: a = arm64.ASUB case OSUB_ | gc.TFLOAT32: a = arm64.AFSUBS case OSUB_ | gc.TFLOAT64: a = arm64.AFSUBD case OMINUS_ | gc.TINT8, OMINUS_ | gc.TUINT8, OMINUS_ | gc.TINT16, OMINUS_ | gc.TUINT16, OMINUS_ | gc.TINT32, OMINUS_ | gc.TUINT32, OMINUS_ | gc.TPTR32, OMINUS_ | gc.TINT64, OMINUS_ | gc.TUINT64, OMINUS_ | gc.TPTR64: a = arm64.ANEG case OMINUS_ | gc.TFLOAT32: a = arm64.AFNEGS case OMINUS_ | gc.TFLOAT64: a = arm64.AFNEGD case OAND_ | gc.TINT8, OAND_ | gc.TUINT8, OAND_ | gc.TINT16, OAND_ | gc.TUINT16, OAND_ | gc.TINT32, OAND_ | gc.TUINT32, OAND_ | gc.TPTR32, OAND_ | gc.TINT64, OAND_ | gc.TUINT64, OAND_ | gc.TPTR64: a = arm64.AAND case OOR_ | gc.TINT8, OOR_ | gc.TUINT8, OOR_ | gc.TINT16, OOR_ | gc.TUINT16, OOR_ | gc.TINT32, OOR_ | gc.TUINT32, OOR_ | gc.TPTR32, OOR_ | gc.TINT64, OOR_ | gc.TUINT64, OOR_ | gc.TPTR64: a = arm64.AORR case OXOR_ | gc.TINT8, OXOR_ | gc.TUINT8, OXOR_ | gc.TINT16, OXOR_ | gc.TUINT16, OXOR_ | gc.TINT32, OXOR_ | gc.TUINT32, OXOR_ | gc.TPTR32, OXOR_ | gc.TINT64, OXOR_ | gc.TUINT64, OXOR_ | gc.TPTR64: a = arm64.AEOR // TODO(minux): handle rotates //case CASE(OLROT, TINT8): //case CASE(OLROT, TUINT8): //case CASE(OLROT, TINT16): //case CASE(OLROT, TUINT16): //case CASE(OLROT, TINT32): //case CASE(OLROT, TUINT32): //case CASE(OLROT, TPTR32): //case CASE(OLROT, TINT64): //case CASE(OLROT, TUINT64): //case CASE(OLROT, TPTR64): // a = 0//???; RLDC? // break; case OLSH_ | gc.TINT8, OLSH_ | gc.TUINT8, OLSH_ | gc.TINT16, OLSH_ | gc.TUINT16, OLSH_ | gc.TINT32, OLSH_ | gc.TUINT32, OLSH_ | gc.TPTR32, OLSH_ | gc.TINT64, OLSH_ | gc.TUINT64, OLSH_ | gc.TPTR64: a = arm64.ALSL case ORSH_ | gc.TUINT8, ORSH_ | gc.TUINT16, ORSH_ | gc.TUINT32, ORSH_ | gc.TPTR32, ORSH_ | gc.TUINT64, ORSH_ | gc.TPTR64: a = arm64.ALSR case ORSH_ | gc.TINT8, ORSH_ | gc.TINT16, ORSH_ | gc.TINT32, ORSH_ | gc.TINT64: a = arm64.AASR // TODO(minux): handle rotates //case CASE(ORROTC, TINT8): //case CASE(ORROTC, TUINT8): //case CASE(ORROTC, TINT16): //case CASE(ORROTC, TUINT16): //case CASE(ORROTC, TINT32): //case CASE(ORROTC, TUINT32): //case CASE(ORROTC, TINT64): //case CASE(ORROTC, TUINT64): // a = 0//??? RLDC?? // break; case OHMUL_ | gc.TINT64: a = arm64.ASMULH case OHMUL_ | gc.TUINT64, OHMUL_ | gc.TPTR64: a = arm64.AUMULH case OMUL_ | gc.TINT8, OMUL_ | gc.TINT16, OMUL_ | gc.TINT32: a = arm64.ASMULL case OMUL_ | gc.TINT64: a = arm64.AMUL case OMUL_ | gc.TUINT8, OMUL_ | gc.TUINT16, OMUL_ | gc.TUINT32, OMUL_ | gc.TPTR32: // don't use word multiply, the high 32-bit are undefined. a = arm64.AUMULL case OMUL_ | gc.TUINT64, OMUL_ | gc.TPTR64: a = arm64.AMUL // for 64-bit multiplies, signedness doesn't matter. case OMUL_ | gc.TFLOAT32: a = arm64.AFMULS case OMUL_ | gc.TFLOAT64: a = arm64.AFMULD case ODIV_ | gc.TINT8, ODIV_ | gc.TINT16, ODIV_ | gc.TINT32, ODIV_ | gc.TINT64: a = arm64.ASDIV case ODIV_ | gc.TUINT8, ODIV_ | gc.TUINT16, ODIV_ | gc.TUINT32, ODIV_ | gc.TPTR32, ODIV_ | gc.TUINT64, ODIV_ | gc.TPTR64: a = arm64.AUDIV case ODIV_ | gc.TFLOAT32: a = arm64.AFDIVS case ODIV_ | gc.TFLOAT64: a = arm64.AFDIVD case OSQRT_ | gc.TFLOAT64: a = arm64.AFSQRTD } return a }
/* * return Axxx for Oxxx on type t. */ func optoas(op int, t *gc.Type) int { if t == nil { gc.Fatal("optoas: t is nil") } a := obj.AXXX switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { default: gc.Fatal("optoas: no entry %v-%v", gc.Oconv(int(op), 0), t) case gc.OADDR<<16 | gc.TPTR32: a = x86.ALEAL case gc.OADDR<<16 | gc.TPTR64: a = x86.ALEAQ case gc.OEQ<<16 | gc.TBOOL, gc.OEQ<<16 | gc.TINT8, gc.OEQ<<16 | gc.TUINT8, gc.OEQ<<16 | gc.TINT16, gc.OEQ<<16 | gc.TUINT16, gc.OEQ<<16 | gc.TINT32, gc.OEQ<<16 | gc.TUINT32, gc.OEQ<<16 | gc.TINT64, gc.OEQ<<16 | gc.TUINT64, gc.OEQ<<16 | gc.TPTR32, gc.OEQ<<16 | gc.TPTR64, gc.OEQ<<16 | gc.TFLOAT32, gc.OEQ<<16 | gc.TFLOAT64: a = x86.AJEQ case gc.ONE<<16 | gc.TBOOL, gc.ONE<<16 | gc.TINT8, gc.ONE<<16 | gc.TUINT8, gc.ONE<<16 | gc.TINT16, gc.ONE<<16 | gc.TUINT16, gc.ONE<<16 | gc.TINT32, gc.ONE<<16 | gc.TUINT32, gc.ONE<<16 | gc.TINT64, gc.ONE<<16 | gc.TUINT64, gc.ONE<<16 | gc.TPTR32, gc.ONE<<16 | gc.TPTR64, gc.ONE<<16 | gc.TFLOAT32, gc.ONE<<16 | gc.TFLOAT64: a = x86.AJNE case gc.OPS<<16 | gc.TBOOL, gc.OPS<<16 | gc.TINT8, gc.OPS<<16 | gc.TUINT8, gc.OPS<<16 | gc.TINT16, gc.OPS<<16 | gc.TUINT16, gc.OPS<<16 | gc.TINT32, gc.OPS<<16 | gc.TUINT32, gc.OPS<<16 | gc.TINT64, gc.OPS<<16 | gc.TUINT64, gc.OPS<<16 | gc.TPTR32, gc.OPS<<16 | gc.TPTR64, gc.OPS<<16 | gc.TFLOAT32, gc.OPS<<16 | gc.TFLOAT64: a = x86.AJPS case gc.OPC<<16 | gc.TBOOL, gc.OPC<<16 | gc.TINT8, gc.OPC<<16 | gc.TUINT8, gc.OPC<<16 | gc.TINT16, gc.OPC<<16 | gc.TUINT16, gc.OPC<<16 | gc.TINT32, gc.OPC<<16 | gc.TUINT32, gc.OPC<<16 | gc.TINT64, gc.OPC<<16 | gc.TUINT64, gc.OPC<<16 | gc.TPTR32, gc.OPC<<16 | gc.TPTR64, gc.OPC<<16 | gc.TFLOAT32, gc.OPC<<16 | gc.TFLOAT64: a = x86.AJPC case gc.OLT<<16 | gc.TINT8, gc.OLT<<16 | gc.TINT16, gc.OLT<<16 | gc.TINT32, gc.OLT<<16 | gc.TINT64: a = x86.AJLT case gc.OLT<<16 | gc.TUINT8, gc.OLT<<16 | gc.TUINT16, gc.OLT<<16 | gc.TUINT32, gc.OLT<<16 | gc.TUINT64: a = x86.AJCS case gc.OLE<<16 | gc.TINT8, gc.OLE<<16 | gc.TINT16, gc.OLE<<16 | gc.TINT32, gc.OLE<<16 | gc.TINT64: a = x86.AJLE case gc.OLE<<16 | gc.TUINT8, gc.OLE<<16 | gc.TUINT16, gc.OLE<<16 | gc.TUINT32, gc.OLE<<16 | gc.TUINT64: a = x86.AJLS case gc.OGT<<16 | gc.TINT8, gc.OGT<<16 | gc.TINT16, gc.OGT<<16 | gc.TINT32, gc.OGT<<16 | gc.TINT64: a = x86.AJGT case gc.OGT<<16 | gc.TUINT8, gc.OGT<<16 | gc.TUINT16, gc.OGT<<16 | gc.TUINT32, gc.OGT<<16 | gc.TUINT64, gc.OLT<<16 | gc.TFLOAT32, gc.OLT<<16 | gc.TFLOAT64: a = x86.AJHI case gc.OGE<<16 | gc.TINT8, gc.OGE<<16 | gc.TINT16, gc.OGE<<16 | gc.TINT32, gc.OGE<<16 | gc.TINT64: a = x86.AJGE case gc.OGE<<16 | gc.TUINT8, gc.OGE<<16 | gc.TUINT16, gc.OGE<<16 | gc.TUINT32, gc.OGE<<16 | gc.TUINT64, gc.OLE<<16 | gc.TFLOAT32, gc.OLE<<16 | gc.TFLOAT64: a = x86.AJCC case gc.OCMP<<16 | gc.TBOOL, gc.OCMP<<16 | gc.TINT8, gc.OCMP<<16 | gc.TUINT8: a = x86.ACMPB case gc.OCMP<<16 | gc.TINT16, gc.OCMP<<16 | gc.TUINT16: a = x86.ACMPW case gc.OCMP<<16 | gc.TINT32, gc.OCMP<<16 | gc.TUINT32, gc.OCMP<<16 | gc.TPTR32: a = x86.ACMPL case gc.OCMP<<16 | gc.TINT64, gc.OCMP<<16 | gc.TUINT64, gc.OCMP<<16 | gc.TPTR64: a = x86.ACMPQ case gc.OCMP<<16 | gc.TFLOAT32: a = x86.AUCOMISS case gc.OCMP<<16 | gc.TFLOAT64: a = x86.AUCOMISD case gc.OAS<<16 | gc.TBOOL, gc.OAS<<16 | gc.TINT8, gc.OAS<<16 | gc.TUINT8: a = x86.AMOVB case gc.OAS<<16 | gc.TINT16, gc.OAS<<16 | gc.TUINT16: a = x86.AMOVW case gc.OAS<<16 | gc.TINT32, gc.OAS<<16 | gc.TUINT32, gc.OAS<<16 | gc.TPTR32: a = x86.AMOVL case gc.OAS<<16 | gc.TINT64, gc.OAS<<16 | gc.TUINT64, gc.OAS<<16 | gc.TPTR64: a = x86.AMOVQ case gc.OAS<<16 | gc.TFLOAT32: a = x86.AMOVSS case gc.OAS<<16 | gc.TFLOAT64: a = x86.AMOVSD case gc.OADD<<16 | gc.TINT8, gc.OADD<<16 | gc.TUINT8: a = x86.AADDB case gc.OADD<<16 | gc.TINT16, gc.OADD<<16 | gc.TUINT16: a = x86.AADDW case gc.OADD<<16 | gc.TINT32, gc.OADD<<16 | gc.TUINT32, gc.OADD<<16 | gc.TPTR32: a = x86.AADDL case gc.OADD<<16 | gc.TINT64, gc.OADD<<16 | gc.TUINT64, gc.OADD<<16 | gc.TPTR64: a = x86.AADDQ case gc.OADD<<16 | gc.TFLOAT32: a = x86.AADDSS case gc.OADD<<16 | gc.TFLOAT64: a = x86.AADDSD case gc.OSUB<<16 | gc.TINT8, gc.OSUB<<16 | gc.TUINT8: a = x86.ASUBB case gc.OSUB<<16 | gc.TINT16, gc.OSUB<<16 | gc.TUINT16: a = x86.ASUBW case gc.OSUB<<16 | gc.TINT32, gc.OSUB<<16 | gc.TUINT32, gc.OSUB<<16 | gc.TPTR32: a = x86.ASUBL case gc.OSUB<<16 | gc.TINT64, gc.OSUB<<16 | gc.TUINT64, gc.OSUB<<16 | gc.TPTR64: a = x86.ASUBQ case gc.OSUB<<16 | gc.TFLOAT32: a = x86.ASUBSS case gc.OSUB<<16 | gc.TFLOAT64: a = x86.ASUBSD case gc.OINC<<16 | gc.TINT8, gc.OINC<<16 | gc.TUINT8: a = x86.AINCB case gc.OINC<<16 | gc.TINT16, gc.OINC<<16 | gc.TUINT16: a = x86.AINCW case gc.OINC<<16 | gc.TINT32, gc.OINC<<16 | gc.TUINT32, gc.OINC<<16 | gc.TPTR32: a = x86.AINCL case gc.OINC<<16 | gc.TINT64, gc.OINC<<16 | gc.TUINT64, gc.OINC<<16 | gc.TPTR64: a = x86.AINCQ case gc.ODEC<<16 | gc.TINT8, gc.ODEC<<16 | gc.TUINT8: a = x86.ADECB case gc.ODEC<<16 | gc.TINT16, gc.ODEC<<16 | gc.TUINT16: a = x86.ADECW case gc.ODEC<<16 | gc.TINT32, gc.ODEC<<16 | gc.TUINT32, gc.ODEC<<16 | gc.TPTR32: a = x86.ADECL case gc.ODEC<<16 | gc.TINT64, gc.ODEC<<16 | gc.TUINT64, gc.ODEC<<16 | gc.TPTR64: a = x86.ADECQ case gc.OMINUS<<16 | gc.TINT8, gc.OMINUS<<16 | gc.TUINT8: a = x86.ANEGB case gc.OMINUS<<16 | gc.TINT16, gc.OMINUS<<16 | gc.TUINT16: a = x86.ANEGW case gc.OMINUS<<16 | gc.TINT32, gc.OMINUS<<16 | gc.TUINT32, gc.OMINUS<<16 | gc.TPTR32: a = x86.ANEGL case gc.OMINUS<<16 | gc.TINT64, gc.OMINUS<<16 | gc.TUINT64, gc.OMINUS<<16 | gc.TPTR64: a = x86.ANEGQ case gc.OAND<<16 | gc.TBOOL, gc.OAND<<16 | gc.TINT8, gc.OAND<<16 | gc.TUINT8: a = x86.AANDB case gc.OAND<<16 | gc.TINT16, gc.OAND<<16 | gc.TUINT16: a = x86.AANDW case gc.OAND<<16 | gc.TINT32, gc.OAND<<16 | gc.TUINT32, gc.OAND<<16 | gc.TPTR32: a = x86.AANDL case gc.OAND<<16 | gc.TINT64, gc.OAND<<16 | gc.TUINT64, gc.OAND<<16 | gc.TPTR64: a = x86.AANDQ case gc.OOR<<16 | gc.TBOOL, gc.OOR<<16 | gc.TINT8, gc.OOR<<16 | gc.TUINT8: a = x86.AORB case gc.OOR<<16 | gc.TINT16, gc.OOR<<16 | gc.TUINT16: a = x86.AORW case gc.OOR<<16 | gc.TINT32, gc.OOR<<16 | gc.TUINT32, gc.OOR<<16 | gc.TPTR32: a = x86.AORL case gc.OOR<<16 | gc.TINT64, gc.OOR<<16 | gc.TUINT64, gc.OOR<<16 | gc.TPTR64: a = x86.AORQ case gc.OXOR<<16 | gc.TINT8, gc.OXOR<<16 | gc.TUINT8: a = x86.AXORB case gc.OXOR<<16 | gc.TINT16, gc.OXOR<<16 | gc.TUINT16: a = x86.AXORW case gc.OXOR<<16 | gc.TINT32, gc.OXOR<<16 | gc.TUINT32, gc.OXOR<<16 | gc.TPTR32: a = x86.AXORL case gc.OXOR<<16 | gc.TINT64, gc.OXOR<<16 | gc.TUINT64, gc.OXOR<<16 | gc.TPTR64: a = x86.AXORQ case gc.OLROT<<16 | gc.TINT8, gc.OLROT<<16 | gc.TUINT8: a = x86.AROLB case gc.OLROT<<16 | gc.TINT16, gc.OLROT<<16 | gc.TUINT16: a = x86.AROLW case gc.OLROT<<16 | gc.TINT32, gc.OLROT<<16 | gc.TUINT32, gc.OLROT<<16 | gc.TPTR32: a = x86.AROLL case gc.OLROT<<16 | gc.TINT64, gc.OLROT<<16 | gc.TUINT64, gc.OLROT<<16 | gc.TPTR64: a = x86.AROLQ case gc.OLSH<<16 | gc.TINT8, gc.OLSH<<16 | gc.TUINT8: a = x86.ASHLB case gc.OLSH<<16 | gc.TINT16, gc.OLSH<<16 | gc.TUINT16: a = x86.ASHLW case gc.OLSH<<16 | gc.TINT32, gc.OLSH<<16 | gc.TUINT32, gc.OLSH<<16 | gc.TPTR32: a = x86.ASHLL case gc.OLSH<<16 | gc.TINT64, gc.OLSH<<16 | gc.TUINT64, gc.OLSH<<16 | gc.TPTR64: a = x86.ASHLQ case gc.ORSH<<16 | gc.TUINT8: a = x86.ASHRB case gc.ORSH<<16 | gc.TUINT16: a = x86.ASHRW case gc.ORSH<<16 | gc.TUINT32, gc.ORSH<<16 | gc.TPTR32: a = x86.ASHRL case gc.ORSH<<16 | gc.TUINT64, gc.ORSH<<16 | gc.TPTR64: a = x86.ASHRQ case gc.ORSH<<16 | gc.TINT8: a = x86.ASARB case gc.ORSH<<16 | gc.TINT16: a = x86.ASARW case gc.ORSH<<16 | gc.TINT32: a = x86.ASARL case gc.ORSH<<16 | gc.TINT64: a = x86.ASARQ case gc.ORROTC<<16 | gc.TINT8, gc.ORROTC<<16 | gc.TUINT8: a = x86.ARCRB case gc.ORROTC<<16 | gc.TINT16, gc.ORROTC<<16 | gc.TUINT16: a = x86.ARCRW case gc.ORROTC<<16 | gc.TINT32, gc.ORROTC<<16 | gc.TUINT32: a = x86.ARCRL case gc.ORROTC<<16 | gc.TINT64, gc.ORROTC<<16 | gc.TUINT64: a = x86.ARCRQ case gc.OHMUL<<16 | gc.TINT8, gc.OMUL<<16 | gc.TINT8, gc.OMUL<<16 | gc.TUINT8: a = x86.AIMULB case gc.OHMUL<<16 | gc.TINT16, gc.OMUL<<16 | gc.TINT16, gc.OMUL<<16 | gc.TUINT16: a = x86.AIMULW case gc.OHMUL<<16 | gc.TINT32, gc.OMUL<<16 | gc.TINT32, gc.OMUL<<16 | gc.TUINT32, gc.OMUL<<16 | gc.TPTR32: a = x86.AIMULL case gc.OHMUL<<16 | gc.TINT64, gc.OMUL<<16 | gc.TINT64, gc.OMUL<<16 | gc.TUINT64, gc.OMUL<<16 | gc.TPTR64: a = x86.AIMULQ case gc.OHMUL<<16 | gc.TUINT8: a = x86.AMULB case gc.OHMUL<<16 | gc.TUINT16: a = x86.AMULW case gc.OHMUL<<16 | gc.TUINT32, gc.OHMUL<<16 | gc.TPTR32: a = x86.AMULL case gc.OHMUL<<16 | gc.TUINT64, gc.OHMUL<<16 | gc.TPTR64: a = x86.AMULQ case gc.OMUL<<16 | gc.TFLOAT32: a = x86.AMULSS case gc.OMUL<<16 | gc.TFLOAT64: a = x86.AMULSD case gc.ODIV<<16 | gc.TINT8, gc.OMOD<<16 | gc.TINT8: a = x86.AIDIVB case gc.ODIV<<16 | gc.TUINT8, gc.OMOD<<16 | gc.TUINT8: a = x86.ADIVB case gc.ODIV<<16 | gc.TINT16, gc.OMOD<<16 | gc.TINT16: a = x86.AIDIVW case gc.ODIV<<16 | gc.TUINT16, gc.OMOD<<16 | gc.TUINT16: a = x86.ADIVW case gc.ODIV<<16 | gc.TINT32, gc.OMOD<<16 | gc.TINT32: a = x86.AIDIVL case gc.ODIV<<16 | gc.TUINT32, gc.ODIV<<16 | gc.TPTR32, gc.OMOD<<16 | gc.TUINT32, gc.OMOD<<16 | gc.TPTR32: a = x86.ADIVL case gc.ODIV<<16 | gc.TINT64, gc.OMOD<<16 | gc.TINT64: a = x86.AIDIVQ case gc.ODIV<<16 | gc.TUINT64, gc.ODIV<<16 | gc.TPTR64, gc.OMOD<<16 | gc.TUINT64, gc.OMOD<<16 | gc.TPTR64: a = x86.ADIVQ case gc.OEXTEND<<16 | gc.TINT16: a = x86.ACWD case gc.OEXTEND<<16 | gc.TINT32: a = x86.ACDQ case gc.OEXTEND<<16 | gc.TINT64: a = x86.ACQO case gc.ODIV<<16 | gc.TFLOAT32: a = x86.ADIVSS case gc.ODIV<<16 | gc.TFLOAT64: a = x86.ADIVSD case gc.OSQRT<<16 | gc.TFLOAT64: a = x86.ASQRTSD } return a }
/* * generate comparison of nl, nr, both 64-bit. * nl is memory; nr is constant or memory. */ func cmp64(nl *gc.Node, nr *gc.Node, op int, likely int, to *obj.Prog) { var lo1 gc.Node var hi1 gc.Node var lo2 gc.Node var hi2 gc.Node var r1 gc.Node var r2 gc.Node split64(nl, &lo1, &hi1) split64(nr, &lo2, &hi2) // compare most significant word; // if they differ, we're done. t := hi1.Type gc.Regalloc(&r1, gc.Types[gc.TINT32], nil) gc.Regalloc(&r2, gc.Types[gc.TINT32], nil) gins(arm.AMOVW, &hi1, &r1) gins(arm.AMOVW, &hi2, &r2) gins(arm.ACMP, &r1, &r2) gc.Regfree(&r1) gc.Regfree(&r2) var br *obj.Prog switch op { default: gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), t) // cmp hi // bne L // cmp lo // beq to // L: case gc.OEQ: br = gc.Gbranch(arm.ABNE, nil, -likely) // cmp hi // bne to // cmp lo // bne to case gc.ONE: gc.Patch(gc.Gbranch(arm.ABNE, nil, likely), to) // cmp hi // bgt to // blt L // cmp lo // bge to (or bgt to) // L: case gc.OGE, gc.OGT: gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to) br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely) // cmp hi // blt to // bgt L // cmp lo // ble to (or jlt to) // L: case gc.OLE, gc.OLT: gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to) br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely) } // compare least significant word t = lo1.Type gc.Regalloc(&r1, gc.Types[gc.TINT32], nil) gc.Regalloc(&r2, gc.Types[gc.TINT32], nil) gins(arm.AMOVW, &lo1, &r1) gins(arm.AMOVW, &lo2, &r2) gins(arm.ACMP, &r1, &r2) gc.Regfree(&r1) gc.Regfree(&r2) // jump again gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to) // point first branch down here if appropriate if br != nil { gc.Patch(br, gc.Pc) } splitclean() splitclean() }
/* * attempt to generate 64-bit * res = n * return 1 on success, 0 if op not handled. */ func cgen64(n *gc.Node, res *gc.Node) { if res.Op != gc.OINDREG && res.Op != gc.ONAME { gc.Dump("n", n) gc.Dump("res", res) gc.Fatal("cgen64 %v of %v", gc.Oconv(int(n.Op), 0), gc.Oconv(int(res.Op), 0)) } l := n.Left var t1 gc.Node if !l.Addable { gc.Tempname(&t1, l.Type) gc.Cgen(l, &t1) l = &t1 } var hi1 gc.Node var lo1 gc.Node split64(l, &lo1, &hi1) switch n.Op { default: gc.Fatal("cgen64 %v", gc.Oconv(int(n.Op), 0)) case gc.OMINUS: var lo2 gc.Node var hi2 gc.Node split64(res, &lo2, &hi2) gc.Regalloc(&t1, lo1.Type, nil) var al gc.Node gc.Regalloc(&al, lo1.Type, nil) var ah gc.Node gc.Regalloc(&ah, hi1.Type, nil) gins(arm.AMOVW, &lo1, &al) gins(arm.AMOVW, &hi1, &ah) gmove(ncon(0), &t1) p1 := gins(arm.ASUB, &al, &t1) p1.Scond |= arm.C_SBIT gins(arm.AMOVW, &t1, &lo2) gmove(ncon(0), &t1) gins(arm.ASBC, &ah, &t1) gins(arm.AMOVW, &t1, &hi2) gc.Regfree(&t1) gc.Regfree(&al) gc.Regfree(&ah) splitclean() splitclean() return case gc.OCOM: gc.Regalloc(&t1, lo1.Type, nil) gmove(ncon(^uint32(0)), &t1) var lo2 gc.Node var hi2 gc.Node split64(res, &lo2, &hi2) var n1 gc.Node gc.Regalloc(&n1, lo1.Type, nil) gins(arm.AMOVW, &lo1, &n1) gins(arm.AEOR, &t1, &n1) gins(arm.AMOVW, &n1, &lo2) gins(arm.AMOVW, &hi1, &n1) gins(arm.AEOR, &t1, &n1) gins(arm.AMOVW, &n1, &hi2) gc.Regfree(&t1) gc.Regfree(&n1) splitclean() splitclean() return // binary operators. // common setup below. case gc.OADD, gc.OSUB, gc.OMUL, gc.OLSH, gc.ORSH, gc.OAND, gc.OOR, gc.OXOR, gc.OLROT: break } // setup for binary operators r := n.Right if r != nil && !r.Addable { var t2 gc.Node gc.Tempname(&t2, r.Type) gc.Cgen(r, &t2) r = &t2 } var hi2 gc.Node var lo2 gc.Node if gc.Is64(r.Type) { split64(r, &lo2, &hi2) } var al gc.Node gc.Regalloc(&al, lo1.Type, nil) var ah gc.Node gc.Regalloc(&ah, hi1.Type, nil) // Do op. Leave result in ah:al. switch n.Op { default: gc.Fatal("cgen64: not implemented: %v\n", n) // TODO: Constants case gc.OADD: var bl gc.Node gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil) var bh gc.Node gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil) gins(arm.AMOVW, &hi1, &ah) gins(arm.AMOVW, &lo1, &al) gins(arm.AMOVW, &hi2, &bh) gins(arm.AMOVW, &lo2, &bl) p1 := gins(arm.AADD, &bl, &al) p1.Scond |= arm.C_SBIT gins(arm.AADC, &bh, &ah) gc.Regfree(&bl) gc.Regfree(&bh) // TODO: Constants. case gc.OSUB: var bl gc.Node gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil) var bh gc.Node gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil) gins(arm.AMOVW, &lo1, &al) gins(arm.AMOVW, &hi1, &ah) gins(arm.AMOVW, &lo2, &bl) gins(arm.AMOVW, &hi2, &bh) p1 := gins(arm.ASUB, &bl, &al) p1.Scond |= arm.C_SBIT gins(arm.ASBC, &bh, &ah) gc.Regfree(&bl) gc.Regfree(&bh) // TODO(kaib): this can be done with 4 regs and does not need 6 case gc.OMUL: var bl gc.Node gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil) var bh gc.Node gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil) var cl gc.Node gc.Regalloc(&cl, gc.Types[gc.TPTR32], nil) var ch gc.Node gc.Regalloc(&ch, gc.Types[gc.TPTR32], nil) // load args into bh:bl and bh:bl. gins(arm.AMOVW, &hi1, &bh) gins(arm.AMOVW, &lo1, &bl) gins(arm.AMOVW, &hi2, &ch) gins(arm.AMOVW, &lo2, &cl) // bl * cl -> ah al p1 := gins(arm.AMULLU, nil, nil) p1.From.Type = obj.TYPE_REG p1.From.Reg = bl.Reg p1.Reg = cl.Reg p1.To.Type = obj.TYPE_REGREG p1.To.Reg = ah.Reg p1.To.Offset = int64(al.Reg) //print("%v\n", p1); // bl * ch + ah -> ah p1 = gins(arm.AMULA, nil, nil) p1.From.Type = obj.TYPE_REG p1.From.Reg = bl.Reg p1.Reg = ch.Reg p1.To.Type = obj.TYPE_REGREG2 p1.To.Reg = ah.Reg p1.To.Offset = int64(ah.Reg) //print("%v\n", p1); // bh * cl + ah -> ah p1 = gins(arm.AMULA, nil, nil) p1.From.Type = obj.TYPE_REG p1.From.Reg = bh.Reg p1.Reg = cl.Reg p1.To.Type = obj.TYPE_REGREG2 p1.To.Reg = ah.Reg p1.To.Offset = int64(ah.Reg) //print("%v\n", p1); gc.Regfree(&bh) gc.Regfree(&bl) gc.Regfree(&ch) gc.Regfree(&cl) // We only rotate by a constant c in [0,64). // if c >= 32: // lo, hi = hi, lo // c -= 32 // if c == 0: // no-op // else: // t = hi // shld hi:lo, c // shld lo:t, c case gc.OLROT: v := uint64(r.Int()) var bl gc.Node gc.Regalloc(&bl, lo1.Type, nil) var bh gc.Node gc.Regalloc(&bh, hi1.Type, nil) if v >= 32 { // reverse during load to do the first 32 bits of rotate v -= 32 gins(arm.AMOVW, &hi1, &bl) gins(arm.AMOVW, &lo1, &bh) } else { gins(arm.AMOVW, &hi1, &bh) gins(arm.AMOVW, &lo1, &bl) } if v == 0 { gins(arm.AMOVW, &bh, &ah) gins(arm.AMOVW, &bl, &al) } else { // rotate by 1 <= v <= 31 // MOVW bl<<v, al // MOVW bh<<v, ah // OR bl>>(32-v), ah // OR bh>>(32-v), al gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v), &al) gshift(arm.AMOVW, &bh, arm.SHIFT_LL, int32(v), &ah) gshift(arm.AORR, &bl, arm.SHIFT_LR, int32(32-v), &ah) gshift(arm.AORR, &bh, arm.SHIFT_LR, int32(32-v), &al) } gc.Regfree(&bl) gc.Regfree(&bh) case gc.OLSH: var bl gc.Node gc.Regalloc(&bl, lo1.Type, nil) var bh gc.Node gc.Regalloc(&bh, hi1.Type, nil) gins(arm.AMOVW, &hi1, &bh) gins(arm.AMOVW, &lo1, &bl) var p6 *obj.Prog var s gc.Node var n1 gc.Node var creg gc.Node var p1 *obj.Prog var p2 *obj.Prog var p3 *obj.Prog var p4 *obj.Prog var p5 *obj.Prog if r.Op == gc.OLITERAL { v := uint64(r.Int()) if v >= 64 { // TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al) // here and below (verify it optimizes to EOR) gins(arm.AEOR, &al, &al) gins(arm.AEOR, &ah, &ah) } else if v > 32 { gins(arm.AEOR, &al, &al) // MOVW bl<<(v-32), ah gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v-32), &ah) } else if v == 32 { gins(arm.AEOR, &al, &al) gins(arm.AMOVW, &bl, &ah) } else if v > 0 { // MOVW bl<<v, al gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v), &al) // MOVW bh<<v, ah gshift(arm.AMOVW, &bh, arm.SHIFT_LL, int32(v), &ah) // OR bl>>(32-v), ah gshift(arm.AORR, &bl, arm.SHIFT_LR, int32(32-v), &ah) } else { gins(arm.AMOVW, &bl, &al) gins(arm.AMOVW, &bh, &ah) } goto olsh_break } gc.Regalloc(&s, gc.Types[gc.TUINT32], nil) gc.Regalloc(&creg, gc.Types[gc.TUINT32], nil) if gc.Is64(r.Type) { // shift is >= 1<<32 var cl gc.Node var ch gc.Node split64(r, &cl, &ch) gmove(&ch, &s) gins(arm.ATST, &s, nil) p6 = gc.Gbranch(arm.ABNE, nil, 0) gmove(&cl, &s) splitclean() } else { gmove(r, &s) p6 = nil } gins(arm.ATST, &s, nil) // shift == 0 p1 = gins(arm.AMOVW, &bl, &al) p1.Scond = arm.C_SCOND_EQ p1 = gins(arm.AMOVW, &bh, &ah) p1.Scond = arm.C_SCOND_EQ p2 = gc.Gbranch(arm.ABEQ, nil, 0) // shift is < 32 gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32) gmove(&n1, &creg) gins(arm.ACMP, &s, &creg) // MOVW.LO bl<<s, al p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LL, &s, &al) p1.Scond = arm.C_SCOND_LO // MOVW.LO bh<<s, ah p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_LL, &s, &ah) p1.Scond = arm.C_SCOND_LO // SUB.LO s, creg p1 = gins(arm.ASUB, &s, &creg) p1.Scond = arm.C_SCOND_LO // OR.LO bl>>creg, ah p1 = gregshift(arm.AORR, &bl, arm.SHIFT_LR, &creg, &ah) p1.Scond = arm.C_SCOND_LO // BLO end p3 = gc.Gbranch(arm.ABLO, nil, 0) // shift == 32 p1 = gins(arm.AEOR, &al, &al) p1.Scond = arm.C_SCOND_EQ p1 = gins(arm.AMOVW, &bl, &ah) p1.Scond = arm.C_SCOND_EQ p4 = gc.Gbranch(arm.ABEQ, nil, 0) // shift is < 64 gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64) gmove(&n1, &creg) gins(arm.ACMP, &s, &creg) // EOR.LO al, al p1 = gins(arm.AEOR, &al, &al) p1.Scond = arm.C_SCOND_LO // MOVW.LO creg>>1, creg p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg) p1.Scond = arm.C_SCOND_LO // SUB.LO creg, s p1 = gins(arm.ASUB, &creg, &s) p1.Scond = arm.C_SCOND_LO // MOVW bl<<s, ah p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LL, &s, &ah) p1.Scond = arm.C_SCOND_LO p5 = gc.Gbranch(arm.ABLO, nil, 0) // shift >= 64 if p6 != nil { gc.Patch(p6, gc.Pc) } gins(arm.AEOR, &al, &al) gins(arm.AEOR, &ah, &ah) gc.Patch(p2, gc.Pc) gc.Patch(p3, gc.Pc) gc.Patch(p4, gc.Pc) gc.Patch(p5, gc.Pc) gc.Regfree(&s) gc.Regfree(&creg) olsh_break: gc.Regfree(&bl) gc.Regfree(&bh) case gc.ORSH: var bl gc.Node gc.Regalloc(&bl, lo1.Type, nil) var bh gc.Node gc.Regalloc(&bh, hi1.Type, nil) gins(arm.AMOVW, &hi1, &bh) gins(arm.AMOVW, &lo1, &bl) var p4 *obj.Prog var p5 *obj.Prog var n1 gc.Node var p6 *obj.Prog var s gc.Node var p1 *obj.Prog var p2 *obj.Prog var creg gc.Node var p3 *obj.Prog if r.Op == gc.OLITERAL { v := uint64(r.Int()) if v >= 64 { if bh.Type.Etype == gc.TINT32 { // MOVW bh->31, al gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &al) // MOVW bh->31, ah gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) } else { gins(arm.AEOR, &al, &al) gins(arm.AEOR, &ah, &ah) } } else if v > 32 { if bh.Type.Etype == gc.TINT32 { // MOVW bh->(v-32), al gshift(arm.AMOVW, &bh, arm.SHIFT_AR, int32(v-32), &al) // MOVW bh->31, ah gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) } else { // MOVW bh>>(v-32), al gshift(arm.AMOVW, &bh, arm.SHIFT_LR, int32(v-32), &al) gins(arm.AEOR, &ah, &ah) } } else if v == 32 { gins(arm.AMOVW, &bh, &al) if bh.Type.Etype == gc.TINT32 { // MOVW bh->31, ah gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) } else { gins(arm.AEOR, &ah, &ah) } } else if v > 0 { // MOVW bl>>v, al gshift(arm.AMOVW, &bl, arm.SHIFT_LR, int32(v), &al) // OR bh<<(32-v), al gshift(arm.AORR, &bh, arm.SHIFT_LL, int32(32-v), &al) if bh.Type.Etype == gc.TINT32 { // MOVW bh->v, ah gshift(arm.AMOVW, &bh, arm.SHIFT_AR, int32(v), &ah) } else { // MOVW bh>>v, ah gshift(arm.AMOVW, &bh, arm.SHIFT_LR, int32(v), &ah) } } else { gins(arm.AMOVW, &bl, &al) gins(arm.AMOVW, &bh, &ah) } goto orsh_break } gc.Regalloc(&s, gc.Types[gc.TUINT32], nil) gc.Regalloc(&creg, gc.Types[gc.TUINT32], nil) if gc.Is64(r.Type) { // shift is >= 1<<32 var ch gc.Node var cl gc.Node split64(r, &cl, &ch) gmove(&ch, &s) gins(arm.ATST, &s, nil) var p1 *obj.Prog if bh.Type.Etype == gc.TINT32 { p1 = gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) } else { p1 = gins(arm.AEOR, &ah, &ah) } p1.Scond = arm.C_SCOND_NE p6 = gc.Gbranch(arm.ABNE, nil, 0) gmove(&cl, &s) splitclean() } else { gmove(r, &s) p6 = nil } gins(arm.ATST, &s, nil) // shift == 0 p1 = gins(arm.AMOVW, &bl, &al) p1.Scond = arm.C_SCOND_EQ p1 = gins(arm.AMOVW, &bh, &ah) p1.Scond = arm.C_SCOND_EQ p2 = gc.Gbranch(arm.ABEQ, nil, 0) // check if shift is < 32 gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32) gmove(&n1, &creg) gins(arm.ACMP, &s, &creg) // MOVW.LO bl>>s, al p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LR, &s, &al) p1.Scond = arm.C_SCOND_LO // SUB.LO s,creg p1 = gins(arm.ASUB, &s, &creg) p1.Scond = arm.C_SCOND_LO // OR.LO bh<<(32-s), al p1 = gregshift(arm.AORR, &bh, arm.SHIFT_LL, &creg, &al) p1.Scond = arm.C_SCOND_LO if bh.Type.Etype == gc.TINT32 { // MOVW bh->s, ah p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_AR, &s, &ah) } else { // MOVW bh>>s, ah p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_LR, &s, &ah) } p1.Scond = arm.C_SCOND_LO // BLO end p3 = gc.Gbranch(arm.ABLO, nil, 0) // shift == 32 p1 = gins(arm.AMOVW, &bh, &al) p1.Scond = arm.C_SCOND_EQ if bh.Type.Etype == gc.TINT32 { gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) } else { gins(arm.AEOR, &ah, &ah) } p4 = gc.Gbranch(arm.ABEQ, nil, 0) // check if shift is < 64 gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64) gmove(&n1, &creg) gins(arm.ACMP, &s, &creg) // MOVW.LO creg>>1, creg p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg) p1.Scond = arm.C_SCOND_LO // SUB.LO creg, s p1 = gins(arm.ASUB, &creg, &s) p1.Scond = arm.C_SCOND_LO if bh.Type.Etype == gc.TINT32 { // MOVW bh->(s-32), al p1 := gregshift(arm.AMOVW, &bh, arm.SHIFT_AR, &s, &al) p1.Scond = arm.C_SCOND_LO } else { // MOVW bh>>(v-32), al p1 := gregshift(arm.AMOVW, &bh, arm.SHIFT_LR, &s, &al) p1.Scond = arm.C_SCOND_LO } // BLO end p5 = gc.Gbranch(arm.ABLO, nil, 0) // s >= 64 if p6 != nil { gc.Patch(p6, gc.Pc) } if bh.Type.Etype == gc.TINT32 { // MOVW bh->31, al gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &al) } else { gins(arm.AEOR, &al, &al) } gc.Patch(p2, gc.Pc) gc.Patch(p3, gc.Pc) gc.Patch(p4, gc.Pc) gc.Patch(p5, gc.Pc) gc.Regfree(&s) gc.Regfree(&creg) orsh_break: gc.Regfree(&bl) gc.Regfree(&bh) // TODO(kaib): literal optimizations // make constant the right side (it usually is anyway). // if(lo1.op == OLITERAL) { // nswap(&lo1, &lo2); // nswap(&hi1, &hi2); // } // if(lo2.op == OLITERAL) { // // special cases for constants. // lv = mpgetfix(lo2.val.u.xval); // hv = mpgetfix(hi2.val.u.xval); // splitclean(); // right side // split64(res, &lo2, &hi2); // switch(n->op) { // case OXOR: // gmove(&lo1, &lo2); // gmove(&hi1, &hi2); // switch(lv) { // case 0: // break; // case 0xffffffffu: // gins(ANOTL, N, &lo2); // break; // default: // gins(AXORL, ncon(lv), &lo2); // break; // } // switch(hv) { // case 0: // break; // case 0xffffffffu: // gins(ANOTL, N, &hi2); // break; // default: // gins(AXORL, ncon(hv), &hi2); // break; // } // break; // case OAND: // switch(lv) { // case 0: // gins(AMOVL, ncon(0), &lo2); // break; // default: // gmove(&lo1, &lo2); // if(lv != 0xffffffffu) // gins(AANDL, ncon(lv), &lo2); // break; // } // switch(hv) { // case 0: // gins(AMOVL, ncon(0), &hi2); // break; // default: // gmove(&hi1, &hi2); // if(hv != 0xffffffffu) // gins(AANDL, ncon(hv), &hi2); // break; // } // break; // case OOR: // switch(lv) { // case 0: // gmove(&lo1, &lo2); // break; // case 0xffffffffu: // gins(AMOVL, ncon(0xffffffffu), &lo2); // break; // default: // gmove(&lo1, &lo2); // gins(AORL, ncon(lv), &lo2); // break; // } // switch(hv) { // case 0: // gmove(&hi1, &hi2); // break; // case 0xffffffffu: // gins(AMOVL, ncon(0xffffffffu), &hi2); // break; // default: // gmove(&hi1, &hi2); // gins(AORL, ncon(hv), &hi2); // break; // } // break; // } // splitclean(); // splitclean(); // goto out; // } case gc.OXOR, gc.OAND, gc.OOR: var n1 gc.Node gc.Regalloc(&n1, lo1.Type, nil) gins(arm.AMOVW, &lo1, &al) gins(arm.AMOVW, &hi1, &ah) gins(arm.AMOVW, &lo2, &n1) gins(optoas(int(n.Op), lo1.Type), &n1, &al) gins(arm.AMOVW, &hi2, &n1) gins(optoas(int(n.Op), lo1.Type), &n1, &ah) gc.Regfree(&n1) } if gc.Is64(r.Type) { splitclean() } splitclean() split64(res, &lo1, &hi1) gins(arm.AMOVW, &al, &lo1) gins(arm.AMOVW, &ah, &hi1) splitclean() //out: gc.Regfree(&al) gc.Regfree(&ah) }
func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { if !gc.Isfloat[t.Etype] && (op == gc.OLT || op == gc.OGE) { // swap nodes to fit SGT instruction n1, n2 = n2, n1 } if gc.Isfloat[t.Etype] && (op == gc.OLT || op == gc.OLE) { // swap nodes to fit CMPGT, CMPGE instructions and reverse relation n1, n2 = n2, n1 if op == gc.OLT { op = gc.OGT } else { op = gc.OGE } } var r1, r2, g1, g2 gc.Node gc.Regalloc(&r1, t, n1) gc.Regalloc(&g1, n1.Type, &r1) gc.Cgen(n1, &g1) gmove(&g1, &r1) gc.Regalloc(&r2, t, n2) gc.Regalloc(&g2, n1.Type, &r2) gc.Cgen(n2, &g2) gmove(&g2, &r2) var p *obj.Prog var ntmp gc.Node gc.Nodreg(&ntmp, gc.Types[gc.TINT], mips.REGTMP) switch gc.Simtype[t.Etype] { case gc.TINT8, gc.TINT16, gc.TINT32, gc.TINT64: if op == gc.OEQ || op == gc.ONE { p = ginsbranch(optoas(op, t), nil, &r1, &r2, likely) } else { gins3(mips.ASGT, &r1, &r2, &ntmp) p = ginsbranch(optoas(op, t), nil, &ntmp, nil, likely) } case gc.TBOOL, gc.TUINT8, gc.TUINT16, gc.TUINT32, gc.TUINT64, gc.TPTR32, gc.TPTR64: if op == gc.OEQ || op == gc.ONE { p = ginsbranch(optoas(op, t), nil, &r1, &r2, likely) } else { gins3(mips.ASGTU, &r1, &r2, &ntmp) p = ginsbranch(optoas(op, t), nil, &ntmp, nil, likely) } case gc.TFLOAT32: switch op { default: gc.Fatalf("ginscmp: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t) case gc.OEQ, gc.ONE: gins3(mips.ACMPEQF, &r1, &r2, nil) case gc.OGE: gins3(mips.ACMPGEF, &r1, &r2, nil) case gc.OGT: gins3(mips.ACMPGTF, &r1, &r2, nil) } p = gc.Gbranch(optoas(op, t), nil, likely) case gc.TFLOAT64: switch op { default: gc.Fatalf("ginscmp: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t) case gc.OEQ, gc.ONE: gins3(mips.ACMPEQD, &r1, &r2, nil) case gc.OGE: gins3(mips.ACMPGED, &r1, &r2, nil) case gc.OGT: gins3(mips.ACMPGTD, &r1, &r2, nil) } p = gc.Gbranch(optoas(op, t), nil, likely) } gc.Regfree(&g2) gc.Regfree(&r2) gc.Regfree(&g1) gc.Regfree(&r1) return p }
/* * return Axxx for Oxxx on type t. */ func optoas(op gc.Op, t *gc.Type) int { if t == nil { gc.Fatalf("optoas: t is nil") } // avoid constant conversions in switches below const ( OMINUS_ = uint32(gc.OMINUS) << 16 OLSH_ = uint32(gc.OLSH) << 16 ORSH_ = uint32(gc.ORSH) << 16 OADD_ = uint32(gc.OADD) << 16 OSUB_ = uint32(gc.OSUB) << 16 OMUL_ = uint32(gc.OMUL) << 16 ODIV_ = uint32(gc.ODIV) << 16 OOR_ = uint32(gc.OOR) << 16 OAND_ = uint32(gc.OAND) << 16 OXOR_ = uint32(gc.OXOR) << 16 OEQ_ = uint32(gc.OEQ) << 16 ONE_ = uint32(gc.ONE) << 16 OLT_ = uint32(gc.OLT) << 16 OLE_ = uint32(gc.OLE) << 16 OGE_ = uint32(gc.OGE) << 16 OGT_ = uint32(gc.OGT) << 16 OCMP_ = uint32(gc.OCMP) << 16 OAS_ = uint32(gc.OAS) << 16 OHMUL_ = uint32(gc.OHMUL) << 16 ) a := int(obj.AXXX) switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { default: gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t) case OEQ_ | gc.TBOOL, OEQ_ | gc.TINT8, OEQ_ | gc.TUINT8, OEQ_ | gc.TINT16, OEQ_ | gc.TUINT16, OEQ_ | gc.TINT32, OEQ_ | gc.TUINT32, OEQ_ | gc.TINT64, OEQ_ | gc.TUINT64, OEQ_ | gc.TPTR32, OEQ_ | gc.TPTR64: a = mips.ABEQ case OEQ_ | gc.TFLOAT32, // ACMPEQF OEQ_ | gc.TFLOAT64: // ACMPEQD a = mips.ABFPT case ONE_ | gc.TBOOL, ONE_ | gc.TINT8, ONE_ | gc.TUINT8, ONE_ | gc.TINT16, ONE_ | gc.TUINT16, ONE_ | gc.TINT32, ONE_ | gc.TUINT32, ONE_ | gc.TINT64, ONE_ | gc.TUINT64, ONE_ | gc.TPTR32, ONE_ | gc.TPTR64: a = mips.ABNE case ONE_ | gc.TFLOAT32, // ACMPEQF ONE_ | gc.TFLOAT64: // ACMPEQD a = mips.ABFPF case OLT_ | gc.TINT8, // ASGT OLT_ | gc.TINT16, OLT_ | gc.TINT32, OLT_ | gc.TINT64, OLT_ | gc.TUINT8, // ASGTU OLT_ | gc.TUINT16, OLT_ | gc.TUINT32, OLT_ | gc.TUINT64: a = mips.ABNE case OLT_ | gc.TFLOAT32, // ACMPGEF OLT_ | gc.TFLOAT64: // ACMPGED a = mips.ABFPT case OLE_ | gc.TINT8, // ASGT OLE_ | gc.TINT16, OLE_ | gc.TINT32, OLE_ | gc.TINT64, OLE_ | gc.TUINT8, // ASGTU OLE_ | gc.TUINT16, OLE_ | gc.TUINT32, OLE_ | gc.TUINT64: a = mips.ABEQ case OLE_ | gc.TFLOAT32, // ACMPGTF OLE_ | gc.TFLOAT64: // ACMPGTD a = mips.ABFPT case OGT_ | gc.TINT8, // ASGT OGT_ | gc.TINT16, OGT_ | gc.TINT32, OGT_ | gc.TINT64, OGT_ | gc.TUINT8, // ASGTU OGT_ | gc.TUINT16, OGT_ | gc.TUINT32, OGT_ | gc.TUINT64: a = mips.ABNE case OGT_ | gc.TFLOAT32, // ACMPGTF OGT_ | gc.TFLOAT64: // ACMPGTD a = mips.ABFPT case OGE_ | gc.TINT8, // ASGT OGE_ | gc.TINT16, OGE_ | gc.TINT32, OGE_ | gc.TINT64, OGE_ | gc.TUINT8, // ASGTU OGE_ | gc.TUINT16, OGE_ | gc.TUINT32, OGE_ | gc.TUINT64: a = mips.ABEQ case OGE_ | gc.TFLOAT32, // ACMPGEF OGE_ | gc.TFLOAT64: // ACMPGED a = mips.ABFPT case OAS_ | gc.TBOOL, OAS_ | gc.TINT8: a = mips.AMOVB case OAS_ | gc.TUINT8: a = mips.AMOVBU case OAS_ | gc.TINT16: a = mips.AMOVH case OAS_ | gc.TUINT16: a = mips.AMOVHU case OAS_ | gc.TINT32: a = mips.AMOVW case OAS_ | gc.TUINT32, OAS_ | gc.TPTR32: a = mips.AMOVWU case OAS_ | gc.TINT64, OAS_ | gc.TUINT64, OAS_ | gc.TPTR64: a = mips.AMOVV case OAS_ | gc.TFLOAT32: a = mips.AMOVF case OAS_ | gc.TFLOAT64: a = mips.AMOVD case OADD_ | gc.TINT8, OADD_ | gc.TUINT8, OADD_ | gc.TINT16, OADD_ | gc.TUINT16, OADD_ | gc.TINT32, OADD_ | gc.TUINT32, OADD_ | gc.TPTR32: a = mips.AADDU case OADD_ | gc.TINT64, OADD_ | gc.TUINT64, OADD_ | gc.TPTR64: a = mips.AADDVU case OADD_ | gc.TFLOAT32: a = mips.AADDF case OADD_ | gc.TFLOAT64: a = mips.AADDD case OSUB_ | gc.TINT8, OSUB_ | gc.TUINT8, OSUB_ | gc.TINT16, OSUB_ | gc.TUINT16, OSUB_ | gc.TINT32, OSUB_ | gc.TUINT32, OSUB_ | gc.TPTR32: a = mips.ASUBU case OSUB_ | gc.TINT64, OSUB_ | gc.TUINT64, OSUB_ | gc.TPTR64: a = mips.ASUBVU case OSUB_ | gc.TFLOAT32: a = mips.ASUBF case OSUB_ | gc.TFLOAT64: a = mips.ASUBD case OMINUS_ | gc.TINT8, OMINUS_ | gc.TUINT8, OMINUS_ | gc.TINT16, OMINUS_ | gc.TUINT16, OMINUS_ | gc.TINT32, OMINUS_ | gc.TUINT32, OMINUS_ | gc.TPTR32, OMINUS_ | gc.TINT64, OMINUS_ | gc.TUINT64, OMINUS_ | gc.TPTR64: a = mips.ASUBVU case OAND_ | gc.TINT8, OAND_ | gc.TUINT8, OAND_ | gc.TINT16, OAND_ | gc.TUINT16, OAND_ | gc.TINT32, OAND_ | gc.TUINT32, OAND_ | gc.TPTR32, OAND_ | gc.TINT64, OAND_ | gc.TUINT64, OAND_ | gc.TPTR64: a = mips.AAND case OOR_ | gc.TINT8, OOR_ | gc.TUINT8, OOR_ | gc.TINT16, OOR_ | gc.TUINT16, OOR_ | gc.TINT32, OOR_ | gc.TUINT32, OOR_ | gc.TPTR32, OOR_ | gc.TINT64, OOR_ | gc.TUINT64, OOR_ | gc.TPTR64: a = mips.AOR case OXOR_ | gc.TINT8, OXOR_ | gc.TUINT8, OXOR_ | gc.TINT16, OXOR_ | gc.TUINT16, OXOR_ | gc.TINT32, OXOR_ | gc.TUINT32, OXOR_ | gc.TPTR32, OXOR_ | gc.TINT64, OXOR_ | gc.TUINT64, OXOR_ | gc.TPTR64: a = mips.AXOR // TODO(minux): handle rotates //case CASE(OLROT, TINT8): //case CASE(OLROT, TUINT8): //case CASE(OLROT, TINT16): //case CASE(OLROT, TUINT16): //case CASE(OLROT, TINT32): //case CASE(OLROT, TUINT32): //case CASE(OLROT, TPTR32): //case CASE(OLROT, TINT64): //case CASE(OLROT, TUINT64): //case CASE(OLROT, TPTR64): // a = 0//???; RLDC? // break; case OLSH_ | gc.TINT8, OLSH_ | gc.TUINT8, OLSH_ | gc.TINT16, OLSH_ | gc.TUINT16, OLSH_ | gc.TINT32, OLSH_ | gc.TUINT32, OLSH_ | gc.TPTR32, OLSH_ | gc.TINT64, OLSH_ | gc.TUINT64, OLSH_ | gc.TPTR64: a = mips.ASLLV case ORSH_ | gc.TUINT8, ORSH_ | gc.TUINT16, ORSH_ | gc.TUINT32, ORSH_ | gc.TPTR32, ORSH_ | gc.TUINT64, ORSH_ | gc.TPTR64: a = mips.ASRLV case ORSH_ | gc.TINT8, ORSH_ | gc.TINT16, ORSH_ | gc.TINT32, ORSH_ | gc.TINT64: a = mips.ASRAV // TODO(minux): handle rotates //case CASE(ORROTC, TINT8): //case CASE(ORROTC, TUINT8): //case CASE(ORROTC, TINT16): //case CASE(ORROTC, TUINT16): //case CASE(ORROTC, TINT32): //case CASE(ORROTC, TUINT32): //case CASE(ORROTC, TINT64): //case CASE(ORROTC, TUINT64): // a = 0//??? RLDC?? // break; case OHMUL_ | gc.TINT64: a = mips.AMULV case OHMUL_ | gc.TUINT64, OHMUL_ | gc.TPTR64: a = mips.AMULVU case OMUL_ | gc.TINT8, OMUL_ | gc.TINT16, OMUL_ | gc.TINT32, OMUL_ | gc.TINT64: a = mips.AMULV case OMUL_ | gc.TUINT8, OMUL_ | gc.TUINT16, OMUL_ | gc.TUINT32, OMUL_ | gc.TPTR32, OMUL_ | gc.TUINT64, OMUL_ | gc.TPTR64: a = mips.AMULVU case OMUL_ | gc.TFLOAT32: a = mips.AMULF case OMUL_ | gc.TFLOAT64: a = mips.AMULD case ODIV_ | gc.TINT8, ODIV_ | gc.TINT16, ODIV_ | gc.TINT32, ODIV_ | gc.TINT64: a = mips.ADIVV case ODIV_ | gc.TUINT8, ODIV_ | gc.TUINT16, ODIV_ | gc.TUINT32, ODIV_ | gc.TPTR32, ODIV_ | gc.TUINT64, ODIV_ | gc.TPTR64: a = mips.ADIVVU case ODIV_ | gc.TFLOAT32: a = mips.ADIVF case ODIV_ | gc.TFLOAT64: a = mips.ADIVD } return a }
/* * return Axxx for Oxxx on type t. */ func optoas(op gc.Op, t *gc.Type) int { if t == nil { gc.Fatalf("optoas: t is nil") } // avoid constant conversions in switches below const ( OMINUS_ = uint32(gc.OMINUS) << 16 OLSH_ = uint32(gc.OLSH) << 16 ORSH_ = uint32(gc.ORSH) << 16 OADD_ = uint32(gc.OADD) << 16 OSUB_ = uint32(gc.OSUB) << 16 OMUL_ = uint32(gc.OMUL) << 16 ODIV_ = uint32(gc.ODIV) << 16 OOR_ = uint32(gc.OOR) << 16 OAND_ = uint32(gc.OAND) << 16 OXOR_ = uint32(gc.OXOR) << 16 OEQ_ = uint32(gc.OEQ) << 16 ONE_ = uint32(gc.ONE) << 16 OLT_ = uint32(gc.OLT) << 16 OLE_ = uint32(gc.OLE) << 16 OGE_ = uint32(gc.OGE) << 16 OGT_ = uint32(gc.OGT) << 16 OCMP_ = uint32(gc.OCMP) << 16 OAS_ = uint32(gc.OAS) << 16 OHMUL_ = uint32(gc.OHMUL) << 16 OSQRT_ = uint32(gc.OSQRT) << 16 ) a := int(obj.AXXX) switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { default: gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t) case OEQ_ | gc.TBOOL, OEQ_ | gc.TINT8, OEQ_ | gc.TUINT8, OEQ_ | gc.TINT16, OEQ_ | gc.TUINT16, OEQ_ | gc.TINT32, OEQ_ | gc.TUINT32, OEQ_ | gc.TINT64, OEQ_ | gc.TUINT64, OEQ_ | gc.TPTR32, OEQ_ | gc.TPTR64, OEQ_ | gc.TFLOAT32, OEQ_ | gc.TFLOAT64: a = s390x.ABEQ case ONE_ | gc.TBOOL, ONE_ | gc.TINT8, ONE_ | gc.TUINT8, ONE_ | gc.TINT16, ONE_ | gc.TUINT16, ONE_ | gc.TINT32, ONE_ | gc.TUINT32, ONE_ | gc.TINT64, ONE_ | gc.TUINT64, ONE_ | gc.TPTR32, ONE_ | gc.TPTR64, ONE_ | gc.TFLOAT32, ONE_ | gc.TFLOAT64: a = s390x.ABNE case OLT_ | gc.TINT8, // ACMP OLT_ | gc.TINT16, OLT_ | gc.TINT32, OLT_ | gc.TINT64, OLT_ | gc.TUINT8, // ACMPU OLT_ | gc.TUINT16, OLT_ | gc.TUINT32, OLT_ | gc.TUINT64, OLT_ | gc.TFLOAT32, // AFCMPU OLT_ | gc.TFLOAT64: a = s390x.ABLT case OLE_ | gc.TINT8, // ACMP OLE_ | gc.TINT16, OLE_ | gc.TINT32, OLE_ | gc.TINT64, OLE_ | gc.TUINT8, // ACMPU OLE_ | gc.TUINT16, OLE_ | gc.TUINT32, OLE_ | gc.TUINT64, OLE_ | gc.TFLOAT32, OLE_ | gc.TFLOAT64: a = s390x.ABLE case OGT_ | gc.TINT8, OGT_ | gc.TINT16, OGT_ | gc.TINT32, OGT_ | gc.TINT64, OGT_ | gc.TUINT8, OGT_ | gc.TUINT16, OGT_ | gc.TUINT32, OGT_ | gc.TUINT64, OGT_ | gc.TFLOAT32, OGT_ | gc.TFLOAT64: a = s390x.ABGT case OGE_ | gc.TINT8, OGE_ | gc.TINT16, OGE_ | gc.TINT32, OGE_ | gc.TINT64, OGE_ | gc.TUINT8, OGE_ | gc.TUINT16, OGE_ | gc.TUINT32, OGE_ | gc.TUINT64, OGE_ | gc.TFLOAT32, OGE_ | gc.TFLOAT64: a = s390x.ABGE case OCMP_ | gc.TBOOL, OCMP_ | gc.TINT8, OCMP_ | gc.TINT16, OCMP_ | gc.TINT32, OCMP_ | gc.TPTR32, OCMP_ | gc.TINT64: a = s390x.ACMP case OCMP_ | gc.TUINT8, OCMP_ | gc.TUINT16, OCMP_ | gc.TUINT32, OCMP_ | gc.TUINT64, OCMP_ | gc.TPTR64: a = s390x.ACMPU case OCMP_ | gc.TFLOAT32: a = s390x.ACEBR case OCMP_ | gc.TFLOAT64: a = s390x.AFCMPU case OAS_ | gc.TBOOL, OAS_ | gc.TINT8: a = s390x.AMOVB case OAS_ | gc.TUINT8: a = s390x.AMOVBZ case OAS_ | gc.TINT16: a = s390x.AMOVH case OAS_ | gc.TUINT16: a = s390x.AMOVHZ case OAS_ | gc.TINT32: a = s390x.AMOVW case OAS_ | gc.TUINT32, OAS_ | gc.TPTR32: a = s390x.AMOVWZ case OAS_ | gc.TINT64, OAS_ | gc.TUINT64, OAS_ | gc.TPTR64: a = s390x.AMOVD case OAS_ | gc.TFLOAT32: a = s390x.AFMOVS case OAS_ | gc.TFLOAT64: a = s390x.AFMOVD case OADD_ | gc.TINT8, OADD_ | gc.TUINT8, OADD_ | gc.TINT16, OADD_ | gc.TUINT16, OADD_ | gc.TINT32, OADD_ | gc.TUINT32, OADD_ | gc.TPTR32, OADD_ | gc.TINT64, OADD_ | gc.TUINT64, OADD_ | gc.TPTR64: a = s390x.AADD case OADD_ | gc.TFLOAT32: a = s390x.AFADDS case OADD_ | gc.TFLOAT64: a = s390x.AFADD case OSUB_ | gc.TINT8, OSUB_ | gc.TUINT8, OSUB_ | gc.TINT16, OSUB_ | gc.TUINT16, OSUB_ | gc.TINT32, OSUB_ | gc.TUINT32, OSUB_ | gc.TPTR32, OSUB_ | gc.TINT64, OSUB_ | gc.TUINT64, OSUB_ | gc.TPTR64: a = s390x.ASUB case OSUB_ | gc.TFLOAT32: a = s390x.AFSUBS case OSUB_ | gc.TFLOAT64: a = s390x.AFSUB case OMINUS_ | gc.TINT8, OMINUS_ | gc.TUINT8, OMINUS_ | gc.TINT16, OMINUS_ | gc.TUINT16, OMINUS_ | gc.TINT32, OMINUS_ | gc.TUINT32, OMINUS_ | gc.TPTR32, OMINUS_ | gc.TINT64, OMINUS_ | gc.TUINT64, OMINUS_ | gc.TPTR64: a = s390x.ANEG case OAND_ | gc.TINT8, OAND_ | gc.TUINT8, OAND_ | gc.TINT16, OAND_ | gc.TUINT16, OAND_ | gc.TINT32, OAND_ | gc.TUINT32, OAND_ | gc.TPTR32, OAND_ | gc.TINT64, OAND_ | gc.TUINT64, OAND_ | gc.TPTR64: a = s390x.AAND case OOR_ | gc.TINT8, OOR_ | gc.TUINT8, OOR_ | gc.TINT16, OOR_ | gc.TUINT16, OOR_ | gc.TINT32, OOR_ | gc.TUINT32, OOR_ | gc.TPTR32, OOR_ | gc.TINT64, OOR_ | gc.TUINT64, OOR_ | gc.TPTR64: a = s390x.AOR case OXOR_ | gc.TINT8, OXOR_ | gc.TUINT8, OXOR_ | gc.TINT16, OXOR_ | gc.TUINT16, OXOR_ | gc.TINT32, OXOR_ | gc.TUINT32, OXOR_ | gc.TPTR32, OXOR_ | gc.TINT64, OXOR_ | gc.TUINT64, OXOR_ | gc.TPTR64: a = s390x.AXOR case OLSH_ | gc.TINT8, OLSH_ | gc.TUINT8, OLSH_ | gc.TINT16, OLSH_ | gc.TUINT16, OLSH_ | gc.TINT32, OLSH_ | gc.TUINT32, OLSH_ | gc.TPTR32, OLSH_ | gc.TINT64, OLSH_ | gc.TUINT64, OLSH_ | gc.TPTR64: a = s390x.ASLD case ORSH_ | gc.TUINT8, ORSH_ | gc.TUINT16, ORSH_ | gc.TUINT32, ORSH_ | gc.TPTR32, ORSH_ | gc.TUINT64, ORSH_ | gc.TPTR64: a = s390x.ASRD case ORSH_ | gc.TINT8, ORSH_ | gc.TINT16, ORSH_ | gc.TINT32, ORSH_ | gc.TINT64: a = s390x.ASRAD case OHMUL_ | gc.TINT64: a = s390x.AMULHD case OHMUL_ | gc.TUINT64, OHMUL_ | gc.TPTR64: a = s390x.AMULHDU case OMUL_ | gc.TINT8, OMUL_ | gc.TINT16, OMUL_ | gc.TINT32, OMUL_ | gc.TINT64: a = s390x.AMULLD case OMUL_ | gc.TUINT8, OMUL_ | gc.TUINT16, OMUL_ | gc.TUINT32, OMUL_ | gc.TPTR32, // don't use word multiply, the high 32-bit are undefined. OMUL_ | gc.TUINT64, OMUL_ | gc.TPTR64: // for 64-bit multiplies, signedness doesn't matter. a = s390x.AMULLD case OMUL_ | gc.TFLOAT32: a = s390x.AFMULS case OMUL_ | gc.TFLOAT64: a = s390x.AFMUL case ODIV_ | gc.TINT8, ODIV_ | gc.TINT16, ODIV_ | gc.TINT32, ODIV_ | gc.TINT64: a = s390x.ADIVD case ODIV_ | gc.TUINT8, ODIV_ | gc.TUINT16, ODIV_ | gc.TUINT32, ODIV_ | gc.TPTR32, ODIV_ | gc.TUINT64, ODIV_ | gc.TPTR64: a = s390x.ADIVDU case ODIV_ | gc.TFLOAT32: a = s390x.AFDIVS case ODIV_ | gc.TFLOAT64: a = s390x.AFDIV case OSQRT_ | gc.TFLOAT64: a = s390x.AFSQRT } return a }
/* * attempt to generate 64-bit * res = n * return 1 on success, 0 if op not handled. */ func cgen64(n *gc.Node, res *gc.Node) { if res.Op != gc.OINDREG && res.Op != gc.ONAME { gc.Dump("n", n) gc.Dump("res", res) gc.Fatalf("cgen64 %v of %v", gc.Oconv(int(n.Op), 0), gc.Oconv(int(res.Op), 0)) } switch n.Op { default: gc.Fatalf("cgen64 %v", gc.Oconv(int(n.Op), 0)) case gc.OMINUS: gc.Cgen(n.Left, res) var hi1 gc.Node var lo1 gc.Node split64(res, &lo1, &hi1) gins(x86.ANEGL, nil, &lo1) gins(x86.AADCL, ncon(0), &hi1) gins(x86.ANEGL, nil, &hi1) splitclean() return case gc.OCOM: gc.Cgen(n.Left, res) var lo1 gc.Node var hi1 gc.Node split64(res, &lo1, &hi1) gins(x86.ANOTL, nil, &lo1) gins(x86.ANOTL, nil, &hi1) splitclean() return // binary operators. // common setup below. case gc.OADD, gc.OSUB, gc.OMUL, gc.OLROT, gc.OLSH, gc.ORSH, gc.OAND, gc.OOR, gc.OXOR: break } l := n.Left r := n.Right if !l.Addable { var t1 gc.Node gc.Tempname(&t1, l.Type) gc.Cgen(l, &t1) l = &t1 } if r != nil && !r.Addable { var t2 gc.Node gc.Tempname(&t2, r.Type) gc.Cgen(r, &t2) r = &t2 } var ax gc.Node gc.Nodreg(&ax, gc.Types[gc.TINT32], x86.REG_AX) var cx gc.Node gc.Nodreg(&cx, gc.Types[gc.TINT32], x86.REG_CX) var dx gc.Node gc.Nodreg(&dx, gc.Types[gc.TINT32], x86.REG_DX) // Setup for binary operation. var hi1 gc.Node var lo1 gc.Node split64(l, &lo1, &hi1) var lo2 gc.Node var hi2 gc.Node if gc.Is64(r.Type) { split64(r, &lo2, &hi2) } // Do op. Leave result in DX:AX. switch n.Op { // TODO: Constants case gc.OADD: gins(x86.AMOVL, &lo1, &ax) gins(x86.AMOVL, &hi1, &dx) gins(x86.AADDL, &lo2, &ax) gins(x86.AADCL, &hi2, &dx) // TODO: Constants. case gc.OSUB: gins(x86.AMOVL, &lo1, &ax) gins(x86.AMOVL, &hi1, &dx) gins(x86.ASUBL, &lo2, &ax) gins(x86.ASBBL, &hi2, &dx) case gc.OMUL: // let's call the next three EX, FX and GX var ex, fx, gx gc.Node gc.Regalloc(&ex, gc.Types[gc.TPTR32], nil) gc.Regalloc(&fx, gc.Types[gc.TPTR32], nil) gc.Regalloc(&gx, gc.Types[gc.TPTR32], nil) // load args into DX:AX and EX:GX. gins(x86.AMOVL, &lo1, &ax) gins(x86.AMOVL, &hi1, &dx) gins(x86.AMOVL, &lo2, &gx) gins(x86.AMOVL, &hi2, &ex) // if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply. gins(x86.AMOVL, &dx, &fx) gins(x86.AORL, &ex, &fx) p1 := gc.Gbranch(x86.AJNE, nil, 0) gins(x86.AMULL, &gx, nil) // implicit &ax p2 := gc.Gbranch(obj.AJMP, nil, 0) gc.Patch(p1, gc.Pc) // full 64x64 -> 64, from 32x32 -> 64. gins(x86.AIMULL, &gx, &dx) gins(x86.AMOVL, &ax, &fx) gins(x86.AIMULL, &ex, &fx) gins(x86.AADDL, &dx, &fx) gins(x86.AMOVL, &gx, &dx) gins(x86.AMULL, &dx, nil) // implicit &ax gins(x86.AADDL, &fx, &dx) gc.Patch(p2, gc.Pc) gc.Regfree(&ex) gc.Regfree(&fx) gc.Regfree(&gx) // We only rotate by a constant c in [0,64). // if c >= 32: // lo, hi = hi, lo // c -= 32 // if c == 0: // no-op // else: // t = hi // shld hi:lo, c // shld lo:t, c case gc.OLROT: v := uint64(r.Int()) if v >= 32 { // reverse during load to do the first 32 bits of rotate v -= 32 gins(x86.AMOVL, &lo1, &dx) gins(x86.AMOVL, &hi1, &ax) } else { gins(x86.AMOVL, &lo1, &ax) gins(x86.AMOVL, &hi1, &dx) } if v == 0 { } else // done { gins(x86.AMOVL, &dx, &cx) p1 := gins(x86.ASHLL, ncon(uint32(v)), &dx) p1.From.Index = x86.REG_AX // double-width shift p1.From.Scale = 0 p1 = gins(x86.ASHLL, ncon(uint32(v)), &ax) p1.From.Index = x86.REG_CX // double-width shift p1.From.Scale = 0 } case gc.OLSH: if r.Op == gc.OLITERAL { v := uint64(r.Int()) if v >= 64 { if gc.Is64(r.Type) { splitclean() } splitclean() split64(res, &lo2, &hi2) gins(x86.AMOVL, ncon(0), &lo2) gins(x86.AMOVL, ncon(0), &hi2) splitclean() return } if v >= 32 { if gc.Is64(r.Type) { splitclean() } split64(res, &lo2, &hi2) gmove(&lo1, &hi2) if v > 32 { gins(x86.ASHLL, ncon(uint32(v-32)), &hi2) } gins(x86.AMOVL, ncon(0), &lo2) splitclean() splitclean() return } // general shift gins(x86.AMOVL, &lo1, &ax) gins(x86.AMOVL, &hi1, &dx) p1 := gins(x86.ASHLL, ncon(uint32(v)), &dx) p1.From.Index = x86.REG_AX // double-width shift p1.From.Scale = 0 gins(x86.ASHLL, ncon(uint32(v)), &ax) break } // load value into DX:AX. gins(x86.AMOVL, &lo1, &ax) gins(x86.AMOVL, &hi1, &dx) // load shift value into register. // if high bits are set, zero value. var p1 *obj.Prog if gc.Is64(r.Type) { gins(x86.ACMPL, &hi2, ncon(0)) p1 = gc.Gbranch(x86.AJNE, nil, +1) gins(x86.AMOVL, &lo2, &cx) } else { cx.Type = gc.Types[gc.TUINT32] gmove(r, &cx) } // if shift count is >=64, zero value gins(x86.ACMPL, &cx, ncon(64)) p2 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) if p1 != nil { gc.Patch(p1, gc.Pc) } gins(x86.AXORL, &dx, &dx) gins(x86.AXORL, &ax, &ax) gc.Patch(p2, gc.Pc) // if shift count is >= 32, zero low. gins(x86.ACMPL, &cx, ncon(32)) p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) gins(x86.AMOVL, &ax, &dx) gins(x86.ASHLL, &cx, &dx) // SHLL only uses bottom 5 bits of count gins(x86.AXORL, &ax, &ax) p2 = gc.Gbranch(obj.AJMP, nil, 0) gc.Patch(p1, gc.Pc) // general shift p1 = gins(x86.ASHLL, &cx, &dx) p1.From.Index = x86.REG_AX // double-width shift p1.From.Scale = 0 gins(x86.ASHLL, &cx, &ax) gc.Patch(p2, gc.Pc) case gc.ORSH: if r.Op == gc.OLITERAL { v := uint64(r.Int()) if v >= 64 { if gc.Is64(r.Type) { splitclean() } splitclean() split64(res, &lo2, &hi2) if hi1.Type.Etype == gc.TINT32 { gmove(&hi1, &lo2) gins(x86.ASARL, ncon(31), &lo2) gmove(&hi1, &hi2) gins(x86.ASARL, ncon(31), &hi2) } else { gins(x86.AMOVL, ncon(0), &lo2) gins(x86.AMOVL, ncon(0), &hi2) } splitclean() return } if v >= 32 { if gc.Is64(r.Type) { splitclean() } split64(res, &lo2, &hi2) gmove(&hi1, &lo2) if v > 32 { gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v-32)), &lo2) } if hi1.Type.Etype == gc.TINT32 { gmove(&hi1, &hi2) gins(x86.ASARL, ncon(31), &hi2) } else { gins(x86.AMOVL, ncon(0), &hi2) } splitclean() splitclean() return } // general shift gins(x86.AMOVL, &lo1, &ax) gins(x86.AMOVL, &hi1, &dx) p1 := gins(x86.ASHRL, ncon(uint32(v)), &ax) p1.From.Index = x86.REG_DX // double-width shift p1.From.Scale = 0 gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v)), &dx) break } // load value into DX:AX. gins(x86.AMOVL, &lo1, &ax) gins(x86.AMOVL, &hi1, &dx) // load shift value into register. // if high bits are set, zero value. var p1 *obj.Prog if gc.Is64(r.Type) { gins(x86.ACMPL, &hi2, ncon(0)) p1 = gc.Gbranch(x86.AJNE, nil, +1) gins(x86.AMOVL, &lo2, &cx) } else { cx.Type = gc.Types[gc.TUINT32] gmove(r, &cx) } // if shift count is >=64, zero or sign-extend value gins(x86.ACMPL, &cx, ncon(64)) p2 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) if p1 != nil { gc.Patch(p1, gc.Pc) } if hi1.Type.Etype == gc.TINT32 { gins(x86.ASARL, ncon(31), &dx) gins(x86.AMOVL, &dx, &ax) } else { gins(x86.AXORL, &dx, &dx) gins(x86.AXORL, &ax, &ax) } gc.Patch(p2, gc.Pc) // if shift count is >= 32, sign-extend hi. gins(x86.ACMPL, &cx, ncon(32)) p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) gins(x86.AMOVL, &dx, &ax) if hi1.Type.Etype == gc.TINT32 { gins(x86.ASARL, &cx, &ax) // SARL only uses bottom 5 bits of count gins(x86.ASARL, ncon(31), &dx) } else { gins(x86.ASHRL, &cx, &ax) gins(x86.AXORL, &dx, &dx) } p2 = gc.Gbranch(obj.AJMP, nil, 0) gc.Patch(p1, gc.Pc) // general shift p1 = gins(x86.ASHRL, &cx, &ax) p1.From.Index = x86.REG_DX // double-width shift p1.From.Scale = 0 gins(optoas(gc.ORSH, hi1.Type), &cx, &dx) gc.Patch(p2, gc.Pc) // make constant the right side (it usually is anyway). case gc.OXOR, gc.OAND, gc.OOR: if lo1.Op == gc.OLITERAL { nswap(&lo1, &lo2) nswap(&hi1, &hi2) } if lo2.Op == gc.OLITERAL { // special cases for constants. lv := uint32(lo2.Int()) hv := uint32(hi2.Int()) splitclean() // right side split64(res, &lo2, &hi2) switch n.Op { case gc.OXOR: gmove(&lo1, &lo2) gmove(&hi1, &hi2) switch lv { case 0: break case 0xffffffff: gins(x86.ANOTL, nil, &lo2) default: gins(x86.AXORL, ncon(lv), &lo2) } switch hv { case 0: break case 0xffffffff: gins(x86.ANOTL, nil, &hi2) default: gins(x86.AXORL, ncon(hv), &hi2) } case gc.OAND: switch lv { case 0: gins(x86.AMOVL, ncon(0), &lo2) default: gmove(&lo1, &lo2) if lv != 0xffffffff { gins(x86.AANDL, ncon(lv), &lo2) } } switch hv { case 0: gins(x86.AMOVL, ncon(0), &hi2) default: gmove(&hi1, &hi2) if hv != 0xffffffff { gins(x86.AANDL, ncon(hv), &hi2) } } case gc.OOR: switch lv { case 0: gmove(&lo1, &lo2) case 0xffffffff: gins(x86.AMOVL, ncon(0xffffffff), &lo2) default: gmove(&lo1, &lo2) gins(x86.AORL, ncon(lv), &lo2) } switch hv { case 0: gmove(&hi1, &hi2) case 0xffffffff: gins(x86.AMOVL, ncon(0xffffffff), &hi2) default: gmove(&hi1, &hi2) gins(x86.AORL, ncon(hv), &hi2) } } splitclean() splitclean() return } gins(x86.AMOVL, &lo1, &ax) gins(x86.AMOVL, &hi1, &dx) gins(optoas(n.Op, lo1.Type), &lo2, &ax) gins(optoas(n.Op, lo1.Type), &hi2, &dx) } if gc.Is64(r.Type) { splitclean() } splitclean() split64(res, &lo1, &hi1) gins(x86.AMOVL, &ax, &lo1) gins(x86.AMOVL, &dx, &hi1) splitclean() }
/* * generate comparison of nl, nr, both 64-bit. * nl is memory; nr is constant or memory. */ func cmp64(nl *gc.Node, nr *gc.Node, op gc.Op, likely int, to *obj.Prog) { var lo1 gc.Node var hi1 gc.Node var lo2 gc.Node var hi2 gc.Node var rr gc.Node split64(nl, &lo1, &hi1) split64(nr, &lo2, &hi2) // compare most significant word; // if they differ, we're done. t := hi1.Type if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL { gins(x86.ACMPL, &hi1, &hi2) } else { gc.Regalloc(&rr, gc.Types[gc.TINT32], nil) gins(x86.AMOVL, &hi1, &rr) gins(x86.ACMPL, &rr, &hi2) gc.Regfree(&rr) } var br *obj.Prog switch op { default: gc.Fatalf("cmp64 %v %v", gc.Oconv(int(op), 0), t) // cmp hi // jne L // cmp lo // jeq to // L: case gc.OEQ: br = gc.Gbranch(x86.AJNE, nil, -likely) // cmp hi // jne to // cmp lo // jne to case gc.ONE: gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to) // cmp hi // jgt to // jlt L // cmp lo // jge to (or jgt to) // L: case gc.OGE, gc.OGT: gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to) br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely) // cmp hi // jlt to // jgt L // cmp lo // jle to (or jlt to) // L: case gc.OLE, gc.OLT: gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to) br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely) } // compare least significant word t = lo1.Type if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL { gins(x86.ACMPL, &lo1, &lo2) } else { gc.Regalloc(&rr, gc.Types[gc.TINT32], nil) gins(x86.AMOVL, &lo1, &rr) gins(x86.ACMPL, &rr, &lo2) gc.Regfree(&rr) } // jump again gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to) // point first branch down here if appropriate if br != nil { gc.Patch(br, gc.Pc) } splitclean() splitclean() }
/* * return Axxx for Oxxx on type t. */ func optoas(op int, t *gc.Type) int { if t == nil { gc.Fatal("optoas: t is nil") } a := obj.AXXX switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { default: gc.Fatal("optoas: no entry %v-%v etype %v simtype %v", gc.Oconv(int(op), 0), t, gc.Types[t.Etype], gc.Types[gc.Simtype[t.Etype]]) /* case CASE(OADDR, TPTR32): a = ALEAL; break; case CASE(OADDR, TPTR64): a = ALEAQ; break; */ // TODO(kaib): make sure the conditional branches work on all edge cases case gc.OEQ<<16 | gc.TBOOL, gc.OEQ<<16 | gc.TINT8, gc.OEQ<<16 | gc.TUINT8, gc.OEQ<<16 | gc.TINT16, gc.OEQ<<16 | gc.TUINT16, gc.OEQ<<16 | gc.TINT32, gc.OEQ<<16 | gc.TUINT32, gc.OEQ<<16 | gc.TINT64, gc.OEQ<<16 | gc.TUINT64, gc.OEQ<<16 | gc.TPTR32, gc.OEQ<<16 | gc.TPTR64, gc.OEQ<<16 | gc.TFLOAT32, gc.OEQ<<16 | gc.TFLOAT64: a = arm.ABEQ case gc.ONE<<16 | gc.TBOOL, gc.ONE<<16 | gc.TINT8, gc.ONE<<16 | gc.TUINT8, gc.ONE<<16 | gc.TINT16, gc.ONE<<16 | gc.TUINT16, gc.ONE<<16 | gc.TINT32, gc.ONE<<16 | gc.TUINT32, gc.ONE<<16 | gc.TINT64, gc.ONE<<16 | gc.TUINT64, gc.ONE<<16 | gc.TPTR32, gc.ONE<<16 | gc.TPTR64, gc.ONE<<16 | gc.TFLOAT32, gc.ONE<<16 | gc.TFLOAT64: a = arm.ABNE case gc.OLT<<16 | gc.TINT8, gc.OLT<<16 | gc.TINT16, gc.OLT<<16 | gc.TINT32, gc.OLT<<16 | gc.TINT64, gc.OLT<<16 | gc.TFLOAT32, gc.OLT<<16 | gc.TFLOAT64: a = arm.ABLT case gc.OLT<<16 | gc.TUINT8, gc.OLT<<16 | gc.TUINT16, gc.OLT<<16 | gc.TUINT32, gc.OLT<<16 | gc.TUINT64: a = arm.ABLO case gc.OLE<<16 | gc.TINT8, gc.OLE<<16 | gc.TINT16, gc.OLE<<16 | gc.TINT32, gc.OLE<<16 | gc.TINT64, gc.OLE<<16 | gc.TFLOAT32, gc.OLE<<16 | gc.TFLOAT64: a = arm.ABLE case gc.OLE<<16 | gc.TUINT8, gc.OLE<<16 | gc.TUINT16, gc.OLE<<16 | gc.TUINT32, gc.OLE<<16 | gc.TUINT64: a = arm.ABLS case gc.OGT<<16 | gc.TINT8, gc.OGT<<16 | gc.TINT16, gc.OGT<<16 | gc.TINT32, gc.OGT<<16 | gc.TINT64, gc.OGT<<16 | gc.TFLOAT32, gc.OGT<<16 | gc.TFLOAT64: a = arm.ABGT case gc.OGT<<16 | gc.TUINT8, gc.OGT<<16 | gc.TUINT16, gc.OGT<<16 | gc.TUINT32, gc.OGT<<16 | gc.TUINT64: a = arm.ABHI case gc.OGE<<16 | gc.TINT8, gc.OGE<<16 | gc.TINT16, gc.OGE<<16 | gc.TINT32, gc.OGE<<16 | gc.TINT64, gc.OGE<<16 | gc.TFLOAT32, gc.OGE<<16 | gc.TFLOAT64: a = arm.ABGE case gc.OGE<<16 | gc.TUINT8, gc.OGE<<16 | gc.TUINT16, gc.OGE<<16 | gc.TUINT32, gc.OGE<<16 | gc.TUINT64: a = arm.ABHS case gc.OCMP<<16 | gc.TBOOL, gc.OCMP<<16 | gc.TINT8, gc.OCMP<<16 | gc.TUINT8, gc.OCMP<<16 | gc.TINT16, gc.OCMP<<16 | gc.TUINT16, gc.OCMP<<16 | gc.TINT32, gc.OCMP<<16 | gc.TUINT32, gc.OCMP<<16 | gc.TPTR32: a = arm.ACMP case gc.OCMP<<16 | gc.TFLOAT32: a = arm.ACMPF case gc.OCMP<<16 | gc.TFLOAT64: a = arm.ACMPD case gc.OPS<<16 | gc.TFLOAT32, gc.OPS<<16 | gc.TFLOAT64: a = arm.ABVS case gc.OAS<<16 | gc.TBOOL: a = arm.AMOVB case gc.OAS<<16 | gc.TINT8: a = arm.AMOVBS case gc.OAS<<16 | gc.TUINT8: a = arm.AMOVBU case gc.OAS<<16 | gc.TINT16: a = arm.AMOVHS case gc.OAS<<16 | gc.TUINT16: a = arm.AMOVHU case gc.OAS<<16 | gc.TINT32, gc.OAS<<16 | gc.TUINT32, gc.OAS<<16 | gc.TPTR32: a = arm.AMOVW case gc.OAS<<16 | gc.TFLOAT32: a = arm.AMOVF case gc.OAS<<16 | gc.TFLOAT64: a = arm.AMOVD case gc.OADD<<16 | gc.TINT8, gc.OADD<<16 | gc.TUINT8, gc.OADD<<16 | gc.TINT16, gc.OADD<<16 | gc.TUINT16, gc.OADD<<16 | gc.TINT32, gc.OADD<<16 | gc.TUINT32, gc.OADD<<16 | gc.TPTR32: a = arm.AADD case gc.OADD<<16 | gc.TFLOAT32: a = arm.AADDF case gc.OADD<<16 | gc.TFLOAT64: a = arm.AADDD case gc.OSUB<<16 | gc.TINT8, gc.OSUB<<16 | gc.TUINT8, gc.OSUB<<16 | gc.TINT16, gc.OSUB<<16 | gc.TUINT16, gc.OSUB<<16 | gc.TINT32, gc.OSUB<<16 | gc.TUINT32, gc.OSUB<<16 | gc.TPTR32: a = arm.ASUB case gc.OSUB<<16 | gc.TFLOAT32: a = arm.ASUBF case gc.OSUB<<16 | gc.TFLOAT64: a = arm.ASUBD case gc.OMINUS<<16 | gc.TINT8, gc.OMINUS<<16 | gc.TUINT8, gc.OMINUS<<16 | gc.TINT16, gc.OMINUS<<16 | gc.TUINT16, gc.OMINUS<<16 | gc.TINT32, gc.OMINUS<<16 | gc.TUINT32, gc.OMINUS<<16 | gc.TPTR32: a = arm.ARSB case gc.OAND<<16 | gc.TINT8, gc.OAND<<16 | gc.TUINT8, gc.OAND<<16 | gc.TINT16, gc.OAND<<16 | gc.TUINT16, gc.OAND<<16 | gc.TINT32, gc.OAND<<16 | gc.TUINT32, gc.OAND<<16 | gc.TPTR32: a = arm.AAND case gc.OOR<<16 | gc.TINT8, gc.OOR<<16 | gc.TUINT8, gc.OOR<<16 | gc.TINT16, gc.OOR<<16 | gc.TUINT16, gc.OOR<<16 | gc.TINT32, gc.OOR<<16 | gc.TUINT32, gc.OOR<<16 | gc.TPTR32: a = arm.AORR case gc.OXOR<<16 | gc.TINT8, gc.OXOR<<16 | gc.TUINT8, gc.OXOR<<16 | gc.TINT16, gc.OXOR<<16 | gc.TUINT16, gc.OXOR<<16 | gc.TINT32, gc.OXOR<<16 | gc.TUINT32, gc.OXOR<<16 | gc.TPTR32: a = arm.AEOR case gc.OLSH<<16 | gc.TINT8, gc.OLSH<<16 | gc.TUINT8, gc.OLSH<<16 | gc.TINT16, gc.OLSH<<16 | gc.TUINT16, gc.OLSH<<16 | gc.TINT32, gc.OLSH<<16 | gc.TUINT32, gc.OLSH<<16 | gc.TPTR32: a = arm.ASLL case gc.ORSH<<16 | gc.TUINT8, gc.ORSH<<16 | gc.TUINT16, gc.ORSH<<16 | gc.TUINT32, gc.ORSH<<16 | gc.TPTR32: a = arm.ASRL case gc.ORSH<<16 | gc.TINT8, gc.ORSH<<16 | gc.TINT16, gc.ORSH<<16 | gc.TINT32: a = arm.ASRA case gc.OMUL<<16 | gc.TUINT8, gc.OMUL<<16 | gc.TUINT16, gc.OMUL<<16 | gc.TUINT32, gc.OMUL<<16 | gc.TPTR32: a = arm.AMULU case gc.OMUL<<16 | gc.TINT8, gc.OMUL<<16 | gc.TINT16, gc.OMUL<<16 | gc.TINT32: a = arm.AMUL case gc.OMUL<<16 | gc.TFLOAT32: a = arm.AMULF case gc.OMUL<<16 | gc.TFLOAT64: a = arm.AMULD case gc.ODIV<<16 | gc.TUINT8, gc.ODIV<<16 | gc.TUINT16, gc.ODIV<<16 | gc.TUINT32, gc.ODIV<<16 | gc.TPTR32: a = arm.ADIVU case gc.ODIV<<16 | gc.TINT8, gc.ODIV<<16 | gc.TINT16, gc.ODIV<<16 | gc.TINT32: a = arm.ADIV case gc.OMOD<<16 | gc.TUINT8, gc.OMOD<<16 | gc.TUINT16, gc.OMOD<<16 | gc.TUINT32, gc.OMOD<<16 | gc.TPTR32: a = arm.AMODU case gc.OMOD<<16 | gc.TINT8, gc.OMOD<<16 | gc.TINT16, gc.OMOD<<16 | gc.TINT32: a = arm.AMOD // case CASE(OEXTEND, TINT16): // a = ACWD; // break; // case CASE(OEXTEND, TINT32): // a = ACDQ; // break; // case CASE(OEXTEND, TINT64): // a = ACQO; // break; case gc.ODIV<<16 | gc.TFLOAT32: a = arm.ADIVF case gc.ODIV<<16 | gc.TFLOAT64: a = arm.ADIVD case gc.OSQRT<<16 | gc.TFLOAT64: a = arm.ASQRTD } return a }
/* * return Axxx for Oxxx on type t. */ func optoas(op int, t *gc.Type) int { if t == nil { gc.Fatalf("optoas: t is nil") } a := int(obj.AXXX) switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { default: gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t) case gc.OEQ<<16 | gc.TBOOL, gc.OEQ<<16 | gc.TINT8, gc.OEQ<<16 | gc.TUINT8, gc.OEQ<<16 | gc.TINT16, gc.OEQ<<16 | gc.TUINT16, gc.OEQ<<16 | gc.TINT32, gc.OEQ<<16 | gc.TUINT32, gc.OEQ<<16 | gc.TINT64, gc.OEQ<<16 | gc.TUINT64, gc.OEQ<<16 | gc.TPTR32, gc.OEQ<<16 | gc.TPTR64, gc.OEQ<<16 | gc.TFLOAT32, gc.OEQ<<16 | gc.TFLOAT64: a = arm64.ABEQ case gc.ONE<<16 | gc.TBOOL, gc.ONE<<16 | gc.TINT8, gc.ONE<<16 | gc.TUINT8, gc.ONE<<16 | gc.TINT16, gc.ONE<<16 | gc.TUINT16, gc.ONE<<16 | gc.TINT32, gc.ONE<<16 | gc.TUINT32, gc.ONE<<16 | gc.TINT64, gc.ONE<<16 | gc.TUINT64, gc.ONE<<16 | gc.TPTR32, gc.ONE<<16 | gc.TPTR64, gc.ONE<<16 | gc.TFLOAT32, gc.ONE<<16 | gc.TFLOAT64: a = arm64.ABNE case gc.OLT<<16 | gc.TINT8, gc.OLT<<16 | gc.TINT16, gc.OLT<<16 | gc.TINT32, gc.OLT<<16 | gc.TINT64: a = arm64.ABLT case gc.OLT<<16 | gc.TUINT8, gc.OLT<<16 | gc.TUINT16, gc.OLT<<16 | gc.TUINT32, gc.OLT<<16 | gc.TUINT64, gc.OLT<<16 | gc.TFLOAT32, gc.OLT<<16 | gc.TFLOAT64: a = arm64.ABLO case gc.OLE<<16 | gc.TINT8, gc.OLE<<16 | gc.TINT16, gc.OLE<<16 | gc.TINT32, gc.OLE<<16 | gc.TINT64: a = arm64.ABLE case gc.OLE<<16 | gc.TUINT8, gc.OLE<<16 | gc.TUINT16, gc.OLE<<16 | gc.TUINT32, gc.OLE<<16 | gc.TUINT64, gc.OLE<<16 | gc.TFLOAT32, gc.OLE<<16 | gc.TFLOAT64: a = arm64.ABLS case gc.OGT<<16 | gc.TINT8, gc.OGT<<16 | gc.TINT16, gc.OGT<<16 | gc.TINT32, gc.OGT<<16 | gc.TINT64, gc.OGT<<16 | gc.TFLOAT32, gc.OGT<<16 | gc.TFLOAT64: a = arm64.ABGT case gc.OGT<<16 | gc.TUINT8, gc.OGT<<16 | gc.TUINT16, gc.OGT<<16 | gc.TUINT32, gc.OGT<<16 | gc.TUINT64: a = arm64.ABHI case gc.OGE<<16 | gc.TINT8, gc.OGE<<16 | gc.TINT16, gc.OGE<<16 | gc.TINT32, gc.OGE<<16 | gc.TINT64, gc.OGE<<16 | gc.TFLOAT32, gc.OGE<<16 | gc.TFLOAT64: a = arm64.ABGE case gc.OGE<<16 | gc.TUINT8, gc.OGE<<16 | gc.TUINT16, gc.OGE<<16 | gc.TUINT32, gc.OGE<<16 | gc.TUINT64: a = arm64.ABHS case gc.OCMP<<16 | gc.TBOOL, gc.OCMP<<16 | gc.TINT8, gc.OCMP<<16 | gc.TINT16, gc.OCMP<<16 | gc.TINT32, gc.OCMP<<16 | gc.TPTR32, gc.OCMP<<16 | gc.TINT64, gc.OCMP<<16 | gc.TUINT8, gc.OCMP<<16 | gc.TUINT16, gc.OCMP<<16 | gc.TUINT32, gc.OCMP<<16 | gc.TUINT64, gc.OCMP<<16 | gc.TPTR64: a = arm64.ACMP case gc.OCMP<<16 | gc.TFLOAT32: a = arm64.AFCMPS case gc.OCMP<<16 | gc.TFLOAT64: a = arm64.AFCMPD case gc.OAS<<16 | gc.TBOOL, gc.OAS<<16 | gc.TINT8: a = arm64.AMOVB case gc.OAS<<16 | gc.TUINT8: a = arm64.AMOVBU case gc.OAS<<16 | gc.TINT16: a = arm64.AMOVH case gc.OAS<<16 | gc.TUINT16: a = arm64.AMOVHU case gc.OAS<<16 | gc.TINT32: a = arm64.AMOVW case gc.OAS<<16 | gc.TUINT32, gc.OAS<<16 | gc.TPTR32: a = arm64.AMOVWU case gc.OAS<<16 | gc.TINT64, gc.OAS<<16 | gc.TUINT64, gc.OAS<<16 | gc.TPTR64: a = arm64.AMOVD case gc.OAS<<16 | gc.TFLOAT32: a = arm64.AFMOVS case gc.OAS<<16 | gc.TFLOAT64: a = arm64.AFMOVD case gc.OADD<<16 | gc.TINT8, gc.OADD<<16 | gc.TUINT8, gc.OADD<<16 | gc.TINT16, gc.OADD<<16 | gc.TUINT16, gc.OADD<<16 | gc.TINT32, gc.OADD<<16 | gc.TUINT32, gc.OADD<<16 | gc.TPTR32, gc.OADD<<16 | gc.TINT64, gc.OADD<<16 | gc.TUINT64, gc.OADD<<16 | gc.TPTR64: a = arm64.AADD case gc.OADD<<16 | gc.TFLOAT32: a = arm64.AFADDS case gc.OADD<<16 | gc.TFLOAT64: a = arm64.AFADDD case gc.OSUB<<16 | gc.TINT8, gc.OSUB<<16 | gc.TUINT8, gc.OSUB<<16 | gc.TINT16, gc.OSUB<<16 | gc.TUINT16, gc.OSUB<<16 | gc.TINT32, gc.OSUB<<16 | gc.TUINT32, gc.OSUB<<16 | gc.TPTR32, gc.OSUB<<16 | gc.TINT64, gc.OSUB<<16 | gc.TUINT64, gc.OSUB<<16 | gc.TPTR64: a = arm64.ASUB case gc.OSUB<<16 | gc.TFLOAT32: a = arm64.AFSUBS case gc.OSUB<<16 | gc.TFLOAT64: a = arm64.AFSUBD case gc.OMINUS<<16 | gc.TINT8, gc.OMINUS<<16 | gc.TUINT8, gc.OMINUS<<16 | gc.TINT16, gc.OMINUS<<16 | gc.TUINT16, gc.OMINUS<<16 | gc.TINT32, gc.OMINUS<<16 | gc.TUINT32, gc.OMINUS<<16 | gc.TPTR32, gc.OMINUS<<16 | gc.TINT64, gc.OMINUS<<16 | gc.TUINT64, gc.OMINUS<<16 | gc.TPTR64: a = arm64.ANEG case gc.OMINUS<<16 | gc.TFLOAT32: a = arm64.AFNEGS case gc.OMINUS<<16 | gc.TFLOAT64: a = arm64.AFNEGD case gc.OAND<<16 | gc.TINT8, gc.OAND<<16 | gc.TUINT8, gc.OAND<<16 | gc.TINT16, gc.OAND<<16 | gc.TUINT16, gc.OAND<<16 | gc.TINT32, gc.OAND<<16 | gc.TUINT32, gc.OAND<<16 | gc.TPTR32, gc.OAND<<16 | gc.TINT64, gc.OAND<<16 | gc.TUINT64, gc.OAND<<16 | gc.TPTR64: a = arm64.AAND case gc.OOR<<16 | gc.TINT8, gc.OOR<<16 | gc.TUINT8, gc.OOR<<16 | gc.TINT16, gc.OOR<<16 | gc.TUINT16, gc.OOR<<16 | gc.TINT32, gc.OOR<<16 | gc.TUINT32, gc.OOR<<16 | gc.TPTR32, gc.OOR<<16 | gc.TINT64, gc.OOR<<16 | gc.TUINT64, gc.OOR<<16 | gc.TPTR64: a = arm64.AORR case gc.OXOR<<16 | gc.TINT8, gc.OXOR<<16 | gc.TUINT8, gc.OXOR<<16 | gc.TINT16, gc.OXOR<<16 | gc.TUINT16, gc.OXOR<<16 | gc.TINT32, gc.OXOR<<16 | gc.TUINT32, gc.OXOR<<16 | gc.TPTR32, gc.OXOR<<16 | gc.TINT64, gc.OXOR<<16 | gc.TUINT64, gc.OXOR<<16 | gc.TPTR64: a = arm64.AEOR // TODO(minux): handle rotates //case CASE(OLROT, TINT8): //case CASE(OLROT, TUINT8): //case CASE(OLROT, TINT16): //case CASE(OLROT, TUINT16): //case CASE(OLROT, TINT32): //case CASE(OLROT, TUINT32): //case CASE(OLROT, TPTR32): //case CASE(OLROT, TINT64): //case CASE(OLROT, TUINT64): //case CASE(OLROT, TPTR64): // a = 0//???; RLDC? // break; case gc.OLSH<<16 | gc.TINT8, gc.OLSH<<16 | gc.TUINT8, gc.OLSH<<16 | gc.TINT16, gc.OLSH<<16 | gc.TUINT16, gc.OLSH<<16 | gc.TINT32, gc.OLSH<<16 | gc.TUINT32, gc.OLSH<<16 | gc.TPTR32, gc.OLSH<<16 | gc.TINT64, gc.OLSH<<16 | gc.TUINT64, gc.OLSH<<16 | gc.TPTR64: a = arm64.ALSL case gc.ORSH<<16 | gc.TUINT8, gc.ORSH<<16 | gc.TUINT16, gc.ORSH<<16 | gc.TUINT32, gc.ORSH<<16 | gc.TPTR32, gc.ORSH<<16 | gc.TUINT64, gc.ORSH<<16 | gc.TPTR64: a = arm64.ALSR case gc.ORSH<<16 | gc.TINT8, gc.ORSH<<16 | gc.TINT16, gc.ORSH<<16 | gc.TINT32, gc.ORSH<<16 | gc.TINT64: a = arm64.AASR // TODO(minux): handle rotates //case CASE(ORROTC, TINT8): //case CASE(ORROTC, TUINT8): //case CASE(ORROTC, TINT16): //case CASE(ORROTC, TUINT16): //case CASE(ORROTC, TINT32): //case CASE(ORROTC, TUINT32): //case CASE(ORROTC, TINT64): //case CASE(ORROTC, TUINT64): // a = 0//??? RLDC?? // break; case gc.OHMUL<<16 | gc.TINT64: a = arm64.ASMULH case gc.OHMUL<<16 | gc.TUINT64, gc.OHMUL<<16 | gc.TPTR64: a = arm64.AUMULH case gc.OMUL<<16 | gc.TINT8, gc.OMUL<<16 | gc.TINT16, gc.OMUL<<16 | gc.TINT32: a = arm64.ASMULL case gc.OMUL<<16 | gc.TINT64: a = arm64.AMUL case gc.OMUL<<16 | gc.TUINT8, gc.OMUL<<16 | gc.TUINT16, gc.OMUL<<16 | gc.TUINT32, gc.OMUL<<16 | gc.TPTR32: // don't use word multiply, the high 32-bit are undefined. a = arm64.AUMULL case gc.OMUL<<16 | gc.TUINT64, gc.OMUL<<16 | gc.TPTR64: a = arm64.AMUL // for 64-bit multiplies, signedness doesn't matter. case gc.OMUL<<16 | gc.TFLOAT32: a = arm64.AFMULS case gc.OMUL<<16 | gc.TFLOAT64: a = arm64.AFMULD case gc.ODIV<<16 | gc.TINT8, gc.ODIV<<16 | gc.TINT16, gc.ODIV<<16 | gc.TINT32, gc.ODIV<<16 | gc.TINT64: a = arm64.ASDIV case gc.ODIV<<16 | gc.TUINT8, gc.ODIV<<16 | gc.TUINT16, gc.ODIV<<16 | gc.TUINT32, gc.ODIV<<16 | gc.TPTR32, gc.ODIV<<16 | gc.TUINT64, gc.ODIV<<16 | gc.TPTR64: a = arm64.AUDIV case gc.ODIV<<16 | gc.TFLOAT32: a = arm64.AFDIVS case gc.ODIV<<16 | gc.TFLOAT64: a = arm64.AFDIVD case gc.OSQRT<<16 | gc.TFLOAT64: a = arm64.AFSQRTD } return a }
/* * return Axxx for Oxxx on type t. */ func optoas(op gc.Op, t *gc.Type) int { if t == nil { gc.Fatalf("optoas: t is nil") } // avoid constant conversions in switches below const ( OMINUS_ = uint32(gc.OMINUS) << 16 OLSH_ = uint32(gc.OLSH) << 16 ORSH_ = uint32(gc.ORSH) << 16 OADD_ = uint32(gc.OADD) << 16 OSUB_ = uint32(gc.OSUB) << 16 OMUL_ = uint32(gc.OMUL) << 16 ODIV_ = uint32(gc.ODIV) << 16 OMOD_ = uint32(gc.OMOD) << 16 OOR_ = uint32(gc.OOR) << 16 OAND_ = uint32(gc.OAND) << 16 OXOR_ = uint32(gc.OXOR) << 16 OEQ_ = uint32(gc.OEQ) << 16 ONE_ = uint32(gc.ONE) << 16 OLT_ = uint32(gc.OLT) << 16 OLE_ = uint32(gc.OLE) << 16 OGE_ = uint32(gc.OGE) << 16 OGT_ = uint32(gc.OGT) << 16 OCMP_ = uint32(gc.OCMP) << 16 OPS_ = uint32(gc.OPS) << 16 OAS_ = uint32(gc.OAS) << 16 OSQRT_ = uint32(gc.OSQRT) << 16 ) a := obj.AXXX switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { default: gc.Fatalf("optoas: no entry %v-%v etype %v simtype %v", gc.Oconv(int(op), 0), t, gc.Types[t.Etype], gc.Types[gc.Simtype[t.Etype]]) /* case CASE(OADDR, TPTR32): a = ALEAL; break; case CASE(OADDR, TPTR64): a = ALEAQ; break; */ // TODO(kaib): make sure the conditional branches work on all edge cases case OEQ_ | gc.TBOOL, OEQ_ | gc.TINT8, OEQ_ | gc.TUINT8, OEQ_ | gc.TINT16, OEQ_ | gc.TUINT16, OEQ_ | gc.TINT32, OEQ_ | gc.TUINT32, OEQ_ | gc.TINT64, OEQ_ | gc.TUINT64, OEQ_ | gc.TPTR32, OEQ_ | gc.TPTR64, OEQ_ | gc.TFLOAT32, OEQ_ | gc.TFLOAT64: a = arm.ABEQ case ONE_ | gc.TBOOL, ONE_ | gc.TINT8, ONE_ | gc.TUINT8, ONE_ | gc.TINT16, ONE_ | gc.TUINT16, ONE_ | gc.TINT32, ONE_ | gc.TUINT32, ONE_ | gc.TINT64, ONE_ | gc.TUINT64, ONE_ | gc.TPTR32, ONE_ | gc.TPTR64, ONE_ | gc.TFLOAT32, ONE_ | gc.TFLOAT64: a = arm.ABNE case OLT_ | gc.TINT8, OLT_ | gc.TINT16, OLT_ | gc.TINT32, OLT_ | gc.TINT64, OLT_ | gc.TFLOAT32, OLT_ | gc.TFLOAT64: a = arm.ABLT case OLT_ | gc.TUINT8, OLT_ | gc.TUINT16, OLT_ | gc.TUINT32, OLT_ | gc.TUINT64: a = arm.ABLO case OLE_ | gc.TINT8, OLE_ | gc.TINT16, OLE_ | gc.TINT32, OLE_ | gc.TINT64, OLE_ | gc.TFLOAT32, OLE_ | gc.TFLOAT64: a = arm.ABLE case OLE_ | gc.TUINT8, OLE_ | gc.TUINT16, OLE_ | gc.TUINT32, OLE_ | gc.TUINT64: a = arm.ABLS case OGT_ | gc.TINT8, OGT_ | gc.TINT16, OGT_ | gc.TINT32, OGT_ | gc.TINT64, OGT_ | gc.TFLOAT32, OGT_ | gc.TFLOAT64: a = arm.ABGT case OGT_ | gc.TUINT8, OGT_ | gc.TUINT16, OGT_ | gc.TUINT32, OGT_ | gc.TUINT64: a = arm.ABHI case OGE_ | gc.TINT8, OGE_ | gc.TINT16, OGE_ | gc.TINT32, OGE_ | gc.TINT64, OGE_ | gc.TFLOAT32, OGE_ | gc.TFLOAT64: a = arm.ABGE case OGE_ | gc.TUINT8, OGE_ | gc.TUINT16, OGE_ | gc.TUINT32, OGE_ | gc.TUINT64: a = arm.ABHS case OCMP_ | gc.TBOOL, OCMP_ | gc.TINT8, OCMP_ | gc.TUINT8, OCMP_ | gc.TINT16, OCMP_ | gc.TUINT16, OCMP_ | gc.TINT32, OCMP_ | gc.TUINT32, OCMP_ | gc.TPTR32: a = arm.ACMP case OCMP_ | gc.TFLOAT32: a = arm.ACMPF case OCMP_ | gc.TFLOAT64: a = arm.ACMPD case OPS_ | gc.TFLOAT32, OPS_ | gc.TFLOAT64: a = arm.ABVS case OAS_ | gc.TBOOL: a = arm.AMOVB case OAS_ | gc.TINT8: a = arm.AMOVBS case OAS_ | gc.TUINT8: a = arm.AMOVBU case OAS_ | gc.TINT16: a = arm.AMOVHS case OAS_ | gc.TUINT16: a = arm.AMOVHU case OAS_ | gc.TINT32, OAS_ | gc.TUINT32, OAS_ | gc.TPTR32: a = arm.AMOVW case OAS_ | gc.TFLOAT32: a = arm.AMOVF case OAS_ | gc.TFLOAT64: a = arm.AMOVD case OADD_ | gc.TINT8, OADD_ | gc.TUINT8, OADD_ | gc.TINT16, OADD_ | gc.TUINT16, OADD_ | gc.TINT32, OADD_ | gc.TUINT32, OADD_ | gc.TPTR32: a = arm.AADD case OADD_ | gc.TFLOAT32: a = arm.AADDF case OADD_ | gc.TFLOAT64: a = arm.AADDD case OSUB_ | gc.TINT8, OSUB_ | gc.TUINT8, OSUB_ | gc.TINT16, OSUB_ | gc.TUINT16, OSUB_ | gc.TINT32, OSUB_ | gc.TUINT32, OSUB_ | gc.TPTR32: a = arm.ASUB case OSUB_ | gc.TFLOAT32: a = arm.ASUBF case OSUB_ | gc.TFLOAT64: a = arm.ASUBD case OMINUS_ | gc.TINT8, OMINUS_ | gc.TUINT8, OMINUS_ | gc.TINT16, OMINUS_ | gc.TUINT16, OMINUS_ | gc.TINT32, OMINUS_ | gc.TUINT32, OMINUS_ | gc.TPTR32: a = arm.ARSB case OAND_ | gc.TINT8, OAND_ | gc.TUINT8, OAND_ | gc.TINT16, OAND_ | gc.TUINT16, OAND_ | gc.TINT32, OAND_ | gc.TUINT32, OAND_ | gc.TPTR32: a = arm.AAND case OOR_ | gc.TINT8, OOR_ | gc.TUINT8, OOR_ | gc.TINT16, OOR_ | gc.TUINT16, OOR_ | gc.TINT32, OOR_ | gc.TUINT32, OOR_ | gc.TPTR32: a = arm.AORR case OXOR_ | gc.TINT8, OXOR_ | gc.TUINT8, OXOR_ | gc.TINT16, OXOR_ | gc.TUINT16, OXOR_ | gc.TINT32, OXOR_ | gc.TUINT32, OXOR_ | gc.TPTR32: a = arm.AEOR case OLSH_ | gc.TINT8, OLSH_ | gc.TUINT8, OLSH_ | gc.TINT16, OLSH_ | gc.TUINT16, OLSH_ | gc.TINT32, OLSH_ | gc.TUINT32, OLSH_ | gc.TPTR32: a = arm.ASLL case ORSH_ | gc.TUINT8, ORSH_ | gc.TUINT16, ORSH_ | gc.TUINT32, ORSH_ | gc.TPTR32: a = arm.ASRL case ORSH_ | gc.TINT8, ORSH_ | gc.TINT16, ORSH_ | gc.TINT32: a = arm.ASRA case OMUL_ | gc.TUINT8, OMUL_ | gc.TUINT16, OMUL_ | gc.TUINT32, OMUL_ | gc.TPTR32: a = arm.AMULU case OMUL_ | gc.TINT8, OMUL_ | gc.TINT16, OMUL_ | gc.TINT32: a = arm.AMUL case OMUL_ | gc.TFLOAT32: a = arm.AMULF case OMUL_ | gc.TFLOAT64: a = arm.AMULD case ODIV_ | gc.TUINT8, ODIV_ | gc.TUINT16, ODIV_ | gc.TUINT32, ODIV_ | gc.TPTR32: a = arm.ADIVU case ODIV_ | gc.TINT8, ODIV_ | gc.TINT16, ODIV_ | gc.TINT32: a = arm.ADIV case OMOD_ | gc.TUINT8, OMOD_ | gc.TUINT16, OMOD_ | gc.TUINT32, OMOD_ | gc.TPTR32: a = arm.AMODU case OMOD_ | gc.TINT8, OMOD_ | gc.TINT16, OMOD_ | gc.TINT32: a = arm.AMOD // case CASE(OEXTEND, TINT16): // a = ACWD; // break; // case CASE(OEXTEND, TINT32): // a = ACDQ; // break; // case CASE(OEXTEND, TINT64): // a = ACQO; // break; case ODIV_ | gc.TFLOAT32: a = arm.ADIVF case ODIV_ | gc.TFLOAT64: a = arm.ADIVD case OSQRT_ | gc.TFLOAT64: a = arm.ASQRTD } return a }