Index: llgo/trunk/irgen/ssa.go =================================================================== --- llgo/trunk/irgen/ssa.go +++ llgo/trunk/irgen/ssa.go @@ -663,7 +663,7 @@ return value } - panic("Instruction not visited yet") + panic(fmt.Errorf("Instruction %q not visited yet", v.Name())) } func (fr *frame) llvmvalue(v ssa.Value) llvm.Value { @@ -696,10 +696,14 @@ } } -func (fr *frame) canAvoidElementLoad(refs []ssa.Instruction) bool { - for _, ref := range refs { - switch ref.(type) { - case *ssa.Field, *ssa.Index: +func (fr *frame) canAvoidElementLoad(ptr ssa.Value) bool { + for _, ref := range *ptr.Referrers() { + switch ref := ref.(type) { + case *ssa.Field: + case *ssa.Index: + if ref.X != ptr { + return false + } // ok default: return false @@ -712,7 +716,7 @@ // If this value is sufficiently large, look through referrers to see if we can // avoid a load. func (fr *frame) canAvoidLoad(instr *ssa.UnOp, op llvm.Value) bool { - if fr.types.Sizeof(instr.Type()) < 16 { + if fr.types.Sizeof(instr.Type()) < 2*fr.types.Sizeof(types.Typ[types.Int]) { // Don't bother with small values. return false } @@ -724,10 +728,16 @@ // We only know how to avoid loads if they are used to create an interface // or read an element of the structure. If we see any other referrer, abort. for _, ref := range *instr.Referrers() { - switch ref.(type) { + switch ref := ref.(type) { case *ssa.MakeInterface: esc = true - case *ssa.Field, *ssa.Index: + case *ssa.Field: + case *ssa.Index: + if ref.X != instr { + // This should never happen, as indices are always of type int + // and we don't bother with values smaller than 2*sizeof(int). + panic("impossible") + } // ok default: return false @@ -895,7 +905,7 @@ fieldtyp := instr.Type() if p, ok := fr.ptr[instr.X]; ok { field := fr.builder.CreateStructGEP(p, instr.Field, instr.Name()) - if fr.canAvoidElementLoad(*instr.Referrers()) { + if fr.canAvoidElementLoad(instr) { fr.ptr[instr] = field } else { fr.env[instr] = newValue(fr.builder.CreateLoad(field, ""), fieldtyp) @@ -959,7 +969,7 @@ fr.condBrRuntimeError(cond, gccgoRuntimeErrorARRAY_INDEX_OUT_OF_BOUNDS) addr := fr.builder.CreateGEP(arrayptr, []llvm.Value{zero, index}, "") - if fr.canAvoidElementLoad(*instr.Referrers()) { + if fr.canAvoidElementLoad(instr) { fr.ptr[instr] = addr } else { fr.env[instr] = newValue(fr.builder.CreateLoad(addr, ""), instr.Type()) Index: llgo/trunk/test/irgen/avoidload.go =================================================================== --- llgo/trunk/test/irgen/avoidload.go +++ llgo/trunk/test/irgen/avoidload.go @@ -0,0 +1,15 @@ +// RUN: llgo -S -emit-llvm -o - %s | FileCheck %s + +package foo + +type X struct { + indices [1]int +} + +// CHECK-NOT: load [200 x i64] +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}, i64 160000, i32 1, i1 false) +var _ = [100][200]int{}[0][0] + +// CHECK-NOT: load [1024 x i64] +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}, i64 8192, i32 1, i1 false) +var _ = [1024]int{}[X{}.indices[0]]