interp: support extractvalue/insertvalue with multiple operands
TinyGo doesn't emit these instructions, but they can occur as a result of optimizations.
Этот коммит содержится в:
родитель
cd517a30af
коммит
944f022060
3 изменённых файлов: 46 добавлений и 6 удалений
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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)
|
result = r.builder.CreateBitCast(operands[0], inst.llvmInst.Type(), inst.name)
|
||||||
case llvm.ExtractValue:
|
case llvm.ExtractValue:
|
||||||
indices := inst.llvmInst.Indices()
|
indices := inst.llvmInst.Indices()
|
||||||
if len(indices) != 1 {
|
// Note: the Go LLVM API doesn't support multiple indices, so simulate
|
||||||
panic("expected exactly one index")
|
// 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:
|
case llvm.InsertValue:
|
||||||
indices := inst.llvmInst.Indices()
|
indices := inst.llvmInst.Indices()
|
||||||
if len(indices) != 1 {
|
// Similar to extractvalue, we're working around a limitation in the Go
|
||||||
panic("expected exactly one index")
|
// 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:
|
case llvm.Add:
|
||||||
result = r.builder.CreateAdd(operands[0], operands[1], inst.name)
|
result = r.builder.CreateAdd(operands[0], operands[1], inst.name)
|
||||||
case llvm.Sub:
|
case llvm.Sub:
|
||||||
|
|
10
interp/testdata/basic.ll
предоставленный
10
interp/testdata/basic.ll
предоставленный
|
@ -8,6 +8,7 @@ target triple = "x86_64--linux"
|
||||||
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
||||||
@main.exposedValue1 = global i16 0
|
@main.exposedValue1 = global i16 0
|
||||||
@main.exposedValue2 = global i16 0
|
@main.exposedValue2 = global i16 0
|
||||||
|
@main.insertedValue = global {i8, i32, {float, {i64, i16}}} zeroinitializer
|
||||||
|
|
||||||
declare void @runtime.printint64(i64) unnamed_addr
|
declare void @runtime.printint64(i64) unnamed_addr
|
||||||
|
|
||||||
|
@ -71,6 +72,13 @@ entry:
|
||||||
call void @runtime.printint64(i64 %switch1)
|
call void @runtime.printint64(i64 %switch1)
|
||||||
call void @runtime.printint64(i64 %switch2)
|
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
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,3 +120,5 @@ two:
|
||||||
otherwise:
|
otherwise:
|
||||||
ret i64 -1
|
ret i64 -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare {i8, i32, {float, {i64, i16}}} @nestedStruct()
|
||||||
|
|
14
interp/testdata/basic.out.ll
предоставленный
14
interp/testdata/basic.out.ll
предоставленный
|
@ -7,6 +7,7 @@ target triple = "x86_64--linux"
|
||||||
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
||||||
@main.exposedValue1 = global i16 0
|
@main.exposedValue1 = global i16 0
|
||||||
@main.exposedValue2 = local_unnamed_addr global i16 0
|
@main.exposedValue2 = local_unnamed_addr global i16 0
|
||||||
|
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
|
||||||
|
|
||||||
declare void @runtime.printint64(i64) unnamed_addr
|
declare void @runtime.printint64(i64) unnamed_addr
|
||||||
|
|
||||||
|
@ -27,6 +28,17 @@ entry:
|
||||||
store i16 7, i16* @main.exposedValue2
|
store i16 7, i16* @main.exposedValue2
|
||||||
call void @runtime.printint64(i64 6)
|
call void @runtime.printint64(i64 6)
|
||||||
call void @runtime.printint64(i64 -1)
|
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
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,3 +79,5 @@ two: ; preds = %entry
|
||||||
otherwise: ; preds = %entry
|
otherwise: ; preds = %entry
|
||||||
ret i64 -1
|
ret i64 -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare { i8, i32, { float, { i64, i16 } } } @nestedStruct() local_unnamed_addr
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче