diff options
author | Ayke van Laethem <[email protected]> | 2022-09-22 13:33:00 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2022-10-19 22:23:19 +0200 |
commit | 62df1d7490ccf495dc08837ec72ee1d6042bc374 (patch) | |
tree | 379a9e4e5f46dc8293beeb3ba1f386f08bdf53c9 /compiler | |
parent | 229746b71ef8c6ab095f0e97aa722959c6f07268 (diff) | |
download | tinygo-62df1d7490ccf495dc08837ec72ee1d6042bc374.tar.gz tinygo-62df1d7490ccf495dc08837ec72ee1d6042bc374.zip |
all: remove pointer ElementType calls
This is needed for opaque pointers, which are enabled by default in
LLVM 15.
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/asserts.go | 4 | ||||
-rw-r--r-- | compiler/calls.go | 58 | ||||
-rw-r--r-- | compiler/compiler.go | 15 | ||||
-rw-r--r-- | compiler/func.go | 2 | ||||
-rw-r--r-- | compiler/interface.go | 4 | ||||
-rw-r--r-- | compiler/ircheck/check.go | 5 | ||||
-rw-r--r-- | compiler/symbol.go | 15 |
7 files changed, 41 insertions, 62 deletions
diff --git a/compiler/asserts.go b/compiler/asserts.go index 2a5265e93..ba4824943 100644 --- a/compiler/asserts.go +++ b/compiler/asserts.go @@ -91,7 +91,7 @@ func (b *builder) createSliceToArrayPointerCheck(sliceLen llvm.Value, arrayLen i // createUnsafeSliceCheck inserts a runtime check used for unsafe.Slice. This // function must panic if the ptr/len parameters are invalid. -func (b *builder) createUnsafeSliceCheck(ptr, len llvm.Value, lenType *types.Basic) { +func (b *builder) createUnsafeSliceCheck(ptr, len llvm.Value, elementType llvm.Type, lenType *types.Basic) { // From the documentation of unsafe.Slice: // > At run time, if len is negative, or if ptr is nil and len is not // > zero, a run-time panic occurs. @@ -105,7 +105,7 @@ func (b *builder) createUnsafeSliceCheck(ptr, len llvm.Value, lenType *types.Bas // Determine the maximum slice size, and therefore the maximum value of the // len parameter. - maxSize := b.maxSliceSize(ptr.Type().ElementType()) + maxSize := b.maxSliceSize(elementType) maxSizeValue := llvm.ConstInt(len.Type(), maxSize, false) // Do the check. By using unsigned greater than for the length check, signed diff --git a/compiler/calls.go b/compiler/calls.go index b38d770f9..b122f0c8d 100644 --- a/compiler/calls.go +++ b/compiler/calls.go @@ -20,7 +20,7 @@ const maxFieldsPerParam = 3 type paramInfo struct { llvmType llvm.Type name string // name, possibly with suffixes for e.g. struct fields - flags paramFlags + elemSize uint64 // size of pointer element type, or 0 if this isn't a pointer } // paramFlags identifies parameter attributes for flags. Most importantly, it @@ -96,13 +96,7 @@ func (c *compilerContext) expandFormalParamType(t llvm.Type, name string, goType // failed to expand this parameter: too many fields } // TODO: split small arrays - return []paramInfo{ - { - llvmType: t, - name: name, - flags: getTypeFlags(goType), - }, - } + return []paramInfo{c.getParamInfo(t, name, goType)} } // expandFormalParamOffsets returns a list of offsets from the start of an @@ -152,7 +146,6 @@ func (b *builder) expandFormalParam(v llvm.Value) []llvm.Value { // Try to flatten a struct type to a list of types. Returns a 1-element slice // with the passed in type if this is not possible. func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType types.Type) []paramInfo { - typeFlags := getTypeFlags(goType) switch t.TypeKind() { case llvm.StructTypeKind: var paramInfos []paramInfo @@ -183,40 +176,37 @@ func (c *compilerContext) flattenAggregateType(t llvm.Type, name string, goType } } subInfos := c.flattenAggregateType(subfield, name+"."+suffix, extractSubfield(goType, i)) - for i := range subInfos { - subInfos[i].flags |= typeFlags - } paramInfos = append(paramInfos, subInfos...) } return paramInfos default: - return []paramInfo{ - { - llvmType: t, - name: name, - flags: typeFlags, - }, - } + return []paramInfo{c.getParamInfo(t, name, goType)} } } -// getTypeFlags returns the type flags for a given type. It will not recurse -// into sub-types (such as in structs). -func getTypeFlags(t types.Type) paramFlags { - if t == nil { - return 0 +// getParamInfo collects information about a parameter. For example, if this +// parameter is pointer-like, it will also store the element type for the +// dereferenceable_or_null attribute. +func (c *compilerContext) getParamInfo(t llvm.Type, name string, goType types.Type) paramInfo { + info := paramInfo{ + llvmType: t, + name: name, } - switch t.Underlying().(type) { - case *types.Pointer: - // Pointers in Go must either point to an object or be nil. - return paramIsDeferenceableOrNull - case *types.Chan, *types.Map: - // Channels and maps are implemented as pointers pointing to some - // object, and follow the same rules as *types.Pointer. - return paramIsDeferenceableOrNull - default: - return 0 + if goType != nil { + switch underlying := goType.Underlying().(type) { + case *types.Pointer: + // Pointers in Go must either point to an object or be nil. + info.elemSize = c.targetData.TypeAllocSize(c.getLLVMType(underlying.Elem())) + case *types.Chan: + // Channels are implemented simply as a *runtime.channel. + info.elemSize = c.targetData.TypeAllocSize(c.getLLVMRuntimeType("channel")) + case *types.Map: + // Maps are similar to channels: they are implemented as a + // *runtime.hashmap. + info.elemSize = c.targetData.TypeAllocSize(c.getLLVMRuntimeType("hashmap")) + } } + return info } // extractSubfield extracts a field from a struct, or returns null if this is diff --git a/compiler/compiler.go b/compiler/compiler.go index 3d29628cd..fc47c29c1 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -862,7 +862,7 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package if files, ok := c.embedGlobals[member.Name()]; ok { c.createEmbedGlobal(member, global, files) } else if !info.extern { - global.SetInitializer(llvm.ConstNull(global.Type().ElementType())) + global.SetInitializer(llvm.ConstNull(global.GlobalValueType())) global.SetVisibility(llvm.HiddenVisibility) if info.section != "" { global.SetSection(info.section) @@ -1405,7 +1405,7 @@ func (b *builder) createInstruction(instr ssa.Instruction) { b.CreateRet(b.getValue(instr.Results[0])) } else { // Multiple return values. Put them all in a struct. - retVal := llvm.ConstNull(b.llvmFn.Type().ElementType().ReturnType()) + retVal := llvm.ConstNull(b.llvmFn.GlobalValueType().ReturnType()) for i, result := range instr.Results { val := b.getValue(result) retVal = b.CreateInsertValue(retVal, val, i, "") @@ -1444,7 +1444,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c elemsBuf := b.CreateExtractValue(elems, 0, "append.elemsBuf") elemsPtr := b.CreateBitCast(elemsBuf, b.i8ptrType, "append.srcPtr") elemsLen := b.CreateExtractValue(elems, 1, "append.elemsLen") - elemType := srcBuf.Type().ElementType() + elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem()) elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false) result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcPtr, elemsPtr, srcLen, srcCap, elemsLen, elemSize}, "append.new") newPtr := b.CreateExtractValue(result, 0, "append.newPtr") @@ -1497,7 +1497,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c srcLen := b.CreateExtractValue(src, 1, "copy.srcLen") dstBuf := b.CreateExtractValue(dst, 0, "copy.dstArray") srcBuf := b.CreateExtractValue(src, 0, "copy.srcArray") - elemType := dstBuf.Type().ElementType() + elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem()) dstBuf = b.CreateBitCast(dstBuf, b.i8ptrType, "copy.dstPtr") srcBuf = b.CreateBitCast(srcBuf, b.i8ptrType, "copy.srcPtr") elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false) @@ -1637,7 +1637,8 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c b.uintptrType, b.uintptrType, }, false)) - b.createUnsafeSliceCheck(ptr, len, argTypes[1].Underlying().(*types.Basic)) + elementType := b.getLLVMType(argTypes[0].Underlying().(*types.Pointer).Elem()) + b.createUnsafeSliceCheck(ptr, len, elementType, argTypes[1].Underlying().(*types.Basic)) if len.Type().IntTypeWidth() < b.uintptrType.IntTypeWidth() { // Too small, zero-extend len. len = b.CreateZExt(len, b.uintptrType, "") @@ -1712,7 +1713,7 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error) // Eventually we might be able to eliminate this special case // entirely. For details, see: // https://discourse.llvm.org/t/rfc-enabling-wstrict-prototypes-by-default-in-c/60521 - calleeType = llvm.FunctionType(callee.Type().ElementType().ReturnType(), nil, false) + calleeType = llvm.FunctionType(callee.GlobalValueType().ReturnType(), nil, false) callee = llvm.ConstBitCast(callee, llvm.PointerType(calleeType, b.funcPtrAddrSpace)) } case *ssa.MakeClosure: @@ -3095,7 +3096,7 @@ func (b *builder) createUnOp(unop *ssa.UnOp) (llvm.Value, error) { } case token.MUL: // *x, dereference pointer valueType := b.getLLVMType(unop.X.Type().Underlying().(*types.Pointer).Elem()) - if b.targetData.TypeAllocSize(x.Type().ElementType()) == 0 { + if b.targetData.TypeAllocSize(valueType) == 0 { // zero-length data return llvm.ConstNull(valueType), nil } else if strings.HasSuffix(unop.X.String(), "$funcaddr") { diff --git a/compiler/func.go b/compiler/func.go index c6a8802d7..4203fdf76 100644 --- a/compiler/func.go +++ b/compiler/func.go @@ -73,7 +73,7 @@ func (c *compilerContext) getFuncType(typ *types.Signature) llvm.Type { return c.ctx.StructType([]llvm.Type{c.i8ptrType, c.rawVoidFuncType}, false) } -// getRawFuncType returns a LLVM function pointer type for a given signature. +// getRawFuncType returns a LLVM function type for a given signature. func (c *compilerContext) getRawFuncType(typ *types.Signature) llvm.Type { // Get the return type. var returnType llvm.Type diff --git a/compiler/interface.go b/compiler/interface.go index 106c327a8..2007b7d7c 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -86,7 +86,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { if _, ok := typ.Underlying().(*types.Pointer); !ok { ptrTo = c.getTypeCode(types.NewPointer(typ)) } - globalValue := llvm.ConstNull(global.Type().ElementType()) + globalValue := llvm.ConstNull(global.GlobalValueType()) if !references.IsNil() { globalValue = c.builder.CreateInsertValue(globalValue, references, 0, "") } @@ -533,7 +533,7 @@ func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFnType receiverValue := b.emitPointerUnpack(wrapper.Param(0), []llvm.Type{receiverType})[0] params := append(b.expandFormalParam(receiverValue), wrapper.Params()[1:]...) - if llvmFn.Type().ElementType().ReturnType().TypeKind() == llvm.VoidTypeKind { + if llvmFnType.ReturnType().TypeKind() == llvm.VoidTypeKind { b.CreateCall(llvmFnType, llvmFn, params, "") b.CreateRetVoid() } else { diff --git a/compiler/ircheck/check.go b/compiler/ircheck/check.go index 30c6ee172..e2b7ed510 100644 --- a/compiler/ircheck/check.go +++ b/compiler/ircheck/check.go @@ -70,10 +70,7 @@ func (c *checker) checkType(t llvm.Type, checked map[llvm.Type]struct{}, special return fmt.Errorf("failed to verify element type of array type %s: %s", t.String(), err.Error()) } case llvm.PointerTypeKind: - // check underlying type - if err := c.checkType(t.ElementType(), checked, specials); err != nil { - return fmt.Errorf("failed to verify underlying type of pointer type %s: %s", t.String(), err.Error()) - } + // Pointers can't be checked in an opaque pointer world. case llvm.VectorTypeKind: // check element type if err := c.checkType(t.ElementType(), checked, specials); err != nil { diff --git a/compiler/symbol.go b/compiler/symbol.go index 83fe050bc..01b3fc377 100644 --- a/compiler/symbol.go +++ b/compiler/symbol.go @@ -83,7 +83,7 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value) // Add an extra parameter as the function context. This context is used in // closures and bound methods, but should be optimized away when not used. if !info.exported { - paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "context", flags: 0}) + paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "context", elemSize: 0}) } var paramTypes []llvm.Type @@ -112,17 +112,8 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value) dereferenceableOrNullKind := llvm.AttributeKindID("dereferenceable_or_null") for i, info := range paramInfos { - if info.flags¶mIsDeferenceableOrNull == 0 { - continue - } - if info.llvmType.TypeKind() == llvm.PointerTypeKind { - el := info.llvmType.ElementType() - size := c.targetData.TypeAllocSize(el) - if size == 0 { - // dereferenceable_or_null(0) appears to be illegal in LLVM. - continue - } - dereferenceableOrNull := c.ctx.CreateEnumAttribute(dereferenceableOrNullKind, size) + if info.elemSize != 0 { + dereferenceableOrNull := c.ctx.CreateEnumAttribute(dereferenceableOrNullKind, info.elemSize) llvmFn.AddAttributeAtIndex(i+1, dereferenceableOrNull) } } |