compiler: add dereferenceable_or_null attribute where possible

This gives a hint to the compiler that such parameters are either NULL
or point to a valid object that can be dereferenced. This is not
directly very useful, but is very useful when combined with
https://reviews.llvm.org/D60047 to remove the runtime.isnil hack without
regressing escape analysis.
This commit is contained in:
Ayke van Laethem
2020-03-19 20:15:03 +01:00
committed by Ron Evans
parent 980068543a
commit 85854cd58b
4 changed files with 98 additions and 17 deletions
+23 -2
View File
@@ -750,10 +750,12 @@ func (c *compilerContext) createFunctionDeclaration(f *ir.Function) {
}
var paramTypes []llvm.Type
var paramTypeVariants []paramFlags
for _, param := range f.Params {
paramType := c.getLLVMType(param.Type())
paramTypeFragments := expandFormalParamType(paramType)
paramTypeFragments, paramTypeFragmentVariants := expandFormalParamType(paramType, param.Type())
paramTypes = append(paramTypes, paramTypeFragments...)
paramTypeVariants = append(paramTypeVariants, paramTypeFragmentVariants...)
}
// Add an extra parameter as the function context. This context is used in
@@ -761,6 +763,7 @@ func (c *compilerContext) createFunctionDeclaration(f *ir.Function) {
if !f.IsExported() {
paramTypes = append(paramTypes, c.i8ptrType) // context
paramTypes = append(paramTypes, c.i8ptrType) // parent coroutine
paramTypeVariants = append(paramTypeVariants, 0, 0)
}
fnType := llvm.FunctionType(retType, paramTypes, false)
@@ -771,6 +774,23 @@ func (c *compilerContext) createFunctionDeclaration(f *ir.Function) {
f.LLVMFn = llvm.AddFunction(c.mod, name, fnType)
}
dereferenceableOrNullKind := llvm.AttributeKindID("dereferenceable_or_null")
for i, typ := range paramTypes {
if paramTypeVariants[i]&paramIsDeferenceableOrNull == 0 {
continue
}
if typ.TypeKind() == llvm.PointerTypeKind {
el := typ.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)
f.LLVMFn.AddAttributeAtIndex(i+1, dereferenceableOrNull)
}
}
// External/exported functions may not retain pointer values.
// https://golang.org/cmd/cgo/#hdr-Passing_pointers
if f.IsExported() {
@@ -901,7 +921,8 @@ func (b *builder) createFunctionDefinition() {
for _, param := range b.fn.Params {
llvmType := b.getLLVMType(param.Type())
fields := make([]llvm.Value, 0, 1)
for range expandFormalParamType(llvmType) {
fieldFragments, _ := expandFormalParamType(llvmType, nil)
for range fieldFragments {
fields = append(fields, b.fn.LLVMFn.Param(llvmParamIndex))
llvmParamIndex++
}