Skip to content

Commit

Permalink
Merge pull request #1665 from lf-lang/enclave-connections
Browse files Browse the repository at this point in the history
Enclave connections and enclave coordination in the C++ target
  • Loading branch information
cmnrd authored May 16, 2023
2 parents 9fa0357 + 036625c commit 4d23747
Show file tree
Hide file tree
Showing 36 changed files with 1,510 additions and 143 deletions.
53 changes: 9 additions & 44 deletions org.lflang/src/lib/cpp/lfutil.hh
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,13 @@ class LFScope {
void request_stop() const { return environment()->sync_shutdown(); }
};

template<class T>
template<class PortPtr>
void bind_multiple_ports(
std::vector<reactor::Port<T>*>& left_ports,
std::vector<reactor::Port<T>*>& right_ports,
bool repeat_left) {

std::vector<PortPtr>& left_ports,
std::vector<PortPtr>& right_ports,
bool repeat_left,
std::function<void(PortPtr, PortPtr, std::size_t)> connect)
{
if (repeat_left) {
auto l_size = left_ports.size();
auto r_size = right_ports.size();
Expand All @@ -92,50 +93,14 @@ void bind_multiple_ports(
<< "Not all ports will be connected!";
}

std::size_t idx{0};
while (left_it != left_ports.end() && right_it != right_ports.end()) {
auto left = *left_it;
auto right = *right_it;
left->bind_to(right);
left_it++;
right_it++;
}
}

template<class T>
void bind_multiple_connections_with_ports(
std::vector<reactor::Connection<T>*>& connections,
std::vector<reactor::Port<T>*>& ports,
bool repeat_left) {

if (repeat_left) {
auto l_size = connections.size();
auto r_size = ports.size();
// divide and round up
auto repetitions = r_size / l_size + (r_size % l_size != 0);
// repeat repetitions-1 times
connections.reserve(repetitions * l_size);
for (std::size_t i{1}; i < repetitions; i++) {
std::copy_n(connections.begin(), l_size, std::back_inserter(connections));
}
}

auto left_it = connections.begin();
auto right_it = ports.begin();

if (connections.size() < ports.size()) {
reactor::log::Warn() << "There are more right ports than left ports. "
<< "Not all ports will be connected!";
} else if (connections.size() > ports.size()) {
reactor::log::Warn() << "There are more left ports than right ports. "
<< "Not all ports will be connected!";
}

while (left_it != connections.end() && right_it != ports.end()) {
auto left = *left_it;
auto right = *right_it;
left->bind_downstream_port(right);
connect(left, right, idx);
left_it++;
right_it++;
idx++;
}
}

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 @@ -547,7 +547,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,11 @@ package org.lflang.generator.cpp

import org.lflang.*
import org.lflang.generator.PrependOperator
import org.lflang.generator.cpp.CppConnectionGenerator.Companion.cppType
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 +89,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 @@ -170,48 +173,51 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) {
* complex logic for finding the actual type, we return a decltype statement and let the C++ compiler do the job.
*/
private val VarRef.portType: String
get() = "reactor::Port<${dataType}>*"
get() = "reactor::Port<typename ${dataType}>*"

private fun declareMultiportConnection(c: Connection, idx: Int): String {
// It should be safe to assume that all ports have the same type. Thus we just pick the
// first left port to determine the type of the entire connection
val portType = c.leftPorts[0].portType

val leftPort = c.leftPorts[0].variable as Port
val dataType = leftPort.inferredType.cppType

// 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) {
"""
|// 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") }}
|lfutil::bind_multiple_ports(__lf_left_ports_$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") }}
|${c.name}.reserve(__lf_left_ports_$idx.size());
|for(size_t __lf_idx{0}; __lf_idx < __lf_left_ports_$idx.size(); __lf_idx++) {
| ${c.name}.emplace_back("${c.name}" + std::to_string(__lf_idx), this, ${c.delay.toCppTime()});
| ${c.name}.back().bind_upstream_port(__lf_left_ports_$idx[__lf_idx]);
|}
|std::vector<reactor::Connection<$dataType>*> __lf_connection_pointers_$idx;
|for (auto& connection : ${c.name}) {
| __lf_connection_pointers_$idx.push_back(&connection);
|}
|std::vector<$portType> __lf_right_ports_$idx;
${" |"..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()
}
"""
|// 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") }}
${" |"..if (c.requiresConnectionClass) "${c.name}.reserve(std::max(__lf_left_ports_$idx.size(), __lf_right_ports_$idx.size()));" else ""}
|lfutil::bind_multiple_ports<$portType>(__lf_left_ports_$idx, __lf_right_ports_$idx, ${c.isIterated},
${" |"..c.getConnectionLambda(portType)}
|);
""".trimMargin()
}
}

private fun Connection.getConnectionLambda(portType: String): String {
return when {
isEnclaveConnection -> """
[this]($portType left, $portType right, std::size_t idx) {
$name.push_back(std::make_unique<$cppType>(
"$name" + std::to_string(idx), right->environment()${if (delay != null) ", ${delay.toCppTime()}" else ""}));
$name.back()->bind_upstream_port(left);
$name.back()->bind_downstream_port(right);
}
""".trimIndent()

requiresConnectionClass -> """
[this]($portType left, $portType right, std::size_t idx) {
$name.push_back(std::make_unique<$cppType>("$name" + std::to_string(idx), this, ${delay.toCppTime()}));
$name.back()->bind_upstream_port(left);
$name.back()->bind_downstream_port(right);
}
""".trimIndent()

else -> "[]($portType left, $portType right, [[maybe_unused]]std::size_t idx) { left->bind_to(right); }"
}
}

Expand Down
54 changes: 39 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,29 @@ 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() {
for (port in leftPorts + rightPorts) {
if (port.container?.isEnclave == true) {
return true
}
}
return false
}

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

fun generateDeclarations() =
Expand All @@ -42,18 +60,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) {
if (hasMultipleConnections) {
"std::vector<std::unique_ptr<${connection.cppType}>> ${connection.name};"
} 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
Loading

0 comments on commit 4d23747

Please sign in to comment.