| // Copyright 2016 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package arm |
| |
| import ( |
| "cmd/compile/internal/gc" |
| "cmd/compile/internal/ssa" |
| "cmd/internal/obj" |
| "cmd/internal/obj/arm" |
| ) |
| |
| var ssaRegToReg = []int16{ |
| arm.REG_R0, |
| arm.REG_R1, |
| arm.REG_R2, |
| arm.REG_R3, |
| arm.REGSP, // aka R13 |
| } |
| |
| func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { |
| s.SetLineno(v.Line) |
| switch v.Op { |
| case ssa.OpInitMem: |
| // memory arg needs no code |
| case ssa.OpArg: |
| // input args need no code |
| case ssa.OpSP, ssa.OpSB: |
| // nothing to do |
| case ssa.OpCopy: |
| case ssa.OpLoadReg: |
| // TODO: by type |
| p := gc.Prog(arm.AMOVW) |
| n, off := gc.AutoVar(v.Args[0]) |
| p.From.Type = obj.TYPE_MEM |
| p.From.Node = n |
| p.From.Sym = gc.Linksym(n.Sym) |
| p.From.Offset = off |
| if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT { |
| p.From.Name = obj.NAME_PARAM |
| p.From.Offset += n.Xoffset |
| } else { |
| p.From.Name = obj.NAME_AUTO |
| } |
| p.To.Type = obj.TYPE_REG |
| p.To.Reg = gc.SSARegNum(v) |
| |
| case ssa.OpStoreReg: |
| // TODO: by type |
| p := gc.Prog(arm.AMOVW) |
| p.From.Type = obj.TYPE_REG |
| p.From.Reg = gc.SSARegNum(v.Args[0]) |
| n, off := gc.AutoVar(v) |
| p.To.Type = obj.TYPE_MEM |
| p.To.Node = n |
| p.To.Sym = gc.Linksym(n.Sym) |
| p.To.Offset = off |
| if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT { |
| p.To.Name = obj.NAME_PARAM |
| p.To.Offset += n.Xoffset |
| } else { |
| p.To.Name = obj.NAME_AUTO |
| } |
| case ssa.OpARMADD: |
| r := gc.SSARegNum(v) |
| r1 := gc.SSARegNum(v.Args[0]) |
| r2 := gc.SSARegNum(v.Args[1]) |
| p := gc.Prog(v.Op.Asm()) |
| p.From.Type = obj.TYPE_REG |
| p.From.Reg = r1 |
| p.Reg = r2 |
| p.To.Type = obj.TYPE_REG |
| p.To.Reg = r |
| case ssa.OpARMADDconst: |
| p := gc.Prog(v.Op.Asm()) |
| p.From.Type = obj.TYPE_CONST |
| p.From.Offset = v.AuxInt |
| if v.Aux != nil { |
| panic("can't handle symbolic constant yet") |
| } |
| p.Reg = gc.SSARegNum(v.Args[0]) |
| p.To.Type = obj.TYPE_REG |
| p.To.Reg = gc.SSARegNum(v) |
| case ssa.OpARMMOVWconst: |
| p := gc.Prog(v.Op.Asm()) |
| p.From.Type = obj.TYPE_CONST |
| p.From.Offset = v.AuxInt |
| p.To.Type = obj.TYPE_REG |
| p.To.Reg = gc.SSARegNum(v) |
| case ssa.OpARMCMP: |
| p := gc.Prog(v.Op.Asm()) |
| p.From.Type = obj.TYPE_REG |
| // Special layout in ARM assembly |
| // Comparing to x86, the operands of ARM's CMP are reversed. |
| p.From.Reg = gc.SSARegNum(v.Args[1]) |
| p.Reg = gc.SSARegNum(v.Args[0]) |
| case ssa.OpARMMOVWload: |
| p := gc.Prog(v.Op.Asm()) |
| p.From.Type = obj.TYPE_MEM |
| p.From.Reg = gc.SSARegNum(v.Args[0]) |
| gc.AddAux(&p.From, v) |
| p.To.Type = obj.TYPE_REG |
| p.To.Reg = gc.SSARegNum(v) |
| case ssa.OpARMMOVWstore: |
| p := gc.Prog(v.Op.Asm()) |
| p.From.Type = obj.TYPE_REG |
| p.From.Reg = gc.SSARegNum(v.Args[1]) |
| p.To.Type = obj.TYPE_MEM |
| p.To.Reg = gc.SSARegNum(v.Args[0]) |
| gc.AddAux(&p.To, v) |
| case ssa.OpARMCALLstatic: |
| // TODO: deferreturn |
| p := gc.Prog(obj.ACALL) |
| p.To.Type = obj.TYPE_MEM |
| p.To.Name = obj.NAME_EXTERN |
| p.To.Sym = gc.Linksym(v.Aux.(*gc.Sym)) |
| if gc.Maxarg < v.AuxInt { |
| gc.Maxarg = v.AuxInt |
| } |
| case ssa.OpVarDef: |
| gc.Gvardef(v.Aux.(*gc.Node)) |
| case ssa.OpVarKill: |
| gc.Gvarkill(v.Aux.(*gc.Node)) |
| case ssa.OpVarLive: |
| gc.Gvarlive(v.Aux.(*gc.Node)) |
| case ssa.OpARMLessThan: |
| v.Fatalf("pseudo-op made it to output: %s", v.LongString()) |
| default: |
| v.Unimplementedf("genValue not implemented: %s", v.LongString()) |
| } |
| } |
| |
| func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { |
| s.SetLineno(b.Line) |
| |
| switch b.Kind { |
| case ssa.BlockCall: |
| if b.Succs[0].Block() != next { |
| p := gc.Prog(obj.AJMP) |
| p.To.Type = obj.TYPE_BRANCH |
| s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) |
| } |
| case ssa.BlockRet: |
| gc.Prog(obj.ARET) |
| case ssa.BlockARMLT: |
| p := gc.Prog(arm.ABLT) |
| p.To.Type = obj.TYPE_BRANCH |
| s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) |
| p = gc.Prog(obj.AJMP) |
| p.To.Type = obj.TYPE_BRANCH |
| s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) |
| } |
| } |