Skip to content

Commit 35fb594

Browse files
committed
loader/cgo: add support for pointer types
1 parent 01f6aff commit 35fb594

File tree

7 files changed

+165
-120
lines changed

7 files changed

+165
-120
lines changed

compiler/compiler.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,7 +1325,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
13251325
return nil
13261326
}
13271327
store := c.builder.CreateStore(llvmVal, llvmAddr)
1328-
valType := instr.Addr.Type().(*types.Pointer).Elem()
1328+
valType := instr.Addr.Type().Underlying().(*types.Pointer).Elem()
13291329
if c.ir.IsVolatile(valType) {
13301330
// Volatile store, for memory-mapped registers.
13311331
store.SetVolatile(true)
@@ -1957,7 +1957,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
19571957
var bufptr, buflen llvm.Value
19581958
switch ptrTyp := expr.X.Type().Underlying().(type) {
19591959
case *types.Pointer:
1960-
typ := expr.X.Type().(*types.Pointer).Elem().Underlying()
1960+
typ := expr.X.Type().Underlying().(*types.Pointer).Elem().Underlying()
19611961
switch typ := typ.(type) {
19621962
case *types.Array:
19631963
bufptr = val
@@ -2986,7 +2986,7 @@ func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) {
29862986
return llvm.Value{}, c.makeError(unop.Pos(), "todo: unknown type for negate: "+unop.X.Type().Underlying().String())
29872987
}
29882988
case token.MUL: // *x, dereference pointer
2989-
valType := unop.X.Type().(*types.Pointer).Elem()
2989+
valType := unop.X.Type().Underlying().(*types.Pointer).Elem()
29902990
if c.targetData.TypeAllocSize(x.Type().ElementType()) == 0 {
29912991
// zero-length data
29922992
return c.getZeroValue(x.Type().ElementType())

loader/cgo.go

Lines changed: 50 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -17,37 +17,33 @@ import (
1717
type fileInfo struct {
1818
*ast.File
1919
filename string
20-
functions []*functionInfo
21-
typedefs []*typedefInfo
22-
globals []*globalInfo
20+
functions map[string]*functionInfo
21+
globals map[string]*globalInfo
22+
typedefs map[string]*typedefInfo
2323
importCPos token.Pos
2424
}
2525

2626
// functionInfo stores some information about a Cgo function found by libclang
2727
// and declared in the AST.
2828
type functionInfo struct {
29-
name string
30-
args []paramInfo
31-
result string
29+
args []paramInfo
30+
results *ast.FieldList
3231
}
3332

3433
// paramInfo is a parameter of a Cgo function (see functionInfo).
3534
type paramInfo struct {
3635
name string
37-
typeName string
36+
typeExpr ast.Expr
3837
}
3938

4039
// typedefInfo contains information about a single typedef in C.
4140
type typedefInfo struct {
42-
newName string // newly defined type name
43-
oldName string // old type name, may be something like "unsigned long long"
44-
size int // size in bytes
41+
typeExpr ast.Expr
4542
}
4643

4744
// globalInfo contains information about a declared global variable in C.
4845
type globalInfo struct {
49-
name string
50-
typeName string
46+
typeExpr ast.Expr
5147
}
5248

5349
// cgoAliases list type aliases between Go and C, for types that are equivalent
@@ -84,8 +80,11 @@ typedef unsigned long long _Cgo_ulonglong;
8480
// comment with libclang, and modifies the AST to use this information.
8581
func (p *Package) processCgo(filename string, f *ast.File, cflags []string) error {
8682
info := &fileInfo{
87-
File: f,
88-
filename: filename,
83+
File: f,
84+
filename: filename,
85+
functions: map[string]*functionInfo{},
86+
globals: map[string]*globalInfo{},
87+
typedefs: map[string]*typedefInfo{},
8988
}
9089

9190
// Find `import "C"` statements in the file.
@@ -151,16 +150,22 @@ func (p *Package) processCgo(filename string, f *ast.File, cflags []string) erro
151150
func (info *fileInfo) addFuncDecls() {
152151
// TODO: replace all uses of importCPos with the real locations from
153152
// libclang.
154-
for _, fn := range info.functions {
153+
names := make([]string, 0, len(info.functions))
154+
for name := range info.functions {
155+
names = append(names, name)
156+
}
157+
sort.Strings(names)
158+
for _, name := range names {
159+
fn := info.functions[name]
155160
obj := &ast.Object{
156161
Kind: ast.Fun,
157-
Name: mapCgoType(fn.name),
162+
Name: "C." + name,
158163
}
159164
args := make([]*ast.Field, len(fn.args))
160165
decl := &ast.FuncDecl{
161166
Name: &ast.Ident{
162167
NamePos: info.importCPos,
163-
Name: mapCgoType(fn.name),
168+
Name: "C." + name,
164169
Obj: obj,
165170
},
166171
Type: &ast.FuncType{
@@ -170,16 +175,7 @@ func (info *fileInfo) addFuncDecls() {
170175
List: args,
171176
Closing: info.importCPos,
172177
},
173-
Results: &ast.FieldList{
174-
List: []*ast.Field{
175-
&ast.Field{
176-
Type: &ast.Ident{
177-
NamePos: info.importCPos,
178-
Name: mapCgoType(fn.result),
179-
},
180-
},
181-
},
182-
},
178+
Results: fn.results,
183179
},
184180
}
185181
obj.Decl = decl
@@ -191,15 +187,12 @@ func (info *fileInfo) addFuncDecls() {
191187
Name: arg.name,
192188
Obj: &ast.Object{
193189
Kind: ast.Var,
194-
Name: mapCgoType(arg.name),
190+
Name: arg.name,
195191
Decl: decl,
196192
},
197193
},
198194
},
199-
Type: &ast.Ident{
200-
NamePos: info.importCPos,
201-
Name: mapCgoType(arg.typeName),
202-
},
195+
Type: arg.typeExpr,
203196
}
204197
}
205198
info.Decls = append(info.Decls, decl)
@@ -221,21 +214,24 @@ func (info *fileInfo) addVarDecls() {
221214
Lparen: info.importCPos,
222215
Rparen: info.importCPos,
223216
}
224-
for _, global := range info.globals {
217+
names := make([]string, 0, len(info.globals))
218+
for name := range info.globals {
219+
names = append(names, name)
220+
}
221+
sort.Strings(names)
222+
for _, name := range names {
223+
global := info.globals[name]
225224
obj := &ast.Object{
226225
Kind: ast.Typ,
227-
Name: mapCgoType(global.name),
226+
Name: "C." + name,
228227
}
229228
valueSpec := &ast.ValueSpec{
230229
Names: []*ast.Ident{&ast.Ident{
231230
NamePos: info.importCPos,
232-
Name: mapCgoType(global.name),
231+
Name: "C." + name,
233232
Obj: obj,
234233
}},
235-
Type: &ast.Ident{
236-
NamePos: info.importCPos,
237-
Name: mapCgoType(global.typeName),
238-
},
234+
Type: global.typeExpr,
239235
}
240236
obj.Decl = valueSpec
241237
gen.Specs = append(gen.Specs, valueSpec)
@@ -292,55 +288,32 @@ func (info *fileInfo) addTypedefs() {
292288
TokPos: info.importCPos,
293289
Tok: token.TYPE,
294290
}
295-
for _, typedef := range info.typedefs {
296-
newType := mapCgoType(typedef.newName)
297-
oldType := mapCgoType(typedef.oldName)
298-
switch oldType {
299-
// TODO: plain char (may be signed or unsigned)
300-
case "C.schar", "C.short", "C.int", "C.long", "C.longlong":
301-
switch typedef.size {
302-
case 1:
303-
oldType = "int8"
304-
case 2:
305-
oldType = "int16"
306-
case 4:
307-
oldType = "int32"
308-
case 8:
309-
oldType = "int64"
310-
}
311-
case "C.uchar", "C.ushort", "C.uint", "C.ulong", "C.ulonglong":
312-
switch typedef.size {
313-
case 1:
314-
oldType = "uint8"
315-
case 2:
316-
oldType = "uint16"
317-
case 4:
318-
oldType = "uint32"
319-
case 8:
320-
oldType = "uint64"
321-
}
322-
}
323-
if strings.HasPrefix(newType, "C._Cgo_") {
324-
newType = "C." + newType[len("C._Cgo_"):]
291+
names := make([]string, 0, len(info.typedefs))
292+
for name := range info.typedefs {
293+
names = append(names, name)
294+
}
295+
sort.Strings(names)
296+
for _, name := range names {
297+
typedef := info.typedefs[name]
298+
typeName := "C." + name
299+
if strings.HasPrefix(name, "_Cgo_") {
300+
typeName = "C." + name[len("_Cgo_"):]
325301
}
326-
if _, ok := cgoAliases[newType]; ok {
302+
if _, ok := cgoAliases[typeName]; ok {
327303
// This is a type that also exists in Go (defined in stdint.h).
328304
continue
329305
}
330306
obj := &ast.Object{
331307
Kind: ast.Typ,
332-
Name: newType,
308+
Name: typeName,
333309
}
334310
typeSpec := &ast.TypeSpec{
335311
Name: &ast.Ident{
336312
NamePos: info.importCPos,
337-
Name: newType,
313+
Name: typeName,
338314
Obj: obj,
339315
},
340-
Type: &ast.Ident{
341-
NamePos: info.importCPos,
342-
Name: oldType,
343-
},
316+
Type: typedef.typeExpr,
344317
}
345318
obj.Decl = typeSpec
346319
gen.Specs = append(gen.Specs, typeSpec)
@@ -362,31 +335,9 @@ func (info *fileInfo) walker(cursor *astutil.Cursor) bool {
362335
if x.Name == "C" {
363336
cursor.Replace(&ast.Ident{
364337
NamePos: x.NamePos,
365-
Name: mapCgoType(node.Sel.Name),
338+
Name: "C." + node.Sel.Name,
366339
})
367340
}
368341
}
369342
return true
370343
}
371-
372-
// mapCgoType converts a C type name into a Go type name with a "C." prefix.
373-
func mapCgoType(t string) string {
374-
switch t {
375-
case "signed char":
376-
return "C.schar"
377-
case "long long":
378-
return "C.longlong"
379-
case "unsigned char":
380-
return "C.schar"
381-
case "unsigned short":
382-
return "C.ushort"
383-
case "unsigned int":
384-
return "C.uint"
385-
case "unsigned long":
386-
return "C.ulong"
387-
case "unsigned long long":
388-
return "C.ulonglong"
389-
default:
390-
return "C." + t
391-
}
392-
}

0 commit comments

Comments
 (0)