diff --git a/compiler/compiler.go b/compiler/compiler.go index d54695ff..5ead43b5 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -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 { diff --git a/compiler/intrinsics.go b/compiler/intrinsics.go index 00e679e3..eb07ccb9 100644 --- a/compiler/intrinsics.go +++ b/compiler/intrinsics.go @@ -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{ diff --git a/src/reflect/value.go b/src/reflect/value.go index 2c310bc1..cb784df6 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -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 diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go index 29ce0cfc..d3db0e83 100644 --- a/src/runtime/runtime.go +++ b/src/runtime/runtime.go @@ -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.