Skip to content

Commit

Permalink
compiler: initialize the new --opt-dynamic optimization flag
Browse files Browse the repository at this point in the history
  • Loading branch information
mertcandav committed Aug 22, 2024
1 parent 1c16d34 commit 3918622
Show file tree
Hide file tree
Showing 12 changed files with 263 additions and 10 deletions.
12 changes: 12 additions & 0 deletions api/any.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,18 @@ namespace jule
return this->data.template as<T>();
}

template <typename T>
inline T unsafe_cast(void) const noexcept
{
return *reinterpret_cast<T *>(this->data.alloc);
}

template <typename T>
inline jule::Ptr<T> unsafe_cast_ptr(void) const noexcept
{
return this->data.template as<T>();
}

inline jule::Any &operator=(const jule::Any &src) noexcept
{
this->dealloc();
Expand Down
1 change: 1 addition & 0 deletions src/julec/compile.jule
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ fn checkFlags(&args: []str): []str {
fs.AddVar[bool](unsafe { (&bool)(&opt::Assign) }, "opt-assign", 0, "Assignment optimizations")
fs.AddVar[bool](unsafe { (&bool)(&opt::Exceptional) }, "opt-exceptional", 0, "Exceptional optimizations")
fs.AddVar[bool](unsafe { (&bool)(&opt::Iter) }, "opt-iter", 0, "Iterations optimizations")
fs.AddVar[bool](unsafe { (&bool)(&opt::Dynamic) }, "opt-dynamic", 0, "Dynamic programming optimizations")

mut content := fs.Parse(args) else {
Throw(str(error))
Expand Down
21 changes: 21 additions & 0 deletions src/julec/obj/cxx/expr.jule
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use opt::{
StrCompExprModel,
EmptyCompareExprModel,
UnsafeDerefExprModel,
UnsafeCastingExprModel,
}
use conv for std::conv
use std::env::{Arch}
Expand Down Expand Up @@ -97,6 +98,7 @@ enum compExprModel: type {
&RefExprModel,
&EmptyCompareExprModel,
&UnsafeDerefExprModel,
&UnsafeCastingExprModel,
}

struct exprCoder {
Expand Down Expand Up @@ -1361,6 +1363,23 @@ impl exprCoder {
}
}

fn unsafeCasting(mut &self, mut m: &UnsafeCastingExprModel) {
match {
| isAny(m.Base.ExprKind):
self.possibleRefExpr(m.Base.Expr.Model)
if m.Base.Kind.Sptr() != nil {
self.oc.write(".unsafe_cast_ptr<")
self.oc.tc.kind(self.oc.Buf, m.Base.Kind.Sptr().Elem)
} else {
self.oc.write(".unsafe_cast<")
self.oc.tc.kind(self.oc.Buf, m.Base.Kind)
}
self.oc.write(">()")
|:
panic("implementation mistake, this panic call should be unreachable")
}
}

fn model(mut &self, mut m: compExprModel) {
match type m {
| str:
Expand Down Expand Up @@ -1455,6 +1474,8 @@ impl exprCoder {
self.emptyCompare((&EmptyCompareExprModel)(m))
| &UnsafeDerefExprModel:
self.unsafeDeref((&UnsafeDerefExprModel)(m))
| &UnsafeCastingExprModel:
self.unsafeCasting((&UnsafeCastingExprModel)(m))
|:
self.oc.write("<unimplemented_expression_model>")
}
Expand Down
2 changes: 1 addition & 1 deletion src/julec/opt/boundary.jule
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::jule::constant::{Const}
use std::jule::lex::{TokenId}
use std::jule::sema::{Var, StructSubIdentExprModel, UnaryExprModel, ExprModel, TypeKind}

const invalidBoundary = 0x0
const invalidBoundary = uintptr(0x0)

struct boundaryVar {
var: uintptr
Expand Down
1 change: 1 addition & 0 deletions src/julec/opt/data.jule
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ static mut emptyData = new(data)
struct data {
boundary: &boundary
nils: &nils
dynamic: &dynamic
}
145 changes: 145 additions & 0 deletions src/julec/opt/dynamic.jule
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright 2024 The Jule Programming Language.
// Use of this source code is governed by a BSD 3-Clause
// license that can be found in the LICENSE file.

use std::jule::lex::{TokenId}
use std::jule::sema::{
Data,
Var,
TypeKind,
ExprModel,
StructSubIdentExprModel,
UnaryExprModel,
CastingExprModel,
}

const invalidDynamic = uintptr(0x0)

struct dynamicVar {
var: uintptr
kind: &TypeKind
}

// Information wrapper for type analysis for dynamic types.
struct dynamic {
vars: []&dynamicVar
}

impl dynamic {
// Appends variable with initial kind.
// If variable is already exist, updates kind information.
fn pushVar(mut &self, var: uintptr, mut kind: &TypeKind) {
if !Dynamic || var == invalidDynamic {
// Ignore it, because this optimizations within scope of the --opt-access flag.
ret
}
kind = isTypeGuaranteedDynamicData(self, kind, nil) // Just accept guaranteed types as kind.
for (_, mut v) in self.vars {
if v.var == var {
v.kind = kind
ret
}
}
// Not exist, append new one.
for (_, mut v) in self.vars {
if v.var == invalidDynamic {
// Empty place, use here instead of append.
v.var, v.kind = var, kind
ret
}
}
self.vars = append(self.vars, &dynamicVar{var: var, kind: kind})
}

fn removeVar(mut self, var: uintptr): bool {
if var != invalidDynamic {
for (_, mut v) in self.vars {
if v.var == var {
v.var = invalidDynamic
v.kind = nil
ret true
}
}
}
ret false
}

// Reports whether variable is fits with kind.
fn isFits(mut self, var: uintptr, kind: &TypeKind): bool {
if var != invalidDynamic {
for _, v in self.vars {
if v.var == var {
ret v.kind != nil && v.kind.Equal(kind)
}
}
}
ret false
}
}

fn possibleDynamicRemove(mut &d: &dynamic, m: ExprModel) {
if d != nil {
_ = d.removeVar(getDynamicVar(m))
}
}

fn isDynamicValidType(mut t: &TypeKind): bool { ret isAny(t) }

fn isTypeGuaranteedDynamicData(mut &dy: &dynamic, mut t: &TypeKind, mut m: ExprModel): &TypeKind {
isAny := isAny(t)
if !isAny && t.Trait() == nil {
ret t
}
if !isAny {
ret nil
}
match type m {
| &CastingExprModel:
mut cem := (&CastingExprModel)(m)
ret isTypeGuaranteedDynamicData(dy, cem.ExprKind, cem.Expr.Model)
}
var := getDynamicVar(m)
if var == invalidDynamic {
ret nil
}
for (_, mut v) in dy.vars {
if v.var == var {
ret v.kind
}
}
ret nil
}

fn getDynamicVar(m: ExprModel): uintptr {
if !Dynamic {
ret invalidDynamic
}
match type m {
| &Var:
v := (&Var)(m)
if !v.Reference {
// Variable is not reference, return address of it.
ret uintptr((&Var)(m))
}
// Variable is reference, it should be initialized at source code.
// Investigate the initial expression for variable address.
ret getDynamicVar(v.Value.Data.Model)
| &StructSubIdentExprModel:
ret uintptr((&StructSubIdentExprModel)(m).Field)
| &UnaryExprModel:
uem := (&UnaryExprModel)(m)
if uem.Op.Id == TokenId.Star { // Dereferencing.
ret getDynamicVar(uem.Expr.Model)
}
}
ret invalidDynamic
}

// Reports whether type is handled as <any> type.
fn isAny(mut &t: &TypeKind): bool {
if t.TypeEnum() != nil {
ret true
}
prim := t.Prim()
ret prim != nil && prim.IsAny()
}
22 changes: 19 additions & 3 deletions src/julec/opt/expr.jule
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,9 @@ impl exprOptimizer {
if self.data.nils != nil {
possibleNilRemove(self.data.nils, arg.Expr.Model)
}
if self.data.dynamic != nil {
possibleDynamicRemove(self.data.dynamic, arg.Expr.Model)
}
exprOptimizer.optimizeData(arg.Expr.Model, self.data)
}
}
Expand All @@ -498,22 +501,35 @@ impl exprOptimizer {
}

fn casting(self, mut m: &CastingExprModel) {
valid := isDynamicValidType(m.ExprKind)
var := getDynamicVar(m.Expr.Model)
if valid && self.data.dynamic != nil && self.data.dynamic.isFits(var, m.Kind) {
mut model := any(&UnsafeCastingExprModel{Base: m})
*self.model = unsafe { *(*ExprModel)(&model) }
ret
}
exprOptimizer.optimizeData(m.Expr.Model, self.data)
if self.data.dynamic != nil && valid {
self.data.dynamic.pushVar(var, m.Kind)
}
}

fn args(self, mut params: []&ParamIns, mut &args: []ExprModel) {
for (i, mut arg) in args {
if i < len(params) {
mut p := params[i]
if p.Decl.Mutable && p.Decl.Reference {
match {
| self.data.boundary != nil:
if self.data.boundary != nil {
if isBoundaryRiskyType(p.Kind) {
possibleBoundaryRemove(self.data.boundary, arg)
}
| self.data.nils != nil:
}
if self.data.nils != nil {
possibleNilRemove(self.data.nils, arg)
}
if self.data.dynamic != nil {
possibleDynamicRemove(self.data.dynamic, arg)
}
}
}
exprOptimizer.optimizeData(arg, self.data)
Expand Down
6 changes: 4 additions & 2 deletions src/julec/opt/flag.jule
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ enum OptLevel {
L0,

// Passed flags:
// Copy, Deadcode, Append, Math, Access, Inline,
// Ptr, Cond, Str, Slice, Assign, Exceptional, Iter
// Copy, Deadcode, Append, Math, Access, Inline, Ptr,
// Cond, Str, Slice, Assign, Exceptional, Iter, Dynamic
L1,
}

Expand All @@ -26,6 +26,7 @@ static mut Slice = false
static mut Assign = false
static mut Exceptional = false
static mut Iter = false
static mut Dynamic = false

// Pushes optimization flags related with optimization level.
fn PushOptLevel(level: OptLevel) {
Expand All @@ -44,4 +45,5 @@ fn PushOptLevel(level: OptLevel) {
Assign = l1
Exceptional = l1
Iter = l1
Dynamic = l1
}
5 changes: 5 additions & 0 deletions src/julec/opt/model.jule
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use std::jule::sema::{
FnCallExprModel,
RangeIter,
UnaryExprModel,
CastingExprModel,
}

struct ExceptionalForwardingExprModel {
Expand Down Expand Up @@ -74,4 +75,8 @@ struct StrRuneIter {

struct UnsafeDerefExprModel {
Base: &UnaryExprModel
}

struct UnsafeCastingExprModel {
Base: &CastingExprModel
}
3 changes: 1 addition & 2 deletions src/julec/opt/nil.jule
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ use std::jule::sema::{
TypeKind,
ExprModel,
StructSubIdentExprModel,
UnaryExprModel,
BuiltinNewCallExprModel,
}

const invalidNil = 0x0
const invalidNil = uintptr(0x0)

struct nilVar {
var: uintptr
Expand Down
3 changes: 2 additions & 1 deletion src/julec/opt/optimizer.jule
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,6 @@ impl Optimizer {

fn detectEnabled() {
exprEnabled = Ptr || Math || Access || Cond
scopeEnabled = Cond || Append || Copy || Str || Slice || Assign || Exceptional || Iter
scopeEnabled = Cond || Append || Copy || Str || Slice || Assign || Exceptional ||
Iter || Dynamic
}
Loading

0 comments on commit 3918622

Please sign in to comment.