]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.ssa] cmd/compile/internal/ssa: add call opcodes
authorKeith Randall <khr@golang.org>
Wed, 10 Jun 2015 22:03:06 +0000 (15:03 -0700)
committerKeith Randall <khr@golang.org>
Thu, 11 Jun 2015 03:10:01 +0000 (03:10 +0000)
Add calls, particularly closure calls.

Reorg SSAable variable test for converting to SSA.

Change-Id: Ia75c04295e6b0b040122f97e2381836a393b7f42
Reviewed-on: https://go-review.googlesource.com/10912
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
src/cmd/compile/internal/gc/opnames.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/ssa/TODO
src/cmd/compile/internal/ssa/gen/AMD64.rules
src/cmd/compile/internal/ssa/gen/AMD64Ops.go
src/cmd/compile/internal/ssa/gen/genericOps.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/rewriteAMD64.go

index fc03ec66662934afda735bf2d1c2161d19eb65fa..9134bd43329327d816de3021e901677621600e8f 100644 (file)
@@ -33,6 +33,7 @@ var opnames = []string{
        OAS2MAPR:         "AS2MAPR",
        OAS2DOTTYPE:      "AS2DOTTYPE",
        OASOP:            "ASOP",
+       OASWB:            "ASWB",
        OCALL:            "CALL",
        OCALLFUNC:        "CALLFUNC",
        OCALLMETH:        "CALLMETH",
index 773d79ba307f7cd6871898c188ca6f3ee6af3bea..fd47c54ad0f96228fa43502538a38a125799340f 100644 (file)
@@ -224,8 +224,9 @@ func (s *state) stmt(n *Node) {
                        s.startBlock(t)
                }
 
-       case OAS:
+       case OAS, OASWB:
                // TODO(khr): colas?
+               // TODO: do write barrier
                var val *ssa.Value
                if n.Right == nil {
                        // n.Right == nil means use the zero value of the assigned type.
@@ -243,15 +244,14 @@ func (s *state) stmt(n *Node) {
                } else {
                        val = s.expr(n.Right)
                }
-               if n.Left.Op == ONAME && !n.Left.Addrtaken && n.Left.Class&PHEAP == 0 && n.Left.Class != PEXTERN && n.Left.Class != PPARAMOUT {
-                       // ssa-able variable.
+               if n.Left.Op == ONAME && canSSA(n.Left) {
+                       // Update variable assignment.
                        s.vars[n.Left.Sym.Name] = val
                        return
                }
                // not ssa-able.  Treat as a store.
                addr := s.addr(n.Left)
                s.vars[".mem"] = s.newValue3(ssa.OpStore, ssa.TypeMem, nil, addr, val, s.mem())
-               // TODO: try to make more variables registerizeable.
        case OIF:
                cond := s.expr(n.Ntest)
                b := s.endBlock()
@@ -338,14 +338,16 @@ func (s *state) expr(n *Node) *ssa.Value {
 
        switch n.Op {
        case ONAME:
-               // TODO: remember offsets for PPARAM names
-               if n.Class == PEXTERN {
-                       // global variable
-                       addr := s.entryNewValue(ssa.OpGlobal, Ptrto(n.Type), n.Sym)
-                       return s.newValue2(ssa.OpLoad, n.Type, nil, addr, s.mem())
+               if n.Class == PFUNC {
+                       // "value" of a function is the address of the function's closure
+                       return s.entryNewValue(ssa.OpGlobal, Ptrto(n.Type), funcsym(n.Sym))
+               }
+               s.argOffsets[n.Sym.Name] = n.Xoffset // TODO: remember this another way?
+               if canSSA(n) {
+                       return s.variable(n.Sym.Name, n.Type)
                }
-               s.argOffsets[n.Sym.Name] = n.Xoffset
-               return s.variable(n.Sym.Name, n.Type)
+               addr := s.addr(n)
+               return s.newValue2(ssa.OpLoad, n.Type, nil, addr, s.mem())
        case OLITERAL:
                switch n.Val.Ctype {
                case CTINT:
@@ -415,17 +417,25 @@ func (s *state) expr(n *Node) *ssa.Value {
                }
 
        case OCALLFUNC:
+               static := n.Left.Op == ONAME && n.Left.Class == PFUNC
+
+               // evaluate closure
+               var closure *ssa.Value
+               if !static {
+                       closure = s.expr(n.Left)
+               }
+
                // run all argument assignments
-               // TODO(khr): do we need to evaluate function first?
-               // Or is it already side-effect-free and does not require a call?
                s.stmtList(n.List)
 
-               if n.Left.Op != ONAME {
-                       // TODO(khr): closure calls?
-                       log.Fatalf("can't handle CALLFUNC with non-ONAME fn %s", opnames[n.Left.Op])
-               }
                bNext := s.f.NewBlock(ssa.BlockPlain)
-               call := s.newValue1(ssa.OpStaticCall, ssa.TypeMem, n.Left.Sym, s.mem())
+               var call *ssa.Value
+               if static {
+                       call = s.newValue1(ssa.OpStaticCall, ssa.TypeMem, n.Left.Sym, s.mem())
+               } else {
+                       entry := s.newValue2(ssa.OpLoad, s.config.Uintptr, nil, closure, s.mem())
+                       call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, nil, entry, closure, s.mem())
+               }
                b := s.endBlock()
                b.Kind = ssa.BlockCall
                b.Control = call
@@ -448,17 +458,18 @@ func (s *state) expr(n *Node) *ssa.Value {
 func (s *state) addr(n *Node) *ssa.Value {
        switch n.Op {
        case ONAME:
-               if n.Class == PEXTERN {
+               switch n.Class {
+               case PEXTERN:
                        // global variable
                        return s.entryNewValue(ssa.OpGlobal, Ptrto(n.Type), n.Sym)
-               }
-               if n.Class == PPARAMOUT {
+               case PPARAMOUT:
                        // store to parameter slot
                        return s.entryNewValue1(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.fp)
+               default:
+                       // TODO: address of locals
+                       log.Fatalf("variable address of %v not implemented", n)
+                       return nil
                }
-               // TODO: address of locals
-               log.Fatalf("variable address of %v not implemented", n)
-               return nil
        case OINDREG:
                // indirect off a register (TODO: always SP?)
                // used for storing/loading arguments/returns to/from callees
@@ -484,6 +495,28 @@ func (s *state) addr(n *Node) *ssa.Value {
        }
 }
 
+// canSSA reports whether n is SSA-able.
+// n must be an ONAME.
+func canSSA(n *Node) bool {
+       if n.Op != ONAME {
+               log.Fatalf("canSSA passed a non-ONAME %s %v", Oconv(int(n.Op), 0), n)
+       }
+       if n.Addrtaken {
+               return false
+       }
+       if n.Class&PHEAP != 0 {
+               return false
+       }
+       if n.Class == PEXTERN {
+               return false
+       }
+       if n.Class == PPARAMOUT {
+               return false
+       }
+       return true
+       // TODO: try to make more variables SSAable.
+}
+
 // nilCheck generates nil pointer checking code.
 // Starts a new block on return.
 func (s *state) nilCheck(ptr *ssa.Value) {
@@ -854,11 +887,15 @@ func genValue(v *ssa.Value) {
                p.From.Offset = g.Offset
                p.To.Type = obj.TYPE_REG
                p.To.Reg = regnum(v)
-       case ssa.OpStaticCall:
+       case ssa.OpAMD64CALLstatic:
                p := Prog(obj.ACALL)
                p.To.Type = obj.TYPE_MEM
                p.To.Name = obj.NAME_EXTERN
                p.To.Sym = Linksym(v.Aux.(*Sym))
+       case ssa.OpAMD64CALLclosure:
+               p := Prog(obj.ACALL)
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = regnum(v.Args[0])
        case ssa.OpFP, ssa.OpSP:
                // nothing to do
        default:
index 7cd2206db34e520e820d55051345e8f9337d295b..d5e8788e36cfc4bc08886965b38b1d91b654ddff 100644 (file)
@@ -26,6 +26,7 @@ Opcodes
  - It's annoying to list the opcode both in the opcode list and an
    opInfo map entry.  Specify it one place and use go:generate to
    produce both?
+ - Write barriers
 
 Regalloc
  - Make less arch-dependent
@@ -33,6 +34,7 @@ Regalloc
  - Allow args and return values to be ssa-able.
  - Handle 2-address instructions.
  - Floating point registers
+ - Make calls clobber all registers
 
 Rewrites
  - Strength reduction (both arch-indep and arch-dependent?)
@@ -51,3 +53,4 @@ Common-Subexpression Elimination
 Other
  - Make go:generate less painful.  Have a subpackage that just has the
    generate commands in it?
+ - Use gc.Fatal for errors.  Add a callback to Frontend?
index c4ff74442174b7db68d0a13298afd43c5f2a5dcd..15cd79a3f519ce542e78687cb3dd37b3ee7a435f 100644 (file)
@@ -40,6 +40,9 @@
 (If (SETB cmp) yes no) -> (ULT cmp yes no)
 (If cond yes no) && cond.Op == OpAMD64MOVBload -> (NE (TESTB <TypeFlags> cond cond) yes no)
 
+(StaticCall [target] mem) -> (CALLstatic [target] mem)
+(ClosureCall entry closure mem) -> (CALLclosure entry closure mem)
+
 // Rules below here apply some simple optimizations after lowering.
 // TODO: Should this be a separate pass?
 
index 38d1e87575e95a4a3125e57da9e45cd949a9f251..b3b2e3b5e28be32eaa158832a70c8c53c1d77729 100644 (file)
@@ -132,6 +132,10 @@ func init() {
                {name: "MOVQloadglobal"},  // Load from aux.(GlobalOffset).  arg0 = memory
                {name: "MOVQstoreglobal"}, // store arg0 to aux.(GlobalOffset).  arg1=memory, returns memory.
 
+               //TODO: set register clobber to everything?
+               {name: "CALLstatic"},                                                            // call static function.  arg0=mem, returns mem
+               {name: "CALLclosure", reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, 0, nil}}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem returns mem
+
                {name: "REPMOVSB", reg: regInfo{[]regMask{buildReg("DI"), buildReg("SI"), buildReg("CX")}, buildReg("DI SI CX"), nil}}, // move arg2 bytes from arg1 to arg0.  arg3=mem, returns memory
 
                {name: "ADDL", reg: gp21}, // arg0+arg1
index e8c3cbeb8af673bb0e6b975eb9375b1fc6e61118..e415f3d16b23b5e224aa24b08624568d08ba1bf0 100644 (file)
@@ -44,8 +44,8 @@ var genericOps = []opData{
        // Function calls.  Arguments to the call have already been written to the stack.
        // Return values appear on the stack.  The method receiver, if any, is treated
        // as a phantom first argument.
-       {name: "Call"},       // arg0=code pointer, arg1=context ptr, arg2=memory.  Returns memory.
-       {name: "StaticCall"}, // call function aux.(*gc.Sym), arg0=memory.  Returns memory.
+       {name: "ClosureCall"}, // arg0=code pointer, arg1=context ptr, arg2=memory.  Returns memory.
+       {name: "StaticCall"},  // call function aux.(*gc.Sym), arg0=memory.  Returns memory.
 
        // Conversions
        {name: "Convert"}, // convert arg0 to another type
index 604f09615281bc067ff33193ab4f36dcef26b2b5..550f641c144f52612e88e2ce73584c23554f78b9 100644 (file)
@@ -82,6 +82,8 @@ const (
        OpAMD64MOVQstoreidx8
        OpAMD64MOVQloadglobal
        OpAMD64MOVQstoreglobal
+       OpAMD64CALLstatic
+       OpAMD64CALLclosure
        OpAMD64REPMOVSB
        OpAMD64ADDL
        OpAMD64InvertFlags
@@ -103,7 +105,7 @@ const (
        OpLoad
        OpStore
        OpMove
-       OpCall
+       OpClosureCall
        OpStaticCall
        OpConvert
        OpConvNop
@@ -553,6 +555,26 @@ var opcodeTable = [...]opInfo{
                        outputs:  []regMask{},
                },
        },
+       {
+               name: "CALLstatic",
+               reg: regInfo{
+                       inputs:   []regMask{},
+                       clobbers: 0,
+                       outputs:  []regMask{},
+               },
+       },
+       {
+               name: "CALLclosure",
+               reg: regInfo{
+                       inputs: []regMask{
+                               4295032831,
+                               4,
+                               0,
+                       },
+                       clobbers: 0,
+                       outputs:  []regMask{},
+               },
+       },
        {
                name: "REPMOVSB",
                reg: regInfo{
@@ -741,7 +763,7 @@ var opcodeTable = [...]opInfo{
                generic: true,
        },
        {
-               name: "Call",
+               name: "ClosureCall",
                reg: regInfo{
                        inputs:   []regMask{},
                        clobbers: 0,
index 0878a12eb9659659b4f7cd0efe5ba95fe5b0dcbd..542dad45008fd7cda349604986a8f6c21e7e130a 100644 (file)
@@ -191,6 +191,25 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
                goto endf8ca12fe79290bc82b11cfa463bc9413
        endf8ca12fe79290bc82b11cfa463bc9413:
                ;
+       case OpClosureCall:
+               // match: (ClosureCall entry closure mem)
+               // cond:
+               // result: (CALLclosure entry closure mem)
+               {
+                       entry := v.Args[0]
+                       closure := v.Args[1]
+                       mem := v.Args[2]
+                       v.Op = OpAMD64CALLclosure
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.AddArg(entry)
+                       v.AddArg(closure)
+                       v.AddArg(mem)
+                       return true
+               }
+               goto endee26da781e813a3c602ccb4f7ade98c7
+       endee26da781e813a3c602ccb4f7ade98c7:
+               ;
        case OpConst:
                // match: (Const <t> [val])
                // cond: is64BitInt(t)
@@ -743,6 +762,23 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
                goto end78e66b6fc298684ff4ac8aec5ce873c9
        end78e66b6fc298684ff4ac8aec5ce873c9:
                ;
+       case OpStaticCall:
+               // match: (StaticCall [target] mem)
+               // cond:
+               // result: (CALLstatic [target] mem)
+               {
+                       target := v.Aux
+                       mem := v.Args[0]
+                       v.Op = OpAMD64CALLstatic
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.Aux = target
+                       v.AddArg(mem)
+                       return true
+               }
+               goto endcf02eb60d90086f6c42bfdc5842b145d
+       endcf02eb60d90086f6c42bfdc5842b145d:
+               ;
        case OpStore:
                // match: (Store ptr val mem)
                // cond: (is64BitInt(val.Type) || isPtr(val.Type))