From 91d1a23b14fd95fb8bdcf306007a2c47d87c32a7 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 26 Mar 2020 16:09:48 +0100 Subject: [PATCH] compiler,runtime: translate memzero calls to LLVM memset intrinsics This gives the optimizer a bit more information about what the calls do. This should result in slightly better generated code. Code size sometimes goes up and sometimes goes down. I blame the code size going up on the inliner which inlines more functions, because compiling the smoke tests in the drivers repository with -opt=1 results in a slight code size reduction in all cases. --- compiler/compiler.go | 2 ++ compiler/intrinsics.go | 20 ++++++++++++++++++++ src/runtime/runtime.go | 8 +++----- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/compiler/compiler.go b/compiler/compiler.go index 561095b0..d7609d13 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -1343,6 +1343,8 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error) 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 == "device/arm.ReadRegister" || name == "device/riscv.ReadRegister": return b.createReadRegister(name, instr.Args) case name == "device/arm.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm": diff --git a/compiler/intrinsics.go b/compiler/intrinsics.go index 4790b70d..634e8362 100644 --- a/compiler/intrinsics.go +++ b/compiler/intrinsics.go @@ -28,3 +28,23 @@ func (b *builder) createMemoryCopyCall(fn *ssa.Function, args []ssa.Value) (llvm b.CreateCall(llvmFn, params, "") return llvm.Value{}, nil } + +// createMemoryZeroCall 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) { + fnName := "llvm.memset.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.ctx.Int8Type(), b.uintptrType, b.ctx.Int1Type()}, false) + llvmFn = llvm.AddFunction(b.mod, fnName, fnType) + } + params := []llvm.Value{ + b.getValue(args[0]), + llvm.ConstInt(b.ctx.Int8Type(), 0, false), + b.getValue(args[1]), + llvm.ConstInt(b.ctx.Int1Type(), 0, false), + } + b.CreateCall(llvmFn, params, "") + return llvm.Value{}, nil +} diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go index d545e151..61d21029 100644 --- a/src/runtime/runtime.go +++ b/src/runtime/runtime.go @@ -41,11 +41,9 @@ func memcpy(dst, src unsafe.Pointer, size uintptr) func memmove(dst, src unsafe.Pointer, size uintptr) // Set the given number of bytes to zero. -func memzero(ptr unsafe.Pointer, size uintptr) { - for i := uintptr(0); i < size; i++ { - *(*byte)(unsafe.Pointer(uintptr(ptr) + i)) = 0 - } -} +// Calls to this function are converted to LLVM intrinsic calls such as +// llvm.memset.p0i8.i32(ptr, 0, size, false). +func memzero(ptr unsafe.Pointer, size uintptr) // Compare two same-size buffers for equality. func memequal(x, y unsafe.Pointer, n uintptr) bool {