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

Implement IR support for method bundles #1012

Merged
merged 6 commits into from
Sep 15, 2023
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
2 changes: 1 addition & 1 deletion Sources/FrontEnd/TypeChecking/TypeChecker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ struct TypeChecker {
return [
program.ast.movableTrait,
program.ast.deinitializableTrait,
program.ast.foreignConvertibleTrait
program.ast.foreignConvertibleTrait,
]
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/IR/Analysis/Module+AccessReification.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ extension Module {
case is Load:
return [.sink]
case is Move:
return [.inout]
return u.index == 0 ? [.sink] : [.inout]
case is ProjectBundle:
return requests(projectBundle: u)
default:
Expand Down
32 changes: 32 additions & 0 deletions Sources/IR/Analysis/Module+CallBundleReification.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Core

extension Module {

/// Replace occurrences of `call_bundle` by `call` depending on the uses of their first operands,
/// reporting errors and warnings to `diagnostics`.
///
/// - Requires: `f` is in `self`.
public mutating func reifyCallsToBundles(in f: Function.ID, diagnostics: inout DiagnosticSet) {
for i in blocks(in: f).map(instructions(in:)).joined() where self[i] is CallBundle {
reify(callBundle: i, for: .let)
}
}

private mutating func reify(callBundle i: InstructionID, for k: AccessEffect) {
let s = self[i] as! CallBundle
assert(s.capabilities.contains(k))

var arguments = Array(s.arguments)
let r = makeAccess(k, from: arguments[0], at: s.site)
arguments[0] = .register(insert(r, before: i))

let b = Block.ID(containing: i)
let f = FunctionReference(
to: s.variants[k]!, in: self, specializedBy: s.bundle.arguments, in: self[b].scope)

let reified = makeCall(
applying: .constant(f), to: arguments, writingResultTo: s.output, at: s.site)
replace(i, with: reified)
}

}
47 changes: 45 additions & 2 deletions Sources/IR/Emitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,46 @@ struct Emitter {
insert(module.makeReturn(at: returnSite))
}

/// Inserts the IR for `d`.
private mutating func lower(method d: MethodDecl.ID) {
for i in ast[d].impls {
lower(methodImpl: i)
}
}

/// Inserts the IR for `d`.
private mutating func lower(methodImpl d: MethodImpl.ID) {
let f = module.demandDeclaration(lowering: d)
guard let b = ast[d].body else { return }

// Create the function entry.
let entry = module.appendEntry(in: program.scopeContainingBody(of: d)!, to: f)

// Configure the locals.
var locals = DeclProperty<Operand>()
locals[ast[d].receiver] = .parameter(entry, 0)

let bundle = MethodDecl.ID(program[d].scope)!
for (i, p) in ast[bundle].parameters.enumerated() {
locals[p] = .parameter(entry, i + 1)
}

let bodyFrame = Frame(locals: locals)

// Emit the body.
self.insertionPoint = .end(of: entry)
switch b {
case .block(let s):
let returnType = LambdaType(program[d].type)!.output
let returnSite = pushing(bodyFrame, { $0.lowerStatements(s, expecting: returnType) })
insert(module.makeReturn(at: returnSite))

case .expr(let e):
pushing(bodyFrame, { $0.emitStore(value: e, to: $0.returnValue!) })
insert(module.makeReturn(at: ast[e].site))
}
}

/// Inserts the IR for `d`.
private mutating func lower(subscript d: SubscriptDecl.ID) {
for i in ast[d].impls {
Expand Down Expand Up @@ -418,6 +458,8 @@ struct Emitter {
lower(function: .init(m)!)
case InitializerDecl.self:
lower(initializer: .init(m)!)
case MethodDecl.self:
lower(method: .init(m)!)
case SubscriptDecl.self:
lower(subscript: .init(m)!)
default:
Expand Down Expand Up @@ -1426,8 +1468,9 @@ struct Emitter {
writingResultTo storage: Operand, at site: SourceRange
) {
let o = insert(module.makeAccess(.set, from: storage, at: site))!
insert(module.makeCallBundle(
applying: .init(callee, in: insertionScope!), to: arguments, writingResultTo: o, at: site))
insert(
module.makeCallBundle(
applying: .init(callee, in: insertionScope!), to: arguments, writingResultTo: o, at: site))
insert(module.makeEndAccess(o, at: site))
}

Expand Down
6 changes: 6 additions & 0 deletions Sources/IR/Mangling/Demangler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ struct Demangler {
return nil
case .monomorphizedFunctionDecl:
return nil
case .methodDecl:
return nil
case .methodImpl:
return nil
case .methodType:
return nil
case .synthesizedFunctionDecl:
return nil
case .conformanceConstraint, .equalityConstraint, .valueConstraint, .whereClause:
Expand Down
35 changes: 35 additions & 0 deletions Sources/IR/Mangling/Mangler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ struct Mangler {
write(initializer: InitializerDecl.ID(symbol)!, to: &output)
case MatchCase.self:
write(anonymousScope: symbol, to: &output)
case MethodDecl.self:
write(methodDecl: MethodDecl.ID(symbol)!, to: &output)
case MethodImpl.self:
write(methodImpl: MethodImpl.ID(symbol)!, to: &output)
case ModuleDecl.self:
write(entity: ModuleDecl.ID(symbol)!, to: &output)
case NamespaceDecl.self:
Expand Down Expand Up @@ -238,6 +242,19 @@ struct Mangler {
mangle(type: program[d].type, to: &output)
}

/// Writes the mangled representation of `d` to `output`.
private mutating func write(methodDecl d: MethodDecl.ID, to output: inout Output) {
write(operator: .methodDecl, to: &output)
write(string: program.ast[d].identifier.value, to: &output)
mangle(type: program[d].type, to: &output)
}

/// Writes the mangled representation of `d` to `output`.
private mutating func write(methodImpl d: MethodImpl.ID, to output: inout Output) {
write(operator: .methodImpl, to: &output)
write(base64Digit: program.ast[d].introducer.value, to: &output)
}

/// Writes the mangled representation of `d` to `output`.
private mutating func write(subscriptDecl d: SubscriptDecl.ID, to output: inout Output) {
if program.ast[d].isProperty {
Expand Down Expand Up @@ -383,6 +400,9 @@ struct Mangler {
case let t as LambdaType:
write(lambda: t, to: &output)

case let t as MethodType:
write(method: t, to: &output)

case let t as MetatypeType:
write(operator: .metatypeType, to: &output)
mangle(type: t.instance, to: &output)
Expand Down Expand Up @@ -499,6 +519,21 @@ struct Mangler {
mangle(type: t.output, to: &output)
}

/// Writes the mangled representation of `symbol` to `output`.
private mutating func write(method t: MethodType, to output: inout Output) {
write(operator: .methodType, to: &output)
write(base64Digit: t.capabilities, to: &output)
mangle(type: t.receiver, to: &output)

write(integer: t.inputs.count, to: &output)
for i in t.inputs {
write(string: i.label ?? "", to: &output)
mangle(type: i.type, to: &output)
}

mangle(type: t.output, to: &output)
}

/// Writes the mangled representation of `symbol` to `output`.
private mutating func write(subscriptType t: SubscriptType, to output: inout Output) {
write(operator: .subscriptType, to: &output)
Expand Down
6 changes: 6 additions & 0 deletions Sources/IR/Mangling/ManglingOperator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ public enum ManglingOperator: String {

case existentializedFunctionDecl = "eF"

case methodDecl = "hF"

case methodImpl = "iF"

case monomorphizedFunctionDecl = "mF"

case staticFunctionDecl = "sF"
Expand Down Expand Up @@ -76,6 +80,8 @@ public enum ManglingOperator: String {

case genericTypeParameterType = "gT"

case methodType = "hT"

case lambdaType = "lT"

case metatypeType = "mT"
Expand Down
1 change: 1 addition & 0 deletions Sources/IR/Module.swift
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ public struct Module {
}

try run({ removeDeadCode(in: $0, diagnostics: &log) })
try run({ reifyCallsToBundles(in: $0, diagnostics: &log) })
try run({ reifyAccesses(in: $0, diagnostics: &log) })
try run({ closeBorrows(in: $0, diagnostics: &log) })
try run({ normalizeObjectStates(in: $0, diagnostics: &log) })
Expand Down
20 changes: 20 additions & 0 deletions Tests/EndToEndTests/TestCases/MethodBundle.hylo
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//- compileAndRun expecting: success

type A: Deinitializable {

public var x: Int

public memberwise init

public fun foo() -> Int {
let { x.copy() }
sink { x }
}

}

public fun main() {
var a = A(x: 42)
precondition(a.foo() == 42)
precondition(a.foo() == 42)
}
Loading