compiler: really define runtime.mem* as LLVM intrinsic wrappers

This makes it possible to //go:linkname them from other places, like in
the reflect package. And is in my opinion a much cleaner solution.
Этот коммит содержится в:
Ayke van Laethem 2022-06-20 15:19:57 +02:00 коммит произвёл Ron Evans
родитель 1ceb63d14c
коммит 4262f0ff1f
4 изменённых файлов: 23 добавлений и 22 удалений

Просмотреть файл

@ -1619,10 +1619,6 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
// applied) function call. If it is anonymous, it may be a closure.
name := fn.RelString(nil)
switch {
case name == "runtime.memcpy" || name == "runtime.memmove" || name == "reflect.memcpy":
return b.createMemoryCopyCall(fn, instr.Args)
case name == "runtime.memzero":
return b.createMemoryZeroCall(instr.Args)
case name == "math.Ceil" || name == "math.Floor" || name == "math.Sqrt" || name == "math.Trunc":
result, ok := b.createMathOp(instr)
if ok {

Просмотреть файл

@ -20,6 +20,10 @@ import (
func (b *builder) defineIntrinsicFunction() {
name := b.fn.RelString(nil)
switch {
case name == "runtime.memcpy" || name == "runtime.memmove":
b.createMemoryCopyImpl()
case name == "runtime.memzero":
b.createMemoryZeroImpl()
case strings.HasPrefix(name, "runtime/volatile.Load"):
b.createVolatileLoad()
case strings.HasPrefix(name, "runtime/volatile.Store"):
@ -35,30 +39,32 @@ func (b *builder) defineIntrinsicFunction() {
}
}
// createMemoryCopyCall creates a call to a builtin LLVM memcpy or memmove
// createMemoryCopyImpl creates a call to a builtin LLVM memcpy or memmove
// function, declaring this function if needed. These calls are treated
// specially by optimization passes possibly resulting in better generated code,
// and will otherwise be lowered to regular libc memcpy/memmove calls.
func (b *builder) createMemoryCopyCall(fn *ssa.Function, args []ssa.Value) (llvm.Value, error) {
fnName := "llvm." + fn.Name() + ".p0i8.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
func (b *builder) createMemoryCopyImpl() {
b.createFunctionStart()
fnName := "llvm." + b.fn.Name() + ".p0i8.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
llvmFn := b.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.i8ptrType, b.uintptrType, b.ctx.Int1Type()}, false)
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
}
var params []llvm.Value
for _, param := range args {
for _, param := range b.fn.Params {
params = append(params, b.getValue(param))
}
params = append(params, llvm.ConstInt(b.ctx.Int1Type(), 0, false))
b.CreateCall(llvmFn, params, "")
return llvm.Value{}, nil
b.CreateRetVoid()
}
// createMemoryZeroCall creates calls to llvm.memset.* to zero a block of
// createMemoryZeroImpl creates calls to llvm.memset.* to zero a block of
// memory, declaring the function if needed. These calls will be lowered to
// regular libc memset calls if they aren't optimized out in a different way.
func (b *builder) createMemoryZeroCall(args []ssa.Value) (llvm.Value, error) {
func (b *builder) createMemoryZeroImpl() {
b.createFunctionStart()
fnName := "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
llvmFn := b.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
@ -66,13 +72,13 @@ func (b *builder) createMemoryZeroCall(args []ssa.Value) (llvm.Value, error) {
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
}
params := []llvm.Value{
b.getValue(args[0]),
b.getValue(b.fn.Params[0]),
llvm.ConstInt(b.ctx.Int8Type(), 0, false),
b.getValue(args[1]),
b.getValue(b.fn.Params[1]),
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
}
b.CreateCall(llvmFn, params, "")
return llvm.Value{}, nil
b.CreateRetVoid()
}
var mathToLLVMMapping = map[string]string{

Просмотреть файл

@ -808,8 +808,7 @@ func (e *ValueError) Error() string {
return "reflect: call of " + e.Method + " on " + e.Kind.String() + " Value"
}
// Calls to this function are converted to LLVM intrinsic calls such as
// llvm.memcpy.p0i8.p0i8.i32().
//go:linkname memcpy runtime.memcpy
func memcpy(dst, src unsafe.Pointer, size uintptr)
//go:linkname alloc runtime.alloc

Просмотреть файл

@ -26,19 +26,19 @@ func GOROOT() string {
}
// Copy size bytes from src to dst. The memory areas must not overlap.
// Calls to this function are converted to LLVM intrinsic calls such as
// llvm.memcpy.p0i8.p0i8.i32(dst, src, size, false).
// This function is implemented by the compiler as a call to a LLVM intrinsic
// like llvm.memcpy.p0i8.p0i8.i32(dst, src, size, false).
func memcpy(dst, src unsafe.Pointer, size uintptr)
// Copy size bytes from src to dst. The memory areas may overlap and will do the
// correct thing.
// Calls to this function are converted to LLVM intrinsic calls such as
// llvm.memmove.p0i8.p0i8.i32(dst, src, size, false).
// This function is implemented by the compiler as a call to a LLVM intrinsic
// like llvm.memmove.p0i8.p0i8.i32(dst, src, size, false).
func memmove(dst, src unsafe.Pointer, size uintptr)
// Set the given number of bytes to zero.
// Calls to this function are converted to LLVM intrinsic calls such as
// llvm.memset.p0i8.i32(ptr, 0, size, false).
// This function is implemented by the compiler as a call to a LLVM intrinsic
// like llvm.memset.p0i8.i32(ptr, 0, size, false).
func memzero(ptr unsafe.Pointer, size uintptr)
// This intrinsic returns the current stack pointer.