all: replace llvm.Const* calls with builder.Create* calls

A number of llvm.Const* functions (in particular extractvalue and
insertvalue) were removed in LLVM 15, so we have to use a builder
instead. This builder will create the same constant values, it simply
uses a different API.
This commit is contained in:
Ayke van Laethem
2022-09-20 23:26:49 +02:00
committed by Ron Evans
parent f57cffce2d
commit 09ec846c9f
13 changed files with 86 additions and 65 deletions
+1 -1
View File
@@ -218,7 +218,7 @@ func MakeGCStackSlots(mod llvm.Module) bool {
initialStackObject := llvm.ConstNull(stackObjectType)
numSlots := (targetData.TypeAllocSize(stackObjectType) - uint64(targetData.PointerSize())*2) / uint64(targetData.ABITypeAlignment(uintptrType))
numSlotsValue := llvm.ConstInt(uintptrType, numSlots, false)
initialStackObject = llvm.ConstInsertValue(initialStackObject, numSlotsValue, []uint32{1})
initialStackObject = builder.CreateInsertValue(initialStackObject, numSlotsValue, 1, "")
builder.CreateStore(initialStackObject, stackObject)
// Update stack start.
+7 -7
View File
@@ -154,7 +154,7 @@ func (p *lowerInterfacesPass) run() error {
if initializer.IsNil() {
continue
}
methodSet := llvm.ConstExtractValue(initializer, []uint32{2})
methodSet := p.builder.CreateExtractValue(initializer, 2, "")
p.addTypeMethods(t, methodSet)
}
}
@@ -288,9 +288,9 @@ func (p *lowerInterfacesPass) run() error {
zeroUintptr := llvm.ConstNull(p.uintptrType)
for _, t := range p.types {
initializer := t.typecode.Initializer()
methodSet := llvm.ConstExtractValue(initializer, []uint32{2})
initializer = llvm.ConstInsertValue(initializer, llvm.ConstNull(methodSet.Type()), []uint32{2})
initializer = llvm.ConstInsertValue(initializer, zeroUintptr, []uint32{4})
methodSet := p.builder.CreateExtractValue(initializer, 2, "")
initializer = p.builder.CreateInsertValue(initializer, llvm.ConstNull(methodSet.Type()), 2, "")
initializer = p.builder.CreateInsertValue(initializer, zeroUintptr, 4, "")
t.typecode.SetInitializer(initializer)
}
@@ -311,10 +311,10 @@ func (p *lowerInterfacesPass) addTypeMethods(t *typeInfo, methodSet llvm.Value)
t.methodSet = methodSet
set := methodSet.Initializer() // get value from global
for i := 0; i < set.Type().ArrayLength(); i++ {
methodData := llvm.ConstExtractValue(set, []uint32{uint32(i)})
signatureGlobal := llvm.ConstExtractValue(methodData, []uint32{0})
methodData := p.builder.CreateExtractValue(set, i, "")
signatureGlobal := p.builder.CreateExtractValue(methodData, 0, "")
signatureName := signatureGlobal.Name()
function := llvm.ConstExtractValue(methodData, []uint32{1}).Operand(0)
function := p.builder.CreateExtractValue(methodData, 1, "").Operand(0)
signature := p.getSignature(signatureName)
method := &methodInfo{
function: function,
+4 -3
View File
@@ -44,7 +44,8 @@ func LowerInterrupts(mod llvm.Module) []error {
// Get the interrupt number from the initializer
initializer := global.Initializer()
num := llvm.ConstExtractValue(initializer, []uint32{2, 0}).SExtValue()
interrupt := builder.CreateExtractValue(initializer, 2, "")
num := builder.CreateExtractValue(interrupt, 0, "").SExtValue()
pkg := packageFromInterruptHandle(global)
handles, exists := handleMap[num]
@@ -89,8 +90,8 @@ func LowerInterrupts(mod llvm.Module) []error {
builder.SetInsertPointBefore(call)
for _, handler := range handlers {
initializer := handler.Initializer()
context := llvm.ConstExtractValue(initializer, []uint32{0})
funcPtr := llvm.ConstExtractValue(initializer, []uint32{1}).Operand(0)
context := builder.CreateExtractValue(initializer, 0, "")
funcPtr := builder.CreateExtractValue(initializer, 1, "").Operand(0)
builder.CreateCall(funcPtr.GlobalValueType(), funcPtr, []llvm.Value{
num,
context,
+9 -7
View File
@@ -36,25 +36,27 @@ func hasUses(value llvm.Value) bool {
// linkage/constant/etc properties yourself.
func makeGlobalArray(mod llvm.Module, bufItf interface{}, name string, elementType llvm.Type) (llvm.Type, llvm.Value) {
buf := reflect.ValueOf(bufItf)
globalType := llvm.ArrayType(elementType, buf.Len())
global := llvm.AddGlobal(mod, globalType, name)
value := llvm.Undef(globalType)
var values []llvm.Value
for i := 0; i < buf.Len(); i++ {
ch := buf.Index(i).Uint()
value = llvm.ConstInsertValue(value, llvm.ConstInt(elementType, ch, false), []uint32{uint32(i)})
values = append(values, llvm.ConstInt(elementType, ch, false))
}
value := llvm.ConstArray(elementType, values)
global := llvm.AddGlobal(mod, value.Type(), name)
global.SetInitializer(value)
return globalType, global
return value.Type(), global
}
// getGlobalBytes returns the slice contained in the array of the provided
// global. It can recover the bytes originally created using makeGlobalArray, if
// makeGlobalArray was given a byte slice.
func getGlobalBytes(global llvm.Value) []byte {
//
// The builder parameter is only used for constant operations.
func getGlobalBytes(global llvm.Value, builder llvm.Builder) []byte {
value := global.Initializer()
buf := make([]byte, value.Type().ArrayLength())
for i := range buf {
buf[i] = byte(llvm.ConstExtractValue(value, []uint32{uint32(i)}).ZExtValue())
buf[i] = byte(builder.CreateExtractValue(value, i, "").ZExtValue())
}
return buf
}
+19 -13
View File
@@ -76,6 +76,10 @@ var nonBasicTypes = map[string]int64{
// typeCodeAssignmentState keeps some global state around for type code
// assignments, used to assign one unique type code to each Go type.
type typeCodeAssignmentState struct {
// Builder used purely for constant operations (because LLVM 15 removed many
// llvm.Const* functions).
builder llvm.Builder
// An integer that's incremented each time it's used to give unique IDs to
// type codes that are not yet fully supported otherwise by the reflect
// package (or are simply unused in the compiled program).
@@ -165,6 +169,7 @@ func LowerReflect(mod llvm.Module) {
defer targetData.Dispose()
uintptrType := mod.Context().IntType(targetData.PointerSize() * 8)
state := typeCodeAssignmentState{
builder: mod.Context().NewBuilder(),
fallbackIndex: 1,
uintptrLen: targetData.PointerSize() * 8,
namedBasicTypes: make(map[string]int),
@@ -177,6 +182,7 @@ func LowerReflect(mod llvm.Module) {
needsStructNamesSidetable: len(getUses(mod.NamedGlobal("reflect.structNamesSidetable"))) != 0,
needsArrayTypesSidetable: len(getUses(mod.NamedGlobal("reflect.arrayTypesSidetable"))) != 0,
}
defer state.builder.Dispose()
for _, t := range types {
num := state.getTypeCodeNum(t.typecode)
if num.BitLen() > state.uintptrLen || !num.IsUint64() {
@@ -238,7 +244,7 @@ func LowerReflect(mod llvm.Module) {
// It also cleans up the IR for testing.
for _, typ := range types {
initializer := typ.typecode.Initializer()
references := llvm.ConstExtractValue(initializer, []uint32{0})
references := state.builder.CreateExtractValue(initializer, 0, "")
typ.typecode.SetInitializer(llvm.ConstNull(initializer.Type()))
if strings.HasPrefix(typ.name, "reflect/types.type:struct:") {
// Structs have a 'references' field that is not a typecode but
@@ -260,7 +266,7 @@ func (state *typeCodeAssignmentState) getTypeCodeNum(typecode llvm.Value) *big.I
name := ""
if class == "named" {
name = value
typecode = llvm.ConstExtractValue(typecode.Initializer(), []uint32{0})
typecode = state.builder.CreateExtractValue(typecode.Initializer(), 0, "")
class, value = getClassAndValueFromTypeCode(typecode)
}
if class == "basic" {
@@ -344,7 +350,7 @@ func (state *typeCodeAssignmentState) getNonBasicTypeCode(class string, typecode
switch class {
case "chan", "pointer", "slice":
// Prefix-style type kinds. The upper bits contain the element type.
sub := llvm.ConstExtractValue(typecode.Initializer(), []uint32{0})
sub := state.builder.CreateExtractValue(typecode.Initializer(), 0, "")
return state.getTypeCodeNum(sub)
case "array":
// An array is basically a pair of (typecode, length) stored in a
@@ -416,7 +422,7 @@ func (state *typeCodeAssignmentState) getArrayTypeNum(typecode llvm.Value) int {
return num
}
elemTypeCode := llvm.ConstExtractValue(typecode.Initializer(), []uint32{0})
elemTypeCode := state.builder.CreateExtractValue(typecode.Initializer(), 0, "")
elemTypeNum := state.getTypeCodeNum(elemTypeCode)
if elemTypeNum.BitLen() > state.uintptrLen || !elemTypeNum.IsUint64() {
// TODO: make this a regular error
@@ -424,7 +430,7 @@ func (state *typeCodeAssignmentState) getArrayTypeNum(typecode llvm.Value) int {
}
// The array side table is a sequence of {element type, array length}.
arrayLength := llvm.ConstExtractValue(typecode.Initializer(), []uint32{1}).ZExtValue()
arrayLength := state.builder.CreateExtractValue(typecode.Initializer(), 1, "").ZExtValue()
buf := makeVarint(elemTypeNum.Uint64())
buf = append(buf, makeVarint(arrayLength)...)
@@ -454,7 +460,7 @@ func (state *typeCodeAssignmentState) getStructTypeNum(typecode llvm.Value) int
// Get the fields this struct type contains.
// The struct number will be the start index of
structTypeGlobal := llvm.ConstExtractValue(typecode.Initializer(), []uint32{0}).Operand(0).Initializer()
structTypeGlobal := state.builder.CreateExtractValue(typecode.Initializer(), 0, "").Operand(0).Initializer()
numFields := structTypeGlobal.Type().ArrayLength()
// The first data that is stored in the struct sidetable is the number of
@@ -471,28 +477,28 @@ func (state *typeCodeAssignmentState) getStructTypeNum(typecode llvm.Value) int
// the sidetable bigger.
for i := 0; i < numFields; i++ {
// Collect some information about this field.
field := llvm.ConstExtractValue(structTypeGlobal, []uint32{uint32(i)})
field := state.builder.CreateExtractValue(structTypeGlobal, i, "")
nameGlobal := llvm.ConstExtractValue(field, []uint32{1})
nameGlobal := state.builder.CreateExtractValue(field, 1, "")
if nameGlobal == llvm.ConstPointerNull(nameGlobal.Type()) {
panic("compiler: no name for this struct field")
}
fieldNameBytes := getGlobalBytes(nameGlobal.Operand(0))
fieldNameBytes := getGlobalBytes(nameGlobal.Operand(0), state.builder)
fieldNameNumber := state.getStructNameNumber(fieldNameBytes)
// See whether this struct field has an associated tag, and if so,
// store that tag in the tags sidetable.
tagGlobal := llvm.ConstExtractValue(field, []uint32{2})
tagGlobal := state.builder.CreateExtractValue(field, 2, "")
hasTag := false
tagNumber := 0
if tagGlobal != llvm.ConstPointerNull(tagGlobal.Type()) {
hasTag = true
tagBytes := getGlobalBytes(tagGlobal.Operand(0))
tagBytes := getGlobalBytes(tagGlobal.Operand(0), state.builder)
tagNumber = state.getStructNameNumber(tagBytes)
}
// The 'embedded' or 'anonymous' flag for this field.
embedded := llvm.ConstExtractValue(field, []uint32{3}).ZExtValue() != 0
embedded := state.builder.CreateExtractValue(field, 3, "").ZExtValue() != 0
// The first byte in the struct types sidetable is a flags byte with
// two bits in it.
@@ -510,7 +516,7 @@ func (state *typeCodeAssignmentState) getStructTypeNum(typecode llvm.Value) int
// Get the type number and add it to the buffer.
// All fields have a type, so include it directly here.
typeNum := state.getTypeCodeNum(llvm.ConstExtractValue(field, []uint32{0}))
typeNum := state.getTypeCodeNum(state.builder.CreateExtractValue(field, 0, ""))
if typeNum.BitLen() > state.uintptrLen || !typeNum.IsUint64() {
// TODO: make this a regular error
panic("struct field has a type code that is too big")
+2 -2
View File
@@ -149,7 +149,7 @@ func OptimizeReflectImplements(mod llvm.Module) {
interfaceType := interfaceTypeBitCast.Operand(0)
if strings.HasPrefix(interfaceType.Name(), "reflect/types.type:named:") {
// Get the underlying type.
interfaceType = llvm.ConstExtractValue(interfaceType.Initializer(), []uint32{0})
interfaceType = builder.CreateExtractValue(interfaceType.Initializer(), 0, "")
}
if !strings.HasPrefix(interfaceType.Name(), "reflect/types.type:interface:") {
// This is an error. The Type passed to Implements should be of
@@ -161,7 +161,7 @@ func OptimizeReflectImplements(mod llvm.Module) {
// Interface is unknown at compile time. This can't be optimized.
continue
}
typeAssertFunction := llvm.ConstExtractValue(interfaceType.Initializer(), []uint32{4}).Operand(0)
typeAssertFunction := builder.CreateExtractValue(interfaceType.Initializer(), 4, "").Operand(0)
// Replace Implements call with the type assert call.
builder.SetInsertPointBefore(call)