Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 145 additions & 7 deletions daslib/aot_cpp.das
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,60 @@ def public describeCppFunc(fn : FunctionPtr; var collector : BlockVariableCollec
}
}

enum private ExitKind { None, Break, Continue, Return }

struct private TryExits {
hasBreak : bool
hasContinue : bool
hasReturn : bool
}

struct private TryFlowLevel {
isLoop : bool
exits : TryExits
flag : string
slot : string
}

struct private TryFlowState {
stack : array<TryFlowLevel>
ret_slot : string
ret_ptr : bool
}

class TryExitScanner : AstVisitor {
found : TryExits;
loopDepth : int = 0;

def override preVisitExprForBody(ffor : ExprFor?) {
loopDepth ++;
}
def override visitExprFor(var ffor : ExprFor?) : ExpressionPtr {
loopDepth --;
return ffor;
}
def override preVisitExprWhileBody(wh : ExprWhile?; body : ExpressionPtr) {
loopDepth ++;
}
def override visitExprWhile(var wh : ExprWhile?) : ExpressionPtr {
loopDepth --;
return wh;
}
def override preVisitExprBreak(that : ExprBreak?) {
found.hasBreak ||= loopDepth == 0;
}
def override preVisitExprContinue(that : ExprContinue?) {
found.hasContinue ||= loopDepth == 0;
}
def override preVisitExprReturn(expr : ExprReturn?) {
found.hasReturn ||= expr.returnFunc != null;
}
};

def private anyExit(exits : TryExits) {
return exits.hasBreak || exits.hasContinue || exits.hasReturn;
}

class public CppAot : AstVisitor {
//! Main AST visitor that generates C++ ahead-of-time compiled code from daslang AST.

Expand Down Expand Up @@ -1333,6 +1387,7 @@ class public CppAot : AstVisitor {
aotPrefix : table<string>;
@do_not_delete local_temp_names : table<Expression?; int>;
@do_not_delete scopes : array<ExprBlock?>;
flow : TryFlowState;
prologue : bool = false;
solidContext : bool = false;
cross_platform : bool = false;
Expand Down Expand Up @@ -1451,7 +1506,12 @@ class public CppAot : AstVisitor {
}
def write_local_temp_type(tmp : Expression?) : void {
write(*ss, tabs())
describeVarLocalCppType(ss, tmp._type, cross_platform)
if (tmp._type.flags.ref) {
write(*ss, describeCppType(tmp._type, DescribeConfig(skip_ref = true,
skip_const = true, cross_platform = cross_platform)))
} else {
describeVarLocalCppType(ss, tmp._type, cross_platform)
}
}

def override preVisitGlobalLet(prog : ProgramPtr) {
Expand Down Expand Up @@ -1500,6 +1560,9 @@ class public CppAot : AstVisitor {
return !fun.moreFlags.isTemplate;
}
def override preVisitFunction(fn : FunctionPtr) {
flow.ret_ptr = fn.result.flags.ref;
flow.ret_slot = fn.result.isVoid ? "" : describeCppType(fn.result, DescribeConfig(skip_const = true,
skip_ref = true, cross_platform = cross_platform)) + (flow.ret_ptr ? " *" : "");
if (!empty(aot_filter_function) && (fn.name == aot_filter_function || aotFuncName(fn) == aot_filter_function)) {
write(*ss, "\n/*<<AOT_FUNC_BEGIN>>*/");
}
Expand Down Expand Up @@ -2190,8 +2253,15 @@ class public CppAot : AstVisitor {
}
return that;
}
def returnLevel(expr : ExprReturn?) : int {
return expr.returnFunc == null ? -1 : flowLevel(ExitKind.Return);
}
def override preVisitExprReturn(expr : ExprReturn?) {
write(*ss, "return ");
let at = returnLevel(expr);
write(*ss, at < 0 ? "return " : "\{ ");
if (at >= 0 && flow.stack[at].slot != "") {
write(*ss, "{flow.stack[at].slot} = {flow.ret_ptr ? "&(" : ""}");
Comment on lines +2262 to +2263

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Added new test

}
if (expr.returnFlags.moveSemantics) {
write(*ss, "/* <- */ ");
}
Expand All @@ -2218,17 +2288,24 @@ class public CppAot : AstVisitor {
write(*ss, "/* no function/block for return */ ");
return expr;
}
let at = returnLevel(expr);
assume retT = expr.returnFunc != null ? expr.returnFunc.result : expr._block.returnType;
if (!retT.isVoid) {
write(*ss, ")");
if (at >= 0 && flow.ret_ptr) {
write(*ss, ")");
}
}
if (at >= 0) {
write(*ss, "{retT.isVoid ? "" : "; "}{flow.stack[at].flag} = {int(ExitKind.Return)}; return; \}");
}
return expr;
}
def override preVisitExprBreak(that : ExprBreak?) {
write(*ss, "break");
writeExit(ExitKind.Break, "");
}
def override preVisitExprContinue(that : ExprContinue?) {
write(*ss, "continue");
writeExit(ExitKind.Continue, "");
}
def override preVisitExprVar(variable : ExprVar?) {
if (variable._type.flags.aotAlias) {
Expand Down Expand Up @@ -2761,11 +2838,14 @@ class public CppAot : AstVisitor {
}
return c;
}
def override canVisitWithAliasSubexpression(_expr : ExprAssume?) : bool {
return false;
}
def override preVisitExprAssume(expr : ExprAssume?) {
write(*ss, "\n#if 0 // with, note optimizations are off\n");
write(*ss, "\n#if 0 // assume {expr.alias} = {describe(expr.subexpr) |> replace("\n", " ")}\n");
}
def override visitExprAssume(var expr : ExprAssume?) : ExpressionPtr {
write(*ss, "\n#endif\n");
write(*ss, "\n#endif // assume {expr.alias}\n");
return expr;
}
def override preVisitExprWith(expr : ExprWith?) {
Expand All @@ -2779,8 +2859,10 @@ class public CppAot : AstVisitor {
}
def override preVisitExprWhileBody(wh : ExprWhile?; body : ExpressionPtr) {
write(*ss, " )\n{tabs()}");
flow.stack |> push(TryFlowLevel(isLoop = true));
}
def override visitExprWhile(var wh : ExprWhile?) : ExpressionPtr {
flow.stack |> pop();
return wh;
}
def override preVisitExprIfThenElse(ifte : ExprIfThenElse?) {
Expand Down Expand Up @@ -2986,7 +3068,49 @@ class public CppAot : AstVisitor {
write(*ss, ")");
return expr;
}
def flowLevel(code : ExitKind) : int {
for (i in range(length(flow.stack))) {
let at = length(flow.stack) - 1 - i;
assume lvl = flow.stack[at];
if (!lvl.isLoop) return lvl.flag != "" ? at : -1;
if (code != ExitKind.Return) return -1;
}
return -1;
}
def writeExit(code : ExitKind; slot : string) {
let at = flowLevel(code);
if (at >= 0) {
write(*ss, "\{ {flow.stack[at].flag} = {int(code)}; return; \}");
} elif (code == ExitKind.Break) {
write(*ss, "break");
} elif (code == ExitKind.Continue) {
write(*ss, "continue");
} else {
write(*ss, "return {slot == "" ? "" : (flow.ret_ptr ? "*" : "") + slot}");
}
}
def scanExits(tc : ExprTryCatch?) : TryExits {
var scanner = new TryExitScanner();
make_visitor(*scanner) $(adp) {
tc.try_block |> visit(adp);
tc.catch_block |> visit(adp);
}
return scanner.found;
}
def override preVisitExprTryCatch(tc : ExprTryCatch?) {
var lvl = TryFlowLevel(exits = scanExits(tc));
if (anyExit(lvl.exits)) {
lvl.flag = "__try_flow_{int(tc.at.line)}_{int(tc.at.column)}";
write(*ss, "int32_t {lvl.flag} = {int(ExitKind.None)};\n{tabs()}");
let at = flowLevel(ExitKind.Return);
if (at >= 0) {
lvl.slot = flow.stack[at].slot;
} elif (lvl.exits.hasReturn && flow.ret_slot != "") {
lvl.slot = "__try_ret_{int(tc.at.line)}_{int(tc.at.column)}";
write(*ss, "{flow.ret_slot} {lvl.slot};\n{tabs()}");
}
}
flow.stack |> push(lvl);
write(*ss, "das_try_recover(__context__, [&]()\n");
write(*ss, "{tabs()}");
}
Expand All @@ -2996,6 +3120,18 @@ class public CppAot : AstVisitor {
}
def override visitExprTryCatch(var tc : ExprTryCatch?) : ExpressionPtr {
write(*ss, ")");
let lvl = flow.stack[length(flow.stack) - 1];
flow.stack |> pop();
if (!anyExit(lvl.exits)) return tc;
write(*ss, ";");
let taken = fixed_array(lvl.exits.hasBreak, lvl.exits.hasContinue, lvl.exits.hasReturn);
let codes = fixed_array(ExitKind.Break, ExitKind.Continue, ExitKind.Return);
for (t, code in taken, codes) {
if (!t) continue;
write(*ss, "\n{tabs()}if ( {lvl.flag} == {int(code)} ) \{ ");
writeExit(code, lvl.slot);
write(*ss, "; \}");
}
return tc;
}
def isDistinctDeref(ptr2ref : ExprPtr2Ref?) {
Expand Down Expand Up @@ -3083,7 +3219,7 @@ class public CppAot : AstVisitor {
let info : TypeInfo? = (expr.ascendFlags.needTypeInfo
? helper.helper |> make_type_info(null, expr.subexpr._type)
: null);
if (expr._type.firstType.baseType == Type.tHandle) {
if (expr._type.baseType == Type.tPointer && expr._type.firstType.baseType == Type.tHandle) {
write(*ss, "das_ascend_handle<{expr._type.flags.smartPtr},{describeCppType(expr._type,DescribeConfig(skip_ref=true,skip_const=true,cross_platform=cross_platform))}>::make(__context__,");
} else {
let type_str = describeCppType(expr._type.firstType, DescribeConfig(skip_ref = true, skip_const = true, cross_platform = cross_platform));
Expand Down Expand Up @@ -3932,6 +4068,7 @@ class public CppAot : AstVisitor {
write(*ss, "{tabs()}bool {nl} = true;\n");
}
def override preVisitExprForBody(ffor : ExprFor?) {
flow.stack |> push(TryFlowLevel(isLoop = true));
let nl = needLoopName(ffor);
write(*ss, "{tabs()}for ( ; {nl} ; {nl} = ");
for (variable in ffor.iteratorVariables) {
Expand Down Expand Up @@ -3997,6 +4134,7 @@ class public CppAot : AstVisitor {
return that;
}
def override visitExprFor(var ffor : ExprFor?) : ExpressionPtr {
flow.stack |> pop();
write(*ss, "\n");
for (x in range(ffor.iteratorVariables |> length)) {
assume variable = ffor.iteratorVariables[ffor.iteratorVariables |> length - 1 - x];
Expand Down
2 changes: 1 addition & 1 deletion include/daScript/ast/ast_generate.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ namespace das {
give variables in the scope of 'expr' block unique names
only for the top-level block
*/
void giveBlockVariablesUniqueNames ( ExpressionPtr expr );
bool giveBlockVariablesUniqueNames ( ExpressionPtr expr );

/*
replace break and continue of a particular loop
Expand Down
2 changes: 1 addition & 1 deletion include/daScript/misc/vectypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ namespace das
}
uint32_t base, sh;
if ( em < ((127u - 14u) << 23) ) { // subnormal half
sh = 126u - (em >> 23) + 13u + 1u;
sh = 126u - (em >> 23);
base = (em & 0x7fffffu) | 0x800000u;
} else { // normal half
sh = 13u;
Expand Down
9 changes: 5 additions & 4 deletions include/daScript/simulate/sim_policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,12 @@ namespace das {
static __forceinline int32_t Mod ( int32_t a, int32_t b, Context & context, LineInfo * at ) {
if ( b==0 ) context.throw_error_at(at, "division by zero in modulo");
double A = a, B = b;
return a - int32_t(A/B)*b;
return int32_t(a - int64_t(A/B)*b);
}
static __forceinline void SetMod ( int32_t & a, int32_t b, Context & context, LineInfo * at ) {
if ( b==0 ) context.throw_error_at(at, "division by zero in modulo");
double A = a, B = b;
a = a - int32_t(A/B)*b;
a = int32_t(a - int64_t(A/B)*b);
}
};

Expand Down Expand Up @@ -179,6 +179,7 @@ namespace das {
};

struct SimPolicy_Double : SimPolicy_Type<double>, SimPolicy_MathTT<double> {
static __forceinline double Abs ( double a, Context &, LineInfo * ) { return fabs(a); }
static __forceinline double Div ( double a, double b, Context &, LineInfo * ) { return a / b; }
static __forceinline void SetDiv ( double & a, double b, Context &, LineInfo * ) { a /= b; }
static __forceinline double Mod ( double a, double b, Context &, LineInfo * ) { return fmod(a,b); }
Expand Down Expand Up @@ -232,7 +233,7 @@ namespace das {

struct SimPolicy_MathFloat {
static __forceinline float Sign ( float a, Context &, LineInfo * ) { return a == 0.0f ? 0.0f : (a > 0.0f) ? 1.0f : -1.0f; }
static __forceinline float Abs ( float a, Context &, LineInfo * ) { return v_extract_x(v_abs(v_set_x(a))); }
static __forceinline float Abs ( float a, Context &, LineInfo * ) { return fabsf(a); }
static __forceinline float Floor ( float a, Context &, LineInfo * ) { return v_extract_x(v_floor(v_set_x(a))); }
static __forceinline float Ceil ( float a, Context &, LineInfo * ) { return v_extract_x(v_ceil(v_set_x(a))); }
static __forceinline float Round ( float a, Context &, LineInfo * ) { return v_extract_x(v_round(v_set_x(a))); }
Expand Down Expand Up @@ -284,7 +285,7 @@ namespace das {
return v_or(v_and(v_splats(1.0f), v_cmp_gt(a, v_zero())), v_and(v_splats(-1.0f), v_cmp_lt(a, v_zero())));
}

static __forceinline vec4f Abs ( vec4f a, Context &, LineInfo * ) { return v_abs(a); }
static __forceinline vec4f Abs ( vec4f a, Context &, LineInfo * ) { return v_andnot(v_msbit(), a); }
static __forceinline vec4f Floor ( vec4f a, Context &, LineInfo * ) { return v_floor(a); }
static __forceinline vec4f Ceil ( vec4f a, Context &, LineInfo * ) { return v_ceil(a); }
static __forceinline vec4f Fract ( vec4f a, Context &, LineInfo * ) { return v_sub(a, v_floor(a)); }
Expand Down
4 changes: 4 additions & 0 deletions modules/dasLLVM/daslib/llvm_exe.das
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ class public CollectExternVisitor : AstVisitor {

// Create the initialize_modules() function, position a builder in it, and emit das_ensure_environment
// plus the builtin-module registrations (all native modules if register_all, else $ + strings). Returns the builder.
def override canVisitWithAliasSubexpression(expr : ExprAssume?) : bool {
return false
}

def private setup_init_builder(register_all : bool) : LLVMBuilderRef {
let init_fn = LLVMGetNamedFunction(g_mod, "initialize_modules")
let init_entry = LLVMAppendBasicBlockInContext(ctx, init_fn, "entry")
Expand Down
43 changes: 43 additions & 0 deletions modules/dasLLVM/daslib/llvm_jit.das
Original file line number Diff line number Diff line change
Expand Up @@ -2982,6 +2982,32 @@ class public LlvmJitVisitor : AstVisitor {
LLVMPositionBuilderAtEnd(g_builder, check_end)
}

def division_overflow_cond(lval, right : LLVMOpaqueValue?; opType : TypeDeclPtr) : LLVMOpaqueValue? {
if (opType.baseType != Type.tInt && opType.baseType != Type.tInt64) {
panic("division overflow guard on {describe(opType)}")
}
let ty = type_to_llvm_type(opType)
let intMin = 1ul << uint64(LLVMGetIntTypeWidth(ty) - 1u)
var is_min = LLVMBuildICmp(g_builder, LLVMIntPredicate.LLVMIntEQ, lval,
LLVMConstInt(ty, intMin, 0), "cmp_is_intmin")
var is_m1 = LLVMBuildICmp(g_builder, LLVMIntPredicate.LLVMIntEQ, right,
LLVMConstAllOnes(ty), "cmp_is_minus_one")
return LLVMBuildAnd(g_builder, is_min, is_m1, "cmp_div_ovf")
}

def check_division_overflow(lval, right : LLVMOpaqueValue?; at : LineInfo; opType : TypeDeclPtr) {
var check_ovf = append_basic_block("check_div_ovf")
var check_true = append_basic_block("check_ovf_true")
var check_end = append_basic_block("check_ovf_end")
LLVMBuildBr(g_builder, check_ovf)
LLVMPositionBuilderAtEnd(g_builder, check_ovf)
LLVMBuildCondBr(g_builder, division_overflow_cond(lval, right, opType), check_true, check_end)
LLVMPositionBuilderAtEnd(g_builder, check_true)
build_exception("division overflow", at)
LLVMBuildBr(g_builder, check_end)
LLVMPositionBuilderAtEnd(g_builder, check_end)
}

def isExprIntNZ(expr : ExpressionPtr) {
return (((expr is ExprConstInt) && (expr as ExprConstInt).value != 0)
|| ((expr is ExprConstUInt) && (expr as ExprConstUInt).value != 0u)
Expand Down Expand Up @@ -3195,6 +3221,15 @@ class public LlvmJitVisitor : AstVisitor {
if (!isExprIntNZ(expr.right)) {
check_divide_by_0(right, expr.at, opType, string(expr.op))
}
if (opType.isSignedInteger) {
let lval = expr.op == "/" || expr.op == "%" ? left : r2v_left
if (expr.op == "%" || expr.op == "%=") {
right = LLVMBuildSelect(g_builder, division_overflow_cond(lval, right, opType),
LLVMConstInt(type_to_llvm_type(opType), 1ul, 0), right, "mod_ovf_to_1")
} else {
check_division_overflow(lval, right, expr.at, opType)
}
}
}
if (expr.op == "/") {
if (opType.isSignedInteger || (opType.isVectorType && opType.vectorBaseType == Type.tInt)) {
Expand Down Expand Up @@ -7652,6 +7687,10 @@ class public ResolveExternVisitor : AstVisitor {
@do_not_delete thisBlock : array<ExprBlock?>
uid : UidNodes?

def override canVisitWithAliasSubexpression(expr : ExprAssume?) : bool {
return false
}

def override preVisitFunction(var fun : FunctionPtr) : void {
uid.reset(fun)
thisFunc = fun
Expand Down Expand Up @@ -8191,6 +8230,10 @@ class public DisableJitVisitor : AstVisitor {
def TypeInfoVisitor {
disable = false
}

def override canVisitWithAliasSubexpression(expr : ExprAssume?) : bool {
return false
}
// Default-argument inits are inlined into call sites at infer, so the copy left on the
// argument is a dead husk LlvmJitVisitor declines too - and ClearUnusedSymbols nulls refs
// inside it, so expr.func there is legitimately null.
Expand Down
Loading
Loading