Skip to content

Commit

Permalink
Merge pull request #1032 from hylo-lang/globals-in-generics
Browse files Browse the repository at this point in the history
Fix monomorphization of constant strings in generic functions
  • Loading branch information
kyouko-taiga authored Sep 26, 2023
2 parents 427b048 + 6c7b36b commit 289ed31
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 57 deletions.
18 changes: 0 additions & 18 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,6 @@
"version" : "1.0.4"
}
},
{
"identity" : "swift-docc-plugin",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-docc-plugin.git",
"state" : {
"revision" : "26ac5758409154cc448d7ab82389c520fa8a8247",
"version" : "1.3.0"
}
},
{
"identity" : "swift-docc-symbolkit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-docc-symbolkit",
"state" : {
"revision" : "b45d1f2ed151d057b54504d653e0da5552844e34",
"version" : "1.0.0"
}
},
{
"identity" : "swift-format",
"kind" : "remoteSourceControl",
Expand Down
17 changes: 14 additions & 3 deletions Sources/CodeGen/LLVM/Transpilation.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Core
import IR
import Foundation
import LLVM
import Utils

Expand Down Expand Up @@ -174,9 +175,6 @@ extension LLVM.Module {
let t = LLVM.FloatingPointType(ir.llvm(c.type.ast, in: &self))!
return t.constant(parsing: v.value)

case let v as IR.BufferConstant:
return LLVM.ArrayConstant(bytes: v.contents, in: &self)

case let v as IR.WitnessTable:
return transpiledWitnessTable(v, usedIn: m, from: ir)

Expand Down Expand Up @@ -572,6 +570,8 @@ extension LLVM.Module {
insert(closeUnion: i)
case is IR.CondBranch:
insert(condBranch: i)
case is IR.ConstantString:
insert(constantString: i)
case is IR.DeallocStack:
return
case is IR.EndAccess:
Expand Down Expand Up @@ -708,6 +708,17 @@ extension LLVM.Module {
insertStore(word().constant(UInt64(n)), to: discriminator, at: insertionPoint)
}

/// Inserts the transpilation of `i` at `insertionPoint`.
func insert(constantString i: IR.InstructionID) {
let s = m[i] as! ConstantString
let v = LLVM.ArrayConstant(bytes: s.value, in: &self)
let d = declareGlobalVariable(UUID().uuidString, v.type)
setInitializer(v, for: d)
setLinkage(.private, for: d)
setGlobalConstant(true, for: d)
register[.register(i)] = d
}

/// Inserts the transpilation of `i` at `insertionPoint`.
func insert(condBranch i: IR.InstructionID) {
let s = m[i] as! CondBranch
Expand Down
8 changes: 8 additions & 0 deletions Sources/IR/Analysis/Module+Depolymorphize.swift
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ extension Module {
rewrite(closeUnion: i, to: b)
case is CondBranch:
rewrite(condBranch: i, to: b)
case is ConstantString:
rewrite(constantString: i, to: b)
case is DeallocStack:
rewrite(deallocStack: i, to: b)
case is EndAccess:
Expand Down Expand Up @@ -311,6 +313,12 @@ extension Module {
append(newInstruction, to: b)
}

/// Rewrites `i`, which is in `r.function`, into `result`, at the end of `b`.
func rewrite(constantString i: InstructionID, to b: Block.ID) {
let s = sourceModule[i] as! ConstantString
append(makeConstantString(utf8: s.value, at: s.site), to: b)
}

/// Rewrites `i`, which is in `r.function`, into `result`, at the end of `b`.
func rewrite(deallocStack i: InstructionID, to b: Block.ID) {
let s = sourceModule[i] as! DeallocStack
Expand Down
8 changes: 8 additions & 0 deletions Sources/IR/Analysis/Module+NormalizeObjectStates.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ extension Module {
pc = interpret(closeUnion: user, in: &context)
case is CondBranch:
pc = interpret(condBranch: user, in: &context)
case is ConstantString:
pc = interpret(constantString: user, in: &context)
case is DeallocStack:
pc = interpret(deallocStack: user, in: &context)
case is EndAccess:
Expand Down Expand Up @@ -271,6 +273,12 @@ extension Module {
return successor(of: i)
}

/// Interprets `i` in `context`, reporting violations into `diagnostics`.
func interpret(constantString i: InstructionID, in context: inout Context) -> PC? {
initializeRegister(createdBy: i, in: &context)
return successor(of: i)
}

/// Interprets `i` in `context`, reporting violations into `diagnostics`.
func interpret(deallocStack i: InstructionID, in context: inout Context) -> PC? {
let s = self[i] as! DeallocStack
Expand Down
15 changes: 5 additions & 10 deletions Sources/IR/Emitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1440,19 +1440,14 @@ struct Emitter {
///
/// - Requires: `storage` is the address of uninitialized memory of type `Hylo.String`.
private mutating func emitStore(string v: String, to storage: Operand, at site: SourceRange) {
var bytes = v.unescaped.data(using: .utf8)!
let utf8 = PointerConstant(module.id, module.addGlobal(BufferConstant(bytes)))
let size = bytes.count

// Make sure the string is null-terminated.
bytes.append(contentsOf: [0])
let bytes = v.unescaped.data(using: .utf8)!

let x0 = emitSubfieldView(storage, at: [0], at: site)
emitStore(int: size, to: x0, at: site)
emitStore(int: bytes.count, to: x0, at: site)

let x1 = emitSubfieldView(storage, at: [1, 0], at: site)
let x2 = insert(module.makeAccess(.set, from: x1, at: site))!
insert(module.makeStore(.constant(utf8), at: x2, at: site))
let x2 = insert(module.makeConstantString(utf8: bytes, at: site))!
emitStore(value: x2, to: x1, at: site)
}

/// Inserts the IR for storing `a`, which is an `access`, to `storage`.
Expand Down Expand Up @@ -2492,7 +2487,7 @@ struct Emitter {
private func reference(
to d: Function.ID, implementedFor c: Core.Conformance
) -> FunctionReference {
var a = module.specialization(in: insertionFunction!).merging(c.arguments)
var a = c.arguments
if let m = program.traitMember(referredBy: d) {
a = a.merging([program[m.trait.decl].receiver: c.model])
}
Expand Down
26 changes: 0 additions & 26 deletions Sources/IR/Operands/Constant/BufferConstant.swift

This file was deleted.

47 changes: 47 additions & 0 deletions Sources/IR/Operands/Instruction/ConstantString.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Core
import Foundation

/// Creates a pointer to a constant string allocated statically.
public struct ConstantString: Instruction {

/// The value of the string, encoded in UTF-8.
public let value: Data

/// The site of the code corresponding to that instruction.
public let site: SourceRange

/// Creates an instance with the given properties.
fileprivate init(value: Data, site: SourceRange) {
self.value = value
self.site = site
}

public var result: IR.`Type`? {
.object(BuiltinType.ptr)
}

public var operands: [Operand] { [] }

public mutating func replaceOperand(at i: Int, with new: Operand) {
preconditionFailure()
}

}

extension ConstantString: CustomStringConvertible {

public var description: String {
"constant_string \"\(value)\""
}

}

extension Module {

/// Creates a `constant_string` anchored at `site` that returns a pointer to a statically
/// allocated string with given `value`, encoded in UTF8.
func makeConstantString(utf8 value: Data, at site: SourceRange) -> ConstantString {
.init(value: value, site: site)
}

}

0 comments on commit 289ed31

Please sign in to comment.