compiler: implement volatile operations as compiler builtins
The long term goal is to remove the //go:volatile hack.
Этот коммит содержится в:
родитель
3c2639ad55
коммит
397b90753c
3 изменённых файлов: 72 добавлений и 7 удалений
|
@ -195,7 +195,7 @@ func (c *Compiler) Compile(mainPath string) []error {
|
|||
},
|
||||
ShouldOverlay: func(path string) bool {
|
||||
switch path {
|
||||
case "machine", "os", "reflect", "runtime", "sync":
|
||||
case "machine", "os", "reflect", "runtime", "runtime/volatile", "sync":
|
||||
return true
|
||||
default:
|
||||
if strings.HasPrefix(path, "device/") || strings.HasPrefix(path, "examples/") {
|
||||
|
@ -1265,17 +1265,22 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, e
|
|||
|
||||
// Try to call the function directly for trivially static calls.
|
||||
if fn := instr.StaticCallee(); fn != nil {
|
||||
switch fn.RelString(nil) {
|
||||
case "device/arm.ReadRegister":
|
||||
name := fn.RelString(nil)
|
||||
switch {
|
||||
case name == "device/arm.ReadRegister":
|
||||
return c.emitReadRegister(instr.Args)
|
||||
case "device/arm.Asm", "device/avr.Asm":
|
||||
case name == "device/arm.Asm" || name == "device/avr.Asm":
|
||||
return c.emitAsm(instr.Args)
|
||||
case "device/arm.AsmFull", "device/avr.AsmFull":
|
||||
case name == "device/arm.AsmFull" || name == "device/avr.AsmFull":
|
||||
return c.emitAsmFull(frame, instr)
|
||||
case "device/arm.SVCall0", "device/arm.SVCall1", "device/arm.SVCall2", "device/arm.SVCall3", "device/arm.SVCall4":
|
||||
case strings.HasPrefix(name, "device/arm.SVCall"):
|
||||
return c.emitSVCall(frame, instr.Args)
|
||||
case "syscall.Syscall", "syscall.Syscall6", "syscall.Syscall9":
|
||||
case strings.HasPrefix(name, "syscall.Syscall"):
|
||||
return c.emitSyscall(frame, instr)
|
||||
case strings.HasPrefix(name, "runtime/volatile.Load"):
|
||||
return c.emitVolatileLoad(frame, instr)
|
||||
case strings.HasPrefix(name, "runtime/volatile.Store"):
|
||||
return c.emitVolatileStore(frame, instr)
|
||||
}
|
||||
|
||||
targetFunc := c.ir.GetFunction(fn)
|
||||
|
|
26
compiler/volatile.go
Обычный файл
26
compiler/volatile.go
Обычный файл
|
@ -0,0 +1,26 @@
|
|||
package compiler
|
||||
|
||||
// This file implements volatile loads/stores in runtime/volatile.LoadT and
|
||||
// runtime/volatile.StoreT as compiler builtins.
|
||||
|
||||
import (
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
func (c *Compiler) emitVolatileLoad(frame *Frame, instr *ssa.CallCommon) (llvm.Value, error) {
|
||||
addr := c.getValue(frame, instr.Args[0])
|
||||
c.emitNilCheck(frame, addr, "deref")
|
||||
val := c.builder.CreateLoad(addr, "")
|
||||
val.SetVolatile(true)
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (c *Compiler) emitVolatileStore(frame *Frame, instr *ssa.CallCommon) (llvm.Value, error) {
|
||||
addr := c.getValue(frame, instr.Args[0])
|
||||
val := c.getValue(frame, instr.Args[1])
|
||||
c.emitNilCheck(frame, addr, "deref")
|
||||
store := c.builder.CreateStore(val, addr)
|
||||
store.SetVolatile(true)
|
||||
return llvm.Value{}, nil
|
||||
}
|
34
src/runtime/volatile/volatile.go
Обычный файл
34
src/runtime/volatile/volatile.go
Обычный файл
|
@ -0,0 +1,34 @@
|
|||
// Package volatile provides definitions for volatile loads and stores. These
|
||||
// are implemented as compiler builtins.
|
||||
//
|
||||
// The load operations load a volatile value. The store operations store to a
|
||||
// volatile value. The compiler will emit exactly one load or store operation
|
||||
// when possible and will not reorder volatile operations. However, the compiler
|
||||
// may move other operations across load/store operations, so make sure that all
|
||||
// relevant loads/stores are done in a volatile way if this is a problem.
|
||||
//
|
||||
// These loads and stores are commonly used to read/write values from memory
|
||||
// mapped peripheral devices. They do not provide atomicity, use the sync/atomic
|
||||
// package for that.
|
||||
//
|
||||
// For more details: https://llvm.org/docs/LangRef.html#volatile-memory-accesses
|
||||
// and https://blog.regehr.org/archives/28.
|
||||
package volatile
|
||||
|
||||
// LoadUint8 loads the volatile value *addr.
|
||||
func LoadUint8(addr *uint8) (val uint8)
|
||||
|
||||
// LoadUint16 loads the volatile value *addr.
|
||||
func LoadUint16(addr *uint16) (val uint16)
|
||||
|
||||
// LoadUint32 loads the volatile value *addr.
|
||||
func LoadUint32(addr *uint32) (val uint32)
|
||||
|
||||
// StoreUint8 stores val to the volatile value *addr.
|
||||
func StoreUint8(addr *uint8, val uint8)
|
||||
|
||||
// StoreUint16 stores val to the volatile value *addr.
|
||||
func StoreUint16(addr *uint16, val uint16)
|
||||
|
||||
// StoreUint32 stores val to the volatile value *addr.
|
||||
func StoreUint32(addr *uint32, val uint32)
|
Загрузка…
Создание таблицы
Сослаться в новой задаче