compiler: rename getZeroValue to llvm.ConstNull

It does the same thing but should be more complete, and it probably is
faster as well (just one CGo call instead of several).
This commit is contained in:
Ayke van Laethem
2019-09-15 16:42:31 +02:00
committed by Ron Evans
parent 8d959b7c63
commit 10ed3decb0
12 changed files with 26 additions and 106 deletions
+1 -1
View File
@@ -163,7 +163,7 @@ func (c *Compiler) collapseFormalParamInternal(t llvm.Type, fields []llvm.Value)
switch t.TypeKind() { switch t.TypeKind() {
case llvm.StructTypeKind: case llvm.StructTypeKind:
if len(c.flattenAggregateType(t)) <= MaxFieldsPerParam { if len(c.flattenAggregateType(t)) <= MaxFieldsPerParam {
value := c.getZeroValue(t) value := llvm.ConstNull(t)
for i, subtyp := range t.StructElementTypes() { for i, subtyp := range t.StructElementTypes() {
structField, remaining := c.collapseFormalParamInternal(subtyp, fields) structField, remaining := c.collapseFormalParamInternal(subtyp, fields)
fields = remaining fields = remaining
+1 -1
View File
@@ -124,7 +124,7 @@ func (c *Compiler) emitSelect(frame *Frame, expr *ssa.Select) llvm.Value {
chanSelectStateType := c.getLLVMRuntimeType("chanSelectState") chanSelectStateType := c.getLLVMRuntimeType("chanSelectState")
for _, state := range expr.States { for _, state := range expr.States {
ch := c.getValue(frame, state.Chan) ch := c.getValue(frame, state.Chan)
selectState := c.getZeroValue(chanSelectStateType) selectState := llvm.ConstNull(chanSelectStateType)
selectState = c.builder.CreateInsertValue(selectState, ch, 0, "") selectState = c.builder.CreateInsertValue(selectState, ch, 0, "")
switch state.Dir { switch state.Dir {
case types.RecvOnly: case types.RecvOnly:
+7 -43
View File
@@ -563,42 +563,6 @@ func (c *Compiler) getLLVMType(goType types.Type) llvm.Type {
} }
} }
// Return a zero LLVM value for any LLVM type. Setting this value as an
// initializer has the same effect as setting 'zeroinitializer' on a value.
// Sadly, I haven't found a way to do it directly with the Go API but this works
// just fine.
func (c *Compiler) getZeroValue(typ llvm.Type) llvm.Value {
switch typ.TypeKind() {
case llvm.ArrayTypeKind:
subTyp := typ.ElementType()
subVal := c.getZeroValue(subTyp)
vals := make([]llvm.Value, typ.ArrayLength())
for i := range vals {
vals[i] = subVal
}
return llvm.ConstArray(subTyp, vals)
case llvm.FloatTypeKind, llvm.DoubleTypeKind:
return llvm.ConstFloat(typ, 0.0)
case llvm.IntegerTypeKind:
return llvm.ConstInt(typ, 0, false)
case llvm.PointerTypeKind:
return llvm.ConstPointerNull(typ)
case llvm.StructTypeKind:
types := typ.StructElementTypes()
vals := make([]llvm.Value, len(types))
for i, subTyp := range types {
vals[i] = c.getZeroValue(subTyp)
}
if typ.StructName() != "" {
return llvm.ConstNamedStruct(typ, vals)
} else {
return c.ctx.ConstStruct(vals, false)
}
default:
panic("unknown LLVM zero inititializer: " + typ.String())
}
}
// Is this a pointer type of some sort? Can be unsafe.Pointer or any *T pointer. // Is this a pointer type of some sort? Can be unsafe.Pointer or any *T pointer.
func isPointer(typ types.Type) bool { func isPointer(typ types.Type) bool {
if _, ok := typ.(*types.Pointer); ok { if _, ok := typ.(*types.Pointer); ok {
@@ -1132,7 +1096,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) {
c.builder.CreateRet(c.getValue(frame, instr.Results[0])) c.builder.CreateRet(c.getValue(frame, instr.Results[0]))
} else { } else {
// Multiple return values. Put them all in a struct. // Multiple return values. Put them all in a struct.
retVal := c.getZeroValue(frame.fn.LLVMFn.Type().ElementType().ReturnType()) retVal := llvm.ConstNull(frame.fn.LLVMFn.Type().ElementType().ReturnType())
for i, result := range instr.Results { for i, result := range instr.Results {
val := c.getValue(frame, result) val := c.getValue(frame, result)
retVal = c.builder.CreateInsertValue(retVal, val, i, "") retVal = c.builder.CreateInsertValue(retVal, val, i, "")
@@ -1460,7 +1424,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
} else { } else {
buf := c.createEntryBlockAlloca(typ, expr.Comment) buf := c.createEntryBlockAlloca(typ, expr.Comment)
if c.targetData.TypeAllocSize(typ) != 0 { if c.targetData.TypeAllocSize(typ) != 0 {
c.builder.CreateStore(c.getZeroValue(typ), buf) // zero-initialize var c.builder.CreateStore(llvm.ConstNull(typ), buf) // zero-initialize var
} }
return buf, nil return buf, nil
} }
@@ -1767,7 +1731,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
panic("unknown type in range: " + typ.String()) panic("unknown type in range: " + typ.String())
} }
it, _, _ := c.createTemporaryAlloca(iteratorType, "range.it") it, _, _ := c.createTemporaryAlloca(iteratorType, "range.it")
c.builder.CreateStore(c.getZeroValue(iteratorType), it) c.builder.CreateStore(llvm.ConstNull(iteratorType), it)
return it, nil return it, nil
case *ssa.Select: case *ssa.Select:
return c.emitSelect(frame, expr), nil return c.emitSelect(frame, expr), nil
@@ -2349,12 +2313,12 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) llvm.Value {
if expr.Value != nil { if expr.Value != nil {
panic("expected nil chan constant") panic("expected nil chan constant")
} }
return c.getZeroValue(c.getLLVMType(expr.Type())) return llvm.ConstNull(c.getLLVMType(expr.Type()))
case *types.Signature: case *types.Signature:
if expr.Value != nil { if expr.Value != nil {
panic("expected nil signature constant") panic("expected nil signature constant")
} }
return c.getZeroValue(c.getLLVMType(expr.Type())) return llvm.ConstNull(c.getLLVMType(expr.Type()))
case *types.Interface: case *types.Interface:
if expr.Value != nil { if expr.Value != nil {
panic("expected nil interface constant") panic("expected nil interface constant")
@@ -2389,7 +2353,7 @@ func (c *Compiler) parseConst(prefix string, expr *ssa.Const) llvm.Value {
panic("non-nil map constant") panic("non-nil map constant")
} }
llvmType := c.getLLVMType(typ) llvmType := c.getLLVMType(typ)
return c.getZeroValue(llvmType) return llvm.ConstNull(llvmType)
default: default:
panic("unknown constant: " + expr.String()) panic("unknown constant: " + expr.String())
} }
@@ -2581,7 +2545,7 @@ func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) {
unop.X.Type().Underlying().(*types.Pointer).Elem() unop.X.Type().Underlying().(*types.Pointer).Elem()
if c.targetData.TypeAllocSize(x.Type().ElementType()) == 0 { if c.targetData.TypeAllocSize(x.Type().ElementType()) == 0 {
// zero-length data // zero-length data
return c.getZeroValue(x.Type().ElementType()), nil return llvm.ConstNull(x.Type().ElementType()), nil
} else if strings.HasSuffix(unop.X.String(), "$funcaddr") { } else if strings.HasSuffix(unop.X.String(), "$funcaddr") {
// CGo function pointer. The cgo part has rewritten CGo function // CGo function pointer. The cgo part has rewritten CGo function
// pointers as stub global variables of the form: // pointers as stub global variables of the form:
+1 -1
View File
@@ -122,7 +122,7 @@ func (c *Compiler) emitDefer(frame *Frame, instr *ssa.Defer) {
// Make a struct out of the collected values to put in the defer frame. // Make a struct out of the collected values to put in the defer frame.
deferFrameType := c.ctx.StructType(valueTypes, false) deferFrameType := c.ctx.StructType(valueTypes, false)
deferFrame := c.getZeroValue(deferFrameType) deferFrame := llvm.ConstNull(deferFrameType)
for i, value := range values { for i, value := range values {
deferFrame = c.builder.CreateInsertValue(deferFrame, value, i, "") deferFrame = c.builder.CreateInsertValue(deferFrame, value, i, "")
} }
+3 -3
View File
@@ -134,7 +134,7 @@ func (c *Compiler) makeGCStackSlots() bool {
} }
stackChainStart := c.mod.NamedGlobal("runtime.stackChainStart") stackChainStart := c.mod.NamedGlobal("runtime.stackChainStart")
if !stackChainStart.IsNil() { if !stackChainStart.IsNil() {
stackChainStart.SetInitializer(c.getZeroValue(stackChainStart.Type().ElementType())) stackChainStart.SetInitializer(llvm.ConstNull(stackChainStart.Type().ElementType()))
stackChainStart.SetGlobalConstant(true) stackChainStart.SetGlobalConstant(true)
} }
} }
@@ -198,7 +198,7 @@ func (c *Compiler) makeGCStackSlots() bool {
panic("stack chain start not found!") panic("stack chain start not found!")
} }
stackChainStartType := stackChainStart.Type().ElementType() stackChainStartType := stackChainStart.Type().ElementType()
stackChainStart.SetInitializer(c.getZeroValue(stackChainStartType)) stackChainStart.SetInitializer(llvm.ConstNull(stackChainStartType))
// Iterate until runtime.trackPointer has no uses left. // Iterate until runtime.trackPointer has no uses left.
for use := trackPointer.FirstUse(); !use.IsNil(); use = trackPointer.FirstUse() { for use := trackPointer.FirstUse(); !use.IsNil(); use = trackPointer.FirstUse() {
@@ -303,7 +303,7 @@ func (c *Compiler) makeGCStackSlots() bool {
// Create the stack object at the function entry. // Create the stack object at the function entry.
c.builder.SetInsertPointBefore(fn.EntryBasicBlock().FirstInstruction()) c.builder.SetInsertPointBefore(fn.EntryBasicBlock().FirstInstruction())
stackObject := c.builder.CreateAlloca(stackObjectType, "gc.stackobject") stackObject := c.builder.CreateAlloca(stackObjectType, "gc.stackobject")
initialStackObject := c.getZeroValue(stackObjectType) initialStackObject := llvm.ConstNull(stackObjectType)
numSlots := (c.targetData.TypeAllocSize(stackObjectType) - c.targetData.TypeAllocSize(c.i8ptrType)*2) / uint64(c.targetData.ABITypeAlignment(c.uintptrType)) numSlots := (c.targetData.TypeAllocSize(stackObjectType) - c.targetData.TypeAllocSize(c.i8ptrType)*2) / uint64(c.targetData.ABITypeAlignment(c.uintptrType))
numSlotsValue := llvm.ConstInt(c.uintptrType, numSlots, false) numSlotsValue := llvm.ConstInt(c.uintptrType, numSlots, false)
initialStackObject = llvm.ConstInsertValue(initialStackObject, numSlotsValue, []uint32{1}) initialStackObject = llvm.ConstInsertValue(initialStackObject, numSlotsValue, []uint32{1})
+4 -4
View File
@@ -74,7 +74,7 @@ func (c *Compiler) getTypeCode(typ types.Type) llvm.Value {
} }
if !references.IsNil() { if !references.IsNil() {
// Set the 'references' field of the runtime.typecodeID struct. // Set the 'references' field of the runtime.typecodeID struct.
globalValue := c.getZeroValue(global.Type().ElementType()) globalValue := llvm.ConstNull(global.Type().ElementType())
globalValue = llvm.ConstInsertValue(globalValue, references, []uint32{0}) globalValue = llvm.ConstInsertValue(globalValue, references, []uint32{0})
if length != 0 { if length != 0 {
lengthValue := llvm.ConstInt(c.uintptrType, uint64(length), false) lengthValue := llvm.ConstInt(c.uintptrType, uint64(length), false)
@@ -96,9 +96,9 @@ func (c *Compiler) makeStructTypeFields(typ *types.Struct) llvm.Value {
runtimeStructField := c.getLLVMRuntimeType("structField") runtimeStructField := c.getLLVMRuntimeType("structField")
structGlobalType := llvm.ArrayType(runtimeStructField, typ.NumFields()) structGlobalType := llvm.ArrayType(runtimeStructField, typ.NumFields())
structGlobal := llvm.AddGlobal(c.mod, structGlobalType, "reflect/types.structFields") structGlobal := llvm.AddGlobal(c.mod, structGlobalType, "reflect/types.structFields")
structGlobalValue := c.getZeroValue(structGlobalType) structGlobalValue := llvm.ConstNull(structGlobalType)
for i := 0; i < typ.NumFields(); i++ { for i := 0; i < typ.NumFields(); i++ {
fieldGlobalValue := c.getZeroValue(runtimeStructField) fieldGlobalValue := llvm.ConstNull(runtimeStructField)
fieldGlobalValue = llvm.ConstInsertValue(fieldGlobalValue, c.getTypeCode(typ.Field(i).Type()), []uint32{0}) fieldGlobalValue = llvm.ConstInsertValue(fieldGlobalValue, c.getTypeCode(typ.Field(i).Type()), []uint32{0})
fieldName := c.makeGlobalArray([]byte(typ.Field(i).Name()), "reflect/types.structFieldName", c.ctx.Int8Type()) fieldName := c.makeGlobalArray([]byte(typ.Field(i).Name()), "reflect/types.structFieldName", c.ctx.Int8Type())
fieldName.SetLinkage(llvm.PrivateLinkage) fieldName.SetLinkage(llvm.PrivateLinkage)
@@ -380,7 +380,7 @@ func (c *Compiler) parseTypeAssert(frame *Frame, expr *ssa.TypeAssert) llvm.Valu
// Continue after the if statement. // Continue after the if statement.
c.builder.SetInsertPointAtEnd(nextBlock) c.builder.SetInsertPointAtEnd(nextBlock)
phi := c.builder.CreatePHI(assertedType, "typeassert.value") phi := c.builder.CreatePHI(assertedType, "typeassert.value")
phi.AddIncoming([]llvm.Value{c.getZeroValue(assertedType), valueOk}, []llvm.BasicBlock{prevBlock, okBlock}) phi.AddIncoming([]llvm.Value{llvm.ConstNull(assertedType), valueOk}, []llvm.BasicBlock{prevBlock, okBlock})
if expr.CommaOk { if expr.CommaOk {
tuple := c.ctx.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(c.ctx.Int1Type())}, false) // create empty tuple tuple := c.ctx.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(c.ctx.Int1Type())}, false) // create empty tuple
+1 -1
View File
@@ -289,7 +289,7 @@ func (c *Compiler) OptimizeAllocs() {
sizeInWords := (size + uint64(alignment) - 1) / uint64(alignment) sizeInWords := (size + uint64(alignment) - 1) / uint64(alignment)
allocaType := llvm.ArrayType(c.ctx.IntType(alignment*8), int(sizeInWords)) allocaType := llvm.ArrayType(c.ctx.IntType(alignment*8), int(sizeInWords))
alloca := c.builder.CreateAlloca(allocaType, "stackalloc.alloca") alloca := c.builder.CreateAlloca(allocaType, "stackalloc.alloca")
zero := c.getZeroValue(alloca.Type().ElementType()) zero := llvm.ConstNull(alloca.Type().ElementType())
c.builder.CreateStore(zero, alloca) c.builder.CreateStore(zero, alloca)
stackalloc := c.builder.CreateBitCast(alloca, bitcast.Type(), "stackalloc") stackalloc := c.builder.CreateBitCast(alloca, bitcast.Type(), "stackalloc")
bitcast.ReplaceAllUsesWith(stackalloc) bitcast.ReplaceAllUsesWith(stackalloc)
+1 -1
View File
@@ -61,7 +61,7 @@ func (c *Compiler) getGlobal(g *ssa.Global) llvm.Value {
llvmType := c.getLLVMType(g.Type().(*types.Pointer).Elem()) llvmType := c.getLLVMType(g.Type().(*types.Pointer).Elem())
llvmGlobal = llvm.AddGlobal(c.mod, llvmType, info.linkName) llvmGlobal = llvm.AddGlobal(c.mod, llvmType, info.linkName)
if !info.extern { if !info.extern {
llvmGlobal.SetInitializer(c.getZeroValue(llvmType)) llvmGlobal.SetInitializer(llvm.ConstNull(llvmType))
llvmGlobal.SetLinkage(llvm.InternalLinkage) llvmGlobal.SetLinkage(llvm.InternalLinkage)
} }
} }
+1 -1
View File
@@ -101,7 +101,7 @@ func (c *Compiler) emitPointerUnpack(ptr llvm.Value, valueTypes []llvm.Type) []l
for i, valueType := range valueTypes { for i, valueType := range valueTypes {
if c.targetData.TypeAllocSize(valueType) == 0 { if c.targetData.TypeAllocSize(valueType) == 0 {
// This value has length zero, so there's nothing to load. // This value has length zero, so there's nothing to load.
values[i] = c.getZeroValue(valueType) values[i] = llvm.ConstNull(valueType)
continue continue
} }
indices := []llvm.Value{ indices := []llvm.Value{
+4 -4
View File
@@ -86,7 +86,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
case !inst.IsAAllocaInst().IsNil(): case !inst.IsAAllocaInst().IsNil():
allocType := inst.Type().ElementType() allocType := inst.Type().ElementType()
alloca := llvm.AddGlobal(fr.Mod, allocType, fr.pkgName+"$alloca") alloca := llvm.AddGlobal(fr.Mod, allocType, fr.pkgName+"$alloca")
alloca.SetInitializer(getZeroValue(allocType)) alloca.SetInitializer(llvm.ConstNull(allocType))
alloca.SetLinkage(llvm.InternalLinkage) alloca.SetLinkage(llvm.InternalLinkage)
fr.locals[inst] = &LocalValue{ fr.locals[inst] = &LocalValue{
Underlying: alloca, Underlying: alloca,
@@ -253,7 +253,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
allocType = llvm.ArrayType(allocType, elementCount) allocType = llvm.ArrayType(allocType, elementCount)
} }
alloc := llvm.AddGlobal(fr.Mod, allocType, fr.pkgName+"$alloc") alloc := llvm.AddGlobal(fr.Mod, allocType, fr.pkgName+"$alloc")
alloc.SetInitializer(getZeroValue(allocType)) alloc.SetInitializer(llvm.ConstNull(allocType))
alloc.SetLinkage(llvm.InternalLinkage) alloc.SetLinkage(llvm.InternalLinkage)
result := &LocalValue{ result := &LocalValue{
Underlying: alloc, Underlying: alloc,
@@ -312,7 +312,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
stringType := fr.Mod.GetTypeByName("runtime._string") stringType := fr.Mod.GetTypeByName("runtime._string")
retPtr := llvm.ConstGEP(global, getLLVMIndices(fr.Mod.Context().Int32Type(), []uint32{0, 0})) retPtr := llvm.ConstGEP(global, getLLVMIndices(fr.Mod.Context().Int32Type(), []uint32{0, 0}))
retLen := llvm.ConstInt(stringType.StructElementTypes()[1], uint64(len(result)), false) retLen := llvm.ConstInt(stringType.StructElementTypes()[1], uint64(len(result)), false)
ret := getZeroValue(stringType) ret := llvm.ConstNull(stringType)
ret = llvm.ConstInsertValue(ret, retPtr, []uint32{0}) ret = llvm.ConstInsertValue(ret, retPtr, []uint32{0})
ret = llvm.ConstInsertValue(ret, retLen, []uint32{1}) ret = llvm.ConstInsertValue(ret, retLen, []uint32{1})
fr.locals[inst] = &LocalValue{fr.Eval, ret} fr.locals[inst] = &LocalValue{fr.Eval, ret}
@@ -335,7 +335,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
sliceType := inst.Type() sliceType := inst.Type()
retPtr := llvm.ConstGEP(global, getLLVMIndices(fr.Mod.Context().Int32Type(), []uint32{0, 0})) retPtr := llvm.ConstGEP(global, getLLVMIndices(fr.Mod.Context().Int32Type(), []uint32{0, 0}))
retLen := llvm.ConstInt(sliceType.StructElementTypes()[1], uint64(len(result)), false) retLen := llvm.ConstInt(sliceType.StructElementTypes()[1], uint64(len(result)), false)
ret := getZeroValue(sliceType) ret := llvm.ConstNull(sliceType)
ret = llvm.ConstInsertValue(ret, retPtr, []uint32{0}) // ptr ret = llvm.ConstInsertValue(ret, retPtr, []uint32{0}) // ptr
ret = llvm.ConstInsertValue(ret, retLen, []uint32{1}) // len ret = llvm.ConstInsertValue(ret, retLen, []uint32{1}) // len
ret = llvm.ConstInsertValue(ret, retLen, []uint32{2}) // cap ret = llvm.ConstInsertValue(ret, retLen, []uint32{2}) // cap
-44
View File
@@ -16,50 +16,6 @@ func getUses(value llvm.Value) []llvm.Value {
return uses return uses
} }
// Return a zero LLVM value for any LLVM type. Setting this value as an
// initializer has the same effect as setting 'zeroinitializer' on a value.
// Sadly, I haven't found a way to do it directly with the Go API but this works
// just fine.
func getZeroValue(typ llvm.Type) llvm.Value {
switch typ.TypeKind() {
case llvm.ArrayTypeKind:
subTyp := typ.ElementType()
subVal := getZeroValue(subTyp)
vals := make([]llvm.Value, typ.ArrayLength())
for i := range vals {
vals[i] = subVal
}
return llvm.ConstArray(subTyp, vals)
case llvm.FloatTypeKind, llvm.DoubleTypeKind:
return llvm.ConstFloat(typ, 0.0)
case llvm.IntegerTypeKind:
return llvm.ConstInt(typ, 0, false)
case llvm.PointerTypeKind:
return llvm.ConstPointerNull(typ)
case llvm.StructTypeKind:
types := typ.StructElementTypes()
vals := make([]llvm.Value, len(types))
for i, subTyp := range types {
val := getZeroValue(subTyp)
vals[i] = val
}
if typ.StructName() != "" {
return llvm.ConstNamedStruct(typ, vals)
} else {
return typ.Context().ConstStruct(vals, false)
}
case llvm.VectorTypeKind:
zero := getZeroValue(typ.ElementType())
vals := make([]llvm.Value, typ.VectorSize())
for i := range vals {
vals[i] = zero
}
return llvm.ConstVector(vals, false)
default:
panic("interp: unknown LLVM type: " + typ.String())
}
}
// getStringBytes loads the byte slice of a Go string represented as a // getStringBytes loads the byte slice of a Go string represented as a
// {ptr, len} pair. // {ptr, len} pair.
func getStringBytes(strPtr Value, strLen llvm.Value) []byte { func getStringBytes(strPtr Value, strLen llvm.Value) []byte {
+2 -2
View File
@@ -162,7 +162,7 @@ func (v *MapValue) newBucket() llvm.Value {
llvm.ArrayType(v.KeyType, 8), // key type llvm.ArrayType(v.KeyType, 8), // key type
llvm.ArrayType(v.ValueType, 8), // value type llvm.ArrayType(v.ValueType, 8), // value type
}, false) }, false)
bucketValue := getZeroValue(bucketType) bucketValue := llvm.ConstNull(bucketType)
bucket := llvm.AddGlobal(v.Eval.Mod, bucketType, v.PkgName+"$mapbucket") bucket := llvm.AddGlobal(v.Eval.Mod, bucketType, v.PkgName+"$mapbucket")
bucket.SetInitializer(bucketValue) bucket.SetInitializer(bucketValue)
bucket.SetLinkage(llvm.InternalLinkage) bucket.SetLinkage(llvm.InternalLinkage)
@@ -311,7 +311,7 @@ func (v *MapValue) PutString(keyBuf, keyLen, valPtr *LocalValue) {
keyType := v.Eval.Mod.GetTypeByName("runtime._string") keyType := v.Eval.Mod.GetTypeByName("runtime._string")
v.KeyType = keyType v.KeyType = keyType
key := getZeroValue(keyType) key := llvm.ConstNull(keyType)
key = llvm.ConstInsertValue(key, keyBuf.Value(), []uint32{0}) key = llvm.ConstInsertValue(key, keyBuf.Value(), []uint32{0})
key = llvm.ConstInsertValue(key, keyLen.Value(), []uint32{1}) key = llvm.ConstInsertValue(key, keyLen.Value(), []uint32{1})