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.
Этот коммит содержится в:
родитель
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.
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче