Skip to content

Commit 91d1a23

Browse files
aykevldeadprogram
authored andcommitted
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.
1 parent eaa54bc commit 91d1a23

File tree

3 files changed

+25
-5
lines changed

3 files changed

+25
-5
lines changed

compiler/compiler.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,8 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
13431343
switch {
13441344
case name == "runtime.memcpy" || name == "runtime.memmove" || name == "reflect.memcpy":
13451345
return b.createMemoryCopyCall(fn, instr.Args)
1346+
case name == "runtime.memzero":
1347+
return b.createMemoryZeroCall(instr.Args)
13461348
case name == "device/arm.ReadRegister" || name == "device/riscv.ReadRegister":
13471349
return b.createReadRegister(name, instr.Args)
13481350
case name == "device/arm.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm":

compiler/intrinsics.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,23 @@ func (b *builder) createMemoryCopyCall(fn *ssa.Function, args []ssa.Value) (llvm
2828
b.CreateCall(llvmFn, params, "")
2929
return llvm.Value{}, nil
3030
}
31+
32+
// createMemoryZeroCall creates calls to llvm.memset.* to zero a block of
33+
// memory, declaring the function if needed. These calls will be lowered to
34+
// regular libc memset calls if they aren't optimized out in a different way.
35+
func (b *builder) createMemoryZeroCall(args []ssa.Value) (llvm.Value, error) {
36+
fnName := "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
37+
llvmFn := b.mod.NamedFunction(fnName)
38+
if llvmFn.IsNil() {
39+
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.ctx.Int8Type(), b.uintptrType, b.ctx.Int1Type()}, false)
40+
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
41+
}
42+
params := []llvm.Value{
43+
b.getValue(args[0]),
44+
llvm.ConstInt(b.ctx.Int8Type(), 0, false),
45+
b.getValue(args[1]),
46+
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
47+
}
48+
b.CreateCall(llvmFn, params, "")
49+
return llvm.Value{}, nil
50+
}

src/runtime/runtime.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,9 @@ func memcpy(dst, src unsafe.Pointer, size uintptr)
4141
func memmove(dst, src unsafe.Pointer, size uintptr)
4242

4343
// Set the given number of bytes to zero.
44-
func memzero(ptr unsafe.Pointer, size uintptr) {
45-
for i := uintptr(0); i < size; i++ {
46-
*(*byte)(unsafe.Pointer(uintptr(ptr) + i)) = 0
47-
}
48-
}
44+
// Calls to this function are converted to LLVM intrinsic calls such as
45+
// llvm.memset.p0i8.i32(ptr, 0, size, false).
46+
func memzero(ptr unsafe.Pointer, size uintptr)
4947

5048
// Compare two same-size buffers for equality.
5149
func memequal(x, y unsafe.Pointer, n uintptr) bool {

0 commit comments

Comments
 (0)