Compare commits
19 Commits
0818f5804e
...
bc692aaaf5
Author | SHA1 | Date |
---|---|---|
David Mak | bc692aaaf5 | |
David Mak | 830835f0f3 | |
David Mak | 38fd7b62e1 | |
David Mak | 605cf6e913 | |
David Mak | 460b150a34 | |
David Mak | 61ce788843 | |
David Mak | 2d941157a1 | |
David Mak | e308846cd8 | |
David Mak | cff30b81b1 | |
David Mak | 49d132702f | |
David Mak | 352f70b885 | |
David Mak | e95586f61e | |
David Mak | bb27e3d400 | |
David Mak | bb5147521f | |
David Mak | 9518d3fe14 | |
David Mak | cbd333ab10 | |
David Mak | 65d6104d00 | |
David Mak | 8373a6cb0f | |
David Mak | f75ae78677 |
|
@ -4,9 +4,9 @@ version = 3
|
|||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.6"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
|
@ -15,14 +15,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.3"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -387,7 +388,7 @@ version = "0.11.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
dependencies = [
|
||||
"ahash 0.7.6",
|
||||
"ahash 0.7.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -674,7 +675,7 @@ dependencies = [
|
|||
name = "nac3parser"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"ahash 0.8.3",
|
||||
"ahash 0.8.5",
|
||||
"insta",
|
||||
"lalrpop",
|
||||
"lalrpop-util",
|
||||
|
@ -1547,3 +1548,23 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
|||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c19fae0c8a9efc6a8281f2e623db8af1db9e57852e04cde3e754dd2dc29340f"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc56589e9ddd1f1c28d4b4b5c773ce232910a6bb67a70133d61c9e347585efe9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
|
|
@ -18,6 +18,13 @@ class EmbeddingMap:
|
|||
"SPIError",
|
||||
"0:ZeroDivisionError",
|
||||
"0:IndexError",
|
||||
"0:ValueError",
|
||||
"0:RuntimeError",
|
||||
"0:AssertionError",
|
||||
"0:KeyError",
|
||||
"0:NotImplementedError",
|
||||
"0:OverflowError",
|
||||
"0:IOError",
|
||||
"0:UnwrapNoneError"])
|
||||
|
||||
def preallocate_runtime_exception_names(self, names):
|
||||
|
|
|
@ -28,9 +28,17 @@ use std::{
|
|||
|
||||
pub struct ArtiqCodeGenerator<'a> {
|
||||
name: String,
|
||||
|
||||
/// The size of a `size_t` variable in bits.
|
||||
size_t: u32,
|
||||
|
||||
/// Monotonic counter for naming `start`/`stop` variables used by `with parallel` blocks.
|
||||
name_counter: u32,
|
||||
|
||||
/// Variable for tracking the start of a `with parallel` block.
|
||||
start: Option<Expr<Option<Type>>>,
|
||||
|
||||
/// Variable for tracking the end of a `with parallel` block.
|
||||
end: Option<Expr<Option<Type>>>,
|
||||
timeline: &'a (dyn TimeFns + Sync),
|
||||
}
|
||||
|
@ -42,7 +50,81 @@ impl<'a> ArtiqCodeGenerator<'a> {
|
|||
timeline: &'a (dyn TimeFns + Sync),
|
||||
) -> ArtiqCodeGenerator<'a> {
|
||||
assert!(size_t == 32 || size_t == 64);
|
||||
ArtiqCodeGenerator { name, size_t, name_counter: 0, start: None, end: None, timeline }
|
||||
ArtiqCodeGenerator {
|
||||
name,
|
||||
size_t,
|
||||
name_counter: 0,
|
||||
start: None,
|
||||
end: None,
|
||||
timeline,
|
||||
}
|
||||
}
|
||||
|
||||
/// If the generator is currently in a direct-`parallel` block context, emits IR that resets the
|
||||
/// position of the timeline to the initial timeline position before entering the `parallel`
|
||||
/// block.
|
||||
///
|
||||
/// Direct-`parallel` block context refers to when the generator is generating statements whose
|
||||
/// closest parent `with` statement is a `with parallel` block.
|
||||
fn timeline_reset_start<'ctx, 'b>(
|
||||
&mut self,
|
||||
ctx: &mut CodeGenContext<'ctx, 'b>
|
||||
) -> Result<(), String> {
|
||||
if let Some(start) = self.start.clone() {
|
||||
let start_val = self.gen_expr(ctx, &start)?
|
||||
.unwrap()
|
||||
.to_basic_value_enum(ctx, self, start.custom.unwrap())?;
|
||||
self.timeline.emit_at_mu(ctx, start_val);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// If the generator is currently in a `parallel` block context, emits IR that updates the
|
||||
/// maximum end position of the `parallel` block as specified by the timeline `end` value.
|
||||
///
|
||||
/// In general the `end` parameter should be set to `self.end` for updating the maximum end
|
||||
/// position for the current `parallel` block. Other values can be passed in to update the
|
||||
/// maximum end position for other `parallel` blocks.
|
||||
///
|
||||
/// `parallel`-block context refers to when the generator is generating statements within a
|
||||
/// (possibly indirect) `parallel` block.
|
||||
///
|
||||
/// * `store_name` - The LLVM value name for the pointer to `end`. `.addr` will be appended to
|
||||
/// the end of the provided value name.
|
||||
fn timeline_update_end_max<'ctx, 'b>(
|
||||
&mut self,
|
||||
ctx: &mut CodeGenContext<'ctx, 'b>,
|
||||
end: Option<Expr<Option<Type>>>,
|
||||
store_name: Option<&str>,
|
||||
) -> Result<(), String> {
|
||||
if let Some(end) = end {
|
||||
let old_end = self.gen_expr(ctx, &end)?
|
||||
.unwrap()
|
||||
.to_basic_value_enum(ctx, self, end.custom.unwrap())?;
|
||||
let now = self.timeline.emit_now_mu(ctx);
|
||||
let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
||||
let i64 = ctx.ctx.i64_type();
|
||||
ctx.module.add_function(
|
||||
"llvm.smax.i64",
|
||||
i64.fn_type(&[i64.into(), i64.into()], false),
|
||||
None,
|
||||
)
|
||||
});
|
||||
let max = ctx
|
||||
.builder
|
||||
.build_call(smax, &[old_end.into(), now.into()], "smax")
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
let end_store = self.gen_store_target(
|
||||
ctx,
|
||||
&end,
|
||||
store_name.map(|name| format!("{name}.addr")).as_deref())?;
|
||||
ctx.builder.build_store(end_store, max);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,30 +149,10 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
|||
params: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
||||
) -> Result<Option<BasicValueEnum<'ctx>>, String> {
|
||||
let result = gen_call(self, ctx, obj, fun, params)?;
|
||||
if let Some(end) = self.end.clone() {
|
||||
let old_end = self.gen_expr(ctx, &end)?.unwrap().to_basic_value_enum(ctx, self, end.custom.unwrap())?;
|
||||
let now = self.timeline.emit_now_mu(ctx);
|
||||
let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
||||
let i64 = ctx.ctx.i64_type();
|
||||
ctx.module.add_function(
|
||||
"llvm.smax.i64",
|
||||
i64.fn_type(&[i64.into(), i64.into()], false),
|
||||
None,
|
||||
)
|
||||
});
|
||||
let max = ctx
|
||||
.builder
|
||||
.build_call(smax, &[old_end.into(), now.into()], "smax")
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
let end_store = self.gen_store_target(ctx, &end, Some("end_store.addr"))?;
|
||||
ctx.builder.build_store(end_store, max);
|
||||
}
|
||||
if let Some(start) = self.start.clone() {
|
||||
let start_val = self.gen_expr(ctx, &start)?.unwrap().to_basic_value_enum(ctx, self, start.custom.unwrap())?;
|
||||
self.timeline.emit_at_mu(ctx, start_val);
|
||||
}
|
||||
|
||||
self.timeline_update_end_max(ctx, self.end.clone(), Some("end"))?;
|
||||
self.timeline_reset_start(ctx)?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
|
@ -102,6 +164,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
|||
if let StmtKind::With { items, body, .. } = &stmt.node {
|
||||
if items.len() == 1 && items[0].optional_vars.is_none() {
|
||||
let item = &items[0];
|
||||
|
||||
// Behavior of parallel and sequential:
|
||||
// Each function call (indirectly, can be inside a sequential block) within a parallel
|
||||
// block will update the end variable to the maximum now_mu in the block.
|
||||
|
@ -119,11 +182,15 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
|||
if id == &"parallel".into() {
|
||||
let old_start = self.start.take();
|
||||
let old_end = self.end.take();
|
||||
|
||||
let now = if let Some(old_start) = &old_start {
|
||||
self.gen_expr(ctx, old_start)?.unwrap().to_basic_value_enum(ctx, self, old_start.custom.unwrap())?
|
||||
self.gen_expr(ctx, old_start)?
|
||||
.unwrap()
|
||||
.to_basic_value_enum(ctx, self, old_start.custom.unwrap())?
|
||||
} else {
|
||||
self.timeline.emit_now_mu(ctx)
|
||||
};
|
||||
|
||||
// Emulate variable allocation, as we need to use the CodeGenContext
|
||||
// HashMap to store our variable due to lifetime limitation
|
||||
// Note: we should be able to store variables directly if generic
|
||||
|
@ -157,8 +224,11 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
|||
ctx.builder.build_store(end, now);
|
||||
self.end = Some(end_expr);
|
||||
self.name_counter += 1;
|
||||
|
||||
gen_block(self, ctx, body.iter())?;
|
||||
|
||||
let current = ctx.builder.get_insert_block().unwrap();
|
||||
|
||||
// if the current block is terminated, move before the terminator
|
||||
// we want to set the timeline before reaching the terminator
|
||||
// TODO: This may be unsound if there are multiple exit paths in the
|
||||
|
@ -172,6 +242,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
|||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// set duration
|
||||
let end_expr = self.end.take().unwrap();
|
||||
let end_val = self
|
||||
|
@ -183,49 +254,31 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
|||
if old_start.is_none() {
|
||||
self.timeline.emit_at_mu(ctx, end_val);
|
||||
}
|
||||
|
||||
// inside a parallel block, should update the outer max now_mu
|
||||
if let Some(old_end) = &old_end {
|
||||
let outer_end_val = self
|
||||
.gen_expr(ctx, old_end)?
|
||||
.unwrap()
|
||||
.to_basic_value_enum(ctx, self, old_end.custom.unwrap())?;
|
||||
let smax =
|
||||
ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
||||
let i64 = ctx.ctx.i64_type();
|
||||
ctx.module.add_function(
|
||||
"llvm.smax.i64",
|
||||
i64.fn_type(&[i64.into(), i64.into()], false),
|
||||
None,
|
||||
)
|
||||
});
|
||||
let max = ctx
|
||||
.builder
|
||||
.build_call(smax, &[end_val.into(), outer_end_val.into()], "smax")
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
let outer_end = self.gen_store_target(ctx, old_end, Some("outer_end.addr"))?;
|
||||
ctx.builder.build_store(outer_end, max);
|
||||
}
|
||||
self.timeline_update_end_max(ctx, old_end.clone(), Some("outer.end"))?;
|
||||
|
||||
self.start = old_start;
|
||||
self.end = old_end;
|
||||
|
||||
if reset_position {
|
||||
ctx.builder.position_at_end(current);
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
} else if id == &"sequential".into() {
|
||||
let start = self.start.take();
|
||||
for stmt in body.iter() {
|
||||
self.gen_stmt(ctx, stmt)?;
|
||||
if ctx.is_terminated() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
gen_block(self, ctx, body.iter())?;
|
||||
self.start = start;
|
||||
|
||||
// Reset the timeline when we are exiting the sequential block
|
||||
self.timeline_reset_start(ctx)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not parallel/sequential
|
||||
gen_with(self, ctx, stmt)
|
||||
} else {
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
use inkwell::{values::BasicValueEnum, AddressSpace, AtomicOrdering};
|
||||
use nac3core::codegen::CodeGenContext;
|
||||
|
||||
/// Functions for manipulating the timeline.
|
||||
pub trait TimeFns {
|
||||
|
||||
/// Emits LLVM IR for `now_mu`.
|
||||
fn emit_now_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>) -> BasicValueEnum<'ctx>;
|
||||
|
||||
/// Emits LLVM IR for `at_mu`.
|
||||
fn emit_at_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>, t: BasicValueEnum<'ctx>);
|
||||
|
||||
/// Emits LLVM IR for `delay_mu`.
|
||||
fn emit_delay_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>, dt: BasicValueEnum<'ctx>);
|
||||
}
|
||||
|
||||
|
@ -20,23 +27,25 @@ impl TimeFns for NowPinningTimeFns64 {
|
|||
.get_global("now")
|
||||
.unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
|
||||
let now_hiptr =
|
||||
ctx.builder.build_bitcast(now, i32_type.ptr_type(AddressSpace::default()), "now_hiptr");
|
||||
ctx.builder.build_bitcast(now, i32_type.ptr_type(AddressSpace::default()), "now.hi.addr");
|
||||
|
||||
if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr {
|
||||
let now_loptr = unsafe {
|
||||
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(2, false)], "now_gep")
|
||||
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(2, false)], "now.lo.addr")
|
||||
};
|
||||
|
||||
if let (BasicValueEnum::IntValue(now_hi), BasicValueEnum::IntValue(now_lo)) = (
|
||||
ctx.builder.build_load(now_hiptr, "now_hi"),
|
||||
ctx.builder.build_load(now_loptr, "now_lo"),
|
||||
ctx.builder.build_load(now_hiptr, "now.hi"),
|
||||
ctx.builder.build_load(now_loptr, "now.lo"),
|
||||
) {
|
||||
let zext_hi = ctx.builder.build_int_z_extend(now_hi, i64_type, "now_zext_hi");
|
||||
let zext_hi = ctx.builder.build_int_z_extend(now_hi, i64_type, "");
|
||||
let shifted_hi = ctx.builder.build_left_shift(
|
||||
zext_hi,
|
||||
i64_type.const_int(32, false),
|
||||
"now_shifted_zext_hi",
|
||||
"",
|
||||
);
|
||||
let zext_lo = ctx.builder.build_int_z_extend(now_lo, i64_type, "now_zext_lo");
|
||||
ctx.builder.build_or(shifted_hi, zext_lo, "now_or").into()
|
||||
let zext_lo = ctx.builder.build_int_z_extend(now_lo, i64_type, "");
|
||||
ctx.builder.build_or(shifted_hi, zext_lo, "now_mu").into()
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
|
@ -48,14 +57,15 @@ impl TimeFns for NowPinningTimeFns64 {
|
|||
fn emit_at_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>, t: BasicValueEnum<'ctx>) {
|
||||
let i32_type = ctx.ctx.i32_type();
|
||||
let i64_type = ctx.ctx.i64_type();
|
||||
|
||||
let i64_32 = i64_type.const_int(32, false);
|
||||
if let BasicValueEnum::IntValue(time) = t {
|
||||
let time_hi = ctx.builder.build_int_truncate(
|
||||
ctx.builder.build_right_shift(time, i64_32, false, "now_lshr"),
|
||||
ctx.builder.build_right_shift(time, i64_32, false, "time.hi"),
|
||||
i32_type,
|
||||
"now_trunc",
|
||||
"",
|
||||
);
|
||||
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "now_trunc");
|
||||
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "time.lo");
|
||||
let now = ctx
|
||||
.module
|
||||
.get_global("now")
|
||||
|
@ -63,11 +73,12 @@ impl TimeFns for NowPinningTimeFns64 {
|
|||
let now_hiptr = ctx.builder.build_bitcast(
|
||||
now,
|
||||
i32_type.ptr_type(AddressSpace::default()),
|
||||
"now_bitcast",
|
||||
"now.hi.addr",
|
||||
);
|
||||
|
||||
if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr {
|
||||
let now_loptr = unsafe {
|
||||
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(2, false)], "now_gep")
|
||||
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(2, false)], "now.lo.addr")
|
||||
};
|
||||
ctx.builder
|
||||
.build_store(now_hiptr, time_hi)
|
||||
|
@ -97,41 +108,43 @@ impl TimeFns for NowPinningTimeFns64 {
|
|||
.get_global("now")
|
||||
.unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
|
||||
let now_hiptr =
|
||||
ctx.builder.build_bitcast(now, i32_type.ptr_type(AddressSpace::default()), "now_hiptr");
|
||||
ctx.builder.build_bitcast(now, i32_type.ptr_type(AddressSpace::default()), "now.hi.addr");
|
||||
|
||||
if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr {
|
||||
let now_loptr = unsafe {
|
||||
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(2, false)], "now_loptr")
|
||||
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(2, false)], "now.lo.addr")
|
||||
};
|
||||
|
||||
if let (
|
||||
BasicValueEnum::IntValue(now_hi),
|
||||
BasicValueEnum::IntValue(now_lo),
|
||||
BasicValueEnum::IntValue(dt),
|
||||
) = (
|
||||
ctx.builder.build_load(now_hiptr, "now_hi"),
|
||||
ctx.builder.build_load(now_loptr, "now_lo"),
|
||||
ctx.builder.build_load(now_hiptr, "now.hi"),
|
||||
ctx.builder.build_load(now_loptr, "now.lo"),
|
||||
dt,
|
||||
) {
|
||||
let zext_hi = ctx.builder.build_int_z_extend(now_hi, i64_type, "now_zext_hi");
|
||||
let zext_hi = ctx.builder.build_int_z_extend(now_hi, i64_type, "");
|
||||
let shifted_hi = ctx.builder.build_left_shift(
|
||||
zext_hi,
|
||||
i64_type.const_int(32, false),
|
||||
"now_shifted_zext_hi",
|
||||
"",
|
||||
);
|
||||
let zext_lo = ctx.builder.build_int_z_extend(now_lo, i64_type, "now_zext_lo");
|
||||
let now_val = ctx.builder.build_or(shifted_hi, zext_lo, "now_or");
|
||||
let zext_lo = ctx.builder.build_int_z_extend(now_lo, i64_type, "");
|
||||
let now_val = ctx.builder.build_or(shifted_hi, zext_lo, "now");
|
||||
|
||||
let time = ctx.builder.build_int_add(now_val, dt, "now_add");
|
||||
let time = ctx.builder.build_int_add(now_val, dt, "time");
|
||||
let time_hi = ctx.builder.build_int_truncate(
|
||||
ctx.builder.build_right_shift(
|
||||
time,
|
||||
i64_type.const_int(32, false),
|
||||
false,
|
||||
"now_lshr",
|
||||
"",
|
||||
),
|
||||
i32_type,
|
||||
"now_trunc",
|
||||
"time.hi",
|
||||
);
|
||||
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "now_trunc");
|
||||
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "time.lo");
|
||||
|
||||
ctx.builder
|
||||
.build_store(now_hiptr, time_hi)
|
||||
|
@ -162,11 +175,12 @@ impl TimeFns for NowPinningTimeFns {
|
|||
.get_global("now")
|
||||
.unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
|
||||
let now_raw = ctx.builder.build_load(now.as_pointer_value(), "now");
|
||||
|
||||
if let BasicValueEnum::IntValue(now_raw) = now_raw {
|
||||
let i64_32 = i64_type.const_int(32, false);
|
||||
let now_lo = ctx.builder.build_left_shift(now_raw, i64_32, "now_shl");
|
||||
let now_hi = ctx.builder.build_right_shift(now_raw, i64_32, false, "now_lshr");
|
||||
ctx.builder.build_or(now_lo, now_hi, "now_or").into()
|
||||
let now_lo = ctx.builder.build_left_shift(now_raw, i64_32, "now.lo");
|
||||
let now_hi = ctx.builder.build_right_shift(now_raw, i64_32, false, "now.hi");
|
||||
ctx.builder.build_or(now_lo, now_hi, "now_mu").into()
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
|
@ -176,11 +190,12 @@ impl TimeFns for NowPinningTimeFns {
|
|||
let i32_type = ctx.ctx.i32_type();
|
||||
let i64_type = ctx.ctx.i64_type();
|
||||
let i64_32 = i64_type.const_int(32, false);
|
||||
|
||||
if let BasicValueEnum::IntValue(time) = t {
|
||||
let time_hi = ctx.builder.build_int_truncate(
|
||||
ctx.builder.build_right_shift(time, i64_32, false, "now_lshr"),
|
||||
ctx.builder.build_right_shift(time, i64_32, false, ""),
|
||||
i32_type,
|
||||
"now_trunc",
|
||||
"time.hi",
|
||||
);
|
||||
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "now_trunc");
|
||||
let now = ctx
|
||||
|
@ -190,11 +205,12 @@ impl TimeFns for NowPinningTimeFns {
|
|||
let now_hiptr = ctx.builder.build_bitcast(
|
||||
now,
|
||||
i32_type.ptr_type(AddressSpace::default()),
|
||||
"now_bitcast",
|
||||
"now.hi.addr",
|
||||
);
|
||||
|
||||
if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr {
|
||||
let now_loptr = unsafe {
|
||||
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(1, false)], "now_gep")
|
||||
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(1, false)], "now.lo.addr")
|
||||
};
|
||||
ctx.builder
|
||||
.build_store(now_hiptr, time_hi)
|
||||
|
@ -224,26 +240,28 @@ impl TimeFns for NowPinningTimeFns {
|
|||
.module
|
||||
.get_global("now")
|
||||
.unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
|
||||
let now_raw = ctx.builder.build_load(now.as_pointer_value(), "now");
|
||||
let now_raw = ctx.builder.build_load(now.as_pointer_value(), "");
|
||||
|
||||
if let (BasicValueEnum::IntValue(now_raw), BasicValueEnum::IntValue(dt)) = (now_raw, dt) {
|
||||
let now_lo = ctx.builder.build_left_shift(now_raw, i64_32, "now_shl");
|
||||
let now_hi = ctx.builder.build_right_shift(now_raw, i64_32, false, "now_lshr");
|
||||
let now_val = ctx.builder.build_or(now_lo, now_hi, "now_or");
|
||||
let time = ctx.builder.build_int_add(now_val, dt, "now_add");
|
||||
let now_lo = ctx.builder.build_left_shift(now_raw, i64_32, "now.lo");
|
||||
let now_hi = ctx.builder.build_right_shift(now_raw, i64_32, false, "now.hi");
|
||||
let now_val = ctx.builder.build_or(now_lo, now_hi, "now_val");
|
||||
let time = ctx.builder.build_int_add(now_val, dt, "time");
|
||||
let time_hi = ctx.builder.build_int_truncate(
|
||||
ctx.builder.build_right_shift(time, i64_32, false, "now_lshr"),
|
||||
ctx.builder.build_right_shift(time, i64_32, false, "time.hi"),
|
||||
i32_type,
|
||||
"now_trunc",
|
||||
);
|
||||
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "now_trunc");
|
||||
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "time.lo");
|
||||
let now_hiptr = ctx.builder.build_bitcast(
|
||||
now,
|
||||
i32_type.ptr_type(AddressSpace::default()),
|
||||
"now_bitcast",
|
||||
"now.hi.addr",
|
||||
);
|
||||
|
||||
if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr {
|
||||
let now_loptr = unsafe {
|
||||
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(1, false)], "now_gep")
|
||||
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(1, false)], "now.lo.addr")
|
||||
};
|
||||
ctx.builder
|
||||
.build_store(now_hiptr, time_hi)
|
||||
|
|
|
@ -253,21 +253,22 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
|||
let body_bb = ctx.ctx.append_basic_block(current, "for.body");
|
||||
let cont_bb = ctx.ctx.append_basic_block(current, "for.end");
|
||||
// if there is no orelse, we just go to cont_bb
|
||||
let orelse_bb =
|
||||
if orelse.is_empty() { cont_bb } else { ctx.ctx.append_basic_block(current, "for.orelse") };
|
||||
let orelse_bb = if orelse.is_empty() {
|
||||
cont_bb
|
||||
} else {
|
||||
ctx.ctx.append_basic_block(current, "for.orelse")
|
||||
};
|
||||
|
||||
// Whether the iterable is a range() expression
|
||||
let is_iterable_range_expr = ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range);
|
||||
|
||||
// The target BB of the loop backedge
|
||||
let backedge_bb_target = if is_iterable_range_expr {
|
||||
body_bb
|
||||
} else {
|
||||
ctx.ctx.append_basic_block(current, "for.cond")
|
||||
};
|
||||
// The BB containing the increment expression
|
||||
let incr_bb = ctx.ctx.append_basic_block(current, "for.incr");
|
||||
// The BB containing the loop condition check
|
||||
let cond_bb = ctx.ctx.append_basic_block(current, "for.cond");
|
||||
|
||||
// store loop bb information and restore it later
|
||||
let loop_bb = ctx.loop_target.replace((backedge_bb_target, cont_bb));
|
||||
let loop_bb = ctx.loop_target.replace((incr_bb, cont_bb));
|
||||
|
||||
let iter_val = generator.gen_expr(ctx, iter)?.unwrap().to_basic_value_enum(
|
||||
ctx,
|
||||
|
@ -294,35 +295,35 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
|||
[None, None, None],
|
||||
ctx.current_loc
|
||||
);
|
||||
ctx.builder.build_unconditional_branch(cond_bb);
|
||||
|
||||
ctx.builder.build_conditional_branch(
|
||||
gen_in_range_check(ctx, start, stop, step),
|
||||
body_bb,
|
||||
orelse_bb,
|
||||
{
|
||||
ctx.builder.position_at_end(cond_bb);
|
||||
ctx.builder.build_conditional_branch(
|
||||
gen_in_range_check(
|
||||
ctx,
|
||||
ctx.builder.build_load(i, "").into_int_value(),
|
||||
stop,
|
||||
step
|
||||
),
|
||||
body_bb,
|
||||
orelse_bb,
|
||||
);
|
||||
}
|
||||
|
||||
ctx.builder.position_at_end(incr_bb);
|
||||
let next_i = ctx.builder.build_int_add(
|
||||
ctx.builder.build_load(i, "").into_int_value(),
|
||||
step,
|
||||
"inc",
|
||||
);
|
||||
ctx.builder.build_store(i, next_i);
|
||||
ctx.builder.build_unconditional_branch(cond_bb);
|
||||
|
||||
ctx.builder.position_at_end(body_bb);
|
||||
ctx.builder.build_store(target_i, ctx.builder.build_load(i, "").into_int_value());
|
||||
gen_block(generator, ctx, body.iter())?;
|
||||
|
||||
// Test if next element is still in range
|
||||
let next_i = ctx.builder.build_int_add(
|
||||
ctx.builder.build_load(i, "").into_int_value(),
|
||||
step,
|
||||
"next_i",
|
||||
);
|
||||
let cond_cont_bb = ctx.ctx.append_basic_block(current, "for.cond.cont");
|
||||
ctx.builder.build_conditional_branch(
|
||||
gen_in_range_check(ctx, next_i, stop, step),
|
||||
cond_cont_bb,
|
||||
orelse_bb,
|
||||
);
|
||||
|
||||
ctx.builder.position_at_end(cond_cont_bb);
|
||||
ctx.builder.build_store(i, next_i);
|
||||
} else {
|
||||
let test_bb = backedge_bb_target;
|
||||
|
||||
let index_addr = generator.gen_var_alloc(ctx, size_t.into(), Some("for.index.addr"))?;
|
||||
ctx.builder.build_store(index_addr, size_t.const_zero());
|
||||
let len = ctx
|
||||
|
@ -332,24 +333,27 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
|||
Some("len")
|
||||
)
|
||||
.into_int_value();
|
||||
ctx.builder.build_unconditional_branch(test_bb);
|
||||
ctx.builder.build_unconditional_branch(cond_bb);
|
||||
|
||||
ctx.builder.position_at_end(test_bb);
|
||||
ctx.builder.position_at_end(cond_bb);
|
||||
let index = ctx.builder.build_load(index_addr, "for.index").into_int_value();
|
||||
let cmp = ctx.builder.build_int_compare(IntPredicate::SLT, index, len, "cond");
|
||||
ctx.builder.build_conditional_branch(cmp, body_bb, orelse_bb);
|
||||
|
||||
ctx.builder.position_at_end(incr_bb);
|
||||
let index = ctx.builder.build_load(index_addr, "").into_int_value();
|
||||
let inc = ctx.builder.build_int_add(index, size_t.const_int(1, true), "inc");
|
||||
ctx.builder.build_store(index_addr, inc);
|
||||
ctx.builder.build_unconditional_branch(cond_bb);
|
||||
|
||||
ctx.builder.position_at_end(body_bb);
|
||||
let arr_ptr = ctx
|
||||
.build_gep_and_load(iter_val.into_pointer_value(), &[zero, zero], Some("arr.addr"))
|
||||
.into_pointer_value();
|
||||
let index = ctx.builder.build_load(index_addr, "for.index").into_int_value();
|
||||
let val = ctx.build_gep_and_load(arr_ptr, &[index], Some("val"));
|
||||
generator.gen_assign(ctx, target, val.into())?;
|
||||
gen_block(generator, ctx, body.iter())?;
|
||||
|
||||
let index = ctx.builder.build_load(index_addr, "for.index").into_int_value();
|
||||
let inc = ctx.builder.build_int_add(index, size_t.const_int(1, true), "");
|
||||
ctx.builder.build_store(index_addr, inc);
|
||||
}
|
||||
|
||||
for (k, (_, _, counter)) in var_assignment.iter() {
|
||||
|
@ -360,7 +364,7 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator>(
|
|||
}
|
||||
|
||||
if !ctx.is_terminated() {
|
||||
ctx.builder.build_unconditional_branch(backedge_bb_target);
|
||||
ctx.builder.build_unconditional_branch(incr_bb);
|
||||
}
|
||||
|
||||
if !orelse.is_empty() {
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
#include <string.h>
|
||||
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
#define usize uint64_t
|
||||
#define usize uint64_t
|
||||
#elif __SIZEOF_POINTER__ == 4
|
||||
#define usize uint32_t
|
||||
#define usize uint32_t
|
||||
#else
|
||||
#error "Unsupported platform - Platform is not 32-bit or 64-bit"
|
||||
#error "Unsupported platform - Platform is not 32-bit or 64-bit"
|
||||
#endif
|
||||
|
||||
double dbl_nan(void) {
|
||||
|
@ -22,87 +22,87 @@ double dbl_inf(void) {
|
|||
}
|
||||
|
||||
void output_bool(bool x) {
|
||||
puts(x ? "True" : "False");
|
||||
puts(x ? "True" : "False");
|
||||
}
|
||||
|
||||
void output_int32(int32_t x) {
|
||||
printf("%d\n", x);
|
||||
printf("%d\n", x);
|
||||
}
|
||||
|
||||
void output_int64(int64_t x) {
|
||||
printf("%ld\n", x);
|
||||
printf("%ld\n", x);
|
||||
}
|
||||
|
||||
void output_uint32(uint32_t x) {
|
||||
printf("%d\n", x);
|
||||
printf("%d\n", x);
|
||||
}
|
||||
|
||||
void output_uint64(uint64_t x) {
|
||||
printf("%ld\n", x);
|
||||
printf("%ld\n", x);
|
||||
}
|
||||
|
||||
void output_float64(double x) {
|
||||
if (isnan(x)) {
|
||||
puts("nan");
|
||||
} else {
|
||||
printf("%f\n", x);
|
||||
}
|
||||
if (isnan(x)) {
|
||||
puts("nan");
|
||||
} else {
|
||||
printf("%f\n", x);
|
||||
}
|
||||
}
|
||||
|
||||
void output_asciiart(int32_t x) {
|
||||
static const char *chars = " .,-:;i+hHM$*#@ ";
|
||||
if (x < 0) {
|
||||
putchar('\n');
|
||||
} else {
|
||||
putchar(chars[x]);
|
||||
}
|
||||
static const char *chars = " .,-:;i+hHM$*#@ ";
|
||||
if (x < 0) {
|
||||
putchar('\n');
|
||||
} else {
|
||||
putchar(chars[x]);
|
||||
}
|
||||
}
|
||||
|
||||
struct cslice {
|
||||
void *data;
|
||||
usize len;
|
||||
void *data;
|
||||
usize len;
|
||||
};
|
||||
|
||||
void output_int32_list(struct cslice *slice) {
|
||||
const int32_t *data = (int32_t *) slice->data;
|
||||
const int32_t *data = (int32_t *) slice->data;
|
||||
|
||||
putchar('[');
|
||||
for (usize i = 0; i < slice->len; ++i) {
|
||||
if (i == slice->len - 1) {
|
||||
printf("%d", data[i]);
|
||||
} else {
|
||||
printf("%d, ", data[i]);
|
||||
putchar('[');
|
||||
for (usize i = 0; i < slice->len; ++i) {
|
||||
if (i == slice->len - 1) {
|
||||
printf("%d", data[i]);
|
||||
} else {
|
||||
printf("%d, ", data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
putchar(']');
|
||||
putchar('\n');
|
||||
putchar(']');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void output_str(struct cslice *slice) {
|
||||
const char *data = (const char *) slice->data;
|
||||
const char *data = (const char *) slice->data;
|
||||
|
||||
for (usize i = 0; i < slice->len; ++i) {
|
||||
putchar(data[i]);
|
||||
}
|
||||
putchar('\n');
|
||||
for (usize i = 0; i < slice->len; ++i) {
|
||||
putchar(data[i]);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
uint64_t dbg_stack_address(__attribute__((unused)) struct cslice *slice) {
|
||||
int i;
|
||||
void *ptr = (void *) &i;
|
||||
return (uintptr_t) ptr;
|
||||
int i;
|
||||
void *ptr = (void *) &i;
|
||||
return (uintptr_t) ptr;
|
||||
}
|
||||
|
||||
uint32_t __nac3_personality(uint32_t state, uint32_t exception_object, uint32_t context) {
|
||||
printf("__nac3_personality(state: %u, exception_object: %u, context: %u\n", state, exception_object, context);
|
||||
exit(101);
|
||||
__builtin_unreachable();
|
||||
printf("__nac3_personality(state: %u, exception_object: %u, context: %u\n", state, exception_object, context);
|
||||
exit(101);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
uint32_t __nac3_raise(uint32_t state, uint32_t exception_object, uint32_t context) {
|
||||
printf("__nac3_raise(state: %u, exception_object: %u, context: %u\n", state, exception_object, context);
|
||||
exit(101);
|
||||
__builtin_unreachable();
|
||||
printf("__nac3_raise(state: %u, exception_object: %u, context: %u\n", state, exception_object, context);
|
||||
exit(101);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void __nac3_end_catch(void) {}
|
||||
|
@ -110,5 +110,5 @@ void __nac3_end_catch(void) {}
|
|||
extern int32_t run(void);
|
||||
|
||||
int main(void) {
|
||||
run();
|
||||
run();
|
||||
}
|
||||
|
|
|
@ -2,29 +2,29 @@
|
|||
# Tests whether all boolean variables (expressed as i8s) are lowered into i1s before used in branching instruction (`br`)
|
||||
|
||||
def bfunc(b: bool) -> bool:
|
||||
return not b
|
||||
return not b
|
||||
|
||||
def run() -> int32:
|
||||
b1 = True
|
||||
b2 = False
|
||||
b1 = True
|
||||
b2 = False
|
||||
|
||||
if b1:
|
||||
pass
|
||||
if b1:
|
||||
pass
|
||||
|
||||
if not b2:
|
||||
pass
|
||||
if not b2:
|
||||
pass
|
||||
|
||||
while b2:
|
||||
pass
|
||||
while b2:
|
||||
pass
|
||||
|
||||
l = [i for i in range(10) if b2]
|
||||
l = [i for i in range(10) if b2]
|
||||
|
||||
b_and = True and False
|
||||
b_or = True or False
|
||||
b_and = True and False
|
||||
b_or = True or False
|
||||
|
||||
b_and = b1 and b2
|
||||
b_or = b1 or b2
|
||||
b_and = b1 and b2
|
||||
b_or = b1 or b2
|
||||
|
||||
bfunc(b1)
|
||||
bfunc(b1)
|
||||
|
||||
return 0
|
||||
return 0
|
|
@ -1,8 +1,8 @@
|
|||
def f():
|
||||
return
|
||||
return
|
||||
return
|
||||
return
|
||||
|
||||
def run() -> int32:
|
||||
f()
|
||||
f()
|
||||
|
||||
return 0
|
||||
return 0
|
|
@ -1,83 +1,83 @@
|
|||
@extern
|
||||
def output_bool(x: bool):
|
||||
...
|
||||
...
|
||||
|
||||
@extern
|
||||
def output_int32(x: int32):
|
||||
...
|
||||
...
|
||||
|
||||
@extern
|
||||
def output_int64(x: int64):
|
||||
...
|
||||
...
|
||||
|
||||
@extern
|
||||
def output_uint32(x: uint32):
|
||||
...
|
||||
...
|
||||
|
||||
@extern
|
||||
def output_uint64(x: uint64):
|
||||
...
|
||||
...
|
||||
|
||||
@extern
|
||||
def output_float64(x: float):
|
||||
...
|
||||
...
|
||||
|
||||
@extern
|
||||
def output_int32_list(x: list[int32]):
|
||||
...
|
||||
...
|
||||
|
||||
@extern
|
||||
def output_asciiart(x: int32):
|
||||
...
|
||||
...
|
||||
|
||||
@extern
|
||||
def output_str(x: str):
|
||||
...
|
||||
...
|
||||
|
||||
def test_output_bool():
|
||||
output_bool(True)
|
||||
output_bool(False)
|
||||
output_bool(True)
|
||||
output_bool(False)
|
||||
|
||||
def test_output_int32():
|
||||
output_int32(-128)
|
||||
output_int32(-128)
|
||||
|
||||
def test_output_int64():
|
||||
output_int64(int64(-256))
|
||||
output_int64(int64(-256))
|
||||
|
||||
def test_output_uint32():
|
||||
output_uint32(uint32(128))
|
||||
output_uint32(uint32(128))
|
||||
|
||||
def test_output_uint64():
|
||||
output_uint64(uint64(256))
|
||||
output_uint64(uint64(256))
|
||||
|
||||
def test_output_float64():
|
||||
output_float64(0.0)
|
||||
output_float64(1.0)
|
||||
output_float64(-1.0)
|
||||
output_float64(128.0)
|
||||
output_float64(-128.0)
|
||||
output_float64(16.25)
|
||||
output_float64(-16.25)
|
||||
output_float64(0.0)
|
||||
output_float64(1.0)
|
||||
output_float64(-1.0)
|
||||
output_float64(128.0)
|
||||
output_float64(-128.0)
|
||||
output_float64(16.25)
|
||||
output_float64(-16.25)
|
||||
|
||||
def test_output_asciiart():
|
||||
for i in range(17):
|
||||
output_asciiart(i)
|
||||
output_asciiart(0)
|
||||
for i in range(17):
|
||||
output_asciiart(i)
|
||||
output_asciiart(0)
|
||||
|
||||
def test_output_int32_list():
|
||||
output_int32_list([0, 1, 3, 5, 10])
|
||||
output_int32_list([0, 1, 3, 5, 10])
|
||||
|
||||
def test_output_str_family():
|
||||
output_str("hello world")
|
||||
output_str("hello world")
|
||||
|
||||
def run() -> int32:
|
||||
test_output_bool()
|
||||
test_output_int32()
|
||||
test_output_int64()
|
||||
test_output_uint32()
|
||||
test_output_uint64()
|
||||
test_output_float64()
|
||||
test_output_asciiart()
|
||||
test_output_int32_list()
|
||||
test_output_str_family()
|
||||
return 0
|
||||
test_output_bool()
|
||||
test_output_int32()
|
||||
test_output_int64()
|
||||
test_output_uint32()
|
||||
test_output_uint64()
|
||||
test_output_float64()
|
||||
test_output_asciiart()
|
||||
test_output_int32_list()
|
||||
test_output_str_family()
|
||||
return 0
|
|
@ -1,17 +1,17 @@
|
|||
@extern
|
||||
def output_int32(x: int32):
|
||||
...
|
||||
...
|
||||
|
||||
@extern
|
||||
def output_int32_list(x: list[int32]):
|
||||
...
|
||||
...
|
||||
|
||||
def run() -> int32:
|
||||
bl = [True, False]
|
||||
bl = [True, False]
|
||||
|
||||
bl1 = bl[:]
|
||||
bl1[1:] = [True]
|
||||
output_int32_list([int32(b) for b in bl1])
|
||||
output_int32_list([int32(b) for b in bl1])
|
||||
bl1 = bl[:]
|
||||
bl1[1:] = [True]
|
||||
output_int32_list([int32(b) for b in bl1])
|
||||
output_int32_list([int32(b) for b in bl1])
|
||||
|
||||
return 0
|
||||
return 0
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
@extern
|
||||
def output_int32(x: int32):
|
||||
...
|
||||
|
||||
def run() -> int32:
|
||||
for i in range(4):
|
||||
output_int32(i)
|
||||
if i < 2:
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
n = [0, 1, 2, 3]
|
||||
for i in n:
|
||||
output_int32(i)
|
||||
if i < 2:
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
return 0
|
|
@ -3,31 +3,31 @@
|
|||
|
||||
@extern
|
||||
def output_int32(x: int32):
|
||||
...
|
||||
...
|
||||
|
||||
@extern
|
||||
def output_float64(x: float):
|
||||
...
|
||||
...
|
||||
|
||||
@extern
|
||||
def output_str(x: str):
|
||||
...
|
||||
...
|
||||
|
||||
def run() -> int32:
|
||||
for n in range(2, 10):
|
||||
for x in range(2, n):
|
||||
try:
|
||||
if n % x == 0:
|
||||
output_int32(n)
|
||||
output_str(" equals ")
|
||||
output_int32(x)
|
||||
output_str(" * ")
|
||||
output_float64(n / x)
|
||||
except: # Assume this is intended to catch x == 0
|
||||
break
|
||||
else:
|
||||
# loop fell through without finding a factor
|
||||
output_int32(n)
|
||||
output_str(" is a prime number")
|
||||
for n in range(2, 10):
|
||||
for x in range(2, n):
|
||||
try:
|
||||
if n % x == 0:
|
||||
output_int32(n)
|
||||
output_str(" equals ")
|
||||
output_int32(x)
|
||||
output_str(" * ")
|
||||
output_float64(n / x)
|
||||
except: # Assume this is intended to catch x == 0
|
||||
break
|
||||
else:
|
||||
# loop fell through without finding a factor
|
||||
output_int32(n)
|
||||
output_str(" is a prime number")
|
||||
|
||||
return 0
|
||||
return 0
|
|
@ -1,15 +1,15 @@
|
|||
@extern
|
||||
def output_bool(x: bool):
|
||||
...
|
||||
...
|
||||
|
||||
@extern
|
||||
def dbg_stack_address(x: str) -> uint64:
|
||||
...
|
||||
...
|
||||
|
||||
def run() -> int32:
|
||||
a = dbg_stack_address("a")
|
||||
b = dbg_stack_address("b")
|
||||
a = dbg_stack_address("a")
|
||||
b = dbg_stack_address("b")
|
||||
|
||||
output_bool(a == b)
|
||||
output_bool(a == b)
|
||||
|
||||
return 0
|
||||
return 0
|
Loading…
Reference in New Issue