// lookupVarOutgoing finds the variable's value at the end of block b. func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t ssa.Type, var_ *Node, line int32) *ssa.Value { for { if v := s.defvars[b.ID][var_]; v != nil { return v } // The variable is not defined by b and we haven't looked it up yet. // If b has exactly one predecessor, loop to look it up there. // Otherwise, give up and insert a new FwdRef and resolve it later. if len(b.Preds) != 1 { break } b = b.Preds[0].Block() } // Generate a FwdRef for the variable and return that. v := b.NewValue0A(line, ssa.OpFwdRef, t, var_) s.defvars[b.ID][var_] = v s.s.addNamedValue(var_, v) s.fwdrefs = append(s.fwdrefs, v) return v }
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { s.SetLineno(b.Line) switch b.Kind { case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck: if b.Succs[0] != next { p := gc.Prog(obj.AJMP) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{p, b.Succs[0]}) } case ssa.BlockDefer: // defer returns in rax: // 0 if we should continue executing // 1 if we should jump to deferreturn call p := gc.Prog(x86.ATESTL) p.From.Type = obj.TYPE_REG p.From.Reg = x86.REG_AX p.To.Type = obj.TYPE_REG p.To.Reg = x86.REG_AX p = gc.Prog(x86.AJNE) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{p, b.Succs[1]}) if b.Succs[0] != next { p := gc.Prog(obj.AJMP) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{p, b.Succs[0]}) } case ssa.BlockExit: gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here case ssa.BlockRet: gc.Prog(obj.ARET) case ssa.BlockRetJmp: p := gc.Prog(obj.AJMP) p.To.Type = obj.TYPE_MEM p.To.Name = obj.NAME_EXTERN p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym)) case ssa.BlockAMD64EQF: gc.SSAGenFPJump(s, b, next, &eqfJumps) case ssa.BlockAMD64NEF: gc.SSAGenFPJump(s, b, next, &nefJumps) case ssa.BlockAMD64EQ, ssa.BlockAMD64NE, ssa.BlockAMD64LT, ssa.BlockAMD64GE, ssa.BlockAMD64LE, ssa.BlockAMD64GT, ssa.BlockAMD64ULT, ssa.BlockAMD64UGT, ssa.BlockAMD64ULE, ssa.BlockAMD64UGE: jmp := blockJump[b.Kind] likely := b.Likely var p *obj.Prog switch next { case b.Succs[0]: p = gc.Prog(jmp.invasm) likely *= -1 p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{p, b.Succs[1]}) case b.Succs[1]: p = gc.Prog(jmp.asm) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{p, b.Succs[0]}) default: p = gc.Prog(jmp.asm) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{p, b.Succs[0]}) q := gc.Prog(obj.AJMP) q.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{q, b.Succs[1]}) } // liblink reorders the instruction stream as it sees fit. // Pass along what we know so liblink can make use of it. // TODO: Once we've fully switched to SSA, // make liblink leave our output alone. switch likely { case ssa.BranchUnlikely: p.From.Type = obj.TYPE_CONST p.From.Offset = 0 case ssa.BranchLikely: p.From.Type = obj.TYPE_CONST p.From.Offset = 1 } default: b.Unimplementedf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString()) } }
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { s.SetLineno(b.Line) switch b.Kind { case ssa.BlockPlain: 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.BlockDefer: // defer returns in R0: // 0 if we should continue executing // 1 if we should jump to deferreturn call p := gc.Prog(arm.ACMP) p.From.Type = obj.TYPE_CONST p.From.Offset = 0 p.Reg = arm.REG_R0 p = gc.Prog(arm.ABNE) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 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.BlockExit: gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here case ssa.BlockRet: gc.Prog(obj.ARET) case ssa.BlockRetJmp: p := gc.Prog(obj.ARET) p.To.Type = obj.TYPE_MEM p.To.Name = obj.NAME_EXTERN p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym)) case ssa.BlockARMEQ, ssa.BlockARMNE, ssa.BlockARMLT, ssa.BlockARMGE, ssa.BlockARMLE, ssa.BlockARMGT, ssa.BlockARMULT, ssa.BlockARMUGT, ssa.BlockARMULE, ssa.BlockARMUGE: jmp := blockJump[b.Kind] var p *obj.Prog switch next { case b.Succs[0].Block(): p = gc.Prog(jmp.invasm) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) case b.Succs[1].Block(): p = gc.Prog(jmp.asm) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) default: p = gc.Prog(jmp.asm) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) q := gc.Prog(obj.AJMP) q.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()}) } default: b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString()) } }
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { s.SetLineno(b.Line) switch b.Kind { case ssa.BlockPlain: 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.BlockDefer: // defer returns in R1: // 0 if we should continue executing // 1 if we should jump to deferreturn call p := gc.Prog(mips.ABNE) p.From.Type = obj.TYPE_REG p.From.Reg = mips.REGZERO p.Reg = mips.REG_R1 p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 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.BlockExit: gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here case ssa.BlockRet: gc.Prog(obj.ARET) case ssa.BlockRetJmp: p := gc.Prog(obj.ARET) p.To.Type = obj.TYPE_MEM p.To.Name = obj.NAME_EXTERN p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym)) case ssa.BlockMIPSEQ, ssa.BlockMIPSNE, ssa.BlockMIPSLTZ, ssa.BlockMIPSGEZ, ssa.BlockMIPSLEZ, ssa.BlockMIPSGTZ, ssa.BlockMIPSFPT, ssa.BlockMIPSFPF: jmp := blockJump[b.Kind] var p *obj.Prog switch next { case b.Succs[0].Block(): p = gc.Prog(jmp.invasm) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) case b.Succs[1].Block(): p = gc.Prog(jmp.asm) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) default: p = gc.Prog(jmp.asm) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) q := gc.Prog(obj.AJMP) q.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()}) } if !b.Control.Type.IsFlags() { p.From.Type = obj.TYPE_REG p.From.Reg = b.Control.Reg() } default: b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString()) } }
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { s.SetLineno(b.Line) switch b.Kind { case ssa.BlockDefer: // defer returns in R3: // 0 if we should continue executing // 1 if we should jump to deferreturn call p := gc.Prog(ppc64.ACMP) p.From.Type = obj.TYPE_REG p.From.Reg = ppc64.REG_R3 p.To.Type = obj.TYPE_REG p.To.Reg = ppc64.REG_R0 p = gc.Prog(ppc64.ABNE) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 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.BlockPlain, ssa.BlockCall, ssa.BlockCheck: 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.BlockExit: gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here case ssa.BlockRet: gc.Prog(obj.ARET) case ssa.BlockRetJmp: p := gc.Prog(obj.AJMP) p.To.Type = obj.TYPE_MEM p.To.Name = obj.NAME_EXTERN p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym)) case ssa.BlockPPC64EQ, ssa.BlockPPC64NE, ssa.BlockPPC64LT, ssa.BlockPPC64GE, ssa.BlockPPC64LE, ssa.BlockPPC64GT, ssa.BlockPPC64FLT, ssa.BlockPPC64FGE, ssa.BlockPPC64FLE, ssa.BlockPPC64FGT: jmp := blockJump[b.Kind] likely := b.Likely var p *obj.Prog switch next { case b.Succs[0].Block(): p = gc.Prog(jmp.invasm) likely *= -1 p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) if jmp.invasmun { // TODO: The second branch is probably predict-not-taken since it is for FP unordered q := gc.Prog(ppc64.ABVS) q.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()}) } case b.Succs[1].Block(): p = gc.Prog(jmp.asm) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) if jmp.asmeq { q := gc.Prog(ppc64.ABEQ) q.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[0].Block()}) } default: p = gc.Prog(jmp.asm) p.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) if jmp.asmeq { q := gc.Prog(ppc64.ABEQ) q.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[0].Block()}) } q := gc.Prog(obj.AJMP) q.To.Type = obj.TYPE_BRANCH s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()}) } // liblink reorders the instruction stream as it sees fit. // Pass along what we know so liblink can make use of it. // TODO: Once we've fully switched to SSA, // make liblink leave our output alone. //switch likely { //case ssa.BranchUnlikely: // p.From.Type = obj.TYPE_CONST // p.From.Offset = 0 //case ssa.BranchLikely: // p.From.Type = obj.TYPE_CONST // p.From.Offset = 1 //} default: b.Unimplementedf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString()) } }