Skip to content

Commit 4262f0f

Browse files
aykevldeadprogram
authored andcommitted
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.
1 parent 1ceb63d commit 4262f0f

File tree

4 files changed

+23
-22
lines changed

4 files changed

+23
-22
lines changed

compiler/compiler.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,10 +1619,6 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
16191619
// applied) function call. If it is anonymous, it may be a closure.
16201620
name := fn.RelString(nil)
16211621
switch {
1622-
case name == "runtime.memcpy" || name == "runtime.memmove" || name == "reflect.memcpy":
1623-
return b.createMemoryCopyCall(fn, instr.Args)
1624-
case name == "runtime.memzero":
1625-
return b.createMemoryZeroCall(instr.Args)
16261622
case name == "math.Ceil" || name == "math.Floor" || name == "math.Sqrt" || name == "math.Trunc":
16271623
result, ok := b.createMathOp(instr)
16281624
if ok {

compiler/intrinsics.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ import (
2020
func (b *builder) defineIntrinsicFunction() {
2121
name := b.fn.RelString(nil)
2222
switch {
23+
case name == "runtime.memcpy" || name == "runtime.memmove":
24+
b.createMemoryCopyImpl()
25+
case name == "runtime.memzero":
26+
b.createMemoryZeroImpl()
2327
case strings.HasPrefix(name, "runtime/volatile.Load"):
2428
b.createVolatileLoad()
2529
case strings.HasPrefix(name, "runtime/volatile.Store"):
@@ -35,44 +39,46 @@ func (b *builder) defineIntrinsicFunction() {
3539
}
3640
}
3741

38-
// createMemoryCopyCall creates a call to a builtin LLVM memcpy or memmove
42+
// createMemoryCopyImpl creates a call to a builtin LLVM memcpy or memmove
3943
// function, declaring this function if needed. These calls are treated
4044
// specially by optimization passes possibly resulting in better generated code,
4145
// and will otherwise be lowered to regular libc memcpy/memmove calls.
42-
func (b *builder) createMemoryCopyCall(fn *ssa.Function, args []ssa.Value) (llvm.Value, error) {
43-
fnName := "llvm." + fn.Name() + ".p0i8.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
46+
func (b *builder) createMemoryCopyImpl() {
47+
b.createFunctionStart()
48+
fnName := "llvm." + b.fn.Name() + ".p0i8.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
4449
llvmFn := b.mod.NamedFunction(fnName)
4550
if llvmFn.IsNil() {
4651
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.i8ptrType, b.uintptrType, b.ctx.Int1Type()}, false)
4752
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
4853
}
4954
var params []llvm.Value
50-
for _, param := range args {
55+
for _, param := range b.fn.Params {
5156
params = append(params, b.getValue(param))
5257
}
5358
params = append(params, llvm.ConstInt(b.ctx.Int1Type(), 0, false))
5459
b.CreateCall(llvmFn, params, "")
55-
return llvm.Value{}, nil
60+
b.CreateRetVoid()
5661
}
5762

58-
// createMemoryZeroCall creates calls to llvm.memset.* to zero a block of
63+
// createMemoryZeroImpl creates calls to llvm.memset.* to zero a block of
5964
// memory, declaring the function if needed. These calls will be lowered to
6065
// regular libc memset calls if they aren't optimized out in a different way.
61-
func (b *builder) createMemoryZeroCall(args []ssa.Value) (llvm.Value, error) {
66+
func (b *builder) createMemoryZeroImpl() {
67+
b.createFunctionStart()
6268
fnName := "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
6369
llvmFn := b.mod.NamedFunction(fnName)
6470
if llvmFn.IsNil() {
6571
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.ctx.Int8Type(), b.uintptrType, b.ctx.Int1Type()}, false)
6672
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
6773
}
6874
params := []llvm.Value{
69-
b.getValue(args[0]),
75+
b.getValue(b.fn.Params[0]),
7076
llvm.ConstInt(b.ctx.Int8Type(), 0, false),
71-
b.getValue(args[1]),
77+
b.getValue(b.fn.Params[1]),
7278
llvm.ConstInt(b.ctx.Int1Type(), 0, false),
7379
}
7480
b.CreateCall(llvmFn, params, "")
75-
return llvm.Value{}, nil
81+
b.CreateRetVoid()
7682
}
7783

7884
var mathToLLVMMapping = map[string]string{

src/reflect/value.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -808,8 +808,7 @@ func (e *ValueError) Error() string {
808808
return "reflect: call of " + e.Method + " on " + e.Kind.String() + " Value"
809809
}
810810

811-
// Calls to this function are converted to LLVM intrinsic calls such as
812-
// llvm.memcpy.p0i8.p0i8.i32().
811+
//go:linkname memcpy runtime.memcpy
813812
func memcpy(dst, src unsafe.Pointer, size uintptr)
814813

815814
//go:linkname alloc runtime.alloc

src/runtime/runtime.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,19 @@ func GOROOT() string {
2626
}
2727

2828
// Copy size bytes from src to dst. The memory areas must not overlap.
29-
// Calls to this function are converted to LLVM intrinsic calls such as
30-
// llvm.memcpy.p0i8.p0i8.i32(dst, src, size, false).
29+
// This function is implemented by the compiler as a call to a LLVM intrinsic
30+
// like llvm.memcpy.p0i8.p0i8.i32(dst, src, size, false).
3131
func memcpy(dst, src unsafe.Pointer, size uintptr)
3232

3333
// Copy size bytes from src to dst. The memory areas may overlap and will do the
3434
// correct thing.
35-
// Calls to this function are converted to LLVM intrinsic calls such as
36-
// llvm.memmove.p0i8.p0i8.i32(dst, src, size, false).
35+
// This function is implemented by the compiler as a call to a LLVM intrinsic
36+
// like llvm.memmove.p0i8.p0i8.i32(dst, src, size, false).
3737
func memmove(dst, src unsafe.Pointer, size uintptr)
3838

3939
// Set the given number of bytes to zero.
40-
// Calls to this function are converted to LLVM intrinsic calls such as
41-
// llvm.memset.p0i8.i32(ptr, 0, size, false).
40+
// This function is implemented by the compiler as a call to a LLVM intrinsic
41+
// like llvm.memset.p0i8.i32(ptr, 0, size, false).
4242
func memzero(ptr unsafe.Pointer, size uintptr)
4343

4444
// This intrinsic returns the current stack pointer.

0 commit comments

Comments
 (0)