all: change special type __volatile to pragma //go:volatile

This is one step towards removing unnecessary special casts in most
cases. It is also part of removing as much magic as possible from the
compiler (the pragma is explicit, the special name is not).
Этот коммит содержится в:
Ayke van Laethem 2018-09-28 13:17:03 +02:00
родитель 0e813c4cb7
коммит 8d170d3bd2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
6 изменённых файлов: 52 добавлений и 30 удалений

Просмотреть файл

@ -1528,9 +1528,8 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error {
} }
store := c.builder.CreateStore(llvmVal, llvmAddr) store := c.builder.CreateStore(llvmVal, llvmAddr)
valType := instr.Addr.Type().(*types.Pointer).Elem() valType := instr.Addr.Type().(*types.Pointer).Elem()
if valType, ok := valType.(*types.Named); ok && valType.Obj().Name() == "__volatile" { if c.ir.IsVolatile(valType) {
// Magic type name to make this store volatile, for memory-mapped // Volatile store, for memory-mapped registers.
// registers.
store.SetVolatile(true) store.SetVolatile(true)
} }
return nil return nil
@ -3040,9 +3039,8 @@ func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) {
case token.MUL: // *x, dereference pointer case token.MUL: // *x, dereference pointer
valType := unop.X.Type().(*types.Pointer).Elem() valType := unop.X.Type().(*types.Pointer).Elem()
load := c.builder.CreateLoad(x, "") load := c.builder.CreateLoad(x, "")
if valType, ok := valType.(*types.Named); ok && valType.Obj().Name() == "__volatile" { if c.ir.IsVolatile(valType) {
// Magic type name to make this load volatile, for memory-mapped // Volatile load, for memory-mapped registers.
// registers.
load.SetVolatile(true) load.SetVolatile(true)
} }
return load, nil return load, nil

Просмотреть файл

@ -90,15 +90,20 @@ func NewProgram(lprogram *loader.Program, mainPath string) *Program {
switch decl := decl.(type) { switch decl := decl.(type) {
case *ast.GenDecl: case *ast.GenDecl:
switch decl.Tok { switch decl.Tok {
case token.VAR: case token.TYPE, token.VAR:
if len(decl.Specs) != 1 { if len(decl.Specs) != 1 {
continue continue
} }
for _, spec := range decl.Specs { for _, spec := range decl.Specs {
valueSpec := spec.(*ast.ValueSpec) switch spec := spec.(type) {
for _, valueName := range valueSpec.Names { case *ast.TypeSpec: // decl.Tok == token.TYPE
id := pkgInfo.Pkg.Path() + "." + valueName.Name id := pkgInfo.Pkg.Path() + "." + spec.Name.Name
comments[id] = decl.Doc comments[id] = decl.Doc
case *ast.ValueSpec: // decl.Tok == token.VAR
for _, name := range spec.Names {
id := pkgInfo.Pkg.Path() + "." + name.Name
comments[id] = decl.Doc
}
} }
} }
} }
@ -414,6 +419,26 @@ func (g *Global) Initializer() Value {
return g.initializer return g.initializer
} }
// Return true if this named type is annotated with the //go:volatile pragma,
// for volatile loads and stores.
func (p *Program) IsVolatile(t types.Type) bool {
if t, ok := t.(*types.Named); !ok {
return false
} else {
id := t.Obj().Pkg().Path() + "." + t.Obj().Name()
doc := p.comments[id]
if doc == nil {
return false
}
for _, line := range doc.List {
if strings.TrimSpace(line.Text) == "//go:volatile" {
return true
}
}
return false
}
}
// Wrapper type to implement sort.Interface for []*types.Selection. // Wrapper type to implement sort.Interface for []*types.Selection.
type methodList struct { type methodList struct {
methods []*types.Selection methods []*types.Selection

Просмотреть файл

@ -33,8 +33,8 @@ import (
"unsafe" "unsafe"
) )
type __volatile uint32 //go:volatile
type RegValue = __volatile type RegValue uint32
type __asm string type __asm string
@ -47,7 +47,7 @@ const (
// Nested Vectored Interrupt Controller (NVIC). // Nested Vectored Interrupt Controller (NVIC).
type NVIC_Type struct { type NVIC_Type struct {
ISER [8]__volatile ISER [8]RegValue
} }
var NVIC = (*NVIC_Type)(unsafe.Pointer(uintptr(NVIC_BASE))) var NVIC = (*NVIC_Type)(unsafe.Pointer(uintptr(NVIC_BASE)))

Просмотреть файл

@ -81,9 +81,10 @@ func ticks() timeUnit {
return timestamp return timestamp
} }
type __volatile bool //go:volatile
type isrFlag bool
var rtc_wakeup __volatile var rtc_wakeup isrFlag
func rtc_sleep(ticks uint32) { func rtc_sleep(ticks uint32) {
nrf.RTC0.INTENSET = nrf.RTC_INTENSET_COMPARE0 nrf.RTC0.INTENSET = nrf.RTC_INTENSET_COMPARE0

Просмотреть файл

@ -142,11 +142,10 @@ package {pkgName}
import "unsafe" import "unsafe"
// Magic type name for the compiler. // Special type that causes loads/stores to be volatile (necessary for
type __volatile uint8 // memory-mapped registers).
//go:volatile
// Export this magic type name. type RegValue uint8
type RegValue = __volatile
// Some information about this device. // Some information about this device.
const ( const (
@ -169,7 +168,7 @@ const (
out.write('\n\t// {description}\n'.format(**peripheral)) out.write('\n\t// {description}\n'.format(**peripheral))
for register in peripheral['registers']: for register in peripheral['registers']:
for variant in register['variants']: for variant in register['variants']:
out.write('\t{name} = (*__volatile)(unsafe.Pointer(uintptr(0x{address:x})))\n'.format(**variant)) out.write('\t{name} = (*RegValue)(unsafe.Pointer(uintptr(0x{address:x})))\n'.format(**variant))
out.write(')\n') out.write(')\n')
for peripheral in device.peripherals: for peripheral in device.peripherals:

Просмотреть файл

@ -216,11 +216,10 @@ package {pkgName}
import "unsafe" import "unsafe"
// Magic type name for the compiler. // Special type that causes loads/stores to be volatile (necessary for
type __volatile uint32 // memory-mapped registers).
//go:volatile
// Export this magic type name. type RegValue uint32
type RegValue = __volatile
// Some information about this device. // Some information about this device.
const ( const (
@ -255,14 +254,14 @@ const (
if address < register['address']: if address < register['address']:
numSkip = (register['address'] - address) // 4 numSkip = (register['address'] - address) // 4
if numSkip == 1: if numSkip == 1:
out.write('\t_padding{padNumber} __volatile\n'.format(padNumber=padNumber)) out.write('\t_padding{padNumber} RegValue\n'.format(padNumber=padNumber))
else: else:
out.write('\t_padding{padNumber} [{num}]__volatile\n'.format(padNumber=padNumber, num=numSkip)) out.write('\t_padding{padNumber} [{num}]RegValue\n'.format(padNumber=padNumber, num=numSkip))
padNumber += 1 padNumber += 1
regType = '__volatile' regType = 'RegValue'
if register['array'] is not None: if register['array'] is not None:
regType = '[{}]__volatile'.format(register['array']) regType = '[{}]RegValue'.format(register['array'])
out.write('\t{name} {regType}\n'.format(**register, regType=regType)) out.write('\t{name} {regType}\n'.format(**register, regType=regType))
# next address # next address