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

Enclave connections and enclave coordination in the C++ target #1665

Merged
merged 45 commits into from
May 16, 2023
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ef489d3
generate a wrapper reactor for enclave
cmnrd Feb 28, 2023
d4abdfc
Merge branch 'cpp-no-keepalive' into enclave-connections
cmnrd Mar 9, 2023
7764cfe
Merge branch 'fix-lfc' into enclave-connections
cmnrd Mar 9, 2023
3eeaf50
use a struct instead of a reactor to wrap enclaves
cmnrd Mar 9, 2023
619a766
first support for simple enclave communication
cmnrd Mar 9, 2023
b1d6dca
add test case
cmnrd Mar 9, 2023
3e45d41
Merge branch 'master' into enclave-connections
cmnrd Mar 14, 2023
b7f2d00
update reactor-cpp
cmnrd Mar 14, 2023
ae3f4bd
Merge branch 'master' into enclave-connections
cmnrd Mar 17, 2023
b8cadb8
Merge branch 'clem.new-equals-initializers' into enclave-connections
cmnrd Mar 18, 2023
07adeac
add simple enclave communication test
cmnrd Mar 18, 2023
9aaa80e
add test combining simple enclave communication with other events
cmnrd Mar 18, 2023
36fc361
updater reactor-cpp
cmnrd Mar 18, 2023
46db052
code generation for delayed and physical enclave connections
cmnrd Mar 18, 2023
06f36fd
add tests for physical and delayed enclave connections
cmnrd Mar 18, 2023
3fb05f5
first (incomplete) implementation of enclave multiport connections
cmnrd Mar 18, 2023
d5f90f2
update reactor-cpp
cmnrd Mar 18, 2023
6612910
add various multiport tests
cmnrd Mar 18, 2023
bd27e1f
formatting
cmnrd Mar 18, 2023
9c114c3
fix NPE
cmnrd Mar 20, 2023
85a21ef
disable keepalive warning in C++
cmnrd Mar 21, 2023
e17852d
update reactor-cpp and add new tests
cmnrd Mar 21, 2023
97632d8
update reactor-cpp and at tests covering sparse upstream events
cmnrd Mar 21, 2023
4d8bf85
format tests
cmnrd Mar 24, 2023
68e89e6
Merge branch 'master' into enclave-connections
cmnrd Mar 28, 2023
9cabad2
update reactor-cpp
cmnrd Mar 28, 2023
a7afcee
update reactor-cpp
cmnrd Mar 31, 2023
9626826
add tests with cycles
cmnrd Mar 31, 2023
58c6b0f
Merge branch 'master' into enclave-connections
cmnrd Apr 20, 2023
0d0fc3d
Merge branch 'master' into enclave-connections
cmnrd May 8, 2023
a36d8a3
update reactor-cpp
cmnrd May 8, 2023
de0af0c
unify connection generation using a lambda function
cmnrd May 8, 2023
d6c4e5a
allow connections where not all ports belong to enclaves
cmnrd May 8, 2023
814e0bf
use vector of unique pointers to store connections
cmnrd May 8, 2023
3d84b6c
format test
cmnrd May 8, 2023
c0b5127
only reserve if we have a dedicated connection vector
cmnrd May 10, 2023
3b49f12
update reactor-cpp
cmnrd May 10, 2023
fa0e058
bugfix
cmnrd May 10, 2023
f7261ea
another C++ syntax fix
cmnrd May 10, 2023
aae5cae
relax deadline
cmnrd May 10, 2023
0554c99
fix test file
cmnrd May 12, 2023
a305596
relax more deadlines and update timings
cmnrd May 12, 2023
48898a2
update reactor-cpp
cmnrd May 12, 2023
b7d0cd1
update reactor-cpp
cmnrd May 15, 2023
036625c
update reactor-cpp
cmnrd May 16, 2023
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: 2 additions & 0 deletions org.lflang/src/lib/cpp/lfutil.hh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include <reactor-cpp/reactor-cpp.hh>
#include <reactor-cpp/logging.hh>

#include <list>
cmnrd marked this conversation as resolved.
Show resolved Hide resolved

namespace lfutil {

template<class T>
Expand Down
2 changes: 1 addition & 1 deletion org.lflang/src/org/lflang/Target.java
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ public String getSingleLineCommentPrefix() {
* program (and keepalive was not explicitly unset by the user).
*/
public boolean setsKeepAliveOptionAutomatically() {
return this != Rust;
return this != Rust && this != CPP;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ package org.lflang.generator.cpp

import org.lflang.*
import org.lflang.generator.PrependOperator
import org.lflang.generator.cpp.CppConnectionGenerator.Companion.isEnclaveConnection
import org.lflang.generator.cpp.CppConnectionGenerator.Companion.name
import org.lflang.generator.cpp.CppConnectionGenerator.Companion.requiresConnectionClass
import org.lflang.generator.cpp.CppInstanceGenerator.Companion.isEnclave
import org.lflang.generator.cpp.CppPortGenerator.Companion.dataType
import org.lflang.lf.Action
import org.lflang.lf.Connection
Expand Down Expand Up @@ -86,7 +88,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) {
// is in a bank, but not a multiport
"""
|for (auto& __lf_instance : ${container.name}) {
${" | "..generateCode("__lf_instance->${port.name}")}
${" | "..generateCode("__lf_instance->${if(container.isEnclave) "__lf_instance->" else ""}${port.name}")}
|}
""".trimMargin()
} else {
Expand Down Expand Up @@ -182,7 +184,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) {

// Generate code which adds all left hand ports and all right hand ports to a vector each. If we are handling multiports
// within a bank, then we normally iterate over all banks in an outer loop and over all ports in an inner loop. However,
// if the connection is a cross connection, than we change the order on the right side and iterate over ports before banks.
// if the connection is an interleaved connection, than we change the order on the right side and iterate over ports before banks.
return with(PrependOperator) {
if (!c.requiresConnectionClass) {
"""
Expand All @@ -193,7 +195,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) {
${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }}
|lfutil::bind_multiple_ports(__lf_left_ports_$idx, __lf_right_ports_$idx, ${c.isIterated});
""".trimMargin()
} else {
} else if (!c.isEnclaveConnection) {
"""
|// connection $idx
|std::vector<$portType> __lf_left_ports_$idx;
Expand All @@ -211,6 +213,19 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) {
${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }}
|lfutil::bind_multiple_connections_with_ports(__lf_connection_pointers_$idx, __lf_right_ports_$idx, ${c.isIterated});
""".trimMargin()
} else {
"""
|// connection $idx
|std::vector<$portType> __lf_left_ports_$idx;
${" |"..c.leftPorts.joinWithLn { addAllPortsToVector(it, "__lf_left_ports_$idx") }}
|std::vector<$portType> __lf_right_ports_$idx;
${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }}
|for(size_t __lf_idx{0}; __lf_idx < std::min(__lf_right_ports_$idx.size(), __lf_left_ports_$idx.size()); __lf_idx++) {
| ${c.name}.emplace_back("${c.name}" + std::to_string(__lf_idx), __lf_right_ports_$idx[__lf_idx]->environment()${if(c.delay != null) ", ${c.delay.toCppTime()}" else ""});
| ${c.name}.back().bind_upstream_port(__lf_left_ports_$idx[__lf_idx]);
| ${c.name}.back().bind_downstream_port(__lf_right_ports_$idx[__lf_idx]);
|}
""".trimMargin()
}
}
}
Expand Down
63 changes: 48 additions & 15 deletions org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package org.lflang.generator.cpp

import org.lflang.*
import org.lflang.generator.cpp.CppConnectionGenerator.Companion.cppType
import org.lflang.generator.cpp.CppConnectionGenerator.Companion.isEnclaveConnection
import org.lflang.generator.cpp.CppInstanceGenerator.Companion.isEnclave
import org.lflang.generator.cpp.CppPortGenerator.Companion.dataType
import org.lflang.lf.Connection
import org.lflang.lf.Port
Expand All @@ -25,13 +27,38 @@ class CppConnectionGenerator(private val reactor: Reactor) {
get() {
val leftPort = leftPorts.first()
return when {
isPhysical -> "reactor::PhysicalConnection<${leftPort.dataType}>"
delay != null -> "reactor::DelayedConnection<${leftPort.dataType}>"
else -> throw IllegalArgumentException("Connection is neither physical nor delayed")
isEnclaveConnection -> when {
isPhysical -> "reactor::PhysicalEnclaveConnection<${leftPort.dataType}>"
delay != null -> "reactor::DelayedEnclaveConnection<${leftPort.dataType}>"
else -> "reactor::EnclaveConnection<${leftPort.dataType}>"
}

isPhysical -> "reactor::PhysicalConnection<${leftPort.dataType}>"
delay != null -> "reactor::DelayedConnection<${leftPort.dataType}>"
else -> throw IllegalArgumentException("Unsupported connection type")
}
}

val Connection.requiresConnectionClass: Boolean get() = isPhysical || delay != null
val Connection.isEnclaveConnection: Boolean
get() {
if (leftPorts.size == 1 && rightPorts.size == 1) {
val leftIsEnclave = leftPorts[0].container?.isEnclave == true
val rightIsEnclave = rightPorts[0].container?.isEnclave == true
return when {
leftIsEnclave && rightIsEnclave -> true
!leftIsEnclave && !rightIsEnclave -> false
else -> TODO("Connections between enclaves and normal reactors are not supported")
}
}
for (port in leftPorts + rightPorts) {
if (port.container?.isEnclave == true) {
TODO("Enclaves can only be used in simple connections")
}
}
return false
}

val Connection.requiresConnectionClass: Boolean get() = isPhysical || delay != null || isEnclaveConnection;
}

fun generateDeclarations() =
Expand All @@ -42,18 +69,24 @@ class CppConnectionGenerator(private val reactor: Reactor) {
reactor.connections.mapNotNull { generateConstructorInitializer(it) }.joinLn()

private fun generateDecleration(connection: Connection): String? =
if (connection.requiresConnectionClass) {
if (connection.hasMultipleConnections) {
"std::vector<${connection.cppType}> ${connection.name};"
} else {
"${connection.cppType} ${connection.name};"
with(connection) {
if (requiresConnectionClass) {
when {
hasMultipleConnections && isEnclaveConnection -> "std::list<${connection.cppType}> ${connection.name};"
hasMultipleConnections && !isEnclaveConnection -> "std::vector<${connection.cppType}> ${connection.name};"
cmnrd marked this conversation as resolved.
Show resolved Hide resolved
else -> "${connection.cppType} ${connection.name};"
}
} else null
}

private fun generateConstructorInitializer(connection: Connection): String? = with(connection) {
if (requiresConnectionClass && !hasMultipleConnections) {
when {
isEnclaveConnection && delay == null -> """, $name{"$name", ${rightPorts[0].container.name}->__lf_env.get()}"""
isEnclaveConnection && delay != null -> """, $name{"$name", ${rightPorts[0].container.name}->__lf_env.get(), ${delay.toCppTime()}}"""
else -> """, $name{"$name", this, ${delay.toCppTime()}}"""
}
} else null
}

private fun generateConstructorInitializer(connection: Connection): String? =
if (connection.requiresConnectionClass && !connection.hasMultipleConnections) {
val delay = connection.delay.toCppTime()
val name = connection.name
""", $name{"$name", this, $delay}"""
} else null
}
8 changes: 6 additions & 2 deletions org.lflang/src/org/lflang/generator/cpp/CppExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.lflang.generator.cpp

import org.eclipse.emf.ecore.resource.Resource
import org.lflang.*
import org.lflang.generator.cpp.CppInstanceGenerator.Companion.isEnclave
import org.lflang.lf.BuiltinTriggerRef
import org.lflang.lf.Expression
import org.lflang.lf.Port
Expand Down Expand Up @@ -111,8 +112,11 @@ val Reactor.templateName: String get() = if (isGeneric) "$name<${typeParms.joinT

/** Get a C++ code representation of the given variable */
val VarRef.name: String
get() = if (this.container == null) this.variable.name
else "${this.container.name}->${this.variable.name}"
get() = when {
container == null -> variable.name
container.isEnclave -> "${container.name}->__lf_instance->${variable.name}"
else -> "${container.name}->${variable.name}"
}

/** Get a C++ code representation of the given trigger */
val TriggerRef.name: String
Expand Down
76 changes: 39 additions & 37 deletions org.lflang/src/org/lflang/generator/cpp/CppInstanceGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,49 @@ class CppInstanceGenerator(
private val fileConfig: CppFileConfig,
private val errorReporter: ErrorReporter
) {
private val Instantiation.isEnclave: Boolean get() = AttributeUtils.isEnclave(this)
companion object {
val Instantiation.isEnclave: Boolean get() = AttributeUtils.isEnclave(this)

private val Instantiation.hasEachParameter: Boolean
get() = AttributeUtils.getBooleanAttributeParameter(
AttributeUtils.getEnclaveAttribute(this), AttributeSpec.EACH_ATTR
) ?: false
val Instantiation.hasEachParameter: Boolean
get() = AttributeUtils.getBooleanAttributeParameter(
AttributeUtils.getEnclaveAttribute(this), AttributeSpec.EACH_ATTR
) ?: false

val Instantiation.cppType: String
get() {
return if (reactor.isGeneric)
private val Instantiation.reactorType: String
get() = if (reactor.isGeneric)
"""${reactor.name}<${typeArgs.joinToString(", ") { it.toText() }}>"""
else
reactor.name
}

val Instantiation.cppClass: String
get() = if (isEnclave) enclaveWrapperClassName else reactorType

val Instantiation.enclaveWrapperClassName get() = "EnclaveWrapper_$name"
}

private fun Instantiation.generateWrapper(): String = """
|struct $enclaveWrapperClassName {
| ${if (!hasEachParameter) "inline static " else ""}std::unique_ptr<reactor::Environment> __lf_env{nullptr};
| std::unique_ptr<$reactorType> __lf_instance{nullptr};
|
| $enclaveWrapperClassName(const std::string& name, reactor::Reactor* container, $reactorType::Parameters&& params) {
| if (__lf_env == nullptr) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

general question the code generator generates c++ code in a totally different style like what is currently standard in reactor-cpp. __lf_env compared it would be probably be named lf_env_ in the style of reactor-cpp.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use the __lf_ prefix for some variables to avoid name clashes. It is unlikely, but if someone would name their state variable or some other reactor component lf_env_, we would see compile errors. __ is kind of a protected namespace in C/C++ that is not supposed to be used by users.

| __lf_env = std::make_unique<reactor::Environment>(container->fqn() + name, container->environment());
cmnrd marked this conversation as resolved.
Show resolved Hide resolved
| }
| __lf_instance = std::make_unique<$reactorType>(name, __lf_env.get(), std::forward<$reactorType::Parameters>(params));
| }
|};
""".trimMargin()

private fun generateDeclaration(inst: Instantiation): String = with(inst) {
val instance = if (isBank) "std::vector<std::unique_ptr<$cppType>>" else "std::unique_ptr<$cppType>"
val instance = if (isBank) "std::vector<std::unique_ptr<$cppClass>>" else "std::unique_ptr<$cppClass>"
if (isEnclave) {
val env = if (hasEachParameter) "std::vector<std::unique_ptr<reactor::Environment>>" else "reactor::Environment"
return """
$env __lf_env_$name;
$instance $name;
""".trimIndent()
return with(PrependOperator) {
"""
${" |"..inst.generateWrapper()}
|$instance $name;
""".trimMargin()
}
}
return "$instance $name;"
}
Expand Down Expand Up @@ -91,43 +111,25 @@ class CppInstanceGenerator(
// by iterating over the reactor parameters we make sure that the parameters are assigned in declaration order
return reactor.parameters.mapNotNull {
if (it.name in assignments) ".${it.name} = ${assignments[it.name]}" else null
}.joinToString(", ", "$cppType::Parameters{", "}")
}.joinToString(", ", "$reactorType::Parameters{", "}")
}

private fun generateInitializer(inst: Instantiation): String? = with(inst) {
when {
!isBank && !isEnclave -> """, $name(std::make_unique<$cppType>("$name", this, ${getParameterStruct()}))"""
!isBank && isEnclave -> """
, __lf_env_$name(this->fqn() + ".$name", this->environment())
, $name(std::make_unique<$cppType>("$name", &__lf_env_$name, ${getParameterStruct()}))
""".trimIndent()

isBank && isEnclave && !hasEachParameter -> """, __lf_env_$name(this->fqn() + ".$name", this->environment())"""
else -> null
}
if (isBank) null else """, $name(std::make_unique<$cppClass>("$name", this, ${getParameterStruct()}))"""
}

private fun generateConstructorInitializer(inst: Instantiation): String {
with(inst) {
assert(isBank)
val containerRef = when {
hasEachParameter -> "__lf_env_$name[__lf_idx].get()"
isEnclave -> "&__lf_env_$name"
else -> "this"
}

val width = inst.widthSpec.toCppCode()
return with(PrependOperator) {
"""
return """
|// initialize instance $name
|$name.reserve($width);
|for (size_t __lf_idx = 0; __lf_idx < $width; __lf_idx++) {
| std::string __lf_inst_name = "${name}_" + std::to_string(__lf_idx);
${"| "..if (hasEachParameter) """__lf_env_$name.emplace_back(std::make_unique<reactor::Environment>(this->fqn() + "." + __lf_inst_name, this->environment()));""" else ""}
| $name.emplace_back(std::make_unique<$cppType>(__lf_inst_name, $containerRef, ${inst.getParameterStruct()}));
| $name.emplace_back(std::make_unique<$cppClass>(__lf_inst_name, this, ${inst.getParameterStruct()}));
|}
""".trimMargin()
}
}
}

Expand Down
20 changes: 13 additions & 7 deletions org.lflang/src/org/lflang/generator/cpp/CppPortGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

package org.lflang.generator.cpp

import org.lflang.generator.cpp.CppInstanceGenerator.Companion.enclaveWrapperClassName
import org.lflang.generator.cpp.CppInstanceGenerator.Companion.isEnclave
import org.lflang.inferredType
import org.lflang.isBank
import org.lflang.isMultiport
Expand All @@ -34,7 +36,6 @@ class CppPortGenerator(private val reactor: Reactor) {

companion object {
private val VarRef.isMultiport get() = (variable as? Port)?.isMultiport == true
private val VarRef.isInBank get() = container?.isBank == true

/**
* Return the C++ type of a port reference.
Expand All @@ -44,11 +45,16 @@ class CppPortGenerator(private val reactor: Reactor) {
* statement and let the C++ compiler do the job.
*/
val VarRef.dataType: String
get() = when {
isInBank && isMultiport -> "std::remove_reference<decltype(${container.name}[0]->${variable.name}[0])>::type::value_type"
isInBank && !isMultiport -> "std::remove_reference<decltype(${container.name}[0]->${variable.name})>::type::value_type"
!isInBank && isMultiport -> "std::remove_reference<decltype($name[0])>::type::value_type"
else -> "std::remove_reference<decltype($name)>::type::value_type"
get() {
val variableRef = when {
this == null -> ""
container == null -> this.name
container.isBank && container.isEnclave -> "${container.name}[0]->__lf_instance->${variable.name}"
container.isBank && !container.isEnclave -> "${container.name}[0]->${variable.name}"
else -> this.name
}
val multiportRef = if (isMultiport) "$variableRef[0]" else variableRef
return "std::remove_reference<decltype($multiportRef)>::type::value_type"
}
}

Expand All @@ -62,7 +68,7 @@ class CppPortGenerator(private val reactor: Reactor) {
}

/** Get the C++ type for the receiving port. */
val Port.cppType: String
private val Port.cppType: String
get() {
val portType = when (this) {
is Input -> "reactor::Input"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package org.lflang.generator.cpp

import org.lflang.generator.PrependOperator
import org.lflang.generator.cpp.CppInstanceGenerator.Companion.cppClass
import org.lflang.isBank
import org.lflang.joinWithLn
import org.lflang.label
Expand Down Expand Up @@ -172,7 +173,7 @@ class CppReactionGenerator(
}

private fun generateViewForContainer(r: Reaction, container: Instantiation): String {
val reactorClass = with(instanceGenerator) { container.cppType }
val reactorClass = container.cppClass
val viewClass = r.getViewClassName(container)
val viewInstance = r.getViewInstanceName(container)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ class CppReactorGenerator(private val reactor: Reactor, fileConfig: CppFileConfi
${" | "..instances.generateInitializers()}
${" | "..timers.generateInitializers()}
${" | "..actions.generateInitializers()}
${" | "..connections.generateInitializers()}
${" | "..reactions.generateReactionViewInitializers()}
${" | "..connections.generateInitializers()}
|{
${" | "..ports.generateConstructorInitializers()}
${" | "..instances.generateConstructorInitializers()}
Expand Down
Loading