Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a variant of RegisterBank for arrays #65

Merged
merged 1 commit into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Sources/MMIO/MMIOMacros.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ public macro RegisterBank() =

@attached(accessor)
public macro RegisterBank(offset: Int) =
#externalMacro(module: "MMIOMacros", type: "RegisterBankOffsetMacro")
#externalMacro(module: "MMIOMacros", type: "RegisterBankScalarMemberMacro")

@attached(accessor)
public macro RegisterBank(offset: Int, stride: Int, count: Int) =
#externalMacro(module: "MMIOMacros", type: "RegisterBankArrayMemberMacro")

// Register macros
@attached(member, names: arbitrary)
Expand Down
97 changes: 97 additions & 0 deletions Sources/MMIO/RegisterArray.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift MMIO open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

/// A container type referencing of a region of memory whose layout is defined
/// by another type.
public struct RegisterArray<Value> where Value: RegisterValue {
public var unsafeAddress: UInt
public var stride: UInt
public var count: UInt

#if FEATURE_INTERPOSABLE
public var interposer: (any MMIOInterposer)?
#endif

@inlinable @inline(__always)
static func preconditionAligned(unsafeAddress: UInt, stride: UInt) {
let alignment = MemoryLayout<Value.Raw.Storage>.alignment
#if $Embedded
// FIXME: Embedded doesn't have static interpolated strings yet
precondition(
unsafeAddress.isMultiple(of: UInt(alignment)),
"Misaligned address")
precondition(
stride.isMultiple(of: UInt(alignment)),
"Misaligned stride")
#else
precondition(
unsafeAddress.isMultiple(of: UInt(alignment)),
"Misaligned address '\(unsafeAddress)' for data of type '\(Value.self)'")
precondition(
stride.isMultiple(of: UInt(alignment)),
"Misaligned stride '\(unsafeAddress)' for data of type '\(Value.self)'")
#endif
}

#if FEATURE_INTERPOSABLE
@inlinable @inline(__always)
public init(
unsafeAddress: UInt,
stride: UInt,
count: UInt,
interposer: (any MMIOInterposer)?
) {
Self.preconditionAligned(unsafeAddress: unsafeAddress, stride: stride)
self.unsafeAddress = unsafeAddress
self.stride = stride
self.count = count
self.interposer = interposer
}
#else
@inlinable @inline(__always)
public init(
unsafeAddress: UInt,
stride: UInt,
count: UInt
) {
Self.preconditionAligned(unsafeAddress: unsafeAddress, stride: stride)
self.unsafeAddress = unsafeAddress
self.stride = stride
self.count = count
}
#endif
}

extension RegisterArray {
@inlinable @inline(__always)
subscript<Index>(
_ index: Index
) -> Register<Value> where Index: BinaryInteger {
#if $Embedded
// FIXME: Embedded doesn't have static interpolated strings yet
precondition(
0 <= index && index < self.count,
"Index out of bounds")
#else
precondition(
0 <= index && index < self.count,
"Index '\(index)' out of bounds '0..<\(self.count)'")
#endif
let index = UInt(index)
#if FEATURE_INTERPOSABLE
return .init(
unsafeAddress: self.unsafeAddress + (index * self.stride),
interposer: self.interposer)
#else
return .init(unsafeAddress: self.unsafeAddress + (index * self.stride))
#endif
}
}
3 changes: 2 additions & 1 deletion Sources/MMIOMacros/CompilerPluginMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ struct CompilerPluginMain: CompilerPlugin {
let providingMacros: [Macro.Type] = [
// RegisterBank macros
RegisterBankMacro.self,
RegisterBankOffsetMacro.self,
RegisterBankScalarMemberMacro.self,
RegisterBankArrayMemberMacro.self,
// Register macros
RegisterMacro.self,
ReservedMacro.self,
Expand Down
2 changes: 1 addition & 1 deletion Sources/MMIOMacros/Macros/RegisterBankMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ extension RegisterBankMacro: MMIOMemberMacro {
// RegisterBankOffsetMacro. Further syntactic checking will be performed
// by that macro.
do {
try variableDecl.requireMacro([RegisterBankOffsetMacro.self], context)
try variableDecl.requireMacro(registerBankMemberMacros, context)
} catch _ {
error = true
}
Expand Down
171 changes: 171 additions & 0 deletions Sources/MMIOMacros/Macros/RegisterBankMemberMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
//===----------------------------------------------------------*- swift -*-===//
//
// This source file is part of the Swift MMIO open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

import SwiftDiagnostics
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacroExpansion
import SwiftSyntaxMacros

protocol RegisterBankMemberMacro: ParsableMacro {}

extension RegisterBankMemberMacro {
func expansion(
of node: AttributeSyntax,
offset: ExprSyntax,
array: (stride: ExprSyntax, count: ExprSyntax)?,
providingAccessorsOf declaration: some DeclSyntaxProtocol,
in context: MacroContext<Self, some MacroExpansionContext>
) throws -> [AccessorDeclSyntax] {
// Can only applied to variables.
let variableDecl =
try declaration.requireAs(VariableDeclSyntax.self, context)

// Must be `var` binding.
try variableDecl.requireBindingSpecifier(.var, context)

// Exactly one binding for the variable.
let binding = try variableDecl.requireSingleBinding(context)

// Binding identifier must be a simple identifier.
_ = try binding.requireSimpleBindingIdentifier(context)

// Binding must have a simple type annotation.
_ = try binding.requireSimpleTypeIdentifier(context)

// Binding must not have any accessors.
try binding.requireNoAccessor(context)

guard let array = array else {
return [
"""
@inlinable @inline(__always) get {
#if FEATURE_INTERPOSABLE
return .init(unsafeAddress: self.unsafeAddress + (\(offset)), interposer: self.interposer)
#else
return .init(unsafeAddress: self.unsafeAddress + (\(offset)))
#endif
}
"""
]
}
return [
"""
@inlinable @inline(__always) get {
#if FEATURE_INTERPOSABLE
return .init(unsafeAddress: self.unsafeAddress + (\(offset)), stride: \(array.stride), count: \(array.count), interposer: self.interposer)
#else
return .init(unsafeAddress: self.unsafeAddress + (\(offset)), stride: \(array.stride), count: \(array.count))
#endif
}
"""
]
}
}

let registerBankMemberMacros: [any RegisterBankMemberMacro.Type] = [
RegisterBankScalarMemberMacro.self,
RegisterBankArrayMemberMacro.self,
]

public struct RegisterBankScalarMemberMacro {
@Argument(label: "offset")
var offset: Int
}

extension RegisterBankScalarMemberMacro: Sendable {}

extension RegisterBankScalarMemberMacro: ParsableMacro {
static let baseName = "RegisterBank"

mutating func update(
label: String,
from expression: ExprSyntax,
in context: MacroContext<some ParsableMacro, some MacroExpansionContext>
) throws {
switch label {
case "offset":
try self._offset.update(from: expression, in: context)
default:
fatalError()
}
}
}

extension RegisterBankScalarMemberMacro: MMIOAccessorMacro {
static var accessorMacroSuppressParsingDiagnostics: Bool { false }

func expansion(
of node: AttributeSyntax,
providingAccessorsOf declaration: some DeclSyntaxProtocol,
in context: MacroContext<Self, some MacroExpansionContext>
) throws -> [AccessorDeclSyntax] {
try self.expansion(
of: node,
offset: self.$offset,
array: nil,
providingAccessorsOf: declaration,
in: context)
}
}

extension RegisterBankScalarMemberMacro: RegisterBankMemberMacro {}

public struct RegisterBankArrayMemberMacro {
@Argument(label: "offset")
var offset: Int
@Argument(label: "stride")
var stride: Int
@Argument(label: "count")
var count: Int
}

extension RegisterBankArrayMemberMacro: Sendable {}

extension RegisterBankArrayMemberMacro: ParsableMacro {
static let baseName = "RegisterBank"

mutating func update(
label: String,
from expression: ExprSyntax,
in context: MacroContext<some ParsableMacro, some MacroExpansionContext>
) throws {
switch label {
case "offset":
try self._offset.update(from: expression, in: context)
case "stride":
try self._stride.update(from: expression, in: context)
case "count":
try self._count.update(from: expression, in: context)
default:
fatalError()
}
}
}

extension RegisterBankArrayMemberMacro: MMIOAccessorMacro {
static var accessorMacroSuppressParsingDiagnostics: Bool { false }

func expansion(
of node: AttributeSyntax,
providingAccessorsOf declaration: some DeclSyntaxProtocol,
in context: MacroContext<Self, some MacroExpansionContext>
) throws -> [AccessorDeclSyntax] {
try self.expansion(
of: node,
offset: self.$offset,
array: (stride: self.$stride, count: self.$count),
providingAccessorsOf: declaration,
in: context)
}
}

extension RegisterBankArrayMemberMacro: RegisterBankMemberMacro {}
81 changes: 0 additions & 81 deletions Sources/MMIOMacros/Macros/RegisterBankOffsetMacro.swift

This file was deleted.

Loading