GitHub Viewer
options gen2
module aot_cpp private
require strings
require daslib/match
require daslib/strings_boost
require daslib/ast_boost
require daslib/templates_boost
require daslib/linq_boost
require daslib/ast_print_flags
require daslib/aot_constants
options strict_smart_pointers = false
options unsafe_table_lookup = false
// describeCppTypeEx recurses once per type-nesting level; a deeply nested
// function/lambda/tuple type (the fuzzer's, #3065) overflows the default ~16KB stack.
// This bump only governs when aot_cpp is the ROOT program -- the direct `daslang -aot`
// C++ driver compiles it as root (utils/daslang/main.cpp::aot_compile). The CMake/CI
// driver utils/aot/main.das only REQUIRES this module, so getContextStackSize() reads
// the driver's options there; it carries a matching twin bump. Pathological depths
// still overflow and are caught fail-closed (see fail_on_aot_emit_error).
options stack = 1_048_576
def aotFieldName(name : string) : string {
var result = replace(name, "`", "__");
if (is_cpp_keyword(result) || result == "DELETE") {
result = "_f_" + result;
}
return result;
}
var private g_aot_main_module_name = ""
def public set_aot_main_module_name(name : string) {
//! aotModuleName returns this for the unnamed (promoted) main module; "" (the default) leaves its types in an anonymous namespace.
//! Module-global for the process - set it around one emission and restore "".
//! Forwards to the C++ twin so DebugInfoHelper's cached cpp type names agree.
g_aot_main_module_name = name
set_aot_main_module_name_cpp(name)
}
def aotModuleName(pm : Module?) {
if (pm.name.empty()) {
return g_aot_main_module_name;
} elif (pm.name == "$") {
return "_builtin_";
} else {
return string(pm.name);
}
}
def aotModuleNameFromString(module_name : string) : string {
if (empty(module_name)) {
return g_aot_main_module_name;
} elif (module_name == "$") {
return "_builtin_";
}
return module_name;
}
def isSequencialMask(fields : dasvector`uint8) {
for (i in range(1, length(fields))) {
if (int(fields[i - 1]) + 1 != int(fields[i])) return false;
}
return true;
}
def das_to_cppString(t : Type) { // nolint:STYLE037 - one match arm per Type enum value
match (t) {
if (Type.anyArgument) { return "vec4f"; }
if (Type.tVoid) { return "void"; }
if (Type.tBool) { return "bool"; }
if (Type.tInt8) { return "int8_t"; }
if (Type.tUInt8) { return "uint8_t"; }
if (Type.tInt16) { return "int16_t"; }
if (Type.tUInt16) { return "uint16_t"; }
if (Type.tInt64) { return "int64_t"; }
if (Type.tUInt64) { return "uint64_t"; }
if (Type.tBitfield) { return "Bitfield"; }
if (Type.tBitfield8) { return "Bitfield8"; }
if (Type.tBitfield16) { return "Bitfield16"; }
if (Type.tBitfield64) { return "Bitfield64"; }
if (Type.tString) { return "char *"; }
if (Type.tInt) { return "int32_t"; }
if (Type.tInt2) { return "int2"; }
if (Type.tInt3) { return "int3"; }
if (Type.tInt4) { return "int4"; }
if (Type.tUInt) { return "uint32_t"; }
if (Type.tUInt2) { return "uint2"; }
if (Type.tUInt3) { return "uint3"; }
if (Type.tUInt4) { return "uint4"; }
if (Type.tFloat) { return "float"; }
if (Type.tFloat2) { return "float2"; }
if (Type.tFloat3) { return "float3"; }
if (Type.tFloat4) { return "float4"; }
if (Type.tFloat16) { return "float16_t"; }
if (Type.tHalf2) { return "half2"; }
if (Type.tHalf3) { return "half3"; }
if (Type.tHalf4) { return "half4"; }
if (Type.tHalf8) { return "half8"; }
if (Type.tShort2) { return "short2"; }
if (Type.tShort3) { return "short3"; }
if (Type.tShort4) { return "short4"; }
if (Type.tShort8) { return "short8"; }
if (Type.tUShort2) { return "ushort2"; }
if (Type.tUShort3) { return "ushort3"; }
if (Type.tUShort4) { return "ushort4"; }
if (Type.tUShort8) { return "ushort8"; }
if (Type.tByte2) { return "byte2"; }
if (Type.tByte3) { return "byte3"; }
if (Type.tByte4) { return "byte4"; }
if (Type.tByte8) { return "byte8"; }
if (Type.tByte16) { return "byte16"; }
if (Type.tUByte2) { return "ubyte2"; }
if (Type.tUByte3) { return "ubyte3"; }
if (Type.tUByte4) { return "ubyte4"; }
if (Type.tUByte8) { return "ubyte8"; }
if (Type.tUByte16) { return "ubyte16"; }
if (Type.tDouble) { return "double"; }
if (Type.tRange) { return "range"; }
if (Type.tURange) { return "urange"; }
if (Type.tRange64) { return "range64"; }
if (Type.tURange64) { return "urange64"; }
if (Type.tBlock) { return "Block"; }
if (Type.tFunction) { return "Func"; }
if (Type.tLambda) { return "Lambda"; }
if (Type.tTuple) { return "Tuple"; }
if (Type.tVariant) { return "Variant"; }
}
panic("Missed type {t}")
return ""
}
def das_to_cppCTypeString(t : Type) { // nolint:STYLE037 - one match arm per Type enum value
match (t) {
if (Type.autoinfer) { return "autoinfer"; }
if (Type.alias) { return "alias"; }
if (Type.anyArgument) { return "anyArgument"; }
if (Type.tVoid) { return "tVoid"; }
if (Type.tStructure) { return "tStructure"; }
if (Type.tPointer) { return "tPointer"; }
if (Type.tBool) { return "tBool"; }
if (Type.tInt8) { return "tInt8"; }
if (Type.tUInt8) { return "tUInt8"; }
if (Type.tInt16) { return "tInt16"; }
if (Type.tUInt16) { return "tUInt16"; }
if (Type.tInt64) { return "tInt64"; }
if (Type.tUInt64) { return "tUInt64"; }
if (Type.tString) { return "tString"; }
if (Type.tPointer) { return "tPointer"; }
if (Type.tEnumeration) { return "tEnumeration"; }
if (Type.tEnumeration8) { return "tEnumeration8"; }
if (Type.tEnumeration16) { return "tEnumeration16"; }
if (Type.tEnumeration64) { return "tEnumeration64"; }
if (Type.tBitfield) { return "tBitfield"; }
if (Type.tBitfield8) { return "tBitfield8"; }
if (Type.tBitfield16) { return "tBitfield16"; }
if (Type.tBitfield64) { return "tBitfield64"; }
if (Type.tIterator) { return "tIterator"; }
if (Type.tArray) { return "tArray"; }
if (Type.tTable) { return "tTable"; }
if (Type.tInt) { return "tInt"; }
if (Type.tInt2) { return "tInt2"; }
if (Type.tInt3) { return "tInt3"; }
if (Type.tInt4) { return "tInt4"; }
if (Type.tUInt) { return "tUInt"; }
if (Type.tUInt2) { return "tUInt2"; }
if (Type.tUInt3) { return "tUInt3"; }
if (Type.tUInt4) { return "tUInt4"; }
if (Type.tFloat) { return "tFloat"; }
if (Type.tFloat2) { return "tFloat2"; }
if (Type.tFloat3) { return "tFloat3"; }
if (Type.tFloat4) { return "tFloat4"; }
if (Type.tFloat16) { return "tFloat16"; }
if (Type.tHalf2) { return "tHalf2"; }
if (Type.tHalf3) { return "tHalf3"; }
if (Type.tHalf4) { return "tHalf4"; }
if (Type.tHalf8) { return "tHalf8"; }
if (Type.tShort2) { return "tShort2"; }
if (Type.tShort3) { return "tShort3"; }
if (Type.tShort4) { return "tShort4"; }
if (Type.tShort8) { return "tShort8"; }
if (Type.tUShort2) { return "tUShort2"; }
if (Type.tUShort3) { return "tUShort3"; }
if (Type.tUShort4) { return "tUShort4"; }
if (Type.tUShort8) { return "tUShort8"; }
if (Type.tByte2) { return "tByte2"; }
if (Type.tByte3) { return "tByte3"; }
if (Type.tByte4) { return "tByte4"; }
if (Type.tByte8) { return "tByte8"; }
if (Type.tByte16) { return "tByte16"; }
if (Type.tUByte2) { return "tUByte2"; }
if (Type.tUByte3) { return "tUByte3"; }
if (Type.tUByte4) { return "tUByte4"; }
if (Type.tUByte8) { return "tUByte8"; }
if (Type.tUByte16) { return "tUByte16"; }
if (Type.tDouble) { return "tDouble"; }
if (Type.tRange) { return "tRange"; }
if (Type.tURange) { return "tURange"; }
if (Type.tRange64) { return "tRange64"; }
if (Type.tURange64) { return "tURange64"; }
if (Type.tBlock) { return "tBlock"; }
if (Type.tFunction) { return "tFunction"; }
if (Type.tLambda) { return "tLambda"; }
if (Type.tTuple) { return "tTuple"; }
if (Type.tVariant) { return "tVariant"; }
if (Type.tHandle) { return "tHandle"; }
}
panic("Missed type {t}")
return ""
}
def isConstRedundantForCpp(typeDecl : TypeDeclPtr) {
if (typeDecl.baseType == Type.tFixedArray) return false;
if (typeDecl.isVectorType) return true;
match (typeDecl.baseType) {
if (Type.tBool || Type.tInt8 || Type.tUInt8 || Type.tInt16 || Type.tUInt16 ||
Type.tInt64 || Type.tUInt64 || Type.tInt || Type.tUInt ||
Type.tFloat || Type.tDouble ||
Type.tEnumeration || Type.tEnumeration8 || Type.tEnumeration16 || Type.tEnumeration64 ||
Type.tBitfield || Type.tBitfield8 || Type.tBitfield16 || Type.tBitfield64) {
return true
}
}
return false
}
enum CpptUseAlias {
//! Controls whether type aliases are used in C++ codegen output.
no
yes
};
enum CpptSubstitureRef {
//! Controls whether references are substituted in C++ type printing.
no
yes
};
enum CpptSkipConst {
//! Controls whether const qualifiers are skipped in C++ type printing.
no
yes
};
struct public DescribeConfig {
//! Configuration for C++ type description printing.
substitute_ref : bool = false
skip_ref : bool = false
skip_const : bool = false
redundant_const : bool = true
cross_platform : bool = false
use_smart_ptr : bool = false
}
def hex_char(var Ch : int) {
Ch &= int(0x0f);
if (Ch write_char(ch);
} else {
prefix = true;
var t_ch : string;
match (ch) {
if ('=') { t_ch = "Equ"; }
if ('+') { t_ch = "Add"; }
if ('-') { t_ch = "Sub"; }
if ('*') { t_ch = "Mul"; }
if ('/') { t_ch = "Div"; }
if ('%') { t_ch = "Mod"; }
if ('&') { t_ch = "And"; }
if ('|') { t_ch = "Or"; }
if ('^') { t_ch = "Xor"; }
if ('?') { t_ch = "Qmark"; }
if ('~') { t_ch = "Tilda"; }
if ('!') { t_ch = "Excl"; }
if ('>') { t_ch = "Greater"; }
if (' key_exists(value))
if (success) {
argNamesCache |> insert(value, name)
}
var res_val : string;
info2Name |> insert(name, value)
verify(argNamesCache |> get(value) $(val) {
info2Name |> insert(name, val)
res_val = val
})
return tuple(res_val, success)
}
def get(k : string) : string {
return info2Name.get_value(k);
}
def contains(k : string) : bool {
return argNamesCache |> key_exists(k);
}
def empty() : bool {
return argNamesCache |> empty();
}
def clear() {
argNamesCache |> clear();
info2Name |> clear();
}
}
def private writeAnnotationArgInit(var sb : StringBuilderWriter; arg : AnnotationArgumentInfo) {
if (arg.basicType == Type.tBool) {
write(sb, "AnnotationArgumentInfo(\"{arg.name}\", {arg.bValue})")
} elif (arg.basicType == Type.tString) {
write(sb, "AnnotationArgumentInfo(\"{arg.name}\", \"{escape(arg.sValue)}\")")
} elif (arg.basicType == Type.tInt) {
write(sb, "AnnotationArgumentInfo(\"{arg.name}\", {arg.iValue})")
} elif (arg.basicType == Type.tFloat) {
write(sb, "AnnotationArgumentInfo(\"{arg.name}\", {to_cpp_float(arg.fValue)})")
}
}
def private writeAnnotationList(var writer : StringBuilderWriter?; info; baseName : string) {
if (info.annotation_count == 0u) return ;
for (ai in range(int(info.annotation_count))) {
unsafe {
let ann & = get_annotation(*info, ai)
if (ann.count > 0u) {
let annArgs = build_string() $(var sb) {
for (gi in range(int(ann.count))) {
if (gi != 0) { write(sb, ", "); }
writeAnnotationArgInit(sb, get_annotation_argument(ann, gi))
}
}
write(*writer, "AnnotationArgumentInfo {baseName}_ann_{ai}_args[{int(ann.count)}] = \{ {annArgs} \};\n")
}
}
}
let anns = build_string() $(var sb) {
for (ai in range(int(info.annotation_count))) {
if (ai != 0) { write(sb, ", "); }
unsafe {
let ann & = get_annotation(*info, ai)
let argsRef = ann.count > 0u ? "{baseName}_ann_{ai}_args" : "nullptr"
write(sb, "AnnotationInfo(\"{ann.name}\", \"{ann.module_name}\", {argsRef}, {int(ann.count)}u)")
}
}
}
write(*writer, "AnnotationInfo {baseName}_ann[{int(info.annotation_count)}] = \{ {anns} \};\n")
}
class public AotDebugInfoHelper {
//! Helper for generating debug type and variable information in AOT C++ output.
private info2Name = new DebugVarCache()
private info2TypeName = new DebugVarCache()
private annInfoNames : table
helper : DebugInfoHelper? = new DebugInfoHelper(uninitialized)
cross_platform : bool = false
def operator delete {
unsafe { delete helper; }
}
def writeDim(var writer : StringBuilderWriter?; info : TypeInfo?; suffix : string = "") {
if (info.dimSize > 0u) {
let dims = (each(range(info.dimSize))
._select("{unsafe(info.dim[_]):d}")
.to_array()
._fold()) |> join(", ")
write(*writer, "uint32_t {typeInfoName(info)}_dim{suffix}[{info.dimSize:d}] = \{ {dims} \};\n");
}
}
def writeArgNames(var writer : StringBuilderWriter?; info : TypeInfo?; suffix : string = "") {
if (info.argCount > 0u && info.argNames != null) {
let dims = (each(range(info.argCount))
._select("\"{unsafe(info.argNames[_])}\"")
.to_array()
._fold()) |> join(", ")
let name = "{typeInfoName(info)}_arg_names{suffix}"
let (_, succ) = info2Name.emplace(name, dims)
if (succ) {
write(*writer, "const char * {name}[{info.argCount:d}] = \{ {dims} \};\n");
}
}
}
def writeArgTypes(var writer : StringBuilderWriter?; info : TypeInfo?; suffix : string = "") {
if (info.argCount > 0u && info.argTypes != null) {
let dims = (each(range(info.argCount))
._select("&{typeInfoName(unsafe(info.argTypes[_]))}")
.to_array()
._fold()) |> join(", ")
let name = "{typeInfoName(info)}_arg_types{suffix}"
let (_, succ) = info2TypeName.emplace(name, dims)
if (succ) {
write(*writer, "TypeInfo * {name}[{info.argCount:d}] = \{ {dims} \};\n");
}
}
}
def str() {
return build_string() $(var writer) {
verify(info2Name.empty() && info2TypeName.empty())
helper |> debug_helper_iter_structs($(_name, ti) {
write(writer, "extern StructInfo {structInfoName(ti)};\n");
});
helper |> debug_helper_iter_types($(_name, ti){
write(writer, "extern TypeInfo {typeInfoName(ti)};\n");
})
write(writer, "\n");
writeHandledAnnotations(unsafe(addr(writer)));
helper |> debug_helper_iter_enums($(_name, ti){
describeCppEnumInfoValues(unsafe(addr(writer)), ti);
write(writer, "EnumInfo {enumInfoName(ti)} = \{ {describeCppEnumInfo(ti)} \};\n");
})
helper |> debug_helper_iter_structs($(_name, ti){
describeCppStructInfoFields(unsafe(addr(writer)), ti);
write(writer, "StructInfo {structInfoName(ti)} = \{{describeCppStructInfo(ti)} \};\n");
})
helper |> debug_helper_iter_funcs($(_name, ti){
describeCppFuncInfoFields(unsafe(addr(writer)), ti);
write(writer, "FuncInfo {funcInfoName(ti)} = \{{describeCppFuncInfo(ti)} \};\n");
})
helper |> debug_helper_iter_types($(_name, ti){
assume wr = unsafe(addr(writer))
writeDim(wr, ti);
writeArgTypes(wr, ti);
writeArgNames(wr, ti);
write(writer, "TypeInfo {typeInfoName(ti)} = \{ {describeCppTypeInfo(ti)} \};\n");
})
write(writer, "\n");
write(writer, "static void resolveTypeInfoAnnotations()\n\{\n");
write(writer, " vector annotations = \{")
helper |> debug_helper_iter_types($(_name, ti) {
if (ti._type == Type.tHandle) {
write(writer, "{typeInfoName(ti)}, ");
}
})
write(writer, "\};\n");
write(writer, " for (auto& ann : annotations) \{\n")
write(writer, " ann.resolveAnnotation();\n")
write(writer, " \}\n")
write(writer, "\}\n\n")
info2Name.clear();
info2TypeName.clear();
annInfoNames |> clear()
}
}
def registerHandledAnnotation(var writer : StringBuilderWriter?; info : TypeInfo?) {
if (info._type != Type.tHandle) return ;
let ann = info.annotation
let key = "{ann._module.name}::{ann.name}"
if (annInfoNames |> key_exists(key)) return ;
let ident = "__handled_ann_{length(annInfoNames)}"
annInfoNames[key] = ident
write(*writer, "AnnotationInfo {ident} = \{ \"{ann.name}\", \"{ann._module.name}\", nullptr, 0u \};\n")
}
def writeHandledAnnotations(var writer : StringBuilderWriter?) {
helper |> debug_helper_iter_types($(_name, ti) {
registerHandledAnnotation(writer, ti);
})
helper |> debug_helper_iter_structs($(_name, si) {
if (si.fields == null) return ;
for (fi in range(si.count)) {
registerHandledAnnotation(writer, unsafe(si.fields[fi]));
}
})
helper |> debug_helper_iter_funcs($(_name, fni) {
if (fni.fields == null) return ;
for (fi in range(fni.count)) {
registerHandledAnnotation(writer, unsafe(fni.fields[fi]));
}
})
}
def annInfoRef(info : TypeInfo?) : string {
let ann = info.annotation
return "&" + annInfoNames.get_value("{ann._module.name}::{ann.name}")
}
def writeVarAnnotationArgs(var writer : StringBuilderWriter?; fld : VarInfo?; arrName : string) {
if (fld.annotation_argument_count == 0u) return ;
let annArgs = build_string() $(var sb) {
for (ai in range(int(fld.annotation_argument_count))) {
if (ai != 0) { write(sb, ", "); }
unsafe {
writeAnnotationArgInit(sb, get_annotation_argument(*fld, ai))
}
}
}
write(*writer, "AnnotationArgumentInfo {arrName}[{int(fld.annotation_argument_count)}] = \{ {annArgs} \};\n")
}
def describeCppVarInfo(struct_name : string; info : VarInfo?; suffix : string) {
return build_string() $(writer) {
write(writer, "{describeCppTypeInfo(info, suffix)}, \"{info.name}\", ");
if (cross_platform) {
write(writer, "offsetof({struct_name},{aotFieldName(info.name)}), {info.nextGcField:d}");
} else {
write(writer, "{info.offset:d}, {info.nextGcField:d}")
}
}
}
def describeCppVarFuncInfo(struct_name : string; info : VarInfo?; suffix : string) {
return build_string() $(writer) {
write(writer, "{describeCppTypeInfo(info, suffix)}, \"{info.name}\", ");
assert(info.offset == 0u);
write(writer, "0, {info.nextGcField:d}");
}
}
def describeCppStructInfoFields(var writer : StringBuilderWriter?; info : StructInfo?) {
writeAnnotationList(writer, info, structInfoName(info));
if (info.fields == null) return ;
for (fi in range(info.count)) {
let suffix = "_var_{info.hash:d}";
let fld & = unsafe(info.fields[fi])
writeDim(writer, fld, suffix);
writeArgTypes(writer, fld, suffix);
writeArgNames(writer, fld, suffix);
let ns = aotModuleNameFromString(info.module_name)
let prefix = !empty(ns) ? "{ns}::" : "";
writeVarAnnotationArgs(writer, fld, "{structInfoName(info)}_field_{fi}_ann");
let fldAnnRef = fld.annotation_argument_count > 0u ? ", {structInfoName(info)}_field_{fi}_ann, {int(fld.annotation_argument_count)}u" : ""
let structCppName = aotSuffixNameEx(info.name, "_S",
g_struct_enum_collide |> key_exists(structEnumNsKey(ns, info.name)))
write(*writer, "VarInfo {structInfoName(info)}_field_{fi} = \{ {describeCppVarInfo(prefix + structCppName, fld,suffix)}{fldAnnRef} \};\n");
}
let fields = (each(range(info.count))
._select("&{structInfoName(info)}_field_{_}")
.to_array()
._fold()) |> join(", ")
write(*writer, "VarInfo * {structInfoName(info)}_fields[{info.count:d}] = \{ {fields} \};\n");
}
def describeCppStructInfo(info : StructInfo?) {
return build_string() $(writer) {
write(writer, "\"{info.name}\", \"{info.module_name}\", {int(info.flags):d}, ");
if (info.fields != null) {
write(writer, "{structInfoName(info)}_fields, ")
} else {
write(writer, "nullptr, ")
}
let info_size = cross_platform ? "TypeSize debug_helper_find_struct_cppname(info)}>::size" : "{info.size:d}";
let annRef = info.annotation_count > 0u ? "{structInfoName(info)}_ann" : "nullptr";
write(writer, "{info.count:d}, {info_size}, UINT64_C(0x{info.init_mnh:x}), {annRef}, {int(info.annotation_count)}u, UINT64_C(0x{info.hash:x}), {info.firstGcField:d}")
}
}
def describeCppFuncInfoFields(var writer : StringBuilderWriter?; info : FuncInfo?) {
writeAnnotationList(writer, info, funcInfoName(info));
if (info.fields == null) return ;
for (fi in range(info.count)) {
let suffix = "_var_{info.hash:d}";
let fld & = unsafe(info.fields[fi])
writeDim(writer, fld, suffix);
writeArgTypes(writer, fld, suffix);
writeArgNames(writer, fld, suffix);
writeVarAnnotationArgs(writer, fld, "{funcInfoName(info)}_field_{fi}_ann");
let fldAnnRef = fld.annotation_argument_count > 0u ? ", {funcInfoName(info)}_field_{fi}_ann, {int(fld.annotation_argument_count)}u" : ""
write(*writer, "VarInfo {funcInfoName(info)}_field_{fi} = \{ {describeCppVarFuncInfo(info.name, fld,suffix)}{fldAnnRef} \};\n");
}
let fields = (each(range(info.count))
._select("&{funcInfoName(info)}_field_{_}")
.to_array()
._fold()) |> join(", ")
write(*writer, "VarInfo * {funcInfoName(info)}_fields[{info.count:d}] = \{ {fields} \};\n");
}
def describeCppFuncInfo(info : FuncInfo?) {
return build_string() $(writer) {
write(writer, "\"{info.name}\", \"{info.cppName}\", ");
if (info.fields != null) {
write(writer, "{funcInfoName(info)}_fields, ")
} else {
write(writer, "nullptr, ")
}
write(writer, "{info.count:d}, {info.stackSize:d}, &{typeInfoName(info.result)}, nullptr,0,UINT64_C(0x{info.hash:x}), 0x{info.flags:x}");
if (info.annotation_count > 0u) {
write(writer, ", {funcInfoName(info)}_ann, {int(info.annotation_count)}u");
}
}
}
def describeCppEnumInfoValues(var writer : StringBuilderWriter?; einfo : EnumInfo?) {
for (v in range(einfo.count)) {
let val = unsafe(einfo.fields[v]);
let bits = uint64(val.value)
var cppLit : string
if (bits == 0x8000000000000000ul) {
cppLit = "(-INT64_C(0x7fffffffffffffff) - INT64_C(1))"
} elif (val.value < 0l) {
let absBits = uint64(-val.value)
cppLit = "-INT64_C(0x{absBits:x})"
} else {
cppLit = "INT64_C(0x{bits:x})"
}
write(*writer, "EnumValueInfo {enumInfoName(einfo)}_value_{v} = \{ \"{val.name}\", {cppLit} \};\n")
}
let enum_vals = (each(range(einfo.count))
._select("&{enumInfoName(einfo)}_value_{_}")
.to_array()
._fold()) |> join(", ")
write(*writer, "EnumValueInfo * {enumInfoName(einfo)}_values [] = \{ {enum_vals} \};\n");
writeAnnotationList(writer, einfo, enumInfoName(einfo));
}
def describeCppEnumInfo(info : EnumInfo?) {
let annRef = info.annotation_count > 0u ? ", {enumInfoName(info)}_ann, {int(info.annotation_count)}u" : "";
return "\"{info.name}\", \"{info.module_name}\", {enumInfoName(info)}_values, {info.count:d}, UINT64_C(0x{info.hash:x}), {info.flags:d}{annRef}";
}
def describeCppTypeInfo(info : TypeInfo?; suffix : string = "") {
return build_string() $(writer) {
let write_sep = $ { write(writer, ", "); };
write(writer, "Type::{das_to_cppCTypeString(info._type)}");
write_sep()
if (info._type == Type.tStructure) {
write(writer, "&{structInfoName(info.structType)}");
} else {
write(writer, "nullptr");
}
write_sep();
if (info._type == Type.tEnumeration ||
info._type == Type.tEnumeration8 ||
info._type == Type.tEnumeration16 ||
info._type == Type.tEnumeration64) {
write(writer, "&{enumInfoName(info.enumType)}");
} else {
write(writer, "nullptr");
}
write_sep();
if (info._type == Type.tHandle) {
write(writer, annInfoRef(info));
} else {
write(writer, "nullptr");
}
write_sep();
if (info.firstType != null) {
write(writer, "&{typeInfoName(info.firstType)}");
} else {
write(writer, "nullptr");
}
write_sep();
if (info.secondType != null) {
write(writer, "&{typeInfoName(info.secondType)}");
} else {
write(writer, "nullptr");
}
write_sep();
if (info.argCount > 0u && info.argTypes != null) {
let name = "{typeInfoName(info)}_arg_types{suffix}"
write(writer, "(TypeInfo **){info2TypeName.get(name)}")
} else {
write(writer, "nullptr");
}
write_sep();
if (info.argCount > 0u && info.argNames != null) {
write(writer, info2Name.get("{typeInfoName(info)}_arg_names{suffix}"))
} else {
write(writer, "nullptr");
}
write_sep();
write(writer, "{info.argCount:d}, {info.dimSize:d}");
write_sep();
if (info.dimSize > 0u) {
write(writer, "{typeInfoName(info)}_dim{suffix}");
} else {
write(writer, "nullptr");
}
write_sep();
write(writer, "{unsafe(reinterpret(info.flags))}")
write_sep();
let info_size = cross_platform ? "TypeSize debug_helper_find_type_cppname(info)}>::size" : "{info.size:d}";
write(writer, "{info_size}")
write_sep();
write(writer, "UINT64_C(0x{info.hash:x})");
}
}
};
def public isLocalVec(vtype : TypeDeclPtr) {
//! Returns true if the type is a non-reference vector type.
return vtype.isVectorType && !vtype.flags.ref;
}
def public describeLocalCppType(var writer : StringBuilderWriter?; vtype : TypeDeclPtr; cross_platform : bool; substituteRef : CpptSubstitureRef = CpptSubstitureRef.yes; skipConst : CpptSkipConst = CpptSkipConst.no) {
//! Writes the C++ type representation of a local variable type to a string builder.
let cfg = DescribeConfig(substitute_ref = substituteRef == CpptSubstitureRef.yes,
skip_const = skipConst == CpptSkipConst.yes,
cross_platform = cross_platform)
write(*writer, "{describeCppType(vtype,cfg)}");
}
def describeVarLocalCppType(var writer : StringBuilderWriter?; vtype : TypeDeclPtr; cross_platform : bool; substituteRef : CpptSubstitureRef = CpptSubstitureRef.yes) {
let cfg = DescribeConfig(substitute_ref = substituteRef == CpptSubstitureRef.yes,
skip_const = true,
skip_ref = false,
redundant_const = true,
cross_platform = cross_platform)
if (vtype.isGoodBlockType) {
write(*writer, "auto");
} else {
write(*writer, "{describeCppType(vtype,cfg)}");
}
}
def public aotFuncName(func : Function?) {
//! Returns the AOT C++ function name for a daslang function, including its hash suffix.
if (func.hash != uint64(0)) {
return "{aotSuffixNameEx(func.name,"_Func")}_{func.hash:x}";
} else {
return "{aotSuffixNameEx(func.name,"_Func")}";
}
}
def private isBlockLet(variable : VariablePtr) : bool {
if (!variable._type.isGoodBlockType) {
return false
}
assert(variable.init != null && variable.init is ExprMakeBlock, "block local must be initialized with a make block expression")
return true
}
class public BlockVariableCollector : AstVisitor {
//! AST visitor that collects block-level variable declarations for AOT code generation.
def override preVisitExprBlock(blk : ExprBlock?) {
push(stack, blk as ExprBlock);
}
def getVarName(variable : VariablePtr) {
return rename?[variable] ?? string(variable.name)
}
def isMoved(variable : VariablePtr) {
return moved |> key_exists(variable)
}
def renameVariableTo(variable : VariablePtr; newName : string) {
rename |> insert(variable, newName);
}
def override visitExprBlock(var blk : ExprBlock?) : ExpressionPtr {
stack |> pop();
return blk;
}
def needRenaming(variable : VariablePtr) {
return true;
}
def renameVariable(variable : VariablePtr) {
if (needRenaming(variable)) {
rename |> insert(variable, "__{aotSuffixNameEx(variable.name,"_Var")}_rename_at_{variable.at.line:d}_{(tempCounter++):d}");
}
}
def override preVisitExprForVariable(expr : ExprFor?; variable : VariablePtr; last : bool) {
for (varr in expr.iteratorVariables) {
renameVariable(varr);
}
}
def override preVisitExprBlockArgument(blk : ExprBlock?; variable : VariablePtr; lastArg : bool) {
renameVariable(variable);
}
def override preVisitFunctionArgument(fn : FunctionPtr; variable : VariablePtr; lastArg : bool) {
renameVariable(variable);
}
def getCurrentBlock() {
var blk : ExprBlock? = null;
for (i in range(length(stack))) {
var pb = stack[length(stack) - i - 1];
if (pb.blockFlags.isClosure) {
blk = pb;
break;
}
if (!(pb.blockFlags.inTheLoop && !pb.finalList |> empty())) {
blk = pb;
break;
}
}
return blk;
}
def getFinalBlock() : ExprBlock? {
for (i in range(length(stack))) {
var blk = stack[length(stack) - i - 1];
if (!empty(blk.finalList)) return blk;
if (blk.blockFlags.isClosure) return null;
}
return null;
}
def getTopBlock() : ExprBlock? {
for (i in range(length(stack))) {
var blk = stack[length(stack) - i - 1];
if (blk.blockFlags.isClosure) return blk;
}
return stack[0];
}
def override preVisitExprLetVariable(let_var : ExprLet?; var variable : VariablePtr; last : bool) {
var bfinal = getFinalBlock()
if (bfinal != null) {
if (isBlockLet(variable)) {
blockLets[bfinal] |> push(variable);
}
bfinal = getTopBlock();
variables[bfinal] |> push(variable);
moved |> insert(variable);
}
renameVariable(variable);
}
def handleExpr(var expr : ExprMakeLocal?) {
let need_insert = expectsLocalTemp(expr);
if (need_insert) {
let blk = getCurrentBlock();
localTemps[blk] |> push(expr);
}
}
def override preVisitExprMakeArray(var expr : ExprMakeArray?) {
handleExpr(expr)
}
def override preVisitExprMakeTuple(var expr : ExprMakeTuple?) {
handleExpr(expr)
}
def override preVisitExprMakeStruct(var expr : ExprMakeStruct?) {
handleExpr(expr)
}
def override preVisitExprMakeVariant(var expr : ExprMakeVariant?) {
handleExpr(expr)
}
def override preVisitExprNew(var expr : ExprNew?) {
if (expr.allocate_on_stack) {
let blk = getCurrentBlock();
stackNew[blk] |> push(expr);
}
}
def override preVisitExprAscend(var expr : ExprAscend?) {
if (expr.ascendFlags.allocate_on_stack && !expr.ascendFlags.needTypeInfo) {
let blk = getCurrentBlock();
stackNew[blk] |> push(expr);
}
}
def override preVisitExprCall(var expr : ExprCall?) {
let need_insert = !expr.doesNotNeedSp && expr.stackTop != 0u;
if (need_insert) {
let blk = getCurrentBlock();
localTemps[blk] |> push(expr);
}
}
def override preVisitExprLooksLikeCall(var expr : ExprLooksLikeCall?) {
if (expr is ExprInvoke) {
let inv = expr as ExprInvoke;
let need_insert = !inv.doesNotNeedSp && inv.stackTop != 0u;
if (need_insert) {
let blk = getCurrentBlock();
localTemps[blk] |> push(expr);
}
}
}
@do_not_delete stack : array
@do_not_delete variables : table
@do_not_delete blockLets : table
@do_not_delete localTemps : table
@do_not_delete stackNew : table
rename : table
moved : table
tempCounter : uint64 = uint64(0)
};
def public describeCppFunc(fn : FunctionPtr; var collector : BlockVariableCollector?; cross_platform : bool; needName : bool = true; needInline : bool = true) {
//! Returns the C++ function signature string for an AOT-compiled function.
return build_string() $(writer) {
if (needInline) {
write(writer, "inline ");
}
describeLocalCppType(unsafe(addr(writer)), fn.result,
cross_platform, CpptSubstitureRef.no, CpptSkipConst.yes);
write(writer, " {needName ? aotFuncName(fn) : "(*)"}");
let prefix = fn.arguments |> empty() ? "" : ", "
let args_str = (each(fn.arguments)
._select(build_string() $(writer2) {
if (isLocalVec(_._type)) {
describeLocalCppType(unsafe(addr(writer2)), _._type, cross_platform);
} else {
write(writer2, "{describeCppType(_._type, DescribeConfig(cross_platform=cross_platform))}");
}
write(writer2, " {(_._type.isRefType) ? "& " : ""}");
if (collector != null) {
write(writer2, "{collector.getVarName(_)}");
}
})
.to_array()
._fold()) |> join(", ")
write(writer, " ( Context * __context__{prefix}{args_str} )");
}
}
class public CppAot : AstVisitor {
//! Main AST visitor that generates C++ ahead-of-time compiled code from daslang AST.
adapter : VisitorAdapter?
def str() {
let maybe_nl = type_info |> empty() ? "" : "\n";
return "\n" + declarations + helper.str() + join(type_info, "\n") + "{maybe_nl}" + join(aot_prefixes, "") + ss |> string_builder_str();
}
def clear() {
ss |> string_builder_clear();
type_info |> clear();
aot_prefixes |> clear();
cachedTi.clear();
}
ss : StringBuilderWriter ?;
declarations : string
type_info : array;
aot_prefixes : array;
lastNewLine : uint64 = -1ul;
tab : int = 0;
debugInfoGlobal : int = 0;
helper : AotDebugInfoHelper ? = new AotDebugInfoHelper();
program : ProgramPtr;
@do_not_delete collector : BlockVariableCollector ? = new BlockVariableCollector();
aotPrefix : table;
@do_not_delete local_temp_names : table;
@do_not_delete scopes : array;
prologue : bool = false;
solidContext : bool = false;
cross_platform : bool = false;
fastMath : bool = false;
aot_filter_function : string;
cachedTi = new DebugVarCache()
def newLine() {
write(*ss, "\n");
}
def tabs() {
return build_string() $(writer) { write_chars(writer, ' ', 4 * tab); }
}
def noBracket(expr : ExpressionPtr) {
return expr.printFlags.topLevel || expr.printFlags.bottomLevel || expr.printFlags.argLevel;
}
def override preVisitEnumeration(enu : EnumerationPtr) {
if (enu.external) {
write(*ss, "#if 0 // external enum\n");
}
write(*ss, "namespace {aotModuleName(enu._module)} \{\n\n");
write(*ss, "enum class {aotEnumName(enu)} : {das_to_cppString(enu.baseType)} \{\n");
}
def override preVisitEnumerationValue(enu : EnumerationPtr; name : das_string; value : ExpressionPtr; last : bool) {
write(*ss, " {aotEnumValueName(name)} = {das_to_cppString(enu.baseType)}(");
}
def override visitEnumerationValue(enu : EnumerationPtr; name : das_string; value : ExpressionPtr; last : bool) {
write(*ss, ")");
if (!last) { write(*ss, ","); };
write(*ss, "\n");
return value;
}
def override visitEnumeration(enu : EnumerationPtr) {
write(*ss, "};\n")
write(*ss, "}\n")
if (enu.external) {
write(*ss, "#endif // external enum\n");
} else {
}
return enu;
}
def override canVisitStructureFieldInit(st : StructurePtr) : bool {
return false;
}
def override canVisitStructure(st : Structure?) {
return !st.flags.isTemplate;
}
def override preVisitStructure(that : StructurePtr) {
if (that.flags.cppLayout) {
write(*ss, "\n#if 0 // skipping structure {that.name} declaration due to CPP layout");
}
write(*ss, "namespace {aotModuleName(that._module)} \{\n");
for (ann in that.annotations) {
if (ann.annotation is StructureAnnotation) {
get_struct_aot_prefix(ann.annotation as StructureAnnotation, that, ann.arguments, ss);
}
}
write(*ss, "\nstruct {aotStructName(that)}");
if (that.flags.cppLayout && that.parent != null) {
write(*ss, " : {aotStructName(that.parent)}");
}
write(*ss, " \{\n");
for (ann in that.annotations) {
if (ann.annotation is StructureAnnotation) {
write_aot_body(ann.annotation as StructureAnnotation, that, ann.arguments, ss);
}
}
}
def override preVisitStructureField(that : StructurePtr; decl : FieldDeclaration; last : bool) {
let from = find_struct_field_parent(that, string(decl.name));
if (that.flags.cppLayout && from != unsafe(reinterpret(that))) {
write(*ss, " /* skipping {decl.name}, from {from.name} */");
} else {
write(*ss, " {describeCppType(decl._type, DescribeConfig(cross_platform=cross_platform,skip_const = true))} {aotFieldName(string(decl.name))};");
if (decl.flags.parentType) {
write(*ss, " /* from {from.name} */");
}
}
}
def override visitStructureField(variable : StructurePtr; decl : FieldDeclaration; last : bool) {
write(*ss, "\n");
}
def override visitStructure(that : StructurePtr) {
write(*ss, "};\n");
if (!cross_platform && !that.fields |> empty()) {
let s_name = aotStructName(that)
write(*ss, "static_assert(sizeof({s_name})=={that.sizeOf},\"structure size mismatch with DAS\");\n");
for (tf in that.fields) {
write(*ss, "static_assert(offsetof({s_name},{aotFieldName(string(tf.name))})=={tf.offset},\"structure field offset mismatch with DAS\");\n");
}
}
for (ann in that.annotations) {
if (ann.annotation is StructureAnnotation) {
write_aot_suffix(ann.annotation as StructureAnnotation, that, ann.arguments, ss);
}
}
write(*ss, "}\n");
if (that.flags.cppLayout) {
write(*ss, "#endif // end of skipping structure {that.name} declaration due to CPP layout\n");
}
return that;
}
def override preVisitProgramBody(prog : ProgramPtr; mod : Module?) {
declarations = ss |> string_builder_str();
ss |> string_builder_clear();
write(*ss, "\n");
prog.getThisModule |> for_each_module_function($(var fn : FunctionPtr) {
if (!fn.flags.builtIn && !fn.flags.noAot && !fn.moreFlags.isTemplate) {
write(*ss, "{describeCppFunc(fn,collector,cross_platform)};\n");
}
});
write(*ss, "\n");
}
def write_local_temp_type(tmp : Expression?) : void {
write(*ss, tabs())
describeVarLocalCppType(ss, tmp._type, cross_platform)
}
def override preVisitGlobalLet(prog : ProgramPtr) {
write(*ss, "void __init_script ( Context * __context__, bool __init_shared )\n\{\n");
tab ++;
assume temps = collector.localTemps[null];
for (tmp in temps) {
write_local_temp_type(tmp)
write(*ss, " {makeLocalTempName(tmp)};\n");
}
}
def override visitGlobalLet(prog : ProgramPtr) {
tab --;
write(*ss, "}\n");
}
def override preVisitGlobalLetVariable(variable : Variable?; lastArg : bool) {
write(*ss, tabs());
if (!variable.flags.used) {
write(*ss, "/* ");
}
if (variable.flags.global_shared) {
write(*ss, "if ( __init_shared ) ");
}
write(*ss, "{variable.flags.global_shared ? "das_shared" : "das_global"}{variable.init != null ? "" : "_zero"}");
if (solidContext) {
write(*ss, "_solid");
}
let hash_val = solidContext ? "{variable.stackTop:d}" : "0x{variable.getMangledNameHash:x}";
let cfg = DescribeConfig(skip_ref = true, skip_const = true, redundant_const = true, cross_platform = cross_platform);
write(*ss, "(__context__)");
}
def override visitGlobalLetVariable(variable : VariablePtr; last : bool) {
write(*ss, ";");
if (!variable.flags.used) {
write(*ss, " */");
}
write(*ss, "/*{variable.name}*/\n");
return variable;
}
def override preVisitGlobalLetVariableInit(variable : VariablePtr; init : ExpressionPtr) {
write(*ss, " = ");
}
def override canVisitFunction(fun : Function?) {
if (fun.flags.noAot) return false;
return !fun.moreFlags.isTemplate;
}
def override preVisitFunction(fn : FunctionPtr) {
if (!empty(aot_filter_function) && (fn.name == aot_filter_function || aotFuncName(fn) == aot_filter_function)) {
write(*ss, "\n/**/");
}
if (fastMath) {
write(*ss, "\nDAS_FAST_MATH_PUSH");
}
write(*ss, "\ninline ");
describeLocalCppType(ss, fn.result, cross_platform, CpptSubstitureRef.no, CpptSkipConst.yes);
write(*ss, " {aotFuncName(fn)} ( Context * __context__");
}
def override preVisitFunctionBody(fn : FunctionPtr; expr : ExpressionPtr) {
if (fn.flags.aotNeedPrologue || prologue) {
write(*ss, " ) \{ das_stack_prologue __prologue(__context__,{fn.totalStackSize:d},\"{fn.name} \" DAS_FILE_LINE);\n");
} elif (!(expr is ExprBlock)) {
write(*ss, " ) \{\n");
tab ++;
write(*ss, tabs());
} else {
write(*ss, " )\n");
}
}
def override preVisitFunctionArgument(fn : FunctionPtr; arg : VariablePtr; last : bool) {
write(*ss, ", ");
if (isLocalVec(arg._type)) {
describeLocalCppType(ss, arg._type, cross_platform);
} else {
write(*ss, describeCppType(arg._type, DescribeConfig(cross_platform = cross_platform)))
}
if (arg._type.isRefType) {
write(*ss, " & ");
}
write(*ss, " {collector.getVarName(arg)}");
}
def override canVisitFunctionArgumentInit(fn : Function?; variable : VariablePtr; expr : ExpressionPtr) {
return false;
}
def override preVisitFunctionArgumentInit(fn : FunctionPtr; arg : VariablePtr; expr : ExpressionPtr) {
write(*ss, " = ");
}
def override visitFunctionArgument(fn : FunctionPtr; that : VariablePtr; last : bool) {
return that;
}
def override visitFunction(fn : FunctionPtr) {
if (fn.flags.aotNeedPrologue || prologue) {
write(*ss, "}\n");
} elif (fn.body != null && !(fn.body is ExprBlock)) {
write(*ss, ";\n");
tab --;
write(*ss, "}\n");
} else {
write(*ss, "\n");
}
if (fastMath) {
write(*ss, "DAS_FAST_MATH_POP\n");
}
if (!empty(aot_filter_function) && (fn.name == aot_filter_function || aotFuncName(fn) == aot_filter_function)) {
write(*ss, "/**/\n");
}
return fn;
}
def makeLocalTempName(expr : ExpressionPtr) {
if (!local_temp_names |> key_exists(expr)) {
local_temp_names |> insert(expr, local_temp_names |> length());
}
if (expr is ExprMakeLocal ||
expr is ExprMakeStruct ||
expr is ExprMakeVariant ||
expr is ExprMakeArray ||
expr is ExprMakeTuple ||
expr is ExprCall ||
expr is ExprInvoke) {
} else {
panic("we should not be here. we need stacktop for the name");
}
return "_temp_make_local_{expr.at.line:d}_{expr.at.column:d}_{local_temp_names |> get_value(expr):d}";
}
def override preVisitExprBlock(var blk : ExprBlock?) {
push(scopes, blk);
blk.blockFlags.finallyBeforeBody = true;
write(*ss, "\{\n");
tab ++;
assume vars = collector.variables[blk];
for (variable in vars) {
continue if (isBlockLet(variable))
write(*ss, "{tabs()}");
describeVarLocalCppType(ss, variable._type, cross_platform);
let varname = collector.getVarName(variable);
var vname = varname
let constRef = (variable._type.flags.constant &&
variable._type.isRefType &&
!variable._type.flags.ref)
if (constRef) {
vname += "_ConstRef";
}
write(*ss, " {vname}; memset((void*)&{vname},0,sizeof({vname}));\n");
if (constRef) {
write(*ss, tabs());
describeLocalCppType(ss, variable._type, cross_platform);
write(*ss, " & {varname} = {vname};\n");
}
}
collector.localTemps.get(blk) $(temps) {
for (tmp in temps) {
write_local_temp_type(tmp)
let tempName = makeLocalTempName(tmp);
write(*ss, " {tempName}; {tempName};\n");
}
}
collector.stackNew.get(blk) $(news) {
for (nw in news) {
let nm = stackNewName(nw);
write(*ss, "{tabs()}{stackNewPointeeType(nw, cross_platform)} {nm}; {nm};\n");
}
}
collector.blockLets.get(blk) $(blets) {
for (variable in blets) {
emitBlockLet(variable);
}
}
}
def emitBlockLet(var variable : VariablePtr) {
let varname = collector.getVarName(variable);
let constRef = (variable._type.flags.constant &&
variable._type.isRefType &&
!variable._type.flags.ref)
let cvname = constRef ? varname + "_ConstRef" : varname;
var mkb = variable.init as ExprMakeBlock;
var mblk = mkb._block as ExprBlock;
mblk.blockFlags.aotSkipMakeBlock = true;
write(*ss, "{tabs()}auto {cvname}_TempFunctor = ");
visit_expression(variable.init, adapter);
write(*ss, ";\n{tabs()}");
mblk.blockFlags.aotSkipMakeBlock = false;
mkb.aotFunctorName := cvname + "_TempFunctor";
write(*ss, "auto {cvname} = ");
visit_expression(variable.init, adapter);
write(*ss, ";\n");
if (constRef) {
write(*ss, tabs());
describeLocalCppType(ss, variable._type, cross_platform);
write(*ss, " & {varname} = {cvname};\n");
}
mkb.aotFunctorName := cvname;
mblk.blockFlags.aotSkipMakeBlock = true;
}
def override preVisitExprBlockArgumentInit(blk : ExprBlock?; variable : VariablePtr; init : ExpressionPtr) {
write(*ss, "\n#if 0\n");
}
def override visitExprBlockArgumentInit(blk : ExprBlock?; variable : VariablePtr; init : ExpressionPtr) {
write(*ss, "\n#endif\n");
return init;
}
def override preVisitExprBlockExpression(blk : ExprBlock?; expr : ExpressionPtr) {
write(*ss, tabs());
}
def override visitExprBlockExpression(blk : ExprBlock?; that : ExpressionPtr) {
write(*ss, ";")
newLine();
return that;
}
def override visitExprBlock(var blk : ExprBlock?) : ExpressionPtr {
tab --;
write(*ss, "{tabs()}\}")
blk.blockFlags.finallyBeforeBody = false
blk.blockFlags.finallyDisabled = false
scopes |> pop();
return blk;
}
def finallyName(blk : ExprBlock?) {
return "__finally_{blk.at.line:d}";
}
def override preVisitExprBlockFinal(blk : ExprBlock?) {
write(*ss, "{tabs()}/* finally */ auto {finallyName(blk)}= das_finally([&]()\{\n");
}
def override preVisitExprBlockFinalExpression(blk : ExprBlock?; expr : ExpressionPtr) {
write(*ss, "{tabs()}");
}
def override visitExprBlockFinalExpression(blk : ExprBlock?; that : ExpressionPtr) {
write(*ss, ";");
newLine();
return that;
}
def override visitExprBlockFinal(blk : ExprBlock?) {
write(*ss, "{tabs()}/* end finally */ \});\n");
}
def override preVisitExprLetVariable(let_ : ExprLet?; var variable : VariablePtr; last : bool) {
if (isBlockLet(variable)) {
if (!collector.isMoved(variable)) {
emitBlockLet(variable);
write(*ss, tabs());
}
return
}
let vname = collector.getVarName(variable);
if (!collector.isMoved(variable)) {
describeVarLocalCppType(ss, variable._type, cross_platform);
write(*ss, " ");
}
var cvname = vname;
if (variable._type.flags.constant && variable._type.isRefType && !variable._type.flags.ref) {
cvname += "_ConstRef";
}
if (variable.init != null) {
write(*ss, cvname);
} elif (variable._type.canInitWithZero) {
var init_val = isLocalVec(variable._type) ? "v_zero()" : "0";
if (variable._type.baseType == Type.tFloat16) {
init_val = "float16_t(0.f)";
}
write(*ss, "{cvname} = {init_val}");
} else {
if (!collector.isMoved(variable)) {
write(*ss, "{cvname};");
}
write(*ss, "das_zero({cvname})");
}
}
def override visitExprLetVariable(let_ : ExprLet?; variable : VariablePtr; last : bool) {
if (!last) write(*ss, "; ");
if (!collector.isMoved(variable) && !isBlockLet(variable)) {
if (variable._type.flags.constant && variable._type.isRefType && !variable._type.flags.ref) {
let vname = collector.getVarName(variable);
write(*ss, ";\n{tabs()}");
describeLocalCppType(ss, variable._type, cross_platform);
write(*ss, " & {vname} = {vname}_ConstRef;\n");
}
}
if (variable.init != null && variable.init is ExprMakeBlock) {
var mkb = variable.init as ExprMakeBlock;
mkb.aotFunctorName := ""
(mkb._block as ExprBlock).blockFlags.aotSkipMakeBlock = false;
}
return variable;
}
def override preVisitExprLetVariableInit(let_ : ExprLet?; variable : VariablePtr; expr : ExpressionPtr) {
return if (isBlockLet(variable))
if (variable.flags.init_via_move && variable.init is ExprMakeBlock) {
write(*ss, " = ");
} elif (variable.flags.init_via_move) {
let vname = collector.getVarName(variable);
var cvname = vname;
if (variable._type.flags.constant && variable._type.isRefType && !variable._type.flags.ref) {
cvname += "_ConstRef";
}
write(*ss, "; das_zero({cvname}); das_move({cvname}, ");
} else {
write(*ss, " = ");
}
if (variable._type.flags.constant) {
if (!variable._type.isGoodBlockType) {
write(*ss, "((");
describeVarLocalCppType(ss, variable._type, cross_platform);
write(*ss, ")");
} else {
write(*ss, "(");
}
}
if (!expr._type.isPointer && !variable._type.flags.ref && expr._type.isAotAlias && !variable._type.isAotAlias) {
if (expr._type.alias.empty()) {
let cfg = DescribeConfig(skip_ref = true, redundant_const = true, cross_platform = cross_platform)
let type_str = describeCppTypeEx(expr._type, cfg, CpptUseAlias.yes);
write(*ss, "das_reinterpret::pass(")
} else {
write(*ss, "das_alias::from(");
}
}
if (variable._type.flags.ref) {
write(*ss, "&(");
}
if (needPtrCast(variable._type, expr._type, expr)) {
write(*ss, "das_auto_cast::cast(");
} elif (variable._type.isPointer && expr._type.isPointer
&& variable._type.firstType != null && expr._type.firstType != null
&& !is_same_type(variable._type.firstType, expr._type.firstType, false, false, false, false)) {
write(*ss, "das_auto_cast::cast(");
}
if (expr._type.isString) {
let maybeRef = variable._type.flags.ref ? " &" : "";
write(*ss, "(char *{maybeRef})(");
}
}
def override visitExprLetVariableInit(let_ : ExprLet?; variable : VariablePtr; expr : ExpressionPtr) {
return expr if (isBlockLet(variable))
if (expr._type.isString) {
write(*ss, ")");
}
if (needPtrCast(variable._type, expr._type, expr)) {
write(*ss, ")");
} elif (variable._type.isPointer && expr._type.isPointer
&& variable._type.firstType != null && expr._type.firstType != null
&& !is_same_type(variable._type.firstType, expr._type.firstType, false, false, false, false)) {
write(*ss, ")");
}
if (variable._type.flags.ref) {
write(*ss, ")");
}
if (!expr._type.isPointer && !variable._type.flags.ref && expr._type.isAotAlias && !variable._type.isAotAlias) {
write(*ss, ")");
}
if (variable.flags.init_via_move && !(variable.init is ExprMakeBlock)) {
write(*ss, ")");
}
if (variable._type.flags.constant) {
write(*ss, ")");
}
return expr;
}
def override preVisitExprLabel(that : ExprLabel?) {
write(*ss, "label_{that.labelName}:;");
}
def override preVisitExprGoto(that : ExprGoto?) {
if (that.subexpr == null) {
write(*ss, "goto label_{that.labelName}");
} else {
write(*ss, "switch (");
}
}
def override visitExprGoto(var that : ExprGoto?) : ExpressionPtr {
if (that.subexpr != null) {
write(*ss, ") \{\n");
scopes |> reverse();
for (blk in scopes) {
for (ex in blk.list) {
if (ex is ExprLabel) {
let lab = ex as ExprLabel;
write(*ss, "{tabs()}case {lab.labelName}: goto label_{lab.labelName};\n");
}
}
}
scopes |> reverse();
write(*ss, "{tabs()}default: __context__->throw_error(\"invalid label\");\n");
write(*ss, "{tabs()}\}");
}
return that;
}
def override preVisitExprCopy(that : ExprCopy?) {
write(*ss, "das_copy(");
}
def override preVisitExprCopyRight(that : ExprCopy?; right : ExpressionPtr) {
write(*ss, ",");
}
def override visitExprCopy(var that : ExprCopy?) : ExpressionPtr {
write(*ss, ")");
return that;
}
def override preVisitExprClone(that : ExprClone?) {
let cfg = DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform)
let cfg2 := cfg
let left_t = describeCppType(that.left._type, cfg);
let right_t = describeCppType(that.right._type, cfg2);
write(*ss, "das_clone::clone(");
}
def override preVisitExprCloneRight(that : ExprClone?; right : ExpressionPtr) {
write(*ss, ",");
}
def override visitExprClone(var that : ExprClone?) : ExpressionPtr {
write(*ss, ")");
return that;
}
def override preVisitExprMove(that : ExprMove?) {
write(*ss, "das_move(");
}
def override preVisitExprMoveRight(that : ExprMove?; right : ExpressionPtr) {
write(*ss, ",");
}
def override visitExprMove(var that : ExprMove?) : ExpressionPtr {
write(*ss, ")");
return that;
}
def override visitExprQuote(var that : ExprQuote?) : ExpressionPtr {
write(*ss, "\n#error quote( ) was not lowered (daslib/quote) at {describe(that.at)}\n")
return that;
}
def outPolicy(decl : TypeDeclPtr) {
if (decl.baseType != Type.tHandle){
write(*ss, "SimPolicy");
} else {
write(*ss, "SimPolicy");
}
}
def isOpPolicy1(that : ExprOp1?) {
if (is_alpha(first_character(that.op))) return true;
return that.subexpr._type.isPolicyType;
}
def isF16Op1(that : ExprOp1?) {
return that._type.baseType == Type.tFloat16 || (that._type.isVectorType && that._type.vectorBaseType == Type.tFloat16);
}
def override preVisitExprOp1(var that : ExprOp1?) {
if (!that.func.flags.builtIn || that.func.flags.callBased) {
that.arguments |> clear();
var subexpr := that.subexpr
that.arguments |> emplace(subexpr);
CallFunc_preVisit(that);
CallFunc_preVisitCallArg(that, that.subexpr, true);
} elif (isOpPolicy1(that)) {
if (isF16Op1(that)) {
let cfg = DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform)
write(*ss, "cast::to(");
}
outPolicy(that.subexpr._type);
write(*ss, "::{opPolicyName(that)}(");
if (that.subexpr._type.baseType == Type.tFloat16) {
write(*ss, "cast::from(");
}
} else {
if (that.op != "+++" && that.op != "---") {
write(*ss, that.op);
}
if (!noBracket(that) && !that.subexpr.printFlags.bottomLevel) {
write(*ss, "(");
}
}
}
def override visitExprOp1(var that : ExprOp1?) : ExpressionPtr {
if (!that.func.flags.builtIn || that.func.flags.callBased) {
CallFunc_visitCallArg(that, that.subexpr, true);
CallFunc_visit(that);
that.arguments.clear();
} elif (isOpPolicy1(that)) {
if (that.subexpr._type.baseType == Type.tFloat16) {
write(*ss, ")");
}
write(*ss, ",*__context__,nullptr)");
if (isF16Op1(that)) {
write(*ss, ")");
}
} else {
if (that.op == "+++" || that.op == "---") {
peek(that.op) $(op) {
write(*ss, slice(op, 0, 2));
}
}
if (!noBracket(that) && !that.subexpr.printFlags.bottomLevel) {
write(*ss, ")");
}
}
return that;
}
def isSetBool(that : ExprOp2?) {
return ((that.op == "||=" || that.op == "&&=" || that.op == "^^=") &&
that.right._type.baseType == Type.tBool && that.right._type.isSimpleType);
}
def isOpPolicy2(that : ExprOp2?) {
if (is_alpha(first_character(that.op))
|| that.op == "/" || that.op == "%"
|| that.op == "" || that.op == "="
|| that.op == "" || that.op == "=") return true;
return that._type.isPolicyType || that.left._type.isPolicyType || that.right._type.isPolicyType;
}
def opPolicyBase(that : ExprOp2?) {
if (that._type.isPolicyType) {
return that._type;
} elif (that.left._type.isPolicyType) {
return that.left._type;
} else {
return that.right._type;
}
}
def opPolicyName(that : ExprOp?) {
assume fn = (unsafe(reinterpret(that))).func;
if (fn.flags.builtIn) {
let bfn = fn as BuiltInFunction;
return string(bfn.cppName.empty() ? bfn.name : bfn.cppName);
} else {
return "/* NotAPolicy */";
}
}
def isRefPolicyOp(th : ExprOp2?) {
let op = string(th.op);
return ["+=", "-=", "*=", "/=", "%=",
"&=", "|=", "^=",
"&&=", "||=", "^^=",
"=", "="
]._any(_ == op)
}
def needsOrderedOperands(that : ExprOp2?) {
if ((that.left.flags.noSideEffects && that.right.flags.noSideEffects)
|| !that.func.flags.builtIn || that.func.flags.callBased
|| isRefPolicyOp(that) || isShortCircuitBoolOp(that)) return false;
if (isOpPolicy2(that)) {
assume pt = opPolicyBase(that);
if (policyRefArg(pt, that.left._type) || policyRefArg(pt, that.right._type)) return false;
}
return true;
}
def isShortCircuitBoolOp(that : ExprOp2?) {
if (isOpPolicy2(that) || that._type.baseType != Type.tBool) return false;
let op = string(that.op);
return op == "&&" || op == "||";
}
def policyRefArg(pt, argType : TypeDeclPtr) {
return policyArgNeedCast(pt, argType) && argType.isRefType;
}
def plainOp2Text(that : ExprOp2?) : string {
if (that._type.baseType == Type.tBool) {
let that_op = string(that.op)
match (that_op) {
if ("&") { return "&&"; }
if ("|") { return "||"; }
if ("^" || "^^") { return "!="; }
}
}
return string(that.op);
}
def writeOrderedPolicyArg(pt, argType : TypeDeclPtr; argExpr : string) {
if (policyArgNeedCast(pt, argType)) {
let cfg = DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform)
let type_str = describeCppType(argType, cfg);
write(*ss, "cast::from({argExpr})");
} else {
write(*ss, argExpr);
}
}
def override preVisitExprOp2(var that : ExprOp2?) {
if (!noBracket(that)) write(*ss, "(");
if (needsOrderedOperands(that)) {
write(*ss, "[&](auto && __lr) \{ return ");
if (isOpPolicy2(that)) {
assume pt = opPolicyBase(that);
if (policyResultNeedCast(pt, that._type)) {
let cfg = DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform)
let type_str = describeCppType(that._type, cfg);
write(*ss, "cast::to(");
}
outPolicy(pt);
write(*ss, "::{opPolicyName(that)}(");
writeOrderedPolicyArg(pt, that.left._type, "__lr.left");
write(*ss, ",");
writeOrderedPolicyArg(pt, that.right._type, "__lr.right");
write(*ss, ",*__context__,nullptr)");
if (policyResultNeedCast(pt, that._type)) {
write(*ss, ")");
}
} else {
write(*ss, "(__lr.left {plainOp2Text(that)} __lr.right)");
}
write(*ss, "; \}(das_ordered2\{ ");
return ;
}
if (!that.func.flags.builtIn || that.func.flags.callBased) {
that.arguments |> clear();
var left := that.left;
var right := that.right;
that.arguments |> emplace(left);
that.arguments |> emplace(right);
CallFunc_preVisit(that);
CallFunc_preVisitCallArg(that, that.left, false);
} elif (isOpPolicy2(that)) {
assume pt = opPolicyBase(that);
if (policyResultNeedCast(pt, that._type)) {
let cfg = DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform)
let type_str = describeCppType(that._type, cfg);
write(*ss, "cast::to(");
}
outPolicy(pt);
write(*ss, "::{opPolicyName(that)}(");
if (isRefPolicyOp(that) && (pt.isVectorType || pt.isString || pt.baseType == Type.tFloat16)) {
write(*ss, "(char *)&(");
} elif (policyArgNeedCast(pt, that.left._type)) {
let cfg = DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform)
let type_str = describeCppType(that.left._type, cfg);
if (that.left._type.isRefType) {
write(*ss, "cast::from(&(");
} else {
write(*ss, "cast::from(");
}
}
} elif (isSetBool(that)) {
if (that.op == "||=") {
write(*ss, "DAS_SETBOOLOR((");
} elif (that.op == "&&=") {
write(*ss, "DAS_SETBOOLAND((");
} elif (that.op == "^^=") {
write(*ss, "DAS_SETBOOLXOR((");
}
}
}
def override preVisitExprOp2Right(that : ExprOp2?; right : ExpressionPtr) {
if (needsOrderedOperands(that)) {
write(*ss, ", ");
return ;
}
if (!that.func.flags.builtIn || that.func.flags.callBased) {
CallFunc_visitCallArg(that, that.left, false);
CallFunc_preVisitCallArg(that, that.right, true);
} elif (isOpPolicy2(that)) {
assume pt = opPolicyBase(that);
if (isRefPolicyOp(that) && (pt.isVectorType || pt.isString || pt.baseType == Type.tFloat16)) {
write(*ss, ")");
} elif (policyArgNeedCast(pt, that.left._type)) {
if (that.left._type.isRefType) {
write(*ss, "))");
} else {
write(*ss, ")");
}
}
write(*ss, ",");
if (policyArgNeedCast(pt, that.right._type)) {
let cfg = DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform)
let right_type = describeCppType(that.right._type, cfg);
if (that.right._type.isRefType) {
write(*ss, "cast::from(&(");
} else {
write(*ss, "cast::from(");
}
}
} elif (isSetBool(that)) {
write(*ss, "),(");
} else {
write(*ss, " {plainOp2Text(that)} ");
}
}
def override visitExprOp2(var that : ExprOp2?) : ExpressionPtr {
if (needsOrderedOperands(that)) {
write(*ss, " \})");
if (!noBracket(that)) {
write(*ss, ")");
}
return that;
}
if (!that.func.flags.builtIn || that.func.flags.callBased) {
CallFunc_visitCallArg(that, that.right, true);
CallFunc_visit(that);
} elif (isOpPolicy2(that)) {
assume pt = opPolicyBase(that);
if (policyArgNeedCast(pt, that.right._type)) {
if (that.right._type.isRefType) {
write(*ss, "))");
} else {
write(*ss, ")");
}
}
write(*ss, ",*__context__,nullptr)");
if (policyResultNeedCast(pt, that._type)) {
write(*ss, ")");
}
} elif (isSetBool(that)) {
write(*ss, "))");
}
if (!noBracket(that)) {
write(*ss, ")");
}
return that;
}
def override preVisitExprOp3(that : ExprOp3?) {
if (!noBracket(that)) {
write(*ss, "(");
}
}
def override preVisitExprOp3Left(that : ExprOp3?; left : ExpressionPtr) {
write(*ss, " ? ");
assume argT = left._type;
if (isLocalVec(argT)) {
write(*ss, "(vec4f)");
}
if (that._type.isRef) {
write(*ss, "das_auto_cast_ref");
} else {
write(*ss, "das_auto_cast");
}
write(*ss, "::cast(");
}
def override preVisitExprOp3Right(that : ExprOp3?; right : ExpressionPtr) {
write(*ss, ") : ");
if (isLocalVec(right._type)) {
write(*ss, "(vec4f)");
}
if (that._type.isRef) {
write(*ss, "das_auto_cast_ref");
} else {
write(*ss, "das_auto_cast");
}
write(*ss, "::cast(");
}
def override visitExprOp3(var that : ExprOp3?) : ExpressionPtr {
write(*ss, ")");
if (!noBracket(that)) {
write(*ss, ")");
}
return that;
}
def override preVisitExprReturn(expr : ExprReturn?) {
write(*ss, "return ");
if (expr.returnFlags.moveSemantics) {
write(*ss, "/* ::get(");
} elif (vtype.isGoodVariantType) {
if (cross_platform) {
panic("Platform independent code enabled. But field {field.name} is tuple")
}
write(*ss, ", {vtype.get_variant_field_offset(field.fieldIndex)}, {field.fieldIndex}>::get(");
} else {
let mod_name = (vtype.structType._module.name.empty() ? "" : string(vtype.structType._module.name) + "::");
write(*ss, ",&{mod_name}{aotStructName(vtype.structType)}::{aotFieldName(string(field.name))}>::get(");
}
}
def override visitExprSafeField(var field : ExprSafeField?) : ExpressionPtr {
assume vtype = field.value._type.firstType;
if (vtype.isHandle) {
let type_str = describeCppType(vtype, DescribeConfig(skip_const = true, redundant_const = true, cross_platform = cross_platform));
write(*ss, ",([&](const {type_str} * __any) -> auto & \{return ");
aot_previsit_get_field_ptr(vtype.annotation, ss, string(field.name));
write(*ss, "__any");
aot_type_ann_get_field_ptr(vtype.annotation, ss, string(field.name));
write(*ss, " /*{field.name}*/");
write(*ss, ";\})");
}
write(*ss, ")");
if (field._type.flags.aotAlias) {
write(*ss, ")");
}
return field;
}
def get_tuple_field(in_field_type : TypeDeclPtr; index : int; is_pointer : bool = false) {
let field_type = fa_element(in_field_type)
let field_tp = describeCppType(field_type.argTypes[index], DescribeConfig(cross_platform = cross_platform));
let maybe_ptr = is_pointer ? "_ptr" : "";
if (cross_platform) {
return "das_get_auto_tuple_field{maybe_ptr}";
} else {
let field_offset = field_type.get_tuple_field_offset(index);
return "das_get_tuple_field{maybe_ptr}";
}
}
def override preVisitExprField(field : ExprField?) {
if (field._type.flags.aotAlias) {
write(*ss, "das_alias::from(");
}
assume field_type = field.value._type;
if (field_type.isBitfield) {
write(*ss, "das_get_bitfield(");
} elif (field_type.isTuple) {
write(*ss, "{get_tuple_field(field_type, field.fieldIndex)}::get(")
} elif (field_type.isVariant) {
write(*ss, "{get_variant_field(field_type, field.fieldIndex)}::get(")
} elif (field_type.isHandle) {
if (field._type.isString) {
if (field.value._type.flags.constant) {
write(*ss, "((char *)(const char *)(");
} else {
write(*ss, "(({describeCppType(field._type, DescribeConfig(cross_platform=cross_platform))})(");
}
}
if (field._type.flags.isNativeDim) {
write(*ss, "das_reinterpret::pass(");
}
aot_previsit_get_field(field_type.annotation, ss, string(field.name));
} elif (field_type.baseType == Type.tPointer) {
if (field_type.firstType.isHandle) {
if (field._type.isString) {
if (field.value._type.flags.constant) {
write(*ss, "((char *)(const char *)(");
} else {
write(*ss, "(({describeCppType(field._type, DescribeConfig(cross_platform=cross_platform))})(");
}
}
if (field._type.flags.isNativeDim) {
write(*ss, "das_reinterpret::pass(");
}
aot_previsit_get_field_ptr(field_type.firstType.annotation, ss, string(field.name));
} elif (field.value._type.firstType.isTuple) {
write(*ss, "{get_tuple_field(field_type.firstType, field.fieldIndex, true)}::get(")
} elif (field.value._type.firstType.isVariant) {
write(*ss, "{get_variant_field(field_type.firstType, field.fieldIndex, true)}::get(")
}
}
}
def write_field_access_suffix(var sb : StringBuilderWriter?; field : ExprField?) : void {
write(*sb, " /*{field.name}*/")
if (field._type.isString) {
write(*sb, "))")
}
if (field._type.flags.isNativeDim) {
write(*sb, ")")
}
}
def override visitExprField(var field : ExprField?) : ExpressionPtr {
if (field.value._type.isBitfield) {
write(*ss, ",1u {aotFieldName(string(field.name))}");
}
} else {
write(*ss, ".{aotFieldName(string(field.name))}");
}
if (field._type.flags.aotAlias) {
write(*ss, ")");
}
return field;
}
def override preVisitExprAt(expr : ExprAt?) {
if (expr._type.flags.aotAlias) {
write(*ss, "das_alias::from(");
}
if (!(expr.subexpr._type.baseType == Type.tFixedArray || expr.subexpr._type.isGoodArrayType || expr.subexpr._type.isGoodTableType)) {
let type_str = describeCppType(expr.subexpr._type, DescribeConfig(skip_ref = true, cross_platform = cross_platform));
write(*ss, "das_index::at(");
}
}
def override preVisitExprAtIndex(var expr : ExprAt?; index : ExpressionPtr) {
if (expr.subexpr._type.baseType == Type.tFixedArray || expr.subexpr._type.isGoodArrayType || expr.subexpr._type.isGoodTableType) {
if (expr.subexpr._type.flags.isNativeDim) {
write(*ss, "[");
} else {
write(*ss, "(");
}
} else {
write(*ss, ",");
}
}
def override visitExprAt(var expr : ExprAt?) : ExpressionPtr {
if (expr.subexpr._type.flags.isNativeDim) {
write(*ss, "]");
} else {
write(*ss, ",__context__)");
}
if (expr._type.flags.aotAlias) {
write(*ss, ")");
}
return expr;
}
def override preVisitExprSafeAt(expr : ExprSafeAt?) {
let isPtr : bool = expr.subexpr._type.isPointer;
assume seT = isPtr ? expr.subexpr._type.firstType : expr.subexpr._type;
if ((seT.baseType == Type.tFixedArray || seT.isGoodArrayType || seT.isGoodTableType)) {
let type_str = describeCppType(seT, DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform))
write(*ss, "{type_str}::safe_index(");
} elif (isPtr && !seT.isVectorType) {
let type_str = describeCppType(expr.subexpr._type, DescribeConfig(skip_ref = true, cross_platform = cross_platform))
write(*ss, "das_index::safe_at(");
} else {
let type_str = describeCppType(seT, DescribeConfig(skip_ref = true, cross_platform = cross_platform))
write(*ss, "das_index::safe_at(");
}
write(*ss, isPtr ? "(" : "&(");
}
def override preVisitExprSafeAtIndex(expr : ExprSafeAt?; index : ExpressionPtr) {
write(*ss, "),");
}
def override visitExprSafeAt(var that : ExprSafeAt?) : ExpressionPtr {
write(*ss, ",__context__)");
return that;
}
def override visitExprFakeContext(var c : ExprFakeContext?) : ExpressionPtr {
write(*ss, "__context__");
return c;
}
def override visitExprFakeLineInfo(var c : ExprFakeLineInfo?) : ExpressionPtr {
write(*ss, "((LineInfoArg *)(&LineInfo::g_LineInfoNULL))");
return c;
}
def override visitExprConstPtr(var c : ExprConstPtr?) : ExpressionPtr {
let pvalue = c.getValue
if (pvalue != null) {
write(*ss, "((void *) 0x{unsafe(reinterpret(pvalue)):x})");
} else {
write(*ss, "nullptr");
}
return c;
}
def override visitExprConstEnumeration(var c : ExprConstEnumeration?) : ExpressionPtr {
let cfg = DescribeConfig(skip_ref = true, skip_const = true, redundant_const = false, cross_platform = cross_platform);
let type_str = describeCppType(c._type, cfg);
write(*ss, type_str);
var ctext = aotEnumValueName(c.value);
for (ee in c.enumType.list) {
if (ee.name == c.value) {
if (!ee.cppName.empty()) {
ctext = string(ee.cppName);
}
break;
}
}
write(*ss, "::{ctext}");
return c;
}
def override visitExprConstInt(var c : ExprConstInt?) : ExpressionPtr {
write(*ss, "{c.getValue}");
return c;
}
def override visitExprConstInt8(var c : ExprConstInt8?) : ExpressionPtr {
write(*ss, "{c.getValue}");
return c;
}
def override visitExprConstInt16(var c : ExprConstInt16?) : ExpressionPtr {
write(*ss, "{c.getValue}");
return c;
}
def override visitExprConstInt64(var c : ExprConstInt64?) : ExpressionPtr{
if (c.getValue == LONG_MIN) {
write(*ss, "INT64_MIN");
} else {
write(*ss, "INT64_C({c.getValue})");
}
return c;
}
def override visitExprConstUInt8(var c : ExprConstUInt8?) : ExpressionPtr {
write(*ss, "0x{uint(c.getValue):x}");
return c;
}
def override visitExprConstUInt16(var c : ExprConstUInt16?) : ExpressionPtr {
write(*ss, "0x{uint(c.getValue):x}");
return c;
}
def override visitExprConstUInt64(var c : ExprConstUInt64?) : ExpressionPtr {
write(*ss, "UINT64_C(0x{c.getValue:x})");
return c;
}
def override visitExprConstUInt(var c : ExprConstUInt?) : ExpressionPtr {
write(*ss, "0x{c.getValue:x}u");
return c;
}
def override visitExprConstBitfield(var c : ExprConstBitfield?) : ExpressionPtr {
if (c._type.baseType == Type.tBitfield64) {
write(*ss, "UINT64_C(0x{c.getValue:x})");
} elif (c._type.baseType == Type.tBitfield16) {
write(*ss, "uint16_t(0x{uint(c.getValue):x})");
} elif (c._type.baseType == Type.tBitfield8) {
write(*ss, "uint8_t(0x{uint(c.getValue):x})");
} else {
write(*ss, "0x{c.getValue:x}u");
}
return c;
}
def override visitExprConstBool(var c : ExprConstBool?) : ExpressionPtr {
write(*ss, (c.getValue ? "true" : "false"));
return c;
}
def to_cpp_double(val : double) : string {
if (val == DBL_MIN) return "DBL_MIN"
if (val == -DBL_MIN) return "(-DBL_MIN)"
if (val == DBL_MAX) return "DBL_MAX"
if (val == -DBL_MAX) return "(-DBL_MAX)"
if (val != val) return "((double)NAN)" // nolint:LINT007 — canonical IEEE-754 NaN test
if (val > DBL_MAX) return "((double)INFINITY)"
if (val < -DBL_MAX) return "((double)(-INFINITY))"
return "{val:.17e}"
}
def writeOutDouble(val : double) {
write(*ss, to_cpp_double(val));
}
def override visitExprConstDouble(var c : ExprConstDouble?) : ExpressionPtr {
writeOutDouble(c.getValue);
return c;
}
def writeOutFloat(value : float) {
write(*ss, to_cpp_float(value));
}
def override visitExprConstFloat(var c : ExprConstFloat?) : ExpressionPtr {
writeOutFloat(c.getValue);
return c;
}
def override visitExprConstFloat16(var c : ExprConstFloat16?) : ExpressionPtr {
write(*ss, "float16_t(");
writeOutFloat(float(c.value));
write(*ss, ")");
return c;
}
def override visitExprConstString(var c : ExprConstString?) : ExpressionPtr {
if (c.value.empty()) {
write(*ss, "nullptr");
} else {
peek(c.value) $(sv) {
write(*ss, "((char *) \"{escape(sv)}\")");
}
}
return c;
}
def override visitExprConstInt2(var c : ExprConstInt2?) : ExpressionPtr {
let val = c.getValue;
write(*ss, "int2({val.x},{val.y})");
return c;
}
def override visitExprConstRange(var c : ExprConstRange?) : ExpressionPtr {
let val = c.getValue;
write(*ss, "range({val.x:d},{val.y:d})");
return c;
}
def override visitExprConstRange64(var c : ExprConstRange64?) : ExpressionPtr {
let val = c.getValue;
write(*ss, "range64({val.x:d}ll,{val.y:d}ll)");
return c;
}
def override visitExprConstInt3(var c : ExprConstInt3?) : ExpressionPtr {
let val = c.getValue;
write(*ss, "int3({val.x:d},{val.y:d},{val.z:d})");
return c;
}
def override visitExprConstInt4(var c : ExprConstInt4?) : ExpressionPtr {
let val = c.getValue;
write(*ss, "int4({val.x:d},{val.y:d},{val.z:d},{val.w:d})");
return c;
}
def override visitExprConstUInt2(var c : ExprConstUInt2?) : ExpressionPtr {
let val = c.getValue;
write(*ss, "uint2({val.x:d},{val.y:d})");
return c;
}
def override visitExprConstURange(var c : ExprConstURange?) : ExpressionPtr {
let val = c.getValue;
write(*ss, "urange({val.x:d},{val.y:d})");
return c;
}
def override visitExprConstURange64(var c : ExprConstURange64?) : ExpressionPtr {
let val = c.getValue;
write(*ss, "urange64({val.x:d}ull,{val.y:d}ull)");
return c;
}
def override visitExprConstUInt3(var c : ExprConstUInt3?) : ExpressionPtr {
let val = c.getValue;
write(*ss, "uint3({val.x:d},{val.y:d},{val.z:d})");
return c;
}
def override visitExprConstUInt4(var c : ExprConstUInt4?) : ExpressionPtr {
let val = c.getValue;
write(*ss, "uint4({val.x:d},{val.y:d},{val.z:d},{val.w:d})");
return c;
}
def override visitExprConstFloat2(var c : ExprConstFloat2?) : ExpressionPtr {
let val = c.getValue;
if (val.x == 0.0f && val.y == 0.0f) {
write(*ss, "v_zero()");
} elif (val.x == val.y) {
write(*ss, "v_splats(");
writeOutFloat(val.x);
write(*ss, ")");
} else {
write(*ss, "v_make_vec4f(");
writeOutFloat(val.x);
write(*ss, ",");
writeOutFloat(val.y);
write(*ss, ",0.f,0.f)");
}
return c;
}
def override visitExprConstFloat3(var c : ExprConstFloat3?) : ExpressionPtr {
let val = c.getValue;
if (val.x == 0.0f && val.y == 0.0f && val.z == 0.0f) {
write(*ss, "v_zero()");
} elif (val.x == val.y && val.x == val.z) {
write(*ss, "v_splats(");
writeOutFloat(val.x);
write(*ss, ")");
} else {
write(*ss, "v_make_vec4f(");
writeOutFloat(val.x);
write(*ss, ",");
writeOutFloat(val.y);
write(*ss, ",");
writeOutFloat(val.z);
write(*ss, ",0.f)");
}
return c;
}
def override visitExprConstFloat4(var c : ExprConstFloat4?) : ExpressionPtr {
let val = c.getValue;
if (val.x == 0.0f && val.y == 0.0f && val.z == 0.0f && val.w == 0.0f) {
write(*ss, "v_zero()");
} elif (val.x == val.y && val.x == val.z && val.x == val.w) {
write(*ss, "v_splats(");
writeOutFloat(val.x);
write(*ss, ")");
} else {
write(*ss, "v_make_vec4f(");
writeOutFloat(val.x);
write(*ss, ",");
writeOutFloat(val.y);
write(*ss, ",");
writeOutFloat(val.z);
write(*ss, ",");
writeOutFloat(val.w);
write(*ss, ")");
}
return c;
}
def override preVisitExprAssume(expr : ExprAssume?) {
write(*ss, "\n#if 0 // with, note optimizations are off\n");
}
def override visitExprAssume(var expr : ExprAssume?) : ExpressionPtr {
write(*ss, "\n#endif\n");
return expr;
}
def override preVisitExprWith(expr : ExprWith?) {
write(*ss, "\n#if 0 // with, note optimizations are off\n");
}
def override preVisitExprWithBody(expr : ExprWith?; body : ExpressionPtr) {
write(*ss, "\n#endif\n");
}
def override preVisitExprWhile(wh : ExprWhile?) {
write(*ss, "while ( ");
}
def override preVisitExprWhileBody(wh : ExprWhile?; body : ExpressionPtr) {
write(*ss, " )\n{tabs()}");
}
def override visitExprWhile(var wh : ExprWhile?) : ExpressionPtr {
return wh;
}
def override preVisitExprIfThenElse(ifte : ExprIfThenElse?) {
write(*ss, "if ( ");
}
def override preVisitExprIfThenElseIfBlock(ifte : ExprIfThenElse?; blk : ExpressionPtr) {
if (!(blk is ExprBlock)) {
write(*ss, " ) \{\n");
tab ++;
write(*ss, tabs());
} else {
write(*ss, " )\n");
write(*ss, tabs());
}
}
def override preVisitExprIfThenElseElseBlock(ifte : ExprIfThenElse?; blk : ExpressionPtr) {
if (ifte.if_true != null && !(ifte.if_true is ExprBlock)) {
write(*ss, ";\n");
tab --;
write(*ss, tabs());
write(*ss, "} else ");
} else {
write(*ss, " else ");
}
if (!(blk is ExprBlock)) {
write(*ss, "\{\n");
tab ++;
write(*ss, tabs());
}
}
def override visitExprIfThenElse(var ifte : ExprIfThenElse?) : ExpressionPtr {
var isNotBlock : bool
if (ifte.if_false != null) {
isNotBlock = !(ifte.if_false is ExprBlock)
} else {
isNotBlock = !(ifte.if_true is ExprBlock)
}
if (isNotBlock) {
write(*ss, ";\n");
tab --;
write(*ss, tabs());
write(*ss, "\}");
}
return ifte;
}
def is_lattice_elem(t : Type) : bool {
return t == Type.tFloat16 || t == Type.tInt16 || t == Type.tUInt16 || t == Type.tInt8 || t == Type.tUInt8
}
def override preVisitExprSwizzle(expr : ExprSwizzle?) {
assume srcT = expr.value._type
if (srcT.isVectorType && is_lattice_elem(srcT.vectorBaseType)) {
let et = das_to_cppString(srcT.vectorBaseType)
let type_str = describeCppType(expr._type, DescribeConfig(skip_ref = true, cross_platform = cross_platform))
if (expr._type.flags.ref) {
write(*ss, "das_swizzle_ref_small::swizzle(")
} else {
let field_str = (each(expr.fields)
._select("{_:d}")
.to_array()
._fold()) |> join(",")
write(*ss, "das_swizzle_small::swizzle(")
}
return
}
if (expr._type.flags.ref) {
let type_str = describeCppType(expr._type, DescribeConfig(skip_ref = true, cross_platform = cross_platform));
let value_str = describeCppType(expr.value._type, DescribeConfig(skip_ref = true, cross_platform = cross_platform));
write(*ss, "das_swizzle_ref::swizzle(");
} else {
if (length(expr.fields) == 1) {
let mask = fixed_array('x', 'y', 'z', 'w');
let is64bit = expr._type.baseType == Type.tInt64 || expr._type.baseType == Type.tUInt64;
write(*ss, "v_extract_")
*ss |> write_char(mask[int(expr.fields[0])]);
if (expr._type.baseType != Type.tFloat) {
write(*ss, is64bit ? "i64" : "i");
}
write(*ss, "(");
if (expr._type.baseType != Type.tFloat) {
write(*ss, "v_cast_vec4i(");
}
} else {
let type_str = describeCppType(expr._type, DescribeConfig(skip_ref = true, cross_platform = cross_platform));
let value_str = describeCppType(expr.value._type, DescribeConfig(skip_ref = true, cross_platform = cross_platform));
if (isSequencialMask(expr.fields)) {
write(*ss, "das_swizzle_seq::swizzle(");
} else {
let field_str = (each(expr.fields)
._select("{_:d}")
.to_array()
._fold()) |> join(",")
write(*ss, "das_swizzle::swizzle(");
}
}
}
if (expr.value._type.flags.aotAlias) {
write(*ss, "das_alias::from(");
}
}
def override visitExprSwizzle(var expr : ExprSwizzle?) : ExpressionPtr {
if (expr.value._type.flags.aotAlias) {
write(*ss, ")");
}
assume srcT = expr.value._type
if (srcT.isVectorType && is_lattice_elem(srcT.vectorBaseType)) {
write(*ss, ")");
return expr;
}
if (expr._type.flags.ref) {
write(*ss, ")");
} else {
if (length(expr.fields) == 1) {
if (expr._type.baseType != Type.tFloat) write(*ss, ")");
write(*ss, ")");
} else {
write(*ss, ")");
}
}
write(*ss, " /*");
for (f in expr.fields) {
match (int(f)) {
if (0) { write(*ss, "x"); }
if (1) { write(*ss, "y"); }
if (2) { write(*ss, "z"); }
if (3) { write(*ss, "w"); }
if (_) { write(*ss, "?"); }
}
}
write(*ss, "*/");
return expr;
}
def outputCallTypeInfo(nArgs : uint; elements : dasvector`ptr`Expression) {
let debug_info_name = "__tinfo_{debugInfoGlobal++:d}";
let tinfo_str = (each(elements)
._select("&{typeInfoName(helper.helper |> make_type_info(null, _._type))}")
.to_array()
._fold()) |> join(", ")
let (val, succ) = cachedTi.emplace(debug_info_name, tinfo_str)
if (!succ) {
return val
} else {
type_info.push(build_string() $(writer) {
write(writer, "TypeInfo * {debug_info_name}[{nArgs:d}] = \{ {tinfo_str} \};");
})
return debug_info_name;
}
}
def override preVisitExprStringBuilder(expr : ExprStringBuilder?) {
let nArgs = uint(length(expr.elements));
write(*ss, "das_string_builder");
if (expr.stringBuilderFlags.isTempString) {write(*ss, "_temp"); }
write(*ss, "(__context__,SimNode_AotInterop(");
if (nArgs != 0u) {
let debug_info_name = outputCallTypeInfo(nArgs, expr.elements);
write(*ss, "{debug_info_name}, ");
}
}
def override preVisitExprStringBuilderElement(sb : ExprStringBuilder?; expr : ExpressionPtr; last : bool) {
write(*ss, "cast::from(");
}
def override visitExprStringBuilderElement(sb : ExprStringBuilder?; expr : ExpressionPtr; last : bool) {
write(*ss, ")");
if (!last) {
write(*ss, ", ");
}
return expr;
}
def override visitExprStringBuilder(var expr : ExprStringBuilder?) : ExpressionPtr {
write(*ss, "))");
return expr;
}
def override preVisitExprTypeDecl(expr : ExprTypeDecl?) {
write(*ss, "das_typedecl_value()()");
}
def override preVisitExprTypeInfo(expr : ExprTypeInfo?) {
if (expr.macro == null) {
panic("internal error. we should only be here if there is a macro.");
}
write(*ss, "(");
expr.macro |> write_aot_macro_prefix(ss, expr);
if (expr.macro |> aot_need_type_info(expr)) {
let info = helper.helper |> make_type_info(null, expr.typeexpr);
write(*ss, typeInfoName(info));
}
}
def override canVisitExprTypeInfo(expr : ExprTypeInfo?; expr_ : ExpressionPtr) {
if (expr.macro == null) {
panic("internal error. we should only be here if there is a macro.");
}
return expr.macro |> macro_aot_infix(ss, expr);
}
def override visitExprTypeInfo(var expr : ExprTypeInfo?) : ExpressionPtr {
if (expr.macro == null) {
panic("internal error. we should only be here if there is a macro.");
}
expr.macro |> write_aot_macro_suffix(ss, expr);
write(*ss, ")");
return expr;
}
def override preVisitExprTryCatch(tc : ExprTryCatch?) {
write(*ss, "das_try_recover(__context__, [&]()\n");
write(*ss, "{tabs()}");
}
def override preVisitExprTryCatchCatch(tc : ExprTryCatch?; blk : ExpressionPtr) {
write(*ss, ", [&]()\n");
write(*ss, "{tabs()}");
}
def override visitExprTryCatch(var tc : ExprTryCatch?) : ExpressionPtr {
write(*ss, ")");
return tc;
}
def isDistinctDeref(ptr2ref : ExprPtr2Ref?) {
return ptr2ref.subexpr._type != null && ptr2ref.subexpr._type.baseType == Type.tDistinct
}
def override preVisitExprPtr2Ref(ptr2ref : ExprPtr2Ref?) {
if (isDistinctDeref(ptr2ref)) {
write(*ss, "(");
} elif (ptr2ref.unsafeDeref) {
write(*ss, "(*(");
} else {
write(*ss, "das_deref(__context__,");
}
}
def override visitExprPtr2Ref(var ptr2ref : ExprPtr2Ref?) : ExpressionPtr {
if (isDistinctDeref(ptr2ref)) {
write(*ss, ")");
} elif (ptr2ref.unsafeDeref) {
write(*ss, "))");
} else {
write(*ss, ",__FILE__,__LINE__)");
}
return ptr2ref;
}
def override preVisitExprRef2Ptr(ref2ptr : ExprRef2Ptr?) {
write(*ss, "das_ref(__context__,");
}
def override visitExprRef2Ptr(var ref2ptr : ExprRef2Ptr?) : ExpressionPtr {
write(*ss, ")");
return ref2ptr;
}
def queryByMNH(name : string; hash : uint64) {
return "Func(__context__->fnByMangledName(/*{name}*/ 0x{hash:x}))";
}
def override preVisitExprAddr(expr : ExprAddr?) {
if (expr.func != null) {
let mangledName = expr.func |> get_mangled_name();
let hash = expr.func.getMangledNameHash;
write(*ss, queryByMNH(mangledName, hash));
} else {
write(*ss, "Func(0 /*nullptr*/)");
}
}
def override preVisitExprCast(expr : ExprCast?) {
write(*ss, "{(expr.castFlags.upcastCast ? "das_upcast" : "das_cast")}::cast(");
}
def override visitExprCast(var expr : ExprCast?) : ExpressionPtr {
write(*ss, ")");
return expr;
}
def override preVisitExprDelete(edel : ExprDelete?) {
assume subt = edel.subexpr._type;
assume subft = subt.firstType;
if (subt.isPointer && subft.baseType == Type.tHandle) {
write(*ss, "das_delete_handle::make(__context__");
}
} else {
if (enew._type.firstType.isStructure && enew._type.firstType.structType.flags.persistent) {
write(*ss, "das_new_persistent::make(__context__");
}
}
}
}
def override preVisitExprNewArgument(enew : ExprNew?; arg : ExpressionPtr; last : bool) {
if (enew.initializer) {
CallFunc_preVisitCallArg(enew, arg, last);
}
}
def override visitExprNewArgument(enew : ExprNew?; arg : ExpressionPtr; last : bool) {
if (enew.initializer) {
CallFunc_visitCallArg(enew, arg, last);
} else {
panic("we should not even be here. we are visiting arguments of a new, but it has no initializer???");
}
return arg;
}
def override visitExprNew(var enew : ExprNew?) : ExpressionPtr {
if (enew.initializer) {
CallFunc_visit(enew);
write(*ss, "; \})");
} else {
write(*ss, ")");
}
return enew;
}
def needTempSrc(expr : ExprMakeLocal?) {
return expectsLocalTemp(expr);
}
def mkvName(expr : ExprMakeVariant?) {
if (needTempSrc(expr)) {
return makeLocalTempName(expr);
} else {
return "__mkv_{expr.at.line:d}";
}
}
def override preVisitExprMakeVariant(expr : ExprMakeVariant?) {
let type_str = describeCppType(expr._type, DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform));
write(*ss, "(([&]() -> {type_str}{needTempSrc(expr) ? "&" : ""} \{\n");
tab ++;
if (!needTempSrc(expr)) {
write(*ss, "{tabs()}{describeCppType(expr._type,DescribeConfig(skip_ref=true,cross_platform=cross_platform))} {mkvName(expr)};\n");
}
if (expr.variants.empty()) {
write(*ss, "{tabs()}das_zero({mkvName(expr)});\n");
}
}
def override preVisitExprMakeVariantField(expr : ExprMakeVariant?; index : int; decl : MakeFieldDeclPtr; last : bool) {
let variantType = fa_element(expr._type)
let variantIndex = find_argument_index(variantType, string(decl.name));
if (variantIndex == -1) {
panic("should not infer otherwise");
}
let type_str = describeCppType(variantType.argTypes[variantIndex], DescribeConfig(cross_platform = cross_platform));
write(*ss, "{tabs()}{get_variant_field(variantType, variantIndex)}::set(");
write(*ss, "{mkvName(expr)}");
if (length(expr.variants) != 1) write(*ss, "({index},__context__)");
write(*ss, ") = ");
if (variantType.argTypes[variantIndex].isPointer && decl.value._type.isPointer && variantType.argTypes[variantIndex].firstType != null && decl.value._type.firstType != null && !is_same_type(variantType.argTypes[variantIndex].firstType, decl.value._type.firstType, false, false, false, false)) {
write(*ss, "das_auto_cast::cast(");
}
}
def override visitExprMakeVariantField(expr : ExprMakeVariant?; index : int; decl : MakeFieldDeclPtr; last : bool) {
let variantType = fa_element(expr._type)
let variantIndex = find_argument_index(variantType, string(decl.name))
if (variantType.argTypes[variantIndex].isPointer && decl.value._type.isPointer && variantType.argTypes[variantIndex].firstType != null && decl.value._type.firstType != null && !is_same_type(variantType.argTypes[variantIndex].firstType, decl.value._type.firstType, false, false, false, false)) {
write(*ss, ")");
}
write(*ss, ";\n");
return decl;
}
def override visitExprMakeVariant(var expr : ExprMakeVariant?) : ExpressionPtr {
write(*ss, "{tabs()}return {mkvName(expr)};\n");
tab --;
write(*ss, "{tabs()}\})())");
return expr;
}
def mksName(expr : ExprMakeStruct?) {
if (needTempSrc(expr)) {
return makeLocalTempName(expr);
} else {
return "__mks_{expr.at.line:d}";
}
}
def override preVisitExprMakeStruct(expr : ExprMakeStruct?) {
write(*ss, "(([&](");
if (expr.makeStructFlags.isNewHandle) {
let type_str = describeCppType(expr._type, DescribeConfig(skip_ref = true, cross_platform = cross_platform));
write(*ss, "{type_str} & {mksName(expr)}");
}
write(*ss, ")");
if (!expr.makeStructFlags.isNewHandle) {
let expr_type = describeCppType(expr._type, DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform));
write(*ss, " -> {expr_type}{needTempSrc(expr) ? "&" : ""}");
}
write(*ss, " \{\n");
tab ++;
if (!expr.makeStructFlags.isNewHandle) {
if (!needTempSrc(expr)) {
let expr_type = describeCppType(expr._type, DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform));
write(*ss, "{tabs()}{expr_type} {mksName(expr)}");
if (expr.constructor != null) {
write(*ss, " = ");
let call_func = expr.constructor;
if (isHybridCall(call_func)) {
write(*ss, "das_invoke_function::invoke_cmres");
assume mangledName = call_func |> get_mangled_name();
let hash = call_func.getMangledNameHash;
write(*ss, "(__context__,nullptr,");
write(*ss, queryByMNH(mangledName, hash));
write(*ss, ")");
} else {
write(*ss, "{aotFuncName(call_func)}(__context__)");
}
}
write(*ss, ";\n");
} else {
if (expr.constructor != null) {
write(*ss, "{tabs()}{mksName(expr)} = ");
let call_func = expr.constructor;
if (isHybridCall(call_func)) {
write(*ss, "das_invoke_function::invoke_cmres");
assume mangledName = call_func |> get_mangled_name();
let hash = call_func.getMangledNameHash;
write(*ss, "(__context__,nullptr,");
write(*ss, queryByMNH(mangledName, hash));
write(*ss, ")");
} else {
write(*ss, "{aotFuncName(call_func)}(__context__)");
}
write(*ss, ";\n");
}
}
if ((expr.constructor == null && !expr.makeFlags.initAllFields) || (expr.makeType.baseType == Type.tTuple && expr.structs |> empty())) {
write(*ss, "{tabs()}das_zero({mksName(expr)});\n");
}
}
}
def override preVisitExprMakeStructField(expr : ExprMakeStruct?; index : int; decl : MakeFieldDeclPtr; last : bool) {
let mkType = fa_element(expr.makeType)
write(*ss, "{tabs()}");
write(*ss, "{decl.flags.moveSemantics ? "das_move((" : "das_copy(("}");
if (mkType.baseType == Type.tHandle) {
aot_previsit_get_field(mkType.annotation, ss, string(decl.name));
}
write(*ss, "{mksName(expr)}");
if (length(expr.structs) != 1) write(*ss, "({index},__context__)");
if (mkType.baseType == Type.tHandle) {
aot_visit_get_field(mkType.annotation, ss, string(decl.name));
write(*ss, " /*{decl.name}*/");
} else {
write(*ss, ".{aotFieldName(string(decl.name))}");
}
write(*ss, "),(");
}
def override visitExprMakeStructField(expr : ExprMakeStruct?; index : int; var decl : MakeFieldDeclPtr; last : bool) {
write(*ss, "));\n");
return decl;
}
def override canVisitExprMakeStructBlock(str : ExprMakeStruct?; expr : ExpressionPtr) { return false; }
def override visitExprMakeStruct(var expr : ExprMakeStruct?) : ExpressionPtr {
if (expr._block != null) {
assert(expr._block is ExprMakeBlock);
var mkb = expr._block as ExprMakeBlock;
assert(mkb._block is ExprBlock);
var blk = unsafe(reinterpret(mkb._block));
collector.renameVariableTo(blk.arguments[0], mksName(expr));
write(*ss, "{tabs()}");
visit_expression(mkb._block, adapter);
}
if (!expr.makeStructFlags.isNewHandle) {
write(*ss, "{tabs()}return {mksName(expr)};\n");
}
tab --;
write(*ss, "{tabs()}\})");
if (!expr.makeStructFlags.isNewHandle) { write(*ss, "()"); }
write(*ss, ")");
return expr;
}
def mkaName(expr : ExprMakeArray?) {
if (!needTempSrc(expr)) {
return "__mka_{expr.at.line:d}";
} else {
return makeLocalTempName(expr);
}
}
def override preVisitExprMakeArray(expr : ExprMakeArray?) {
let type_str = describeCppType(expr._type, DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform));
write(*ss, "(([&]() -> {type_str}{(needTempSrc(expr) ? "&" : "")} \{\n");
tab ++;
if (!needTempSrc(expr)) {
write(*ss, "{tabs()}{describeCppType(expr._type,DescribeConfig(skip_ref=true,cross_platform=cross_platform))} {mkaName(expr)};\n");
}
if (!expr.makeFlags.initAllFields || expr.makeArrayOnHeap) {
write(*ss, "{tabs()}das_zero({mkaName(expr)});\n");
}
if (expr.makeArrayOnHeap) {
let elem_str = describeCppType(expr.recordType, DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform));
write(*ss, "{tabs()}builtin_array_resize({mkaName(expr)},{length(expr.values)},sizeof({elem_str}),__context__,nullptr);\n");
}
}
def override preVisitExprMakeArrayIndex(expr : ExprMakeArray?; index : int; init : ExpressionPtr; last : bool) {
if (init._type.canCopy) {
write(*ss, "{tabs()}das_copy(({mkaName(expr)}({index},__context__)),(");
} else {
write(*ss, "{tabs()}das_move({mkaName(expr)}({index},__context__),");
}
}
def override visitExprMakeArrayIndex(expr : ExprMakeArray?; index : int; init : ExpressionPtr; last : bool) {
if (init._type.canCopy) {
write(*ss, "));\n");
} else {
write(*ss, ");\n");
}
return init;
}
def override visitExprMakeArray(var expr : ExprMakeArray?) : ExpressionPtr {
write(*ss, "{tabs()}return {mkaName(expr)};\n");
tab --;
write(*ss, "{tabs()}\})())");
return expr;
}
def mktName(expr : ExprMakeTuple?) {
if (!needTempSrc(expr)) {
return "__mkt_{expr.at.line:d}";
} else {
return makeLocalTempName(expr);
}
}
def override preVisitExprMakeTuple(expr : ExprMakeTuple?) {
let type_str1 = describeCppType(expr._type, DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform))
write(*ss, "(([&]() -> {type_str1}{(needTempSrc(expr) ? "&" : "")} \{\n");
tab ++;
if (!needTempSrc(expr)) {
let type_str2 = describeCppType(expr._type, DescribeConfig(skip_ref = true, cross_platform = cross_platform));
write(*ss, "{tabs()}{type_str2} {mktName(expr)};\n");
}
if (!expr.makeFlags.initAllFields) {
write(*ss, "{tabs()}das_zero({mktName(expr)});\n");
}
}
def override preVisitExprMakeTupleIndex(expr : ExprMakeTuple?; index : int; init : ExpressionPtr; last : bool) {
if (init._type.canCopy) {
write(*ss, "{tabs()}{get_tuple_field(expr.makeType, index)}::get({mktName(expr)}) = ");
} else {
write(*ss, "{tabs()}das_move({get_tuple_field(expr.makeType, index)}::get({mktName(expr)}),");
}
}
def override visitExprMakeTupleIndex(expr : ExprMakeTuple?; index : int; var init : ExpressionPtr; last : bool) {
if (init._type.canCopy) {
write(*ss, ";\n");
} else {
write(*ss, ");\n");
}
return init;
}
def override visitExprMakeTuple(var expr : ExprMakeTuple?) : ExpressionPtr {
write(*ss, "{tabs()}return {mktName(expr)};\n");
tab --;
write(*ss, "{tabs()}\})())");
return expr;
}
def override canVisitMakeBlockBody(blk : ExprMakeBlockPtr) {
return blk.aotFunctorName.empty();
}
def override preVisitExprMakeBlock(expr : ExprMakeBlockPtr) {
let blk = expr._block as ExprBlock;
if (!blk.blockFlags.aotSkipMakeBlock) {
write(*ss, "das_make_block");
if (blk.returnType.isRefType && !blk.returnType.flags.ref) {
write(*ss, "_cmres");
}
let type_str = describeCppType(blk.returnType, DescribeConfig(skip_const = true, cross_platform = cross_platform));
let args = (each(blk.arguments)
._select("{describeCppType(_._type,DescribeConfig(cross_platform=cross_platform))}{_._type.isRefType && !_._type.flags.ref ? " &" : ""}")
.to_array()
._fold()) |> join(",")
let maybe_comma = args |> empty() ? "" : ",";
write(*ss, "(__context__,{blk.stackTop:d},");
}
if (!blk.blockFlags.aotSkipMakeBlock || blk.blockFlags.aotDoNotSkipAnnotationData) {
if (blk.annotationDataSid != uint64(0)) {
write(*ss, "__context__->adBySid({blk.annotationDataSid:d}u)");
} else {
write(*ss, "0");
}
write(*ss, ",");
}
if (!blk.blockFlags.aotSkipMakeBlock) {
var blk_t = blk |> make_block_type()
let info = helper.helper |> make_invokable_type_debug_info(blk_t, blk.at);
write(*ss, "&{funcInfoName(info)},");
}
if (expr.aotFunctorName.empty()) {
write(*ss, "[&](");
var ai = 0;
for (arg in blk.arguments) {
if (ai++ != 0) {
write(*ss, ", ");
}
if (isLocalVec(arg._type)) {
describeLocalCppType(ss, arg._type, cross_platform);
} else {
write(*ss, "{describeCppType(arg._type,DescribeConfig(redundant_const=false,cross_platform=cross_platform))}");
if (arg._type.isRefType && !arg._type.flags.ref) {
write(*ss, " &");
}
}
write(*ss, " {collector.getVarName(arg)}");
}
write(*ss, ") ");
if (blk.blockFlags.aotSkipMakeBlock) {
write(*ss, "DAS_AOT_INLINE_LAMBDA ");
}
write(*ss, "-> {describeCppType(blk.returnType, DescribeConfig(skip_const=true,cross_platform=cross_platform))}");
} else {
write(*ss, "{expr.aotFunctorName}");
}
}
def override visitExprMakeBlock(var expr : ExprMakeBlockPtr) : ExpressionPtr {
let blk = expr._block as ExprBlock;
if (!blk.blockFlags.aotSkipMakeBlock) {
write(*ss, ")");
}
return expr;
}
def override preVisitExprLooksLikeCall(var call : ExprLooksLikeCall?) { // nolint:STYLE037,STYLE038 - one arm per intrinsic call name
if (isInvokeWithTemp(call)) {
write(*ss, "({makeLocalTempName(call)} = (");
}
if (call.name == "debug") {
assume argType = call.arguments[0]._type;
let info = helper.helper |> make_type_info(null, argType);
write(*ss, "das_debug(__context__,&{typeInfoName(info)},__FILE__,__LINE__,");
let maybe_ref = ((argType.isRefType && !argType.flags.ref) ? "&" : "")
write(*ss, "cast::from(");
} elif (call.name == "assert" || call.name == "verify") {
let ea = call as ExprAssert;
if (length(call.arguments) == 1) {
write(*ss, "{ea.isVerify ? "das_verify" : "das_assert"}(");
} else {
write(*ss, "{ea.isVerify ? "das_verifyf" : "das_assertf"}(");
}
} elif (call.name == "erase") {
write(*ss, "__builtin_table_erase(__context__,");
} elif (call.name == "insert") {
write(*ss, "__builtin_table_set_insert(__context__,");
} elif (call.name == "find") {
write(*ss, "__builtin_table_find(__context__,");
} elif (call.name == "key_exists") {
write(*ss, "__builtin_table_key_exists(__context__,");
} elif (call.name == "keys") {
write(*ss, "__builtin_table_keys(__context__,");
} elif (call.name == "values") {
write(*ss, "__builtin_table_values(__context__,");
} elif (call.name == "invoke" || call is ExprInvoke) {
let bt = call.arguments[0]._type.baseType;
var methodOffset = -1;
var methodName = "";
if (bt == Type.tFunction) {
let einv = call as ExprInvoke;
if (einv.isInvokeMethod) {
if (call.arguments[0] is ExprRef2Value && (call.arguments[0] as ExprRef2Value).subexpr is ExprField) {
let field = (call.arguments[0] as ExprRef2Value).subexpr as ExprField;
methodOffset = field.field.offset;
methodName = string(field.field.name);
} elif (call.arguments[0] is ExprField) {
let field = call.arguments[0] as ExprField;
methodOffset = field.field.offset;
methodName = string(field.field.name);
} else {
panic("internal error. expected field");
}
}
}
if (bt == Type.tBlock) {
write(*ss, "das_invoke");
} elif (bt == Type.tLambda) {
write(*ss, "das_invoke_lambda");
} elif (bt == Type.tFunction && methodOffset != -1) {
write(*ss, "das_invoke_method");
} elif (bt == Type.tFunction) {
write(*ss, "das_invoke_function");
} elif (bt == Type.tString) {
write(*ss, "das_invoke_function_by_name");
} else {
write(*ss, "das_invoke /*unknown*/");
}
let einv = call as ExprInvoke;
write(*ss, "::invoke");
if (einv.isCopyOrMove) {
write(*ss, "_cmres");
}
if (length(call.arguments) > 1) {
unsafe {
let args = (each(range(1, length(call.arguments)))
._select("{describeCppType(call.arguments[_]._type, DescribeConfig(cross_platform=cross_platform))}{(call.arguments[_]._type.isRefType && !call.arguments[_]._type.flags.ref) ? " &" : ""}")
.to_array()
._fold()) |> join(",")
write(*ss, "");
}
}
write(*ss, "(__context__,nullptr,");
} elif (call.name == "memzero") {
write(*ss, "memset((void*)&(");
} elif (call.name == "static_assert") {
write(*ss, "das_static_assert(");
} else {
write(*ss, "{call.name}(");
}
}
def override canVisitExprLooksLikeCallArgument(call : ExprLooksLikeCall?; arg : ExpressionPtr; last : bool) {
if (!empty(call.arguments) && call.arguments[0] == arg && call is ExprInvoke) {
let inv = call as ExprInvoke;
if (inv.isInvokeMethod) return false;
}
return true;
}
def override preVisitExprLooksLikeCallArgument(call : ExprLooksLikeCall?; arg : ExpressionPtr; last : bool) {
if (call.name == "invoke") {
assume argType = arg._type;
if (arg._type.isRefType) {
if (needsArgPass(arg)) {
write(*ss, "das_arg::pass(");
}
}
}
}
def override visitExprLooksLikeCallArgument(call : ExprLooksLikeCall?; arg : ExpressionPtr; last : bool) {
if (call.name == "invoke") {
assume argType = arg._type;
if (arg._type.isRefType) {
if (needsArgPass(arg)) {
write(*ss, ")");
}
}
}
if (!last) {
if (call.name == "debug") {
write(*ss, "),(");
} else {
write(*ss, ",");
}
}
return arg;
}
def override visitExprLooksLikeCall(var call : ExprLooksLikeCall?) : ExpressionPtr {
if (call.name == "debug") {
write(*ss, "))");
} elif (call.name == "assert" || call.name == "verify") {
write(*ss, ",__context__)");
} elif (call.name == "memzero") {
assume cur_type = call.arguments[0]._type;
if (cross_platform) {
write(*ss, "), 0, TypeSize::size)");
} else {
write(*ss, "), 0, {cur_type.sizeOf})");
}
} else {
write(*ss, ")");
}
if (isInvokeWithTemp(call)) {
write(*ss, "))");
}
return call;
}
def policyArgNeedCast(polType : TypeDeclPtr; argType : TypeDeclPtr) {
if (argType.isVectorType) return false;
if (!polType.isHandle) {
if (polType.isVecPolicyType && argType.isVecPolicyType && argType.baseType != Type.tFloat16) return false;
}
return polType.isPolicyType;
}
def policyResultNeedCast(polType : TypeDeclPtr; resType : TypeDeclPtr) {
if (resType.isVoid || !resType.isPolicyType) return false;
if (resType.isVectorType && is_lattice_elem(resType.vectorBaseType)) return true;
return policyArgNeedCast(polType, resType);
}
def isPolicyBasedCall(call : ExprCall?) {
let bif = call.func as BuiltInFunction;
if (call.arguments |> empty() && call.func.result.baseType == Type.tHandle) return false;
return bif.flags.policyBased;
}
def isPolicyBasedCallFunc(call : ExprCallFunc?) {
if (call.func.flags.builtIn) {
let bif = call.func as BuiltInFunction;
if (bif.flags.policyBased) return true;
}
return false;
}
def isHybridCall(func : Function?) {
if (func.flags.builtIn) {
let bif = func as BuiltInFunction;
if (func.flags.policyBased) {
panic("we should not be here. policy based calls are handled elsewhere");
}
if (func.flags.callBased) {
panic("we should not be here. call-based calls handled elsewhere");
}
return empty(bif.cppName);
}
if (func.flags.noAot || func.flags.aotHybrid) return true;
return func._module != program.getThisModule;
}
def needsArgPassType(argType : TypeDeclPtr) {
return !argType.flags.constant && !argType.isGoodBlockType;
}
def needsArgPass(expr : ExpressionPtr) {
if (expr is ExprMakeBlock) {
let mkblk = expr as ExprMakeBlock;
let blk = mkblk._block as ExprBlock;
if (blk.blockFlags.aotSkipMakeBlock) return false;
}
return needsArgPassType(expr._type);
}
def isCallWithTemp(call : ExprCallFunc?) {
if (call is ExprCall) {
let expr = call as ExprCall;
return !expr.doesNotNeedSp && expr.stackTop != 0u;
}
return false;
}
def isInvokeWithTemp(call : ExprLooksLikeCall?) {
if (call is ExprInvoke) {
let inv = call as ExprInvoke;
return !inv.doesNotNeedSp && inv.stackTop != 0u;
}
return false;
}
def CallFunc_preVisit(call : ExprCallFunc?) { // nolint:STYLE037,STYLE038 - one arm per call-emission form
if (call.func.moreFlags.propertyFunction) {
if (call.func.result.flags.aotAlias) {
write(*ss, "das_alias::from(");
}
if (call.func.result.isString) {
write(*ss, "(({describeCppType(call.func.result,DescribeConfig(cross_platform=cross_platform))})(");
}
write(*ss, "((");
return ;
}
let aotName = get_aot_name(call.func, call);
for (ann in call.func.annotations) {
if (ann.annotation is FunctionAnnotation) {
let pAnn = ann.annotation as FunctionAnnotation;
if (!(aotPrefix |> key_exists(aotName))) {
aot_prefixes.push(build_string() $(writer) {
get_func_aot_prefix(pAnn, unsafe(addr(writer)), call);
})
aotPrefix |> insert(aotName);
}
}
}
if (isCallWithTemp(call)) {
write(*ss, "({makeLocalTempName(call)} = (");
}
if (call.func.result.flags.aotAlias) {
write(*ss, "das_alias::from(");
}
if (call.func.flags.builtIn) {
if (call.func.result.isString) {
write(*ss, "(({describeCppType(call.func.result,DescribeConfig(cross_platform=cross_platform))})(");
}
let bif = call.func as BuiltInFunction;
if (call.arguments |> empty() && call.func.result.baseType == Type.tHandle) {
write(*ss, "/*c-tor*/ ");
} elif (bif.flags.policyBased) {
outPolicy(call.arguments[0]._type);
write(*ss, "::");
}
if (bif.flags.interopFn) {
write(*ss, "das_call_interop::call(&");
}
write(*ss, "{aotName}");
if (bif.flags.interopFn) {
let nArgs : uint = uint(length(call.arguments));
write(*ss, ",__context__,SimNode_AotInterop(");
if (nArgs != 0u) {
write(*ss, "{outputCallTypeInfo(nArgs, call.arguments)},");
}
} else {
write(*ss, "(");
}
} else {
if (isHybridCall(call.func)) {
write(*ss, "das_invoke_function::invoke");
if (call.func.result.isRefType && !call.func.result.flags.ref) {
write(*ss, "_cmres");
}
assume mangledName = call.func |> get_mangled_name();
let hash = call.func.getMangledNameHash;
if (!empty(call.arguments)) {
write(*ss, "(__context__,nullptr,");
write(*ss, "{queryByMNH(mangledName, hash)},");
} else {
write(*ss, "(__context__,nullptr,");
write(*ss, queryByMNH(mangledName, hash));
}
} else {
write(*ss, "{aotFuncName(call.func)}(__context__");
if (!call.arguments |> empty()) write(*ss, ",");
}
}
}
def needSubstitute(argType : TypeDeclPtr; passType : TypeDeclPtr) {
if (argType.baseType == Type.anyArgument) return false;
let ref_matters = false;
let const_matters = false;
let temporary_matters = false;
let allow_substitute = false;
return !is_same_type(argType, passType, ref_matters, const_matters, temporary_matters, allow_substitute);
}
def needPtrCast(argType : TypeDeclPtr; passType : TypeDeclPtr; passExpr : ExpressionPtr) {
if (passExpr is ExprConstPtr) return true;
return argType.isVoidPointer ^^ passType.isVoidPointer;
}
def needStringCast(func : Function?; arg : TypeDeclPtr) {
return func.moreFlags.needStringCast && arg.isString && !arg.flags.ref;
}
def CallFunc_preVisitCallArg(call : ExprCallFunc?; arg : ExpressionPtr; is_last : bool) {
if (call.func.moreFlags.propertyFunction) return ;
var argIndex = 0;
for (it in range(length(call.arguments))) {
if (call.arguments[it] == arg) break;
argIndex++;
}
assert(argIndex != length(call.arguments));
write(*ss, "{get_aot_arg_prefix(call.func, call, argIndex)}");
assume argType = call.arguments[argIndex]._type;
assume funArgType = call.func.arguments[argIndex]._type;
if (call.func.flags.builtIn && funArgType.isAotAlias) {
if (funArgType.alias |> empty()) {
let fun_t_str = describeCppTypeEx(funArgType, DescribeConfig(skip_ref = true, redundant_const = true, cross_platform = cross_platform), CpptUseAlias.yes);
write(*ss, "das_reinterpret::pass(");
} else {
write(*ss, "das_alias::to(");
}
}
if (!call.func.flags.noPointerCast && needPtrCast(funArgType, arg._type, arg)) {
write(*ss, "das_auto_cast::cast(");
}
if (!call.func.flags.anyTemplate && (call.func.flags.interopFn || funArgType.baseType == Type.anyArgument)) {
let maybe_ref = argType.isRefType && !argType.flags.ref ? " &" : "";
write(*ss, "cast::from(");
}
if (needSubstitute(funArgType, arg._type)) {
write(*ss, "das_reinterpret::pass(");
}
if (!call.func.flags.interopFn && arg._type.isRefType) {
if (needsArgPass(arg)) {
write(*ss, "das_arg::pass(");
}
}
if (isPolicyBasedCallFunc(call) && policyArgNeedCast(call.func.result, argType)) {
write(*ss, "cast::from(");
}
if (needStringCast(call.func, argType)) {
write(*ss, "(das_string_cast(");
}
}
def CallFunc_visitCallArg(call : ExprCallFunc?; arg : ExpressionPtr; last : bool) {
if (call.func.moreFlags.propertyFunction) return ;
var argIndex = 0;
for (it in range(length(call.arguments))) {
if (call.arguments[it] == arg) break;
argIndex++;
}
assert(argIndex != length(call.arguments));
assume argType = call.func.arguments[argIndex]._type;
if (needStringCast(call.func, argType)) {
write(*ss, "))");
}
if (isPolicyBasedCallFunc(call) && policyArgNeedCast(call.func.result, argType)) {
write(*ss, ")");
}
assume funArgType = call.func.arguments[argIndex]._type;
if (!call.func.flags.anyTemplate && (call.func.flags.interopFn || funArgType.baseType == Type.anyArgument)) {
write(*ss, ")");
}
if (needSubstitute(funArgType, arg._type)) {
write(*ss, ")");
}
if (!call.func.flags.interopFn && arg._type.isRefType) {
if (needsArgPass(arg)) {
write(*ss, ")");
}
}
if (!call.func.flags.noPointerCast && needPtrCast(funArgType, arg._type, arg)) {
write(*ss, ")");
}
if (call.func.flags.builtIn && funArgType.isAotAlias) write(*ss, ")");
write(*ss, "{get_aot_arg_suffix(call.func, call, argIndex)}");
if (!last) {
write(*ss, ",");
}
}
def CallFunc_visit(call : ExprCallFunc?) {
if (call.func.moreFlags.propertyFunction) {
if (call.func.flags.builtIn) {
let efn = call.func as ExternalFnBase;
write(*ss, ").{efn.cppName}())");
} else {
peek(call.func.name) $(fn) {
assert(starts_with(fn, ".`"));
write(*ss, ").{aotFieldName(fn.chop(2, length(fn)))}())");
}
}
if (call.func.result.isString) {
write(*ss, "))");
}
if (call.func.result.flags.aotAlias) {
write(*ss, ")");
}
return ;
}
if (call.func.flags.interopFn) {
write(*ss, ")");
}
if (call.arguments |> empty() && call.func.result.baseType == Type.tHandle) {
write(*ss, "/*end-c-tor*/");
} elif (isPolicyBasedCallFunc(call)) {
write(*ss, ",*__context__,nullptr");
}
write(*ss, ")");
if (call.func.flags.builtIn && call.func.result.isString) {
write(*ss, "))");
}
if (call.func.result.flags.aotAlias) {
write(*ss, ")");
}
if (isCallWithTemp(call)) {
write(*ss, "))");
}
}
def override preVisitExprCall(call : ExprCall?) {
CallFunc_preVisit(call);
}
def override preVisitExprCallArgument(call : ExprCall?; arg : ExpressionPtr; last : bool) {
CallFunc_preVisitCallArg(call, arg, last);
}
def override visitExprCallArgument(call : ExprCall?; arg : ExpressionPtr; last : bool) {
CallFunc_visitCallArg(call, arg, last);
return arg;
}
def override visitExprCall(var call : ExprCall?) : ExpressionPtr {
CallFunc_visit(call);
return call;
}
def forSrcName(varName : das_string) {
return "__{aotSuffixNameEx(varName, "")}_iterator";
}
def needLoopName(ffor : ExprFor?) {
return "__need_loop_{ffor.at.line:d}";
}
def override preVisitExprFor(ffor : ExprFor?) {
write(*ss, "\{\n");
tab ++;
let nl = needLoopName(ffor);
write(*ss, "{tabs()}bool {nl} = true;\n");
}
def override preVisitExprForBody(ffor : ExprFor?) {
let nl = needLoopName(ffor);
write(*ss, "{tabs()}for ( ; {nl} ; {nl} = ");
for (variable in ffor.iteratorVariables) {
if (variable != ffor.iteratorVariables[0]) {
write(*ss, " && ");
}
write(*ss, "{forSrcName(variable.name)}.next(__context__,");
write(*ss, "({collector.getVarName(variable)}))");
}
write(*ss, " )\n");
write(*ss, "{tabs()}");
}
def isCountOrUCount(expr : ExpressionPtr) {
if (!(isExprCallFunc(expr))) return false;
assume call = unsafe(reinterpret(expr));
return call.func != null && call.func.flags.builtIn && call.func._module.name == "$" && (call.name == "count" || call.name == "ucount");
}
def override preVisitExprForSource(ffor : ExprFor?; that : ExpressionPtr; last : bool) {
var idx = 0;
let idxs = length(ffor.sources);
for (id in range(idxs)) {
if (ffor.sources[id] == that) break;
idx++
}
assume src = ffor.sources[idx];
assume variable = ffor.iteratorVariables[idx];
write(*ss, "{tabs()}// {variable.name}: {variable._type.describe()}\n");
if (isCountOrUCount(src)) {
write(*ss, "{tabs()}das_iterator_{(unsafe(reinterpret(src))).func.name} DAS_COMMENT(");
} else {
let type_str = describeCppType(src._type, DescribeConfig(substitute_ref = true, skip_ref = true, cross_platform = cross_platform));
write(*ss, "{tabs()}das_iterator {forSrcName(variable.name)}((");
}
}
def override visitExprForSource(ffor : ExprFor?; that : ExpressionPtr; last : bool) {
var idx = 0;
let idxs = length(ffor.sources);
for (id in range(idxs)) {
if (ffor.sources[id] == that) break;
idx++
}
assume src = ffor.sources[idx];
assume variable = ffor.iteratorVariables[idx];
if (isCountOrUCount(src)) {
assume pCall = unsafe(reinterpret(src));
write(*ss, ") {forSrcName(variable.name)}(");
visit_expression(pCall.arguments[0], adapter);
write(*ss, ",");
visit_expression(pCall.arguments[1], adapter);
write(*ss, ");\n");
} else {
write(*ss, "));\n");
}
let skipTC : bool = !variable._type.flags.ref
let cfg = DescribeConfig(substitute_ref = true, skip_const = skipTC, cross_platform = cross_platform)
let type_str = describeCppType(variable._type, cfg);
write(*ss, "{tabs()}{type_str} {collector.getVarName(variable)};\n");
let nl = needLoopName(ffor);
write(*ss, "{tabs()}{nl} = {forSrcName(variable.name)}.first(__context__,");
write(*ss, "({collector.getVarName(variable)})");
write(*ss, ") && {nl};\n");
return that;
}
def override visitExprFor(var ffor : ExprFor?) : ExpressionPtr {
write(*ss, "\n");
for (x in range(ffor.iteratorVariables |> length)) {
assume variable = ffor.iteratorVariables[ffor.iteratorVariables |> length - 1 - x];
write(*ss, "{tabs()}{forSrcName(variable.name)}.close(__context__,");
write(*ss, "({collector.getVarName(variable)}));\n");
}
tab --;
write(*ss, "{tabs()}\}");
return ffor;
}
};
def private aotEmitStruct(ps : Structure?;
emitSet : table;
var visited : table;
program : ProgramPtr;
adapter : VisitorAdapter?) {
if (visited |> key_exists(ps)) return ;
visited |> insert(ps);
for (fld in ps.fields) {
let ft = fld._type
if (ft.baseType == Type.tStructure && ft.structType != null && emitSet |> key_exists(ft.structType)) {
aotEmitStruct(ft.structType, emitSet, visited, program, adapter);
}
}
program |> visit_structure(ps, adapter);
}
def public dumpDependencies(program : ProgramPtr; var aotVisitor : CppAot?) {
//! Writes forward declarations and dependent type/function definitions for AOT output.
buildStructEnumCollisions(program);
var utm = new UseTypeMarker();
make_visitor(*utm) $(adapter) {
visit(program, adapter);
}
let remUS = program._options |> find_arg("remove_unused_symbols") ?as tBool ?? true;
program.get_ptr() |> for_each_module_no_order($(pm) {
if (pm.moduleFlags.fromExtraDependency) return ;
pm |> for_each_structure($(ps) {
write(*aotVisitor.ss, "namespace {aotModuleName(ps._module)} \{ struct {aotStructName(ps)}; \};\n");
});
});
program.get_ptr() |> for_each_module_no_order($(pm) {
if (pm == program.getThisModule || pm.moduleFlags.fromExtraDependency) return ;
pm |> for_each_enumeration($(penum) {
if (!remUS || utm.useEnums |> key_exists(penum)) {
program |> visit_enumeration(penum, aotVisitor.adapter)
} else {
write(*aotVisitor.ss, "// unused enumeration {penum.name}\n");
}
});
var emitSet : table;
pm |> for_each_structure($(ps) {
if (!remUS || utm.useStructs |> key_exists(ps)) {
emitSet |> insert(ps);
} else {
write(*aotVisitor.ss, "// unused structure {ps.name}\n");
}
});
var visited : table;
pm |> for_each_structure($(ps) {
if (emitSet |> key_exists(ps)) {
aotEmitStruct(ps, emitSet, visited, program, aotVisitor.adapter);
}
});
})
unsafe {
delete utm
}
}
class ArgsConverter : AstVisitor {
//! AST visitor that converts function arguments to C++ AOT calling conventions.
private arg_id : uint = 0u
private ss : StringBuilderWriter?
private cross_platform : bool
def ArgsConverter(var ss_ : StringBuilderWriter?; cp : bool) { ss = ss_; cross_platform = cp; }
def override canVisitFunction(fun : Function?) {
if (fun.flags.noAot) return false;
return !fun.moreFlags.isTemplate;
}
def override preVisitFunction(fn : FunctionPtr) {
write(*ss, "static vec4f __wrap_{aotFuncName(fn)} ( Context * __context__ ) \{\n")
assert(arg_id == 0u)
}
def override preVisitFunctionArgument(fn : FunctionPtr, arg : VariablePtr, last : bool) {
let type_name = build_string() $(writer) {
if (isLocalVec(arg._type)) {
describeLocalCppType(unsafe(addr(writer)), arg._type, cross_platform)
} else {
write(writer, describeCppType(arg._type, DescribeConfig(cross_platform = cross_platform)))
}
if (arg._type.isRefType) {
write(writer, " & ")
}
}
write(*ss, " {type_name} arg_{aotSuffixNameEx(arg.name, "")} = cast_aot_arg::to(*__context__,__context__->abiArguments()[{arg_id |> int}]);\n")
arg_id++
}
def override visitFunction(fn : FunctionPtr) {
let is_cmres = fn.flags.copyOnReturn || fn.flags.moveOnReturn
arg_id = 0u
write(*ss, " ")
if (!fn.result.isVoid && !is_cmres) {
write(*ss, "return cast::from(")
}
if (is_cmres) {
write(*ss, "*((")
describeLocalCppType(ss, fn.result, cross_platform, CpptSubstitureRef.no, CpptSkipConst.yes)
write(*ss, " *) __context__->abiCMRES) = ")
}
write(*ss, "{aotFuncName(fn)}(__context__")
for (arg in fn.arguments) {
write(*ss, ", arg_{aotSuffixNameEx(arg.name, "")}")
}
write(*ss, ")")
if (!fn.result.isVoid && !is_cmres) {
write(*ss, ");\n")
} else {
write(*ss, ";\n")
write(*ss, " return v_zero();\n")
}
write(*ss, "}\n")
return fn;
}
}
def collectUsedFunctions(modules : array; totalFunctions : int; this_module : Module?; all_modules : bool; is_all : bool = false) : array {
var fnn : array;
fnn.reserve(totalFunctions);
for (pm in modules) {
pm |> for_each_module_function($(pfun) {
if ((!all_modules && pfun._module != this_module)
|| pfun.index < 0 || !pfun.flags.used) return ;
if (!is_all) {
if (pfun.flags.builtIn || pfun.flags.noAot) return ;
}
fnn |> push(pfun);
});
}
return