github.com/consensys/gnark-crypto@v0.14.0/field/generator/asm/amd64/build.go (about) 1 // Copyright 2020 ConsenSys Software Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package amd64 contains syntactic sugar to generate amd64 assembly code 16 package amd64 17 18 import ( 19 "fmt" 20 "io" 21 "strings" 22 23 "github.com/consensys/bavard" 24 25 "github.com/consensys/bavard/amd64" 26 "github.com/consensys/gnark-crypto/field/generator/config" 27 ) 28 29 const SmallModulus = 6 30 31 func NewFFAmd64(w io.Writer, F *config.FieldConfig) *FFAmd64 { 32 return &FFAmd64{F, amd64.NewAmd64(w), 0, 0} 33 } 34 35 type FFAmd64 struct { 36 *config.FieldConfig 37 *amd64.Amd64 38 nbElementsOnStack int 39 maxOnStack int 40 } 41 42 func (f *FFAmd64) StackSize(maxNbRegistersNeeded, nbRegistersReserved, minStackSize int) int { 43 got := amd64.NbRegisters - nbRegistersReserved 44 r := got - maxNbRegistersNeeded 45 if r >= 0 { 46 return minStackSize 47 } 48 r *= -8 49 return max(r, minStackSize) 50 } 51 52 func max(a, b int) int { 53 if a > b { 54 return a 55 } 56 return b 57 } 58 59 func (f *FFAmd64) AssertCleanStack(reservedStackSize, minStackSize int) { 60 if f.nbElementsOnStack != 0 { 61 panic("missing f.Push stack elements") 62 } 63 if reservedStackSize < minStackSize { 64 panic("invalid minStackSize or reservedStackSize") 65 } 66 usedStackSize := f.maxOnStack * 8 67 if usedStackSize > reservedStackSize { 68 panic("using more stack size than reserved") 69 } else if max(usedStackSize, minStackSize) < reservedStackSize { 70 // this panic is for dev purposes as this may be by design for aligment 71 panic("reserved more stack size than needed") 72 } 73 74 f.maxOnStack = 0 75 } 76 77 func (f *FFAmd64) Push(registers *amd64.Registers, rIn ...amd64.Register) { 78 for _, r := range rIn { 79 if strings.HasPrefix(string(r), "s") { 80 // it's on the stack, decrease the offset 81 f.nbElementsOnStack-- 82 continue 83 } 84 registers.Push(r) 85 } 86 } 87 88 func (f *FFAmd64) Pop(registers *amd64.Registers, forceStack ...bool) amd64.Register { 89 if registers.Available() >= 1 && !(len(forceStack) > 0 && forceStack[0]) { 90 return registers.Pop() 91 } 92 r := amd64.Register(fmt.Sprintf("s%d-%d(SP)", f.nbElementsOnStack, 8+f.nbElementsOnStack*8)) 93 f.nbElementsOnStack++ 94 if f.nbElementsOnStack > f.maxOnStack { 95 f.maxOnStack = f.nbElementsOnStack 96 } 97 return r 98 } 99 100 func (f *FFAmd64) PopN(registers *amd64.Registers, forceStack ...bool) []amd64.Register { 101 if len(forceStack) > 0 && forceStack[0] { 102 nbStack := f.NbWords 103 var u []amd64.Register 104 105 for i := f.nbElementsOnStack; i < nbStack+f.nbElementsOnStack; i++ { 106 u = append(u, amd64.Register(fmt.Sprintf("s%d-%d(SP)", i, 8+i*8))) 107 } 108 f.nbElementsOnStack += nbStack 109 if f.nbElementsOnStack > f.maxOnStack { 110 f.maxOnStack = f.nbElementsOnStack 111 } 112 return u 113 } 114 if registers.Available() >= f.NbWords { 115 return registers.PopN(f.NbWords) 116 } 117 nbStack := f.NbWords - registers.Available() 118 u := registers.PopN(registers.Available()) 119 120 for i := f.nbElementsOnStack; i < nbStack+f.nbElementsOnStack; i++ { 121 u = append(u, amd64.Register(fmt.Sprintf("s%d-%d(SP)", i, 8+i*8))) 122 } 123 f.nbElementsOnStack += nbStack 124 if f.nbElementsOnStack > f.maxOnStack { 125 f.maxOnStack = f.nbElementsOnStack 126 } 127 return u 128 } 129 130 func (f *FFAmd64) qAt(index int) string { 131 return fmt.Sprintf("q<>+%d(SB)", index*8) 132 } 133 134 func (f *FFAmd64) qInv0() string { 135 return "qInv0<>(SB)" 136 } 137 138 // Generate generates assembly code for the base field provided to goff 139 // see internal/templates/ops* 140 func Generate(w io.Writer, F *config.FieldConfig) error { 141 f := NewFFAmd64(w, F) 142 f.WriteLn(bavard.Apache2Header("ConsenSys Software Inc.", 2020)) 143 144 f.WriteLn("#include \"textflag.h\"") 145 f.WriteLn("#include \"funcdata.h\"") 146 f.WriteLn("") 147 148 f.GenerateDefines() 149 150 // reduce 151 f.generateReduce() 152 153 // mul by constants 154 f.generateMulBy3() 155 f.generateMulBy5() 156 f.generateMulBy13() 157 158 // fft butterflies 159 f.generateButterfly() 160 161 return nil 162 } 163 164 func GenerateMul(w io.Writer, F *config.FieldConfig) error { 165 f := NewFFAmd64(w, F) 166 f.WriteLn(bavard.Apache2Header("ConsenSys Software Inc.", 2020)) 167 168 f.WriteLn("#include \"textflag.h\"") 169 f.WriteLn("#include \"funcdata.h\"") 170 f.WriteLn("") 171 f.GenerateDefines() 172 173 // mul 174 f.generateMul(false) 175 176 // from mont 177 f.generateFromMont(false) 178 179 return nil 180 } 181 182 func GenerateMulADX(w io.Writer, F *config.FieldConfig) error { 183 f := NewFFAmd64(w, F) 184 f.WriteLn(bavard.Apache2Header("ConsenSys Software Inc.", 2020)) 185 186 f.WriteLn("#include \"textflag.h\"") 187 f.WriteLn("#include \"funcdata.h\"") 188 f.WriteLn("") 189 f.GenerateDefines() 190 191 // mul 192 f.generateMul(true) 193 194 // from mont 195 f.generateFromMont(true) 196 197 return nil 198 }