Skip to content

Commit 944f022

Browse files
aykevldeadprogram
authored andcommitted
interp: support extractvalue/insertvalue with multiple operands
TinyGo doesn't emit these instructions, but they can occur as a result of optimizations.
1 parent cd517a3 commit 944f022

File tree

3 files changed

+46
-6
lines changed

3 files changed

+46
-6
lines changed

interp/interpreter.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"math"
77
"os"
8+
"strconv"
89
"strings"
910
"time"
1011

@@ -930,16 +931,31 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me
930931
result = r.builder.CreateBitCast(operands[0], inst.llvmInst.Type(), inst.name)
931932
case llvm.ExtractValue:
932933
indices := inst.llvmInst.Indices()
933-
if len(indices) != 1 {
934-
panic("expected exactly one index")
934+
// Note: the Go LLVM API doesn't support multiple indices, so simulate
935+
// this operation with some extra extractvalue instructions. Hopefully
936+
// this is optimized to a single instruction.
937+
agg := operands[0]
938+
for i := 0; i < len(indices)-1; i++ {
939+
agg = r.builder.CreateExtractValue(agg, int(indices[i]), inst.name+".agg")
935940
}
936-
result = r.builder.CreateExtractValue(operands[0], int(indices[0]), inst.name)
941+
result = r.builder.CreateExtractValue(agg, int(indices[len(indices)-1]), inst.name)
937942
case llvm.InsertValue:
938943
indices := inst.llvmInst.Indices()
939-
if len(indices) != 1 {
940-
panic("expected exactly one index")
944+
// Similar to extractvalue, we're working around a limitation in the Go
945+
// LLVM API here by splitting the insertvalue into multiple instructions
946+
// if there is more than one operand.
947+
agg := operands[0]
948+
aggregates := []llvm.Value{agg}
949+
for i := 0; i < len(indices)-1; i++ {
950+
agg = r.builder.CreateExtractValue(agg, int(indices[i]), inst.name+".agg"+strconv.Itoa(i))
951+
aggregates = append(aggregates, agg)
941952
}
942-
result = r.builder.CreateInsertValue(operands[0], operands[1], int(indices[0]), inst.name)
953+
result = operands[1]
954+
for i := len(indices) - 1; i >= 0; i-- {
955+
agg := aggregates[i]
956+
result = r.builder.CreateInsertValue(agg, result, int(indices[i]), inst.name+".insertvalue"+strconv.Itoa(i))
957+
}
958+
943959
case llvm.Add:
944960
result = r.builder.CreateAdd(operands[0], operands[1], inst.name)
945961
case llvm.Sub:

interp/testdata/basic.ll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ target triple = "x86_64--linux"
88
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
99
@main.exposedValue1 = global i16 0
1010
@main.exposedValue2 = global i16 0
11+
@main.insertedValue = global {i8, i32, {float, {i64, i16}}} zeroinitializer
1112

1213
declare void @runtime.printint64(i64) unnamed_addr
1314

@@ -71,6 +72,13 @@ entry:
7172
call void @runtime.printint64(i64 %switch1)
7273
call void @runtime.printint64(i64 %switch2)
7374

75+
; Test extractvalue/insertvalue with multiple operands.
76+
%agg = call {i8, i32, {float, {i64, i16}}} @nestedStruct()
77+
%elt = extractvalue {i8, i32, {float, {i64, i16}}} %agg, 2, 1, 0
78+
call void @runtime.printint64(i64 %elt)
79+
%agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0
80+
store {i8, i32, {float, {i64, i16}}} %agg2, {i8, i32, {float, {i64, i16}}}* @main.insertedValue
81+
7482
ret void
7583
}
7684

@@ -112,3 +120,5 @@ two:
112120
otherwise:
113121
ret i64 -1
114122
}
123+
124+
declare {i8, i32, {float, {i64, i16}}} @nestedStruct()

interp/testdata/basic.out.ll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ target triple = "x86_64--linux"
77
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
88
@main.exposedValue1 = global i16 0
99
@main.exposedValue2 = local_unnamed_addr global i16 0
10+
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
1011

1112
declare void @runtime.printint64(i64) unnamed_addr
1213

@@ -27,6 +28,17 @@ entry:
2728
store i16 7, i16* @main.exposedValue2
2829
call void @runtime.printint64(i64 6)
2930
call void @runtime.printint64(i64 -1)
31+
%agg = call { i8, i32, { float, { i64, i16 } } } @nestedStruct()
32+
%elt.agg = extractvalue { i8, i32, { float, { i64, i16 } } } %agg, 2
33+
%elt.agg1 = extractvalue { float, { i64, i16 } } %elt.agg, 1
34+
%elt = extractvalue { i64, i16 } %elt.agg1, 0
35+
call void @runtime.printint64(i64 %elt)
36+
%agg2.agg0 = extractvalue { i8, i32, { float, { i64, i16 } } } %agg, 2
37+
%agg2.agg1 = extractvalue { float, { i64, i16 } } %agg2.agg0, 1
38+
%agg2.insertvalue2 = insertvalue { i64, i16 } %agg2.agg1, i64 5, 0
39+
%agg2.insertvalue1 = insertvalue { float, { i64, i16 } } %agg2.agg0, { i64, i16 } %agg2.insertvalue2, 1
40+
%agg2.insertvalue0 = insertvalue { i8, i32, { float, { i64, i16 } } } %agg, { float, { i64, i16 } } %agg2.insertvalue1, 2
41+
store { i8, i32, { float, { i64, i16 } } } %agg2.insertvalue0, { i8, i32, { float, { i64, i16 } } }* @main.insertedValue
3042
ret void
3143
}
3244

@@ -67,3 +79,5 @@ two: ; preds = %entry
6779
otherwise: ; preds = %entry
6880
ret i64 -1
6981
}
82+
83+
declare { i8, i32, { float, { i64, i16 } } } @nestedStruct() local_unnamed_addr

0 commit comments

Comments
 (0)