Skip to content

Commit fb9e904

Browse files
committed
ir: assign global IDs of unnamed global variables and functions
Fixes #148.
1 parent f722fd9 commit fb9e904

File tree

4 files changed

+112
-15
lines changed

4 files changed

+112
-15
lines changed

ir/func.go

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"github.com/llir/llvm/ir/constant"
1010
"github.com/llir/llvm/ir/enum"
1111
"github.com/llir/llvm/ir/types"
12-
"github.com/llir/llvm/ir/value"
1312
"github.com/pkg/errors"
1413
)
1514

@@ -156,7 +155,7 @@ func (f *Func) AssignIDs() error {
156155
f.mu.Lock()
157156
defer f.mu.Unlock()
158157
id := int64(0)
159-
setName := func(n local) error {
158+
setName := func(n namedVar) error {
160159
if n.IsUnnamed() {
161160
if n.ID() != 0 && id != n.ID() {
162161
want := id
@@ -180,7 +179,7 @@ func (f *Func) AssignIDs() error {
180179
return errors.WithStack(err)
181180
}
182181
for _, inst := range block.Insts {
183-
n, ok := inst.(local)
182+
n, ok := inst.(namedVar)
184183
if !ok {
185184
continue
186185
}
@@ -193,7 +192,7 @@ func (f *Func) AssignIDs() error {
193192
return errors.WithStack(err)
194193
}
195194
}
196-
n, ok := block.Term.(local)
195+
n, ok := block.Term.(namedVar)
197196
if !ok {
198197
continue
199198
}
@@ -304,14 +303,3 @@ func bodyString(body *Func) string {
304303
buf.WriteString("}")
305304
return buf.String()
306305
}
307-
308-
// local is a local variable.
309-
type local interface {
310-
value.Named
311-
// ID returns the ID of the local identifier.
312-
ID() int64
313-
// SetID sets the ID of the local identifier.
314-
SetID(id int64)
315-
// IsUnnamed reports whether the local identifier is unnamed.
316-
IsUnnamed() bool
317-
}

ir/global_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package ir_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/google/go-cmp/cmp"
7+
"github.com/llir/llvm/ir"
8+
"github.com/llir/llvm/ir/constant"
9+
"github.com/llir/llvm/ir/types"
10+
)
11+
12+
func TestAssignGlobalIDs(t *testing.T) {
13+
// ref: https://github.com/llir/llvm/issues/148
14+
const want = `@0 = global [15 x i8] c"Hello, world!\0A\00"
15+
@1 = global i32 0
16+
17+
define i32 @2() {
18+
0:
19+
ret i32 1
20+
}
21+
`
22+
23+
m := ir.NewModule()
24+
25+
// should be @0
26+
s := "Hello, world!\n\x00"
27+
i := constant.NewCharArrayFromString(s)
28+
m.NewGlobalDef("", i)
29+
30+
// should be @1
31+
i32 := types.I32
32+
zero := constant.NewInt(i32, 0)
33+
m.NewGlobalDef("", zero)
34+
35+
// should be @2
36+
one := constant.NewInt(i32, 1)
37+
m.NewFunc("", i32).NewBlock("").NewRet(one)
38+
39+
// Compare module output.
40+
got := m.String()
41+
if diff := cmp.Diff(want, got); diff != "" {
42+
t.Errorf("module mismatch (-want +got):\n%s", diff)
43+
}
44+
}

ir/helper.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,3 +469,14 @@ func (fw *fmtWriter) Fprintln(a ...interface{}) (n int, err error) {
469469
fw.err = err
470470
return n, err
471471
}
472+
473+
// namedVar is a named variable.
474+
type namedVar interface {
475+
value.Named
476+
// ID returns the ID of the local identifier.
477+
ID() int64
478+
// SetID sets the ID of the local identifier.
479+
SetID(id int64)
480+
// IsUnnamed reports whether the local identifier is unnamed.
481+
IsUnnamed() bool
482+
}

ir/module.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"io"
66
"strings"
7+
"sync"
78

89
"github.com/llir/llvm/internal/enc"
910
"github.com/llir/llvm/internal/natsort"
@@ -52,6 +53,9 @@ type Module struct {
5253
UseListOrders []*UseListOrder
5354
// (optional) Basic block specific use-list order directives.
5455
UseListOrderBBs []*UseListOrderBB
56+
57+
// mu prevents races on AssignGlobalIDs and AssignMetadataIDs.
58+
mu sync.Mutex
5559
}
5660

5761
// NewModule returns a new LLVM IR module.
@@ -75,6 +79,10 @@ func (m *Module) String() string {
7579
// syntax to w.
7680
func (m *Module) WriteTo(w io.Writer) (n int64, err error) {
7781
fw := &fmtWriter{w: w}
82+
// Assign global IDs.
83+
if err := m.AssignGlobalIDs(); err != nil {
84+
panic(fmt.Errorf("unable to assign globals IDs of module; %v", err))
85+
}
7886
// Assign metadata IDs.
7987
if err := m.AssignMetadataIDs(); err != nil {
8088
panic(fmt.Errorf("unable to assign metadata IDs of module; %v", err))
@@ -317,9 +325,55 @@ func (u *UseListOrderBB) String() string {
317325

318326
// ### [ Helper functions ] ####################################################
319327

328+
// AssignGlobalIDs assigns IDs to unnamed global variables.
329+
func (m *Module) AssignGlobalIDs() error {
330+
m.mu.Lock()
331+
defer m.mu.Unlock()
332+
id := int64(0)
333+
setName := func(n namedVar) error {
334+
if n.IsUnnamed() {
335+
if n.ID() != 0 && id != n.ID() {
336+
want := id
337+
got := n.ID()
338+
return errors.Errorf("invalid global ID, expected %s, got %s", enc.GlobalID(want), enc.GlobalID(got))
339+
}
340+
n.SetID(id)
341+
id++
342+
}
343+
return nil
344+
}
345+
// Assign global IDs to unnamed global variables.
346+
for _, n := range m.Globals {
347+
if err := setName(n); err != nil {
348+
return errors.WithStack(err)
349+
}
350+
}
351+
// Assign global IDs to unnamed aliases.
352+
for _, n := range m.Aliases {
353+
if err := setName(n); err != nil {
354+
return errors.WithStack(err)
355+
}
356+
}
357+
// Assign global IDs to unnamed IFuncs.
358+
for _, n := range m.IFuncs {
359+
if err := setName(n); err != nil {
360+
return errors.WithStack(err)
361+
}
362+
}
363+
// Assign global IDs to unnamed functions.
364+
for _, n := range m.Funcs {
365+
if err := setName(n); err != nil {
366+
return errors.WithStack(err)
367+
}
368+
}
369+
return nil
370+
}
371+
320372
// AssignMetadataIDs assigns metadata IDs to the unnamed metadata definitions of
321373
// the module.
322374
func (m *Module) AssignMetadataIDs() error {
375+
m.mu.Lock()
376+
defer m.mu.Unlock()
323377
// Index used IDs.
324378
used := make(map[int64]bool)
325379
for _, md := range m.MetadataDefs {

0 commit comments

Comments
 (0)