1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package s390x 6 7 import ( 8 "cmd/compile/internal/gc" 9 "cmd/internal/obj" 10 "cmd/internal/obj/s390x" 11 ) 12 13 // clearLoopCutOff is the (somewhat arbitrary) value above which it is better 14 // to have a loop of clear instructions (e.g. XCs) rather than just generating 15 // multiple instructions (i.e. loop unrolling). 16 // Must be between 256 and 4096. 17 const clearLoopCutoff = 1024 18 19 func defframe(ptxt *obj.Prog) { 20 // fill in argument size, stack size 21 ptxt.To.Type = obj.TYPE_TEXTSIZE 22 23 ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.ArgWidth(), int64(gc.Widthptr))) 24 frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg))) 25 ptxt.To.Offset = int64(frame) 26 27 // insert code to zero ambiguously live variables 28 // so that the garbage collector only sees initialized values 29 // when it looks for pointers. 30 p := ptxt 31 32 hi := int64(0) 33 lo := hi 34 35 // iterate through declarations - they are sorted in decreasing xoffset order. 36 for _, n := range gc.Curfn.Func.Dcl { 37 if !n.Name.Needzero { 38 continue 39 } 40 if n.Class != gc.PAUTO { 41 gc.Fatalf("needzero class %d", n.Class) 42 } 43 if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 { 44 gc.Fatalf("var %L has size %d offset %d", n, int(n.Type.Width), int(n.Xoffset)) 45 } 46 47 if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) { 48 // merge with range we already have 49 lo = n.Xoffset 50 51 continue 52 } 53 54 // zero old range 55 p = zerorange(p, int64(frame), lo, hi) 56 57 // set new range 58 hi = n.Xoffset + n.Type.Width 59 60 lo = n.Xoffset 61 } 62 63 // zero final range 64 zerorange(p, int64(frame), lo, hi) 65 } 66 67 // zerorange clears the stack in the given range. 68 func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog { 69 cnt := hi - lo 70 if cnt == 0 { 71 return p 72 } 73 74 // Adjust the frame to account for LR. 75 frame += gc.Ctxt.FixedFrameSize() 76 offset := frame + lo 77 reg := int16(s390x.REGSP) 78 79 // If the offset cannot fit in a 12-bit unsigned displacement then we 80 // need to create a copy of the stack pointer that we can adjust. 81 // We also need to do this if we are going to loop. 82 if offset < 0 || offset > 4096-clearLoopCutoff || cnt > clearLoopCutoff { 83 p = gc.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset, obj.TYPE_REG, s390x.REGRT1, 0) 84 p.Reg = int16(s390x.REGSP) 85 reg = s390x.REGRT1 86 offset = 0 87 } 88 89 // Generate a loop of large clears. 90 if cnt > clearLoopCutoff { 91 n := cnt - (cnt % 256) 92 end := int16(s390x.REGRT2) 93 p = gc.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset+n, obj.TYPE_REG, end, 0) 94 p.Reg = reg 95 p = gc.Appendpp(p, s390x.AXC, obj.TYPE_MEM, reg, offset, obj.TYPE_MEM, reg, offset) 96 p.From3 = new(obj.Addr) 97 p.From3.Type = obj.TYPE_CONST 98 p.From3.Offset = 256 99 pl := p 100 p = gc.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, 256, obj.TYPE_REG, reg, 0) 101 p = gc.Appendpp(p, s390x.ACMP, obj.TYPE_REG, reg, 0, obj.TYPE_REG, end, 0) 102 p = gc.Appendpp(p, s390x.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0) 103 gc.Patch(p, pl) 104 105 cnt -= n 106 } 107 108 // Generate remaining clear instructions without a loop. 109 for cnt > 0 { 110 n := cnt 111 112 // Can clear at most 256 bytes per instruction. 113 if n > 256 { 114 n = 256 115 } 116 117 switch n { 118 // Handle very small clears with move instructions. 119 case 8, 4, 2, 1: 120 ins := s390x.AMOVB 121 switch n { 122 case 8: 123 ins = s390x.AMOVD 124 case 4: 125 ins = s390x.AMOVW 126 case 2: 127 ins = s390x.AMOVH 128 } 129 p = gc.Appendpp(p, ins, obj.TYPE_CONST, 0, 0, obj.TYPE_MEM, reg, offset) 130 131 // Handle clears that would require multiple move instructions with XC. 132 default: 133 p = gc.Appendpp(p, s390x.AXC, obj.TYPE_MEM, reg, offset, obj.TYPE_MEM, reg, offset) 134 p.From3 = new(obj.Addr) 135 p.From3.Type = obj.TYPE_CONST 136 p.From3.Offset = n 137 } 138 139 cnt -= n 140 offset += n 141 } 142 143 return p 144 } 145 146 func ginsnop() { 147 p := gc.Prog(s390x.AOR) 148 p.From.Type = obj.TYPE_REG 149 p.From.Reg = int16(s390x.REG_R0) 150 p.To.Type = obj.TYPE_REG 151 p.To.Reg = int16(s390x.REG_R0) 152 } 153