diff --git a/compiler/compiler.go b/compiler/compiler.go index ba8d77ac..0da00b40 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -1528,9 +1528,8 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) error { } store := c.builder.CreateStore(llvmVal, llvmAddr) valType := instr.Addr.Type().(*types.Pointer).Elem() - if valType, ok := valType.(*types.Named); ok && valType.Obj().Name() == "__volatile" { - // Magic type name to make this store volatile, for memory-mapped - // registers. + if c.ir.IsVolatile(valType) { + // Volatile store, for memory-mapped registers. store.SetVolatile(true) } return nil @@ -3040,9 +3039,8 @@ func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) { case token.MUL: // *x, dereference pointer valType := unop.X.Type().(*types.Pointer).Elem() load := c.builder.CreateLoad(x, "") - if valType, ok := valType.(*types.Named); ok && valType.Obj().Name() == "__volatile" { - // Magic type name to make this load volatile, for memory-mapped - // registers. + if c.ir.IsVolatile(valType) { + // Volatile load, for memory-mapped registers. load.SetVolatile(true) } return load, nil diff --git a/ir/ir.go b/ir/ir.go index 76dce610..684d94a4 100644 --- a/ir/ir.go +++ b/ir/ir.go @@ -90,15 +90,20 @@ func NewProgram(lprogram *loader.Program, mainPath string) *Program { switch decl := decl.(type) { case *ast.GenDecl: switch decl.Tok { - case token.VAR: + case token.TYPE, token.VAR: if len(decl.Specs) != 1 { continue } for _, spec := range decl.Specs { - valueSpec := spec.(*ast.ValueSpec) - for _, valueName := range valueSpec.Names { - id := pkgInfo.Pkg.Path() + "." + valueName.Name + switch spec := spec.(type) { + case *ast.TypeSpec: // decl.Tok == token.TYPE + id := pkgInfo.Pkg.Path() + "." + spec.Name.Name 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 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. type methodList struct { methods []*types.Selection diff --git a/src/device/arm/arm.go b/src/device/arm/arm.go index e0c4a070..7f6858fb 100644 --- a/src/device/arm/arm.go +++ b/src/device/arm/arm.go @@ -33,8 +33,8 @@ import ( "unsafe" ) -type __volatile uint32 -type RegValue = __volatile +//go:volatile +type RegValue uint32 type __asm string @@ -47,7 +47,7 @@ const ( // Nested Vectored Interrupt Controller (NVIC). type NVIC_Type struct { - ISER [8]__volatile + ISER [8]RegValue } var NVIC = (*NVIC_Type)(unsafe.Pointer(uintptr(NVIC_BASE))) diff --git a/src/runtime/runtime_nrf.go b/src/runtime/runtime_nrf.go index 40ecd098..1cccce97 100644 --- a/src/runtime/runtime_nrf.go +++ b/src/runtime/runtime_nrf.go @@ -81,9 +81,10 @@ func ticks() timeUnit { return timestamp } -type __volatile bool +//go:volatile +type isrFlag bool -var rtc_wakeup __volatile +var rtc_wakeup isrFlag func rtc_sleep(ticks uint32) { nrf.RTC0.INTENSET = nrf.RTC_INTENSET_COMPARE0 diff --git a/tools/gen-device-avr.py b/tools/gen-device-avr.py index f2592c1f..1b7efe3f 100755 --- a/tools/gen-device-avr.py +++ b/tools/gen-device-avr.py @@ -142,11 +142,10 @@ package {pkgName} import "unsafe" -// Magic type name for the compiler. -type __volatile uint8 - -// Export this magic type name. -type RegValue = __volatile +// Special type that causes loads/stores to be volatile (necessary for +// memory-mapped registers). +//go:volatile +type RegValue uint8 // Some information about this device. const ( @@ -169,7 +168,7 @@ const ( out.write('\n\t// {description}\n'.format(**peripheral)) for register in peripheral['registers']: 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') for peripheral in device.peripherals: diff --git a/tools/gen-device-svd.py b/tools/gen-device-svd.py index fb8c077c..97acee6f 100755 --- a/tools/gen-device-svd.py +++ b/tools/gen-device-svd.py @@ -216,11 +216,10 @@ package {pkgName} import "unsafe" -// Magic type name for the compiler. -type __volatile uint32 - -// Export this magic type name. -type RegValue = __volatile +// Special type that causes loads/stores to be volatile (necessary for +// memory-mapped registers). +//go:volatile +type RegValue uint32 // Some information about this device. const ( @@ -255,14 +254,14 @@ const ( if address < register['address']: numSkip = (register['address'] - address) // 4 if numSkip == 1: - out.write('\t_padding{padNumber} __volatile\n'.format(padNumber=padNumber)) + out.write('\t_padding{padNumber} RegValue\n'.format(padNumber=padNumber)) 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 - regType = '__volatile' + regType = 'RegValue' 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)) # next address