From e5029c63d138d11c7e5304c815c4746d72b4ce54 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sun, 7 Apr 2019 16:37:57 +0200 Subject: [PATCH] compiler: optimize ptrtoint+add+inttoptr pattern This pattern is often used in some runtime intrinsics (especially the ones related to slices) to do pointer arithmetic with unsafe.Pointer and uintptr because Go does not support pointer arithmetic. Recognizing this pattern and replacing it with a gep instruction improves code size in various tests. --- compiler/compiler.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/compiler/compiler.go b/compiler/compiler.go index b19765de..46a991d6 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -2504,6 +2504,27 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, p if isPtrFrom && !isPtrTo { return c.builder.CreatePtrToInt(value, llvmTypeTo, ""), nil } else if !isPtrFrom && isPtrTo { + if !value.IsABinaryOperator().IsNil() && value.InstructionOpcode() == llvm.Add { + // This is probably a pattern like the following: + // unsafe.Pointer(uintptr(ptr) + index) + // Used in functions like memmove etc. for lack of pointer + // arithmetic. Convert it to real pointer arithmatic here. + ptr := value.Operand(0) + index := value.Operand(1) + if !index.IsAPtrToIntInst().IsNil() { + // Swap if necessary, if ptr and index are reversed. + ptr, index = index, ptr + } + if !ptr.IsAPtrToIntInst().IsNil() { + origptr := ptr.Operand(0) + if origptr.Type() == c.i8ptrType { + // This pointer can be calculated from the original + // ptrtoint instruction with a GEP. The leftover inttoptr + // instruction is trivial to optimize away. + return c.builder.CreateGEP(origptr, []llvm.Value{index}, ""), nil + } + } + } return c.builder.CreateIntToPtr(value, llvmTypeTo, ""), nil }