/
ir.go
200 lines (174 loc) · 4.75 KB
/
ir.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package patch
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
"go/constant"
"runtime"
"strings"
)
func ifConstant(pos src.XPos, b bool, body []ir.Node, els []ir.Node) *ir.IfStmt {
return ir.NewIfStmt(pos,
NewBoolLit(pos, b),
body,
els,
)
}
func NewStringLit(pos src.XPos, s string) ir.Node {
return NewBasicLit(pos, types.Types[types.TSTRING], constant.MakeString(s))
}
func NewInt64Lit(pos src.XPos, i int64) ir.Node {
return NewBasicLit(pos, types.Types[types.TINT64], constant.MakeInt64(i))
}
func NewIntLit(pos src.XPos, i int) ir.Node {
return NewBasicLit(pos, types.Types[types.TINT], constant.MakeInt64(int64(i)))
}
func NewBoolLit(pos src.XPos, b bool) ir.Node {
return NewBasicLit(pos, types.Types[types.TBOOL], constant.MakeBool(b))
}
// how to declare a new function?
// init names are usually init.0, init.1, ...
//
// NOTE: when there is already an init function, declare new init function
// will give an error: main..inittask: relocation target main.init.1 not defined
// with go1.22, modifying existing init's body may cause the error:
//
// __xgo_autogen.go:2:6: internal compiler error: unexpected initialization statement: (.)
const needToCreateInit = goMajor > 1 || (goMajor == 1 && goMinor >= 22)
// Deprecated: use __xgo_link_generate_init_regs_body instead
// principal: Don't rely too much on IR
// don't add function on the fly, instead, modify existing
// functions body
func prependInit(pos src.XPos, target *ir.Package, body []ir.Node) {
if !needToCreateInit && len(target.Inits) > 0 {
target.Inits[0].Body.Prepend(body...)
return
}
sym := types.LocalPkg.Lookup(fmt.Sprintf("init.%d", len(target.Inits)))
regFunc := NewFunc(pos, pos, sym, NewSignature(types.LocalPkg, nil, nil, nil, nil))
regFunc.Body = body
target.Inits = append(target.Inits, regFunc)
// must call this in go1.22
if needToCreateInit {
// typecheck.DeclFunc(regFunc)
} else {
AddFuncs(regFunc)
}
}
func takeAddr(fn *ir.Func, field *types.Field, nameOnly bool) ir.Node {
pos := fn.Pos()
if field == nil {
return newNilInterface(pos)
}
// go1.20 only? no Nname, so cannot refer to it
// but we should display it in trace?(better to do so)
var isNilOrEmptyName bool
if field.Nname == nil {
isNilOrEmptyName = true
} else if field.Sym != nil && field.Sym.Name == "_" {
isNilOrEmptyName = true
}
var fieldRef *ir.Name
if isNilOrEmptyName {
// if name is "_" or empty, return nil
if true {
return newNilInterface(pos)
}
if false {
// NOTE: not working when IR
tmpName := typecheck.TempAt(pos, fn, field.Type)
field.Nname = tmpName
field.Sym = tmpName.Sym()
fieldRef = tmpName
}
} else {
fieldRef = field.Nname.(*ir.Name)
}
arg := ir.NewAddrExpr(pos, fieldRef)
if nameOnly {
fieldType := field.Type
arg.SetType(types.NewPtr(fieldType))
return arg
}
return convToEFace(pos, arg, field.Type, true)
}
func getFieldName(fn *ir.Func, field *types.Field) string {
if field == nil {
return ""
}
if field.Nname == nil {
return ""
}
if false {
// debug
if field.Sym != nil {
return field.Sym.Name
}
}
return field.Nname.(*ir.Name).Sym().Name
}
func convToEFace(pos src.XPos, x ir.Node, t *types.Type, ptr bool) *ir.ConvExpr {
conv := ir.NewConvExpr(pos, ir.OCONV, types.Types[types.TINTER], x)
conv.SetImplicit(true)
// go1.20 and above: must have Typeword
if ptr {
SetConvTypeWordPtr(conv, t)
} else {
SetConvTypeWord(conv, t)
}
return conv
}
func isFirstStmtSkipTrap(nodes ir.Nodes) bool {
// NOTE: for performance reason, only check the first
if len(nodes) > 0 && isCallTo(nodes[0], xgoRuntimeTrapPkg, "Skip") {
return true
}
if false {
for _, node := range nodes {
if isCallTo(node, xgoRuntimeTrapPkg, "Skip") {
return true
}
}
}
return false
}
func isCallTo(node ir.Node, pkgPath string, name string) bool {
callNode, ok := node.(*ir.CallExpr)
if !ok {
return false
}
nameNode, ok := getCallee(callNode).(*ir.Name)
if !ok {
return false
}
sym := nameNode.Sym()
if sym == nil {
return false
}
return sym.Pkg != nil && sym.Name == name && sym.Pkg.Path == pkgPath
}
func newNilInterface(pos src.XPos) ir.Expr {
return NewNilExpr(pos, types.Types[types.TINTER])
}
func newEmptyStr(pos src.XPos) ir.Node {
return NewStringLit(pos, "")
}
func newNilInterfaceSlice(pos src.XPos) ir.Expr {
return NewNilExpr(pos, types.NewSlice(types.Types[types.TINTER]))
}
func getPosInfo(pos src.XPos) src.Pos {
return base.Ctxt.PosTable.Pos(pos)
}
func getAdjustedFile(f string) string {
if runtime.GOOS != "windows" {
return ""
}
// for Windows, posFile has the form:
// C:/a/b/c
// while syncDeclMapping's file has the form:
// C:\a\b\c
return strings.ReplaceAll(f, "/", "\\")
}