xplshn
·
2025-09-10
ir.go
Go
1package ir
2
3import (
4 "github.com/xplshn/gbc/pkg/ast"
5)
6
7type Op int
8
9const (
10 OpAlloc Op = iota
11 OpLoad
12 OpStore
13 OpBlit
14 OpAdd
15 OpSub
16 OpMul
17 OpDiv
18 OpRem
19 OpAnd
20 OpOr
21 OpXor
22 OpShl
23 OpShr
24 OpAddF
25 OpSubF
26 OpMulF
27 OpDivF
28 OpRemF
29 OpNegF
30 OpCEq
31 OpCNeq
32 OpCLt
33 OpCGt
34 OpCLe
35 OpCGe
36 OpExtSB
37 OpExtUB
38 OpExtSH
39 OpExtUH
40 OpExtSW
41 OpExtUW
42 OpTrunc
43 OpCast
44 OpFToSI
45 OpFToUI
46 OpSWToF
47 OpUWToF
48 OpSLToF
49 OpULToF
50 OpFToF
51 OpJmp
52 OpJnz
53 OpRet
54 OpCall
55 OpPhi
56)
57
58type Type int
59
60const (
61 TypeNone Type = iota
62 TypeB // byte (8-bit, ambiguous signedness)
63 TypeH // half-word (16-bit, ambiguous signedness)
64 TypeW // word (32-bit)
65 TypeL // long (64-bit)
66 TypeS // single float (32-bit)
67 TypeD // double float (64-bit)
68 TypePtr
69 TypeSB // signed byte (8-bit)
70 TypeUB // unsigned byte (8-bit)
71 TypeSH // signed half-word (16-bit)
72 TypeUH // unsigned half-word (16-bit)
73)
74
75type Value interface {
76 isValue()
77 String() string
78}
79
80type Const struct{ Value int64 }
81type FloatConst struct{ Value float64; Typ Type }
82type Global struct{ Name string }
83type Temporary struct{ Name string; ID int }
84type Label struct{ Name string }
85type CastValue struct{ Value; TargetType string }
86
87func (c *Const) isValue() {}
88func (f *FloatConst) isValue() {}
89func (g *Global) isValue() {}
90func (t *Temporary) isValue() {}
91func (l *Label) isValue() {}
92func (c *CastValue) isValue() {}
93
94func (c *Const) String() string { return "" }
95func (f *FloatConst) String() string { return "" }
96func (g *Global) String() string { return g.Name }
97func (t *Temporary) String() string { return t.Name }
98func (l *Label) String() string { return l.Name }
99func (c *CastValue) String() string { return c.Value.String() }
100
101type Func struct {
102 Name string
103 Params []*Param
104 AstParams []*ast.Node
105 ReturnType Type
106 AstReturnType *ast.BxType
107 HasVarargs bool
108 Blocks []*BasicBlock
109 Node *ast.Node
110}
111
112type Param struct{ Name string; Typ Type; Val Value }
113
114type BasicBlock struct{ Label *Label; Instructions []*Instruction }
115
116type Instruction struct {
117 Op Op
118 Typ Type
119 OperandType Type
120 Result Value
121 Args []Value
122 ArgTypes []Type
123 Align int
124}
125
126type Program struct {
127 Globals []*Data
128 Strings map[string]string
129 Funcs []*Func
130 ExtrnFuncs []string
131 ExtrnVars map[string]bool
132 WordSize int
133 BackendTempCount int
134 GlobalSymbols map[string]*ast.Node
135}
136
137type Data struct {
138 Name string
139 Align int
140 AstType *ast.BxType
141 Items []DataItem
142}
143
144type DataItem struct{ Typ Type; Value Value; Count int }
145
146func GetType(typ *ast.BxType, wordSize int) Type {
147 if typ == nil || typ.Kind == ast.TYPE_UNTYPED { return typeFromSize(wordSize, false) }
148
149 switch typ.Kind {
150 case ast.TYPE_LITERAL_INT: return typeFromSize(wordSize, false)
151 case ast.TYPE_LITERAL_FLOAT: return typeFromSize(wordSize, true)
152 case ast.TYPE_VOID: return TypeNone
153 case ast.TYPE_POINTER, ast.TYPE_ARRAY, ast.TYPE_STRUCT: return TypePtr
154 case ast.TYPE_ENUM: return typeFromSize(wordSize, false)
155 case ast.TYPE_FLOAT:
156 size := getTypeSizeByName(typ.Name, wordSize)
157 return typeFromSize(int(size), true)
158 case ast.TYPE_PRIMITIVE:
159 switch typ.Name {
160 case "int", "uint", "string": return typeFromSize(wordSize, false)
161 case "int64", "uint64": return TypeL
162 case "int32", "uint32": return TypeW
163 case "int16": return TypeSH
164 case "uint16": return TypeUH
165 case "int8": return TypeSB
166 case "uint8": return TypeUB
167 case "byte", "bool": return TypeB
168 default: return typeFromSize(wordSize, false)
169 }
170 }
171 return typeFromSize(wordSize, false)
172}
173
174func typeFromSize(size int, isFloat bool) Type {
175 if isFloat {
176 switch size {
177 case 4: return TypeS
178 case 8: return TypeD
179 default: return TypeD
180 }
181 }
182
183 switch size {
184 case 8: return TypeL
185 case 4: return TypeW
186 case 2: return TypeH
187 case 1: return TypeB
188 default: return TypeL
189 }
190}
191
192func getTypeSizeByName(typeName string, wordSize int) int64 {
193 switch typeName {
194 case "int64", "uint64", "float64": return 8
195 case "int32", "uint32", "float32": return 4
196 case "int16", "uint16": return 2
197 case "int8", "uint8", "byte", "bool": return 1
198 case "int", "uint", "string", "float": return int64(wordSize)
199 }
200 return 0
201}
202
203type TypeSizeResolver struct{ wordSize int }
204
205func NewTypeSizeResolver(wordSize int) *TypeSizeResolver { return &TypeSizeResolver{wordSize: wordSize} }
206
207func (r *TypeSizeResolver) GetTypeSize(typeName string) int64 { return getTypeSizeByName(typeName, r.wordSize) }
208
209func floatTypeFromSize(size int) Type { return typeFromSize(size, true) }
210
211func SizeOfType(t Type, wordSize int) int64 {
212 switch t {
213 case TypeB, TypeSB, TypeUB: return 1
214 case TypeH, TypeSH, TypeUH: return 2
215 case TypeW: return 4
216 case TypeL: return 8
217 case TypeS: return 4
218 case TypeD: return 8
219 case TypePtr: return int64(wordSize)
220 default:
221 return int64(wordSize)
222 }
223}
224
225func (p *Program) GetBackendTempCount() int { return p.BackendTempCount }
226func (p *Program) IncBackendTempCount() { p.BackendTempCount++ }
227
228func (p *Program) IsStringLabel(name string) (string, bool) {
229 for s, label := range p.Strings {
230 if label == name { return s, true }
231 }
232 return "", false
233}
234
235func (p *Program) FindFunc(name string) *Func {
236 for _, f := range p.Funcs {
237 if f.Name == name { return f }
238 }
239 return nil
240}
241
242func (p *Program) FindFuncSymbol(name string) *ast.Node {
243 if p.GlobalSymbols != nil {
244 if node, ok := p.GlobalSymbols[name]; ok {
245 if _, isFunc := node.Data.(ast.FuncDeclNode); isFunc { return node }
246 }
247 }
248 return nil
249}