diff options
author | Ayke van Laethem <[email protected]> | 2021-05-02 17:39:52 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2021-05-04 21:21:56 +0200 |
commit | 944f0220602bb6a30af8f3b894499e51a69517ed (patch) | |
tree | 418305ff9e05985aa902b3eec2a7713258d9edda | |
parent | cd517a30afd608dc6dd52745690c6dbd4f7fb010 (diff) | |
download | tinygo-944f0220602bb6a30af8f3b894499e51a69517ed.tar.gz tinygo-944f0220602bb6a30af8f3b894499e51a69517ed.zip |
interp: support extractvalue/insertvalue with multiple operands
TinyGo doesn't emit these instructions, but they can occur as a result
of optimizations.
-rw-r--r-- | interp/interpreter.go | 28 | ||||
-rw-r--r-- | interp/testdata/basic.ll | 10 | ||||
-rw-r--r-- | interp/testdata/basic.out.ll | 14 |
3 files changed, 46 insertions, 6 deletions
diff --git a/interp/interpreter.go b/interp/interpreter.go index ec71c56e0..c6ce6b7f9 100644 --- a/interp/interpreter.go +++ b/interp/interpreter.go @@ -5,6 +5,7 @@ import ( "fmt" "math" "os" + "strconv" "strings" "time" @@ -930,16 +931,31 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me result = r.builder.CreateBitCast(operands[0], inst.llvmInst.Type(), inst.name) case llvm.ExtractValue: indices := inst.llvmInst.Indices() - if len(indices) != 1 { - panic("expected exactly one index") + // Note: the Go LLVM API doesn't support multiple indices, so simulate + // this operation with some extra extractvalue instructions. Hopefully + // this is optimized to a single instruction. + agg := operands[0] + for i := 0; i < len(indices)-1; i++ { + agg = r.builder.CreateExtractValue(agg, int(indices[i]), inst.name+".agg") } - result = r.builder.CreateExtractValue(operands[0], int(indices[0]), inst.name) + result = r.builder.CreateExtractValue(agg, int(indices[len(indices)-1]), inst.name) case llvm.InsertValue: indices := inst.llvmInst.Indices() - if len(indices) != 1 { - panic("expected exactly one index") + // Similar to extractvalue, we're working around a limitation in the Go + // LLVM API here by splitting the insertvalue into multiple instructions + // if there is more than one operand. + agg := operands[0] + aggregates := []llvm.Value{agg} + for i := 0; i < len(indices)-1; i++ { + agg = r.builder.CreateExtractValue(agg, int(indices[i]), inst.name+".agg"+strconv.Itoa(i)) + aggregates = append(aggregates, agg) } - result = r.builder.CreateInsertValue(operands[0], operands[1], int(indices[0]), inst.name) + result = operands[1] + for i := len(indices) - 1; i >= 0; i-- { + agg := aggregates[i] + result = r.builder.CreateInsertValue(agg, result, int(indices[i]), inst.name+".insertvalue"+strconv.Itoa(i)) + } + case llvm.Add: result = r.builder.CreateAdd(operands[0], operands[1], inst.name) case llvm.Sub: diff --git a/interp/testdata/basic.ll b/interp/testdata/basic.ll index e3ff974e2..001170582 100644 --- a/interp/testdata/basic.ll +++ b/interp/testdata/basic.ll @@ -8,6 +8,7 @@ target triple = "x86_64--linux" @main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1] @main.exposedValue1 = global i16 0 @main.exposedValue2 = global i16 0 [email protected] = global {i8, i32, {float, {i64, i16}}} zeroinitializer declare void @runtime.printint64(i64) unnamed_addr @@ -71,6 +72,13 @@ entry: call void @runtime.printint64(i64 %switch1) call void @runtime.printint64(i64 %switch2) + ; Test extractvalue/insertvalue with multiple operands. + %agg = call {i8, i32, {float, {i64, i16}}} @nestedStruct() + %elt = extractvalue {i8, i32, {float, {i64, i16}}} %agg, 2, 1, 0 + call void @runtime.printint64(i64 %elt) + %agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0 + store {i8, i32, {float, {i64, i16}}} %agg2, {i8, i32, {float, {i64, i16}}}* @main.insertedValue + ret void } @@ -112,3 +120,5 @@ two: otherwise: ret i64 -1 } + +declare {i8, i32, {float, {i64, i16}}} @nestedStruct() diff --git a/interp/testdata/basic.out.ll b/interp/testdata/basic.out.ll index e873b1c8a..24f5558ba 100644 --- a/interp/testdata/basic.out.ll +++ b/interp/testdata/basic.out.ll @@ -7,6 +7,7 @@ target triple = "x86_64--linux" @main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1] @main.exposedValue1 = global i16 0 @main.exposedValue2 = local_unnamed_addr global i16 0 [email protected] = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer declare void @runtime.printint64(i64) unnamed_addr @@ -27,6 +28,17 @@ entry: store i16 7, i16* @main.exposedValue2 call void @runtime.printint64(i64 6) call void @runtime.printint64(i64 -1) + %agg = call { i8, i32, { float, { i64, i16 } } } @nestedStruct() + %elt.agg = extractvalue { i8, i32, { float, { i64, i16 } } } %agg, 2 + %elt.agg1 = extractvalue { float, { i64, i16 } } %elt.agg, 1 + %elt = extractvalue { i64, i16 } %elt.agg1, 0 + call void @runtime.printint64(i64 %elt) + %agg2.agg0 = extractvalue { i8, i32, { float, { i64, i16 } } } %agg, 2 + %agg2.agg1 = extractvalue { float, { i64, i16 } } %agg2.agg0, 1 + %agg2.insertvalue2 = insertvalue { i64, i16 } %agg2.agg1, i64 5, 0 + %agg2.insertvalue1 = insertvalue { float, { i64, i16 } } %agg2.agg0, { i64, i16 } %agg2.insertvalue2, 1 + %agg2.insertvalue0 = insertvalue { i8, i32, { float, { i64, i16 } } } %agg, { float, { i64, i16 } } %agg2.insertvalue1, 2 + store { i8, i32, { float, { i64, i16 } } } %agg2.insertvalue0, { i8, i32, { float, { i64, i16 } } }* @main.insertedValue ret void } @@ -67,3 +79,5 @@ two: ; preds = %entry otherwise: ; preds = %entry ret i64 -1 } + +declare { i8, i32, { float, { i64, i16 } } } @nestedStruct() local_unnamed_addr |