Skip to content
Draft
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
31 changes: 29 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ if(TOOLCHAIN STREQUAL GCC)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()

set(platform MemPool CACHE STRING "Platform (MemPool, SoftHier, QEMU, Siracusa, Siracusa_w_neureka, PULP-Open, GAP9, Generic, Snitch)")
set_property(CACHE platform PROPERTY STRINGS MemPool SoftHier QEMU Siracusa Siracusa_w_neureka PULP-Open GAP9 Generic Snitch)
set(platform MemPool CACHE STRING "Platform (MemPool, SoftHier, QEMU, Siracusa, Siracusa_w_neureka, PULP-Open, GAP9, Generic, Snitch, Xheep)")
set_property(CACHE platform PROPERTY STRINGS MemPool SoftHier QEMU Siracusa Siracusa_w_neureka PULP-Open GAP9 Generic Snitc Xheep)

if(platform STREQUAL MemPool)
message(STATUS "Building for platform 'MemPool'")
Expand Down Expand Up @@ -57,6 +57,8 @@ elseif(platform STREQUAL Chimera)
message(STATUS "Building for platform 'Chimera'")
elseif(platform STREQUAL XDNA2)
message(STATUS "Building for platform 'XDNA2'")
elseif(platform STREQUAL Xheep)
message(STATUS "Building for platform 'X-HEEP'")
else()
message(FATAL_ERROR "Invalid platform '${platform}' specified!")
endif()
Expand Down Expand Up @@ -326,5 +328,30 @@ if(platform STREQUAL XDNA2)

endif()

if(platform STREQUAL Xheep)
if(TOOLCHAIN STREQUAL LLVM)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/xheep/toolchain_llvm.cmake)
else()
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/xheep/toolchain_gcc.cmake)
endif()

include(${CMAKE_CURRENT_LIST_DIR}/cmake/xheep/xheep.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/cmake/xheep/xheep_verilator.cmake)

project(deeploy LANGUAGES C ASM)

message(STATUS "============================= X-HEEP Configuration ============================")
message(STATUS "[cMake ] GENERATED_SOURCE = " ${GENERATED_SOURCE})
message(STATUS "[cMake ] TESTNAME = " ${TESTNAME})
message(STATUS "==============================================================================")
message(STATUS "")

add_subdirectory(TargetLibraries/Generic)
add_subdirectory(TargetLibraries/xheep)
add_subdirectory(DeeployTest)

target_link_libraries(deeploylib INTERFACE deeploybasic deeployxheep)
endif()


print_simulation_config()
31 changes: 29 additions & 2 deletions Deeploy/Targets/Generic/Bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
FloatSwishTemplate, GatherTemplate, GemmTemplate, IntegerDivTemplate, ITAMaxTemplate, ITAPartialMaxTemplate, \
MatMulTemplate, MaxPoolTemplate, MulTemplate, PadTemplate, QuantTemplate, ReduceMeanTemplate, ReduceSumTemplate, \
RequantShiftTemplate, ReshapeTemplate, RQIntegerDivTemplate, RQSiGELUTemplate, SliceTemplate, SubTemplate, \
TransposeTemplate, iGELUTemplate, iLayernormTemplate, iRMSNormTemplate, iSoftmaxTemplate
TransposeTemplate, iGELUTemplate, iLayernormTemplate, iRMSNormTemplate, iSoftmaxTemplate, \
TanhTemplate, ReduceMaxTemplate
from Deeploy.Targets.Generic.TypeCheckers import AddChecker, BatchNormChecker, ConcatChecker, ConvChecker, \
DebugPrintChecker, DequantChecker, DivChecker, DummyChecker, GatherChecker, GELUChecker, GEMMChecker, \
LayerNormChecker, MatMulChecker, MaxPoolChecker, MulChecker, PadChecker, QuantChecker, ReduceMeanChecker, \
ReduceSumChecker, ReluChecker, RequantShiftChecker, ReshapeChecker, RQIntegerDivChecker, SliceChecker, \
SoftmaxChecker, TransposeChecker
SoftmaxChecker, TransposeChecker, \
ReduceMaxChecker, FloatConcatChecker, TanhChecker

BasicTransformer = CodeTransformation([ArgumentStructGeneration(), MemoryManagementGeneration(), FutureGeneration()])

Expand Down Expand Up @@ -420,3 +422,28 @@
NodeBinding(DummyChecker([PointerClass(float32_t)], [PointerClass(float32_t)]),
FloatGlobalMaxPoolTemplate.referenceTemplate, BasicTransformer)
]


### NEWLY ADDED LAYERS:
BasicTanhBindings = [
NodeBinding(TanhChecker([PointerClass(float32_t), PointerClass(float32_t)], [PointerClass(float32_t)]),
TanhTemplate.referenceTemplate, BasicTransformer)
]


BasicReduceMaxBindings = [
NodeBinding(ReduceMaxChecker([PointerClass(type1), PointerClass(type2)], [PointerClass(int32_t)]),
ReduceMaxTemplate.referenceTemplate, BasicTransformer)
for type1 in IntegerDataTypes
for type2 in IntegerDataTypes
] + [
NodeBinding(ReduceMaxChecker([PointerClass(float32_t), PointerClass(float32_t)], [PointerClass(float32_t)]),
ReduceMaxTemplate.referenceTemplate, BasicTransformer)
]

BasicConcatBindings += [NodeBinding(
FloatConcatChecker([PointerClass(float32_t), PointerClass(float32_t)],
[PointerClass(float32_t)]),
ConcatTemplate.referenceTemplate,
BasicTransformer
)]
14 changes: 14 additions & 0 deletions Deeploy/Targets/Generic/Layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -792,3 +792,17 @@ def computeOps(self):
opRep = self.mapper.parser.operatorRepresentation
# (spatial_size - 1) comparisons per output channel
return int(opRep['batch_size'] * opRep['num_channels'] * (opRep['spatial_size'] - 1))


### NEWLY ADDED LAYERS :

class TanhLayer(ONNXLayer):

def __init__(self, maps: List[NodeMapper]):
super().__init__(maps)

class ReduceMaxLayer(ONNXLayer):

def __init__(self, maps: List[NodeMapper]):
super().__init__(maps)

73 changes: 73 additions & 0 deletions Deeploy/Targets/Generic/Parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3124,3 +3124,76 @@ class GlobalMaxPoolParser(GlobalPoolParser):

def parseNode(self, node: gs.Node) -> bool:
return super().parseNode(node) and node.op == 'GlobalMaxPool'


### NEWLY ADDED LAYERS :

class TanhParser(NodeParser):

def __init__(self):
super().__init__()

def parseNode(self, node: gs.Node) -> bool:

ret = all([len(node.inputs) == 1, len(node.outputs) == 1])

return ret

def parseNodeCtxt(self,
ctxt: NetworkContext,
node: gs.Node,
channels_first: bool = True) -> Tuple[NetworkContext, bool]:

data_in = ctxt.lookup(node.inputs[0].name)
data_out = ctxt.lookup(node.outputs[0].name)
self.operatorRepresentation['data_in'] = data_in.name
self.operatorRepresentation['data_out'] = data_out.name
self.operatorRepresentation['size'] = np.prod(data_in.shape)

return ctxt, True



class ReduceMaxParser(NodeParser):
"""
Reduce Max Parser.
Only supports maximizing through one dimension. (axes.shape == 1)
"""
def __init__(self):
super().__init__()

def parseNode(self, node: gs.Node) -> bool:

ret = all(['axes' in node.attrs, len(node.inputs) <= 2, len(node.outputs) == 1])

if ret:
axes = node.attrs.get('axes', 0)
if len(axes) > 1:
return False
else:
self.operatorRepresentation['axes'] = axes[0]
return True

return False

def parseNodeCtxt(self,
ctxt: NetworkContext,
node: gs.Node,
channels_first: bool = True) -> Tuple[NetworkContext, bool]:

data_in = ctxt.lookup(node.inputs[0].name)
data_out = ctxt.lookup(node.outputs[0].name)
self.operatorRepresentation['data_in'] = data_in.name
self.operatorRepresentation['data_out'] = data_out.name

axes = self.operatorRepresentation['axes']

inner_size = int(np.prod(data_in.shape[axes+1:]))
outer_size = int(np.prod(data_in.shape[:axes]))

self.operatorRepresentation['inner_size'] = inner_size
self.operatorRepresentation['output_size'] = inner_size * outer_size
self.operatorRepresentation['d_axes'] = int(data_in.shape[axes])
self.operatorRepresentation['outer_step'] = int(data_in.shape[axes] * inner_size)

return ctxt, True
21 changes: 17 additions & 4 deletions Deeploy/Targets/Generic/Platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
BasicPowBindings, BasicQuantBindings, BasicReduceMeanBindings, BasicReduceSumBindings, BasicReluBinding, \
BasicReshapeBindings, BasicRQIntegerDivBinding, BasicRQSBindings, BasicRQSGELUBinding, BasicSigmoidBindings, \
BasicSliceBindings, BasicSoftmaxBindings, BasicSqrtBindings, BasicSubBindings, BasicSwishBindings, \
BasicTransposeBindings, DummyBinding
BasicTransposeBindings, DummyBinding, \
BasicTanhBindings, BasicReduceMaxBindings
from Deeploy.Targets.Generic.Layers import AddLayer, AveragePoolLayer, BatchNormalizationLayer, CeilLayer, ClipLayer, \
ConcatLayer, ConvLayer, ConvTransposeLayer, DebugPrintLayer, DequantLayer, DivLayer, ExpLayer, FloorLayer, \
GatherLayer, GELULayer, GEMMLayer, GlobalAveragePoolLayer, GlobalMaxPoolLayer, GroupNormLayer, InstanceNormLayer, \
ITAMaxLayer, LayerNormLayer, MatMulLayer, MaxPoolLayer, MulLayer, PadLayer, PowLayer, QuantLayer, ReduceMeanLayer, \
ReduceSumLayer, ReluLayer, RequantShiftLayer, ReshapeLayer, RQIntegerDivLayer, RQSiGELULayer, SigmoidLayer, \
SliceLayer, SoftmaxLayer, SqrtLayer, SubLayer, SwishLayer, TransposeLayer
SliceLayer, SoftmaxLayer, SqrtLayer, SubLayer, SwishLayer, TransposeLayer, \
TanhLayer, ReduceMaxLayer
from Deeploy.Targets.Generic.Parsers import AddParser, AveragePool1DParser, AveragePool2DParser, BatchNormParser, \
CeilParser, ClipParser, ConcatParser, ConvTranspose1DParser, DebugParser, DequantParser, DivParser, DummyParser, \
ExpParser, FlattenParser, FloorParser, GatherParser, GELUParser, GenericConv1DParser, GenericConv2DParser, \
Expand All @@ -32,11 +34,12 @@
ITAMaxParser, ITAPartialMaxParser, LayerNormParser, MatMulParser, MaxPool1DParser, MulParser, Pad1DParser, \
Pad2DParser, PowParser, QuantParser, ReduceMeanParser, ReduceSumParser, ReluParser, RequantShiftParser, \
ReshapeParser, RQIntegerDivParser, RQSiGELUParser, SigmoidParser, SliceParser, SoftmaxParser, SqrtParser, \
SubParser, SwishParser, TransposeParser, UnsqueezeParser, iLayerNormParser, iSoftmaxParser
SubParser, SwishParser, TransposeParser, UnsqueezeParser, iLayerNormParser, iSoftmaxParser, \
TanhParser, ReduceMaxParser
from Deeploy.Targets.Generic.Templates import AllocateTemplate, FreeTemplate
from Deeploy.Targets.Generic.TopologyOptimizationPasses.Passes import DequantPatternPass, ExtractPaddingFromConvPass, \
ExtractPaddingFromPoolPass, MatMulAddMergePass, MergeConstAddAndRequantPass, QuantPatternPass, \
iGELURequantMergePass
iGELURequantMergePass, UnrollConcatPass

AddMapper = NodeMapper(AddParser(), BasicAddBindings)
SubMapper = NodeMapper(SubParser(), BasicSubBindings)
Expand Down Expand Up @@ -99,6 +102,11 @@
# They should always generate compiler errors to not accidentally end up in production code
DummyMapper = NodeMapper(DummyParser(), [DummyBinding])

### NEWLY ADDED LAYERS:
TanhMapper = NodeMapper(TanhParser(), BasicTanhBindings)
ReduceMaxMapper = NodeMapper(ReduceMaxParser(), BasicReduceMaxBindings)


GenericMapping = {
'Add': AddLayer([AddMapper]),
'Sub': SubLayer([SubMapper]),
Expand Down Expand Up @@ -158,6 +166,10 @@
# # deployment or optimizations with GlobalAveragePool nodes but did not yet
# # implement the corresponding kernel
# 'GlobalAveragePool': ConvLayer([DummyMapper]),

### NEWLY ADDED LAYERS:
'Tanh' : TanhLayer([TanhMapper]),
'ReduceMax' : ReduceMaxLayer([ReduceMaxMapper])
}


Expand Down Expand Up @@ -198,6 +210,7 @@ class GenericStructBuffer(StructBuffer):
MergeConstAddAndRequantPass(),
ExtractPaddingFromConvPass(),
ExtractPaddingFromPoolPass(),
UnrollConcatPass(),
RemoveEmptyConvBiasPass(),
RemoveOnlySingletonReduceMeanPass(),
# DebugPrintPass(r'.*[Mm]at[Mm]ul.*', position = 'after'),
Expand Down
50 changes: 50 additions & 0 deletions Deeploy/Targets/Generic/Templates/ReduceMaxTemplate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright (C) 2026 EPFL.
# Solderpad Hardware License, Version 2.1, see LICENSE.md for details.
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
#
# File: ReduceMaxTemplate.py
# Author: Mohammad Hossein Nikkhah
# Description:

from typing import Dict, List, Tuple

from Deeploy.DeeployTypes import NetworkContext, NodeTemplate, OperatorRepresentation


referenceTemplate = NodeTemplate("""
// ReduceMax (Name: ${nodeName}, Op: ${nodeOp})
BEGIN_SINGLE_CORE
uint32_t outer_base = 0;
uint32_t inner_index = 0;
uint32_t input_base;


for (uint32_t i=0;i<${output_size};i++){
input_base = outer_base + inner_index;
uint32_t input_offset = input_base;


${data_in_type.referencedType.typeName} max_value = ${data_in}[input_offset];



for (uint32_t i_a = 0; i_a < ${d_axes}; i_a++) {
// Max operation :
if (max_value < ${data_in}[input_offset])
max_value = ${data_in}[input_offset];

input_offset += ${inner_size};
}

${data_out}[i] = max_value;

inner_index ++;

if (inner_index >= ${inner_size}) {
inner_index = 0;
outer_base += ${outer_step};
}

}
END_SINGLE_CORE
""")
22 changes: 22 additions & 0 deletions Deeploy/Targets/Generic/Templates/TanhTemplate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright (C) 2026 EPFL.
# Solderpad Hardware License, Version 2.1, see LICENSE.md for details.
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
#
# File: Tanh.py
# Author: Mohammad Hossein Nikkhah
# Description:


from typing import Dict, List, Tuple

from Deeploy.DeeployTypes import NetworkContext, NodeTemplate, OperatorRepresentation


referenceTemplate = NodeTemplate("""
// Tan (Name: ${nodeName}, Op: ${nodeOp})
BEGIN_SINGLE_CORE
for (uint32_t i=0;i<${size};i++){
${data_out}[i] = tanh(${data_in}[i]);
}
END_SINGLE_CORE
""")
62 changes: 62 additions & 0 deletions Deeploy/Targets/Generic/TopologyOptimizationPasses/Passes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1177,3 +1177,65 @@ def __init__(self):

name = "_RECOGNIZE_DEQUANT_PASS"
super().__init__(graph, _recognize_dequant_fun, name)


### EXTRA TOPOLOGY LOWERING PASSES


## TODO: for now only replaces 3 input concat layer with 2-2input concat layers
def _unroll_concat_layer_fun(graph: gs.Graph, match: Match, name: str):
"""
This function only works for concat layers with 3 inputs
"""

matched_nodes = [m for k, m in match.nodes_map.items()]
concat_node = matched_nodes[0]

if len(concat_node.inputs) != 3:
return graph

if 'axis' not in concat_node.attrs:
return graph

axis = concat_node.attrs['axis']
firstInputShape = copy.deepcopy(concat_node.inputs[0].shape)
if firstInputShape is not None:
shapeAxis = axis if axis >= 0 else axis + len(firstInputShape)
firstInputShape[shapeAxis] += concat_node.inputs[1].shape[shapeAxis]

intermediate = gs.Variable(name + '_out_0', dtype = concat_node.outputs[0].dtype, shape = firstInputShape)
originalOutputs = list(concat_node.outputs)

firstConcat = gs.Node(op = 'Concat',
name = name + '_0',
attrs = copy.copy(concat_node.attrs),
inputs = list(concat_node.inputs[:2]),
outputs = [intermediate])
secondConcat = gs.Node(op = 'Concat',
name = name + '_1',
attrs = copy.copy(concat_node.attrs),
inputs = [intermediate, concat_node.inputs[2]],
outputs = originalOutputs)

graph.nodes.append(firstConcat)
graph.nodes.append(secondConcat)

concat_node.inputs.clear()
concat_node.outputs.clear()
graph.cleanup().toposort()

return graph


@contextagnostic
class UnrollConcatPass(ReplaceSequentialPatternPass):

def __init__(self):
graph = gs.Graph()
inputs = [gs.Variable(name = f'input_{i}') for i in range(3)]
concat_output = graph.layer(inputs = inputs, outputs = ['concat_out'], op = 'Concat', name = 'concat')
graph.outputs.append(concat_output)
graph.inputs = inputs

name = "_UNROLL_CONCAT_PASS"
super().__init__(graph, _unroll_concat_layer_fun, name)
Loading