github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_abispec.go (about) 1 /* 2 * Copyright 2022 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package ssa 18 19 import ( 20 `fmt` 21 ) 22 23 // ABILowering lowers ABI-specific instructions to machine specific instructions. 24 type ABILowering struct{} 25 26 func (self ABILowering) Apply(cfg *CFG) { 27 rr := make([]Reg, len(cfg.Layout.Args)) 28 rb := rr[:0] 29 30 /* map each argument load to register alias or stack load */ 31 for i, v := range cfg.Root.Ins { 32 if iv, ok := v.(*IrLoadArg); !ok { 33 break 34 } else if iv.I < 0 || iv.I >= len(cfg.Layout.Args) { 35 panic("abi: argument load out of bound: " + v.String()) 36 } else if rr[iv.I] != 0 { 37 panic("abi: second load of the same argument: " + v.String()) 38 } else if a := cfg.Layout.Args[iv.I]; a.InRegister { 39 rr[iv.I] = IrSetArch(Rz, a.Reg) 40 cfg.Root.Ins[i] = &IrAlias { R: iv.R, V: rr[iv.I] } 41 } else { 42 rr[iv.I] = Rz 43 cfg.Root.Ins[i] = IrArchLoadStack(iv.R, a.Mem, IrSlotArgs) 44 } 45 } 46 47 /* extract all the registers */ 48 for _, r := range rr { 49 if r != 0 && r != Rz { 50 rb = append(rb, r) 51 } 52 } 53 54 /* insert an entry point node to hold all the register arguments */ 55 if len(rb) != 0 { 56 cfg.Root.Ins = append( 57 []IrNode { &IrEntry { rb } }, 58 cfg.Root.Ins... 59 ) 60 } 61 62 /* lower the entire program */ 63 cfg.PostOrder().ForEach(func(bb *BasicBlock) { 64 ins := bb.Ins 65 bb.Ins = make([]IrNode, 0, len(ins)) 66 67 /* scan every instruction */ 68 for _, v := range ins { 69 switch p := v.(type) { 70 case *IrLoadArg : panic(fmt.Sprintf("abi: argument load in the middle of CFG: bb_%d: %s", bb.Id, v)) 71 case *IrCallFunc : self.abiCallFunc(cfg, bb, p) 72 case *IrCallNative : self.abiCallNative(cfg, bb, p) 73 case *IrCallMethod : self.abiCallMethod(cfg, bb, p) 74 default : bb.Ins = append(bb.Ins, p) 75 } 76 } 77 78 /* scan the terminator */ 79 if p, ok := bb.Term.(*IrReturn); ok { 80 rr = make([]Reg, len(p.R)) 81 rb = rr[:0] 82 83 /* check for return value count */ 84 if len(p.R) != len(cfg.Layout.Rets) { 85 panic("abi: return value store size mismatch: " + p.String()) 86 } 87 88 /* copy return values */ 89 for i, rv := range p.R { 90 if r := cfg.Layout.Rets[i]; r.InRegister { 91 rr[i] = IrSetArch(cfg.CreateRegister(rv.Ptr()), r.Reg) 92 bb.Ins = append(bb.Ins, IrArchCopy(rr[i], rv)) 93 } else { 94 rr[i] = Rz 95 bb.Ins = append(bb.Ins, IrArchStoreStack(rv, r.Mem, IrSlotArgs)) 96 } 97 } 98 99 /* extract all the registers */ 100 for _, r := range rr { 101 if r != 0 && r != Rz { 102 rb = append(rb, r) 103 } 104 } 105 106 /* replace the terminator */ 107 if len(rb) != 0 { 108 bb.Term = IrArchReturn(rb) 109 } else { 110 bb.Term = IrArchReturn(nil) 111 } 112 } 113 }) 114 }