compiler: implement casting named structs and pointers to them
Этот коммит содержится в:
родитель
85f2ef40f8
коммит
38c3d0852e
3 изменённых файлов: 50 добавлений и 10 удалений
|
@ -1517,21 +1517,41 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
// https://research.swtch.com/interfaces
|
// https://research.swtch.com/interfaces
|
||||||
return c.parseExpr(frame, expr.X)
|
return c.parseExpr(frame, expr.X)
|
||||||
case *ssa.ChangeType:
|
case *ssa.ChangeType:
|
||||||
|
// This instruction changes the type, but the underlying value remains
|
||||||
|
// the same. This is often a no-op, but sometimes we have to change the
|
||||||
|
// LLVM type as well.
|
||||||
x, err := c.parseExpr(frame, expr.X)
|
x, err := c.parseExpr(frame, expr.X)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
// The only case when we need to bitcast is when casting between named
|
llvmType, err := c.getLLVMType(expr.Type())
|
||||||
// struct types, as those are actually different in LLVM. Let's just
|
|
||||||
// bitcast all struct types for ease of use.
|
|
||||||
if _, ok := expr.Type().Underlying().(*types.Struct); ok {
|
|
||||||
llvmType, err := c.getLLVMType(expr.X.Type())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
return c.builder.CreateBitCast(x, llvmType, "changetype"), nil
|
if x.Type() == llvmType {
|
||||||
}
|
// Different Go type but same LLVM type (for example, named int).
|
||||||
|
// This is the common case.
|
||||||
return x, nil
|
return x, nil
|
||||||
|
}
|
||||||
|
// Figure out what kind of type we need to cast.
|
||||||
|
switch llvmType.TypeKind() {
|
||||||
|
case llvm.StructTypeKind:
|
||||||
|
// Unfortunately, we can't just bitcast structs. We have to
|
||||||
|
// actually create a new struct of the correct type and insert the
|
||||||
|
// values from the previous struct in there.
|
||||||
|
value := llvm.Undef(llvmType)
|
||||||
|
for i := 0; i < llvmType.StructElementTypesCount(); i++ {
|
||||||
|
field := c.builder.CreateExtractValue(x, i, "changetype.field")
|
||||||
|
value = c.builder.CreateInsertValue(value, field, i, "changetype.struct")
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
|
case llvm.PointerTypeKind:
|
||||||
|
// This can happen with pointers to structs. This case is easy:
|
||||||
|
// simply bitcast the pointer to the destination type.
|
||||||
|
return c.builder.CreateBitCast(x, llvmType, "changetype.pointer"), nil
|
||||||
|
default:
|
||||||
|
return llvm.Value{}, errors.New("todo: unknown ChangeType type: " + expr.X.Type().String())
|
||||||
|
}
|
||||||
case *ssa.Const:
|
case *ssa.Const:
|
||||||
return c.parseConst(frame.fn.LinkName(), expr)
|
return c.parseConst(frame.fn.LinkName(), expr)
|
||||||
case *ssa.Convert:
|
case *ssa.Convert:
|
||||||
|
|
18
testdata/structexpand.go → testdata/structs.go
предоставленный
18
testdata/structexpand.go → testdata/structs.go
предоставленный
|
@ -28,6 +28,14 @@ type s4 struct {
|
||||||
d byte
|
d byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same struct, different type
|
||||||
|
type s4b struct {
|
||||||
|
a byte
|
||||||
|
b byte
|
||||||
|
c byte
|
||||||
|
d byte
|
||||||
|
}
|
||||||
|
|
||||||
type s5 struct {
|
type s5 struct {
|
||||||
a struct {
|
a struct {
|
||||||
aa byte
|
aa byte
|
||||||
|
@ -70,6 +78,16 @@ func test3(s s3) {
|
||||||
|
|
||||||
func test4(s s4) {
|
func test4(s s4) {
|
||||||
println("test4", s.a, s.b, s.c, s.d)
|
println("test4", s.a, s.b, s.c, s.d)
|
||||||
|
test4b(s4b(s))
|
||||||
|
test4bp((*s4b)(&s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func test4b(s s4b) {
|
||||||
|
println("test4b", s.a, s.b, s.c, s.d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test4bp(s *s4b) {
|
||||||
|
println("test4bp", s.a, s.b, s.c, s.d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func test5(s s5) {
|
func test5(s s5) {
|
2
testdata/structexpand.txt → testdata/structs.txt
предоставленный
2
testdata/structexpand.txt → testdata/structs.txt
предоставленный
|
@ -3,6 +3,8 @@ test1 1
|
||||||
test2 1 2
|
test2 1 2
|
||||||
test3 1 2 3
|
test3 1 2 3
|
||||||
test4 1 2 3 4
|
test4 1 2 3 4
|
||||||
|
test4b 1 2 3 4
|
||||||
|
test4bp 1 2 3 4
|
||||||
test5 1 2 3
|
test5 1 2 3
|
||||||
test6 foo 3 5
|
test6 foo 3 5
|
||||||
test7 (0:nil) 8
|
test7 (0:nil) 8
|
Загрузка…
Создание таблицы
Сослаться в новой задаче