Skip to content

Commit 34efc3a

Browse files
aykevldeadprogram
authored andcommitted
compiler: implement internal/abi.Escape
1 parent 5c46efb commit 34efc3a

File tree

3 files changed

+47
-0
lines changed

3 files changed

+47
-0
lines changed

compiler/intrinsics.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,29 @@ func (b *builder) createKeepAliveImpl() {
121121
b.CreateRetVoid()
122122
}
123123

124+
// createAbiEscapeImpl implements the generic internal/abi.Escape function. It
125+
// currently only supports pointer types.
126+
func (b *builder) createAbiEscapeImpl() {
127+
b.createFunctionStart(true)
128+
129+
// The first parameter is assumed to be a pointer. This is checked at the
130+
// call site of createAbiEscapeImpl.
131+
pointerValue := b.getValue(b.fn.Params[0], getPos(b.fn))
132+
133+
// Create an equivalent of the following C code, which is basically just a
134+
// nop but ensures the pointerValue is kept alive:
135+
//
136+
// __asm__ __volatile__("" : : "r"(pointerValue))
137+
//
138+
// It should be portable to basically everything as the "r" register type
139+
// exists basically everywhere.
140+
asmType := llvm.FunctionType(b.dataPtrType, []llvm.Type{b.dataPtrType}, false)
141+
asmFn := llvm.InlineAsm(asmType, "", "=r,0", true, false, 0, false)
142+
result := b.createCall(asmType, asmFn, []llvm.Value{pointerValue}, "")
143+
144+
b.CreateRet(result)
145+
}
146+
124147
var mathToLLVMMapping = map[string]string{
125148
"math.Ceil": "llvm.ceil.f64",
126149
"math.Exp": "llvm.exp.f64",

compiler/symbol.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,23 @@ func (c *compilerContext) maybeCreateSyntheticFunction(fn *ssa.Function, llvmFn
253253
// The exception is the package initializer, which does appear in the
254254
// *ssa.Package members and so shouldn't be created here.
255255
if fn.Synthetic != "" && fn.Synthetic != "package initializer" && fn.Synthetic != "generic function" && fn.Synthetic != "range-over-func yield" {
256+
if origin := fn.Origin(); origin != nil && origin.RelString(nil) == "internal/abi.Escape" {
257+
// This is a special implementation or internal/abi.Escape, which
258+
// can only really be implemented in the compiler.
259+
// For simplicity we'll only implement pointer parameters for now.
260+
if _, ok := fn.Params[0].Type().Underlying().(*types.Pointer); ok {
261+
irbuilder := c.ctx.NewBuilder()
262+
defer irbuilder.Dispose()
263+
b := newBuilder(c, irbuilder, fn)
264+
b.createAbiEscapeImpl()
265+
llvmFn.SetLinkage(llvm.LinkOnceODRLinkage)
266+
llvmFn.SetUnnamedAddr(true)
267+
}
268+
// If the parameter is not of a pointer type, it will be left
269+
// unimplemented. This will result in a linker error if the function
270+
// is really called, making it clear it needs to be implemented.
271+
return
272+
}
256273
if len(fn.Blocks) == 0 {
257274
c.addError(fn.Pos(), "missing function body")
258275
return

src/internal/abi/escape.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,10 @@ import "unsafe"
88
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
99
return p
1010
}
11+
12+
func Escape[T any](x T) T {
13+
// This function is either implemented in the compiler, or left undefined
14+
// for some variation of T. The body of this function should not be compiled
15+
// as-is.
16+
panic("internal/abi.Escape: unreachable (implemented in the compiler)")
17+
}

0 commit comments

Comments
 (0)