can write all 3 output files and then compile them by hand.
R=r
DELTA=919 (841 added, 16 deleted, 62 changed)
OCL=34954
CL=34973
ast.go\
gcc.go\
main.go\
+ out.go\
util.go\
include $(GOROOT)/src/Make.cmd
+
+# Tests
+# TODO(rsc): Delete
+
+gmp:
+ make cgo
+ cgo gmp.go
+ gcc -fPIC -O2 -o gcc.o -c _cgo_gcc.c
+ gcc -shared -o gmp.so gcc.o -L$(GOROOT)/pkg/$(GOOS)_$(GOARCH) -lcgo -lgmp
+ 6c -D_64BIT -I$(GOROOT)/src/pkg/runtime _cgo_c.c
+ 6g _cgo_go.go
+ gopack grc gmp.a _cgo_c.6 _cgo_go.6
+ 6g pidigits.go
+ 6l pidigits.6
+ LD_LIBRARY_PATH=.:$(GOROOT)/pkg/$(GOOS)_$(GOARCH) 6.out
+
+stdio:
+ make cgo
+ cgo stdio.go
+ gcc -fPIC -O2 -o gcc.o -c _cgo_gcc.c
+ gcc -shared -Wl,--rpath -Wl,$(GOROOT)/pkg/$(GOOS)_$(GOARCH) -o main.so gcc.o -L$(GOROOT)/pkg/$(GOOS)_$(GOARCH) -lcgo
+ 6c -D_64BIT -I$(GOROOT)/src/pkg/runtime _cgo_c.c
+ 6g _cgo_go.go
+ 6l _cgo_c.6 _cgo_go.6
+ LD_LIBRARY_PATH=.:$(GOROOT)/pkg/$(GOOS)_$(GOARCH) 6.out
package main
import (
- "debug/dwarf";
"fmt";
"go/ast";
"go/doc";
"go/parser";
"go/scanner";
"os";
+ "strings";
)
// A Cref refers to an expression of the form C.xxx in the AST.
Expr *ast.Expr;
Context string; // "type", "expr", or "call"
TypeName bool; // whether xxx is a C type name
- DebugType dwarf.Type; // the type of xxx
+ Type *Type; // the type of xxx
+ FuncType *FuncType;
}
// A Prog collects information about a cgo program.
type Prog struct {
AST *ast.File; // parsed AST
Preamble string; // C preamble (doc comment on import "C")
+ PackagePath string;
+ Package string;
Crefs []*Cref;
+ Typedef map[string]ast.Expr;
+ Vardef map[string]*Type;
+ Funcdef map[string]*FuncType;
+}
+
+// A Type collects information about a type in both the C and Go worlds.
+type Type struct {
+ Size int64;
+ Align int64;
+ C string;
+ Go ast.Expr;
+}
+
+// A FuncType collects information about a function type in both the C and Go worlds.
+type FuncType struct {
+ Params []*Type;
+ Result *Type;
+ Go *ast.FuncType;
}
func openProg(name string) *Prog {
}
fatal("parsing %s: %s", name, err);
}
+ p.Package = p.AST.Name.Value;
// Find the import "C" line and get any extra C preamble.
- found := false;
- for _, d := range p.AST.Decls {
- d, ok := d.(*ast.GenDecl);
+ // Delete the import "C" line along the way or convert it
+ // to an import of "unsafe" (needed for the translation of void*).
+ sawC := false;
+ sawUnsafe := false;
+ rewroteUnsafe := false;
+ w := 0;
+ for _, decl := range p.AST.Decls {
+ d, ok := decl.(*ast.GenDecl);
if !ok {
+ p.AST.Decls[w] = decl;
+ w++;
continue;
}
- for _, s := range d.Specs {
- s, ok := s.(*ast.ImportSpec);
- if !ok {
- continue;
- }
- if len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` {
+ ws := 0;
+ for _, spec := range d.Specs {
+ s, ok := spec.(*ast.ImportSpec);
+ if !ok || len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` {
+ if s != nil && len(s.Path) == 1 && string(s.Path[0].Value) == `"unsafe"` {
+ if rewroteUnsafe {
+ // we rewrote the import "C" into import "unsafe",
+ // so drop this one.
+ continue;
+ }
+ sawUnsafe = true;
+ }
+ d.Specs[ws] = spec;
+ ws++;
continue;
}
- found = true;
+ sawC = true;
if s.Name != nil {
error(s.Path[0].Pos(), `cannot rename import "C"`);
}
if s.Doc != nil {
p.Preamble += doc.CommentText(s.Doc) + "\n";
- }
- else if len(d.Specs) == 1 && d.Doc != nil {
+ } else if len(d.Specs) == 1 && d.Doc != nil {
p.Preamble += doc.CommentText(d.Doc) + "\n";
}
+ if !sawUnsafe {
+ rewroteUnsafe = true;
+ s.Path[0].Value = strings.Bytes(`"unsafe"`);
+ d.Specs[ws] = spec;
+ ws++;
+ }
+ }
+ if ws == 0 {
+ continue;
}
+ d.Specs = d.Specs[0:ws];
+ p.AST.Decls[w] = d;
+ w++;
}
- if !found {
+ p.AST.Decls = p.AST.Decls[0:w];
+
+ if !sawC {
error(noPos, `cannot find import "C"`);
}
walk(n.Lhs, p, "expr");
walk(n.Rhs, p, "expr");
case *ast.GoStmt:
- walk(&n.Call, p, "expr");
+ walk(n.Call, p, "expr");
case *ast.DeferStmt:
- walk(&n.Call, p, "expr");
+ walk(n.Call, p, "expr");
case *ast.ReturnStmt:
walk(n.Results, p, "expr");
case *ast.BranchStmt:
walk(n.Recv, p, "field");
}
walk(n.Type, p, "type");
- walk(n.Body, p, "stmt");
+ if n.Body != nil {
+ walk(n.Body, p, "stmt");
+ }
case *ast.File:
walk(n.Decls, p, "decl");
// license that can be found in the LICENSE file.
// Annotate Crefs in Prog with C types by parsing gcc debug output.
+// Conversion of debug output to Go types.
package main
import (
+ "bytes";
"debug/dwarf";
"debug/elf";
"debug/macho";
"fmt";
+ "go/ast";
+ "go/token";
"os";
"strconv";
"strings";
)
-func (p *Prog) loadDebugInfo() {
+func (p *Prog) loadDebugInfo(ptrSize int64) {
// Construct a slice of unique names from p.Crefs.
m := make(map[string]int);
for _, c := range p.Crefs {
// x.c:2: error: 'name' undeclared (first use in this function)
// A line number directive causes the line number to
// correspond to the index in the names array.
- var b strings.Buffer;
+ var b bytes.Buffer;
b.WriteString(p.Preamble);
b.WriteString("void f(void) {\n");
b.WriteString("#line 0 \"cgo-test\"\n");
}
}
- // Apply types to Crefs.
+ // Record types and typedef information in Crefs.
+ var conv typeConv;
+ conv.Init(ptrSize);
for _, c := range p.Crefs {
i := m[c.Name];
c.TypeName = kind[c.Name] == "type";
- c.DebugType = types[i];
+ f, fok := types[i].(*dwarf.FuncType);
+ if c.Context == "call" && !c.TypeName && fok {
+ c.FuncType = conv.FuncType(f);
+ } else {
+ c.Type = conv.Type(types[i]);
+ }
}
+ p.Typedef = conv.typedef;
}
// gccDebug runs gcc -gdwarf-2 over the C program stdin and
return d, "";
}
+// A typeConv is a translator from dwarf types to Go types
+// with equivalent memory layout.
+type typeConv struct {
+ // Cache of already-translated or in-progress types.
+ m map[dwarf.Type]*Type;
+ typedef map[string]ast.Expr;
+
+ // Predeclared types.
+ byte ast.Expr; // denotes padding
+ int8, int16, int32, int64 ast.Expr;
+ uint8, uint16, uint32, uint64, uintptr ast.Expr;
+ float32, float64 ast.Expr;
+ void ast.Expr;
+ unsafePointer ast.Expr;
+ string ast.Expr;
+
+ ptrSize int64;
+
+ tagGen int;
+}
+
+func (c *typeConv) Init(ptrSize int64) {
+ c.ptrSize = ptrSize;
+ c.m = make(map[dwarf.Type]*Type);
+ c.typedef = make(map[string]ast.Expr);
+ c.byte = c.Ident("byte");
+ c.int8 = c.Ident("int8");
+ c.int16 = c.Ident("int16");
+ c.int32 = c.Ident("int32");
+ c.int64 = c.Ident("int64");
+ c.uint8 = c.Ident("uint8");
+ c.uint16 = c.Ident("uint16");
+ c.uint32 = c.Ident("uint32");
+ c.uint64 = c.Ident("uint64");
+ c.uintptr = c.Ident("uintptr");
+ c.float32 = c.Ident("float32");
+ c.float64 = c.Ident("float64");
+ c.unsafePointer = c.Ident("unsafe.Pointer");
+ c.void = c.Ident("void");
+ c.string = c.Ident("string");
+}
+
+// base strips away qualifiers and typedefs to get the underlying type
+func base(dt dwarf.Type) dwarf.Type {
+ for {
+ if d, ok := dt.(*dwarf.QualType); ok {
+ dt = d.Type;
+ continue;
+ }
+ if d, ok := dt.(*dwarf.TypedefType); ok {
+ dt = d.Type;
+ continue;
+ }
+ break;
+ }
+ return dt;
+}
+
+// Map from dwarf text names to aliases we use in package "C".
+var cnameMap = map[string] string {
+ "long int": "long",
+ "long unsigned int": "ulong",
+ "unsigned int": "uint",
+ "short unsigned int": "ushort",
+ "short int": "short",
+ "long long int": "longlong",
+ "long long unsigned int": "ulonglong",
+ "signed char": "schar",
+};
+
+// Type returns a *Type with the same memory layout as
+// dtype when used as the type of a variable or a struct field.
+func (c *typeConv) Type(dtype dwarf.Type) *Type {
+ if t, ok := c.m[dtype]; ok {
+ if t.Go == nil {
+ fatal("type conversion loop at %s", dtype);
+ }
+ return t;
+ }
+
+ t := new(Type);
+ t.Size = dtype.Size();
+ t.Align = -1;
+ t.C = dtype.Common().Name;
+ if t.Size < 0 {
+ fatal("dwarf.Type %s reports unknown size", dtype);
+ }
+
+ c.m[dtype] = t;
+ switch dt := dtype.(type) {
+ default:
+ fatal("unexpected type: %s", dtype);
+
+ case *dwarf.AddrType:
+ if t.Size != c.ptrSize {
+ fatal("unexpected: %d-byte address type - %s", t.Size, dtype);
+ }
+ t.Go = c.uintptr;
+ t.Align = t.Size;
+
+ case *dwarf.ArrayType:
+ if dt.StrideBitSize > 0 {
+ // Cannot represent bit-sized elements in Go.
+ t.Go = c.Opaque(t.Size);
+ break;
+ }
+ gt := &ast.ArrayType{
+ Len: c.intExpr(dt.Count),
+ };
+ t.Go = gt; // publish before recursive call
+ sub := c.Type(dt.Type);
+ t.Align = sub.Align;
+ gt.Elt = sub.Go;
+ t.C = fmt.Sprintf("typeof(%s[%d])", sub.C, dt.Count);
+
+ case *dwarf.CharType:
+ if t.Size != 1 {
+ fatal("unexpected: %d-byte char type - %s", t.Size, dtype);
+ }
+ t.Go = c.int8;
+ t.Align = 1;
+
+ case *dwarf.EnumType:
+ switch t.Size {
+ default:
+ fatal("unexpected: %d-byte enum type - %s", t.Size, dtype);
+ case 1:
+ t.Go = c.uint8;
+ case 2:
+ t.Go = c.uint16;
+ case 4:
+ t.Go = c.uint32;
+ case 8:
+ t.Go = c.uint64;
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize;
+ }
+ t.C = "enum " + dt.EnumName;
+
+ case *dwarf.FloatType:
+ switch t.Size {
+ default:
+ fatal("unexpected: %d-byte float type - %s", t.Size, dtype);
+ case 4:
+ t.Go = c.float32;
+ case 8:
+ t.Go = c.float64;
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize;
+ }
+
+ case *dwarf.FuncType:
+ // No attempt at translation: would enable calls
+ // directly between worlds, but we need to moderate those.
+ t.Go = c.uintptr;
+ t.Align = c.ptrSize;
+
+ case *dwarf.IntType:
+ if dt.BitSize > 0 {
+ fatal("unexpected: %d-bit int type - %s", dt.BitSize, dtype);
+ }
+ switch t.Size {
+ default:
+ fatal("unexpected: %d-byte int type - %s", t.Size, dtype);
+ case 1:
+ t.Go = c.int8;
+ case 2:
+ t.Go = c.int16;
+ case 4:
+ t.Go = c.int32;
+ case 8:
+ t.Go = c.int64;
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize;
+ }
+
+ case *dwarf.PtrType:
+ t.Align = c.ptrSize;
+
+ // Translate void* as unsafe.Pointer
+ if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
+ t.Go = c.unsafePointer;
+ t.C = "void*";
+ break;
+ }
+
+ gt := &ast.StarExpr{};
+ t.Go = gt; // publish before recursive call
+ sub := c.Type(dt.Type);
+ gt.X = sub.Go;
+ t.C = sub.C + "*";
+
+ case *dwarf.QualType:
+ // Ignore qualifier.
+ t = c.Type(dt.Type);
+ c.m[dtype] = t;
+ return t;
+
+ case *dwarf.StructType:
+ // Convert to Go struct, being careful about alignment.
+ // Have to give it a name to simulate C "struct foo" references.
+ tag := dt.StructName;
+ if tag == "" {
+ tag = "__" + strconv.Itoa(c.tagGen);
+ c.tagGen++;
+ } else if t.C == "" {
+ t.C = dt.Kind + " " + tag;
+ }
+ name := c.Ident("_C" + dt.Kind + "_" + tag);
+ t.Go = name; // publish before recursive calls
+ switch dt.Kind {
+ case "union", "class":
+ c.typedef[name.Value] = c.Opaque(t.Size);
+ if t.C == "" {
+ t.C = fmt.Sprintf("typeof(unsigned char[%d])", t.Size);
+ }
+ case "struct":
+ g, csyntax, align := c.Struct(dt);
+ if t.C == "" {
+ t.C = csyntax;
+ }
+ t.Align = align;
+ c.typedef[name.Value] = g;
+ }
+
+ case *dwarf.TypedefType:
+ // Record typedef for printing.
+ if dt.Name == "_GoString_" {
+ // Special C name for Go string type.
+ // Knows string layout used by compilers: pointer plus length,
+ // which rounds up to 2 pointers after alignment.
+ t.Go = c.string;
+ t.Size = c.ptrSize * 2;
+ t.Align = c.ptrSize;
+ break;
+ }
+ name := c.Ident("_C_" + dt.Name);
+ t.Go = name; // publish before recursive call
+ sub := c.Type(dt.Type);
+ t.Size = sub.Size;
+ t.Align = sub.Align;
+ if _, ok := c.typedef[name.Value]; !ok {
+ c.typedef[name.Value] = sub.Go;
+ }
+
+ case *dwarf.UcharType:
+ if t.Size != 1 {
+ fatal("unexpected: %d-byte uchar type - %s", t.Size, dtype);
+ }
+ t.Go = c.uint8;
+ t.Align = 1;
+
+ case *dwarf.UintType:
+ if dt.BitSize > 0 {
+ fatal("unexpected: %d-bit uint type - %s", dt.BitSize, dtype);
+ }
+ switch t.Size {
+ default:
+ fatal("unexpected: %d-byte uint type - %s", t.Size, dtype);
+ case 1:
+ t.Go = c.uint8;
+ case 2:
+ t.Go = c.uint16;
+ case 4:
+ t.Go = c.uint32;
+ case 8:
+ t.Go = c.uint64;
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize;
+ }
+
+ case *dwarf.VoidType:
+ t.Go = c.void;
+ t.C = "void";
+ }
+
+ switch dtype.(type) {
+ case *dwarf.AddrType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
+ s := dtype.Common().Name;
+ if s != "" {
+ if ss, ok := cnameMap[s]; ok {
+ s = ss;
+ }
+ s = strings.Join(strings.Split(s, " ", 0), ""); // strip spaces
+ name := c.Ident("_C_" + s);
+ c.typedef[name.Value] = t.Go;
+ t.Go = name;
+ }
+ }
+
+ if t.C == "" {
+ fatal("internal error: did not create C name for %s", dtype);
+ }
+
+ return t;
+}
+
+// FuncArg returns a Go type with the same memory layout as
+// dtype when used as the type of a C function argument.
+func (c *typeConv) FuncArg(dtype dwarf.Type) *Type {
+ t := c.Type(dtype);
+ switch dt := dtype.(type) {
+ case *dwarf.ArrayType:
+ // Arrays are passed implicitly as pointers in C.
+ // In Go, we must be explicit.
+ return &Type{
+ Size: c.ptrSize,
+ Align: c.ptrSize,
+ Go: &ast.StarExpr{X: t.Go},
+ C: t.C + "*"
+ };
+ case *dwarf.TypedefType:
+ // C has much more relaxed rules than Go for
+ // implicit type conversions. When the parameter
+ // is type T defined as *X, simulate a little of the
+ // laxness of C by making the argument *X instead of T.
+ if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
+ return c.Type(ptr);
+ }
+ }
+ return t;
+}
+
+// FuncType returns the Go type analogous to dtype.
+// There is no guarantee about matching memory layout.
+func (c *typeConv) FuncType(dtype *dwarf.FuncType) *FuncType {
+ p := make([]*Type, len(dtype.ParamType));
+ gp := make([]*ast.Field, len(dtype.ParamType));
+ for i, f := range dtype.ParamType {
+ p[i] = c.FuncArg(f);
+ gp[i] = &ast.Field{Type: p[i].Go};
+ }
+ var r *Type;
+ var gr []*ast.Field;
+ if _, ok := dtype.ReturnType.(*dwarf.VoidType); !ok && dtype.ReturnType != nil {
+ r = c.Type(dtype.ReturnType);
+ gr = []*ast.Field{&ast.Field{Type: r.Go}};
+ }
+ return &FuncType{
+ Params: p,
+ Result: r,
+ Go: &ast.FuncType{
+ Params: gp,
+ Results: gr
+ }
+ };
+}
+
+// Identifier
+func (c *typeConv) Ident(s string) *ast.Ident {
+ return &ast.Ident{Value: s};
+}
+
+// Opaque type of n bytes.
+func (c *typeConv) Opaque(n int64) ast.Expr {
+ return &ast.ArrayType{
+ Len: c.intExpr(n),
+ Elt: c.byte
+ };
+}
+
+// Expr for integer n.
+func (c *typeConv) intExpr(n int64) ast.Expr {
+ return &ast.BasicLit{
+ Kind: token.INT,
+ Value: strings.Bytes(strconv.Itoa64(n)),
+ }
+}
+
+// Add padding of given size to fld.
+func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
+ n := len(fld);
+ fld = fld[0:n+1];
+ fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)};
+ return fld;
+}
+
+// Struct conversion
+func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax string, align int64) {
+ csyntax = "struct { ";
+ fld := make([]*ast.Field, 0, 2*len(dt.Field)+1); // enough for padding around every field
+ off := int64(0);
+ for _, f := range dt.Field {
+ if f.ByteOffset > off {
+ fld = c.pad(fld, f.ByteOffset - off);
+ off = f.ByteOffset;
+ }
+ t := c.Type(f.Type);
+ n := len(fld);
+ fld = fld[0:n+1];
+ fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(f.Name)}, Type: t.Go};
+ off += t.Size;
+ csyntax += t.C + " " + f.Name + "; ";
+ if t.Align > align {
+ align = t.Align;
+ }
+ }
+ if off < dt.ByteSize {
+ fld = c.pad(fld, dt.ByteSize - off);
+ off = dt.ByteSize;
+ }
+ if off != dt.ByteSize {
+ fatal("struct size calculation error");
+ }
+ csyntax += "}";
+ expr = &ast.StructType{Fields: fld};
+ return;
+}
package gmp
// #include <gmp.h>
+// #include <stdlib.h>
import "C"
+import (
+ "os";
+ "unsafe";
+)
/*
* one of a kind
// NewInt returns a new Int initialized to x.
func NewInt(x int64) *Int {
- z := new(Int);
- z.init = true;
- C.mpz_init(&z.i);
- C.mpz_set(&z.i, x);
- return z;
+ return new(Int).SetInt64(x);
}
// Int promises that the zero value is a 0, but in gmp
return;
}
z.init = true;
- C.mpz_init(&z.i);
+ C.mpz_init(&z.i[0]);
}
// Bytes returns z's representation as a big-endian byte array.
func (z *Int) Bytes() []byte {
b := make([]byte, (z.Len() + 7) / 8);
n := C.size_t(len(b));
- C.mpz_export(&b[0], &n, 1, 1, 1, 0, &z.i);
+ C.mpz_export(unsafe.Pointer(&b[0]), &n, 1, 1, 1, 0, &z.i[0]);
return b[0:n];
}
// Len returns the length of z in bits. 0 is considered to have length 1.
func (z *Int) Len() int {
z.doinit();
- return int(C.mpz_sizeinbase(&z.i, 2));
+ return int(C.mpz_sizeinbase(&z.i[0], 2));
}
// Set sets z = x and returns z.
func (z *Int) Set(x *Int) *Int {
z.doinit();
- C.mpz_set(&z.i, x);
+ C.mpz_set(&z.i[0], &x.i[0]);
return z;
}
if len(b) == 0 {
z.SetInt64(0);
} else {
- C.mpz_import(&z.i, len(b), 1, 1, 1, 0, &b[0]);
+ C.mpz_import(&z.i[0], C.size_t(len(b)), 1, 1, 1, 0, unsafe.Pointer(&b[0]));
}
return z;
}
func (z *Int) SetInt64(x int64) *Int {
z.doinit();
// TODO(rsc): more work on 32-bit platforms
- C.mpz_set_si(z, x);
+ C.mpz_set_si(&z.i[0], C.long(x));
return z;
}
if base < 2 || base > 36 {
return os.EINVAL;
}
- if C.mpz_set_str(&z.i, s, base) < 0 {
+ p := C.CString(s);
+ defer C.free(unsafe.Pointer(p));
+ if C.mpz_set_str(&z.i[0], p, C.int(base)) < 0 {
return os.EINVAL;
}
return z;
// String returns the decimal representation of z.
func (z *Int) String() string {
z.doinit();
- return C.mpz_get_str(nil, 10, &z.i);
+ p := C.mpz_get_str(nil, 10, &z.i[0]);
+ s := C.GoString(p);
+ C.free(unsafe.Pointer(p));
+ return s;
}
func (z *Int) destroy() {
if z.init {
- C.mpz_clear(z);
+ C.mpz_clear(&z.i[0]);
}
z.init = false;
}
x.doinit();
y.doinit();
z.doinit();
- C.mpz_add(&z.i, &x.i, &y.i);
+ C.mpz_add(&z.i[0], &x.i[0], &y.i[0]);
return z;
}
x.doinit();
y.doinit();
z.doinit();
- C.mpz_sub(&z.i, &x.i, &y.i);
+ C.mpz_sub(&z.i[0], &x.i[0], &y.i[0]);
return z;
}
x.doinit();
y.doinit();
z.doinit();
- C.mpz_mul(&z.i, &x.i, &y.i);
+ C.mpz_mul(&z.i[0], &x.i[0], &y.i[0]);
return z;
}
x.doinit();
y.doinit();
z.doinit();
- C.mpz_tdiv_q(&z.i, &x.i, &y.i);
+ C.mpz_tdiv_q(&z.i[0], &x.i[0], &y.i[0]);
return z;
}
x.doinit();
y.doinit();
z.doinit();
- C.mpz_tdiv_r(&z.i, &x.i, &y.i);
+ C.mpz_tdiv_r(&z.i[0], &x.i[0], &y.i[0]);
return z;
}
// Lsh sets z = x << s and returns z.
func (z *Int) Lsh(x *Int, s uint) *Int {
x.doinit();
- y.doinit();
z.doinit();
- C.mpz_mul_2exp(&z.i, &x.i, s);
+ C.mpz_mul_2exp(&z.i[0], &x.i[0], C.ulong(s));
+ return z;
}
// Rsh sets z = x >> s and returns z.
-func (z *Int) Rsh(x *int, s uint) *Int {
+func (z *Int) Rsh(x *Int, s uint) *Int {
x.doinit();
- y.doinit();
z.doinit();
- C.mpz_div_2exp(&z.i, &x.i, s);
+ C.mpz_div_2exp(&z.i[0], &x.i[0], C.ulong(s));
+ return z;
}
// Exp sets z = x^y % m and returns z.
y.doinit();
z.doinit();
if m == nil {
- C.mpz_pow_ui(&z.i, &x.i, mpz_get_ui(&y.i));
+ C.mpz_pow_ui(&z.i[0], &x.i[0], C.mpz_get_ui(&y.i[0]));
} else {
- C.mpz_powm(&z.i, &x.i, &y.i, &m.i);
+ C.mpz_powm(&z.i[0], &x.i[0], &y.i[0], &m.i[0]);
}
return z;
}
+func (z *Int) Int64() int64 {
+ if !z.init {
+ return 0;
+ }
+ return int64(C.mpz_get_si(&z.i[0]));
+}
+
+
// Neg sets z = -x and returns z.
func (z *Int) Neg(x *Int) *Int {
x.doinit();
z.doinit();
- C.mpz_neg(&z.i, &x.i);
+ C.mpz_neg(&z.i[0], &x.i[0]);
return z;
}
func (z *Int) Abs(x *Int) *Int {
x.doinit();
z.doinit();
- C.mpz_abs(&z.i, &x.i);
+ C.mpz_abs(&z.i[0], &x.i[0]);
return z;
}
func CmpInt(x, y *Int) int {
x.doinit();
y.doinit();
- return C.mpz_cmp(&x.i, &y.i);
+ switch cmp := C.mpz_cmp(&x.i[0], &y.i[0]); {
+ case cmp < 0:
+ return -1;
+ case cmp == 0:
+ return 0;
+ }
+ return +1;
}
// DivModInt sets q = x / y and r = x % y.
r.doinit();
x.doinit();
y.doinit();
- C.mpz_tdiv_qr(&q.i, &r.i, &x.i, &y.i);
+ C.mpz_tdiv_qr(&q.i[0], &r.i[0], &x.i[0], &y.i[0]);
}
// GcdInt sets d to the greatest common divisor of a and b,
y.doinit();
a.doinit();
b.doinit();
- C.mpz_gcdext(&d.i, &x.i, &y.i, &a.i, &b.i);
+ C.mpz_gcdext(&d.i[0], &x.i[0], &y.i[0], &a.i[0], &b.i[0]);
}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Cgo; see gmp.go for an overview.
+
+// TODO(rsc):
+// Emit correct line number annotations.
+// Make 6g understand the annotations.
+
package main
import (
"flag";
"fmt";
+ "go/ast";
"os";
- "tabwriter";
)
-// Cgo; see gmp.go for an overview.
-
-// TODO(rsc):
-// Emit correct line number annotations.
-// Make 6g understand the annotations.
-
func usage() {
fmt.Fprint(os.Stderr, "usage: cgo file.cgo\n");
flag.PrintDefaults();
}
+const ptrSize = 8 // TODO
+
func main() {
flag.Usage = usage;
flag.Parse();
os.Exit(2);
}
p := openProg(args[0]);
- p.loadDebugInfo();
+ p.Preamble = p.Preamble + "\n" + builtinProlog;
+ p.loadDebugInfo(ptrSize);
+ p.Vardef = make(map[string]*Type);
+ p.Funcdef = make(map[string]*FuncType);
- tw := tabwriter.NewWriter(os.Stdout, 1, 1, ' ', 0);
for _, cref := range p.Crefs {
- what := "value";
- if cref.TypeName {
- what = "type";
+ switch cref.Context {
+ case "call":
+ if !cref.TypeName {
+ // Is an actual function call.
+ *cref.Expr = &ast.Ident{Value: "_C_" + cref.Name};
+ p.Funcdef[cref.Name] = cref.FuncType;
+ break;
+ }
+ *cref.Expr = cref.Type.Go;
+ case "expr":
+ if cref.TypeName {
+ error((*cref.Expr).Pos(), "type C.%s used as expression", cref.Name);
+ }
+ // Reference to C variable.
+ // We declare a pointer and arrange to have it filled in.
+ *cref.Expr = &ast.StarExpr{X: &ast.Ident{Value: "_C_" + cref.Name}};
+ p.Vardef[cref.Name] = cref.Type;
+ case "type":
+ if !cref.TypeName {
+ error((*cref.Expr).Pos(), "expression C.%s used as type", cref.Name);
+ }
+ *cref.Expr = cref.Type.Go;
}
- fmt.Fprintf(tw, "%s:\t%s %s\tC %s\t%s\n", (*cref.Expr).Pos(), cref.Context, cref.Name, what, cref.DebugType);
}
- tw.Flush();
+ if nerrors > 0 {
+ os.Exit(2);
+ }
+
+ p.PackagePath = p.Package;
+ p.writeOutput(args[0], "_cgo_go.go", "_cgo_c.c", "_cgo_gcc.c");
}
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt";
+ "go/ast";
+ "go/printer";
+ "os";
+)
+
+// writeOutput creates output files to be compiled by 6g, 6c, and gcc.
+// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
+func (p *Prog) writeOutput(srcfile, go_, c, gcc string) {
+ fgo, err := os.Open(go_, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666);
+ if err != nil {
+ fatal("%s", err);
+ }
+ fc, err := os.Open(c, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666);
+ if err != nil {
+ fatal("%s", err);
+ }
+ fgcc, err := os.Open(gcc, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666);
+ if err != nil {
+ fatal("%s", err);
+ }
+
+ // Write Go output: Go input with rewrites of C.xxx to _C_xxx,
+ // then append the definitions of the _C_xxx types and vars and funcs.
+ fmt.Fprintf(fgo, "//line %s:1\n", srcfile);
+ printer.Fprint(fgo, p.AST, 0, 8);
+ fmt.Fprintf(fgo, "\n\n// Added by cgo\n");
+
+ for name, def := range p.Typedef {
+ fmt.Fprintf(fgo, "type %s ", name);
+ printer.Fprint(fgo, def, 0, 8);
+ fmt.Fprintf(fgo, "\n");
+ }
+ fmt.Fprintf(fgo, "type _C_void [0]byte\n");
+
+ // While we process the vars and funcs, also write 6c and gcc output.
+ // Gcc output starts with the preamble.
+ fmt.Fprintf(fgcc, "%s\n", p.Preamble);
+ fmt.Fprintf(fgcc, "%s\n", gccProlog);
+
+ fmt.Fprintf(fc, cProlog, p.Package, p.Package);
+
+ for name, def := range p.Vardef {
+ fmt.Fprintf(fc, "#pragma dynld %s·_C_%s %s \"%s.so\"\n", p.Package, name, name, p.PackagePath);
+ fmt.Fprintf(fgo, "var _C_%s ", name);
+ printer.Fprint(fgo, &ast.StarExpr{X: def.Go}, 0, 8);
+ fmt.Fprintf(fgo, "\n");
+ }
+ fmt.Fprintf(fc, "\n");
+
+ for name, def := range p.Funcdef {
+ // Go func declaration.
+ d := &ast.FuncDecl{
+ Name: &ast.Ident{Value: "_C_" + name},
+ Type: def.Go,
+ };
+ printer.Fprint(fgo, d, 0, 8);
+ fmt.Fprintf(fgo, "\n");
+
+ if name == "CString" || name == "GoString" {
+ // The builtins are already defined in the C prolog.
+ continue;
+ }
+
+ // Construct a gcc struct matching the 6c argument frame.
+ // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
+ // These assumptions are checked by the gccProlog.
+ // Also assumes that 6c convention is to word-align the
+ // input and output parameters.
+ structType := "struct {\n";
+ off := int64(0);
+ npad := 0;
+ for i, t := range def.Params {
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align;
+ structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
+ off += pad;
+ npad++;
+ }
+ structType += fmt.Sprintf("\t\t%s p%d;\n", t.C, i);
+ off += t.Size;
+ }
+ if off%ptrSize != 0 {
+ pad := ptrSize - off%ptrSize;
+ structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
+ off += pad;
+ npad++;
+ }
+ if t := def.Result; t != nil {
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align;
+ structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
+ off += pad;
+ npad++;
+ }
+ structType += fmt.Sprintf("\t\t%s r;\n", t.C);
+ off += t.Size;
+ }
+ if off%ptrSize != 0 {
+ pad := ptrSize - off%ptrSize;
+ structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
+ off += pad;
+ npad++;
+ }
+ if len(def.Params) == 0 && def.Result == nil {
+ structType += "\t\tchar unused;\n"; // avoid empty struct
+ off++;
+ }
+ structType += "\t}";
+ argSize := off;
+
+ // C wrapper calls into gcc, passing a pointer to the argument frame.
+ // Also emit #pragma to get a pointer to the gcc wrapper.
+ fmt.Fprintf(fc, "#pragma dynld _cgo_%s _cgo_%s \"%s.so\"\n", name, name, p.PackagePath);
+ fmt.Fprintf(fc, "void (*_cgo_%s)(void*);\n", name);
+ fmt.Fprintf(fc, "\n");
+ fmt.Fprintf(fc, "void\n");
+ fmt.Fprintf(fc, "%s·_C_%s(struct{uint8 x[%d];}p)\n", p.Package, name, argSize);
+ fmt.Fprintf(fc, "{\n");
+ fmt.Fprintf(fc, "\tcgocall(_cgo_%s, &p);\n", name);
+ fmt.Fprintf(fc, "}\n");
+ fmt.Fprintf(fc, "\n");
+
+ // Gcc wrapper unpacks the C argument struct
+ // and calls the actual C function.
+ fmt.Fprintf(fgcc, "void\n");
+ fmt.Fprintf(fgcc, "_cgo_%s(void *v)\n", name);
+ fmt.Fprintf(fgcc, "{\n");
+ fmt.Fprintf(fgcc, "\t%s *a = v;\n", structType);
+ fmt.Fprintf(fgcc, "\t");
+ if def.Result != nil {
+ fmt.Fprintf(fgcc, "a->r = ");
+ }
+ fmt.Fprintf(fgcc, "%s(", name);
+ for i := range def.Params {
+ if i > 0 {
+ fmt.Fprintf(fgcc, ", ");
+ }
+ fmt.Fprintf(fgcc, "a->p%d", i);
+ }
+ fmt.Fprintf(fgcc, ");\n");
+ fmt.Fprintf(fgcc, "}\n");
+ fmt.Fprintf(fgcc, "\n");
+ }
+}
+
+const gccProlog = `
+// Usual nonsense: if x and y are not equal, the type will be invalid
+// (have a negative array count) and an inscrutable error will come
+// out of the compiler and hopefully mention "name".
+#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
+
+// Check at compile time that the sizes we use match our expectations.
+#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
+
+__cgo_size_assert(char, 1)
+__cgo_size_assert(short, 2)
+__cgo_size_assert(int, 4)
+typedef long long __cgo_long_long;
+__cgo_size_assert(__cgo_long_long, 8)
+__cgo_size_assert(float, 4)
+__cgo_size_assert(double, 8)
+`
+
+const builtinProlog = `
+typedef struct { char *p; int n; } _GoString_;
+_GoString_ GoString(char *p);
+char *CString(_GoString_);
+`
+
+const cProlog = `
+#include "runtime.h"
+#include "cgocall.h"
+
+#pragma dynld initcgo initcgo "libcgo.so"
+#pragma dynld cgo cgo "libcgo.so"
+#pragma dynld _cgo_malloc _cgo_malloc "libcgo.so"
+#pragma dynld _cgo_free free "libcgo.so"
+
+void
+%s·_C_GoString(int8 *p, String s)
+{
+ s = gostring((byte*)p);
+ FLUSH(&s);
+}
+
+void
+%s·_C_CString(String s, int8 *p)
+{
+ p = cmalloc(s.len+1);
+ mcpy((byte*)p, s.str, s.len);
+ p[s.len] = 0;
+ FLUSH(&p);
+}
+`
+
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// #include <stdio.h>
+// #include <stdlib.h>
+import "C"
+
+type File C.FILE;
+
+func (f *File) Putc(c int) {
+ C.putc(C.int(c), (*C.FILE)(f));
+}
+
+func (f *File) Puts(s string) {
+ p := C.CString(s);
+ C.fputs(p, (*C.FILE)(f));
+ C.free(unsafe.Pointer(p));
+}
+
+var Stdout = (*File)(C.stdout);
+
+func main() {
+ Stdout.Puts("hello, world\n");
+}
}
}
+// Helper.
+
+void
+_cgo_malloc(void *p)
+{
+ struct a {
+ long long n;
+ void *ret;
+ } *a = p;
+
+ a->ret = malloc(a->n);
+}
FLUSH(&ret);
}
+void (*_cgo_malloc)(void*);
+void (*_cgo_free)(void*);
+
+void*
+cmalloc(uintptr n)
+{
+ struct a {
+ uint64 n;
+ void *ret;
+ } a;
+
+ a.n = n;
+ a.ret = nil;
+ cgocall(_cgo_malloc, &a);
+ return a.ret;
+}
+
+void
+cfree(void *p)
+{
+ cgocall(_cgo_free, p);
+}
+
/*
* Cgo interface.
* Dynamically linked shared libraries compiled with gcc
- * know these data structures too. See ../../libcgo/cgocall.c
+ * know these data structures and functions too.
+ * See ../../libcgo/cgocall.c
*/
typedef struct CgoWork CgoWork;
void cgocall(void (*fn)(void*), void*);
+void *cmalloc(uintptr);
+void cfree(void*);