Skip to content

Commit c3992bd

Browse files
aykevldeadprogram
authored andcommitted
compiler: improve position information
In many cases, position information is not stored in Go SSA instructions because they don't exit directly in the source code. This includes implicit type conversions, implicit returns at the end of a function, the creation of a (hidden) slice when calling a variadic function, and many other cases. I'm not sure where this information is supposed to come from, but this patch takes the value (usually) from the value the instruction refers to. This seems to work well for these implicit conversions. I've also added a few extra tests to the heap-to-stack transform pass, of which one requires this improved position information.
1 parent f79e66a commit c3992bd

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

compiler/compiler.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -964,11 +964,59 @@ func (b *builder) createFunction() {
964964
}
965965
}
966966

967+
// posser is an interface that's implemented by both ssa.Value and
968+
// ssa.Instruction. It is implemented by everything that has a Pos() method,
969+
// which is all that getPos() needs.
970+
type posser interface {
971+
Pos() token.Pos
972+
}
973+
974+
// getPos returns position information for a ssa.Value or ssa.Instruction.
975+
//
976+
// Not all instructions have position information, especially when they're
977+
// implicit (such as implicit casts or implicit returns at the end of a
978+
// function). In these cases, it makes sense to try a bit harder to guess what
979+
// the position really should be.
980+
func getPos(val posser) token.Pos {
981+
pos := val.Pos()
982+
if pos != token.NoPos {
983+
// Easy: position is known.
984+
return pos
985+
}
986+
987+
// No position information is known.
988+
switch val := val.(type) {
989+
case *ssa.MakeInterface:
990+
return getPos(val.X)
991+
case *ssa.Return:
992+
syntax := val.Parent().Syntax()
993+
if syntax != nil {
994+
// non-synthetic
995+
return syntax.End()
996+
}
997+
return token.NoPos
998+
case *ssa.FieldAddr:
999+
return getPos(val.X)
1000+
case *ssa.IndexAddr:
1001+
return getPos(val.X)
1002+
case *ssa.Slice:
1003+
return getPos(val.X)
1004+
case *ssa.Store:
1005+
return getPos(val.Addr)
1006+
case *ssa.Extract:
1007+
return getPos(val.Tuple)
1008+
default:
1009+
// This is reachable, for example with *ssa.Const, *ssa.If, and
1010+
// *ssa.Jump. They might be implemented in some way in the future.
1011+
return token.NoPos
1012+
}
1013+
}
1014+
9671015
// createInstruction builds the LLVM IR equivalent instructions for the
9681016
// particular Go SSA instruction.
9691017
func (b *builder) createInstruction(instr ssa.Instruction) {
9701018
if b.Debug {
971-
pos := b.program.Fset.Position(instr.Pos())
1019+
pos := b.program.Fset.Position(getPos(instr))
9721020
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
9731021
}
9741022

transform/testdata/allocs2.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,24 @@ func main() {
2424
readByteSlice(s4)
2525

2626
s5 := make([]int, 4) // OUT: object allocated on the heap: escapes at line 27
27-
s5 = append(s5, 5)
27+
_ = append(s5, 5)
2828

2929
s6 := make([]int, 3)
3030
s7 := []int{1, 2, 3}
3131
copySlice(s6, s7)
32+
33+
c1 := getComplex128() // OUT: object allocated on the heap: escapes at line 34
34+
useInterface(c1)
35+
36+
n3 := 5 // OUT: object allocated on the heap: escapes at line 39
37+
func() int {
38+
return n3
39+
}()
40+
41+
callVariadic(3, 5, 8) // OUT: object allocated on the heap: escapes at line 41
42+
43+
s8 := []int{3, 5, 8} // OUT: object allocated on the heap: escapes at line 44
44+
callVariadic(s8...)
3245
}
3346

3447
func derefInt(x *int) int {
@@ -56,3 +69,9 @@ func getUnknownNumber() int
5669
func copySlice(out, in []int) {
5770
copy(out, in)
5871
}
72+
73+
func getComplex128() complex128
74+
75+
func useInterface(interface{})
76+
77+
func callVariadic(...int)

0 commit comments

Comments
 (0)