repos / gbc

GBC - Go B Compiler
git clone https://github.com/xplshn/gbc.git

gbc / pkg / ir
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}