mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
Add a basic CLI
This commit is contained in:
parent
70936841c8
commit
5f817d8019
26 changed files with 2461 additions and 291 deletions
804
2
Normal file
804
2
Normal file
|
@ -0,0 +1,804 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate pretty_assertions;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate indoc;
|
||||||
|
|
||||||
|
extern crate bumpalo;
|
||||||
|
extern crate inkwell;
|
||||||
|
extern crate libc;
|
||||||
|
extern crate roc_gen;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod helpers;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod gen_tags {
|
||||||
|
use crate::helpers::{can_expr, infer_expr, uniq_expr, CanExprOut};
|
||||||
|
use bumpalo::Bump;
|
||||||
|
use inkwell::context::Context;
|
||||||
|
use inkwell::execution_engine::JitFunction;
|
||||||
|
use inkwell::passes::PassManager;
|
||||||
|
use inkwell::types::BasicType;
|
||||||
|
use inkwell::OptimizationLevel;
|
||||||
|
use roc_collections::all::ImMap;
|
||||||
|
use roc_gen::llvm::build::{build_proc, build_proc_header};
|
||||||
|
use roc_gen::llvm::convert::basic_type_from_layout;
|
||||||
|
use roc_mono::expr::{Expr, Procs};
|
||||||
|
use roc_mono::layout::Layout;
|
||||||
|
use roc_types::subs::Subs;
|
||||||
|
|
||||||
|
use inkwell::targets::{
|
||||||
|
CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine, TargetTriple,
|
||||||
|
};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn applied_tag_nothing() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Maybe a : [ Just a, Nothing ]
|
||||||
|
|
||||||
|
x : Maybe Int
|
||||||
|
x = Nothing
|
||||||
|
|
||||||
|
0x1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
1,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn applied_tag_just() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Maybe a : [ Just a, Nothing ]
|
||||||
|
|
||||||
|
y : Maybe Int
|
||||||
|
y = Just 0x4
|
||||||
|
|
||||||
|
0x1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
1,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn applied_tag_just_unit() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Fruit : [ Orange, Apple, Banana ]
|
||||||
|
Maybe a : [ Just a, Nothing ]
|
||||||
|
|
||||||
|
orange : Fruit
|
||||||
|
orange = Orange
|
||||||
|
|
||||||
|
y : Maybe Fruit
|
||||||
|
y = Just orange
|
||||||
|
|
||||||
|
0x1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
1,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn raw_result() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// x : Result Int Int
|
||||||
|
// x = Err 41
|
||||||
|
|
||||||
|
// x
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// 0,
|
||||||
|
// i8
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn true_is_true() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
bool : [True, False]
|
||||||
|
bool = True
|
||||||
|
|
||||||
|
bool
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn false_is_false() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
bool : [True, False]
|
||||||
|
bool = False
|
||||||
|
|
||||||
|
bool
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn basic_enum() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Fruit : [ Apple, Orange, Banana ]
|
||||||
|
|
||||||
|
apple : Fruit
|
||||||
|
apple = Apple
|
||||||
|
|
||||||
|
orange : Fruit
|
||||||
|
orange = Orange
|
||||||
|
|
||||||
|
apple == orange
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn linked_list_empty() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// LinkedList a : [ Cons a (LinkedList a), Nil ]
|
||||||
|
//
|
||||||
|
// empty : LinkedList Int
|
||||||
|
// empty = Nil
|
||||||
|
//
|
||||||
|
// 1
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// 1,
|
||||||
|
// i64
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// #[test]
|
||||||
|
// fn linked_list_singleton() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// LinkedList a : [ Cons a (LinkedList a), Nil ]
|
||||||
|
//
|
||||||
|
// singleton : LinkedList Int
|
||||||
|
// singleton = Cons 0x1 Nil
|
||||||
|
//
|
||||||
|
// 1
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// 1,
|
||||||
|
// i64
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// #[test]
|
||||||
|
// fn linked_list_is_empty() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// LinkedList a : [ Cons a (LinkedList a), Nil ]
|
||||||
|
//
|
||||||
|
// isEmpty : LinkedList a -> Bool
|
||||||
|
// isEmpty = \list ->
|
||||||
|
// when list is
|
||||||
|
// Nil -> True
|
||||||
|
// Cons _ _ -> False
|
||||||
|
//
|
||||||
|
// isEmpty (Cons 4 Nil)
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// false,
|
||||||
|
// bool
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn even_odd() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
even = \n ->
|
||||||
|
when n is
|
||||||
|
0 -> True
|
||||||
|
1 -> False
|
||||||
|
_ -> odd (n - 1)
|
||||||
|
|
||||||
|
odd = \n ->
|
||||||
|
when n is
|
||||||
|
0 -> False
|
||||||
|
1 -> True
|
||||||
|
_ -> even (n - 1)
|
||||||
|
|
||||||
|
odd 5 && even 42
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gen_literal_true() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
if True then -1 else 1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
-1,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gen_if_float() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
if True then -1.0 else 1.0
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
-1.0,
|
||||||
|
f64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn when_on_nothing() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : [ Nothing, Just Int ]
|
||||||
|
x = Nothing
|
||||||
|
|
||||||
|
when x is
|
||||||
|
Nothing -> 0x2
|
||||||
|
Just _ -> 0x1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
2,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn when_on_just() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : [ Nothing, Just Int ]
|
||||||
|
x = Just 41
|
||||||
|
|
||||||
|
when x is
|
||||||
|
Just v -> v + 0x1
|
||||||
|
Nothing -> 0x1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
42,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn when_on_result() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : Result Int Int
|
||||||
|
x = Err 41
|
||||||
|
|
||||||
|
when x is
|
||||||
|
Err v -> v + 1
|
||||||
|
Ok _ -> 1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
42,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn when_on_these() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
These a b : [ This a, That b, These a b ]
|
||||||
|
|
||||||
|
x : These Int Int
|
||||||
|
x = These 0x3 0x2
|
||||||
|
|
||||||
|
when x is
|
||||||
|
These a b -> a + b
|
||||||
|
That v -> 8
|
||||||
|
This v -> v
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
5,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn match_on_two_values() {
|
||||||
|
// this will produce a Chain internally
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
when Pair 2 3 is
|
||||||
|
Pair 4 3 -> 9
|
||||||
|
Pair a b -> a + b
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
5,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pair_with_guard_pattern() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
when Pair 2 3 is
|
||||||
|
Pair 4 _ -> 1
|
||||||
|
Pair 3 _ -> 2
|
||||||
|
Pair a b -> a + b
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
5,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn result_with_guard_pattern() {
|
||||||
|
// This test revealed an issue with hashing Test values
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : Result Int Int
|
||||||
|
x = Ok 2
|
||||||
|
|
||||||
|
when x is
|
||||||
|
Ok 3 -> 1
|
||||||
|
Ok _ -> 2
|
||||||
|
Err _ -> 3
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
2,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn maybe_is_just() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Maybe a : [ Just a, Nothing ]
|
||||||
|
|
||||||
|
isJust : Maybe a -> Bool
|
||||||
|
isJust = \list ->
|
||||||
|
when list is
|
||||||
|
Nothing -> False
|
||||||
|
Just _ -> True
|
||||||
|
|
||||||
|
isJust (Just 42)
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_pattern_match() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Maybe a : [ Nothing, Just a ]
|
||||||
|
|
||||||
|
x : Maybe (Maybe Int)
|
||||||
|
x = Just (Just 41)
|
||||||
|
|
||||||
|
when x is
|
||||||
|
Just (Just v) -> v + 0x1
|
||||||
|
_ -> 0x1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
42,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn if_guard_pattern_false() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
when 2 is
|
||||||
|
2 if False -> 0
|
||||||
|
_ -> 42
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
42,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_guard_pattern_true() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
when 2 is
|
||||||
|
2 if True -> 42
|
||||||
|
_ -> 0
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
42,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_guard_exhaustiveness() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
when 2 is
|
||||||
|
_ if False -> 0
|
||||||
|
_ -> 42
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
42,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn when_on_enum() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Fruit : [ Apple, Orange, Banana ]
|
||||||
|
|
||||||
|
apple : Fruit
|
||||||
|
apple = Apple
|
||||||
|
|
||||||
|
when apple is
|
||||||
|
Apple -> 1
|
||||||
|
Banana -> 2
|
||||||
|
Orange -> 3
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
1,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pattern_matching_unit() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Unit : [ Unit ]
|
||||||
|
|
||||||
|
f : Unit -> Int
|
||||||
|
f = \Unit -> 42
|
||||||
|
|
||||||
|
f Unit
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
42,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Unit : [ Unit ]
|
||||||
|
|
||||||
|
x : Unit
|
||||||
|
x = Unit
|
||||||
|
|
||||||
|
when x is
|
||||||
|
Unit -> 42
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
42,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
f : {} -> Int
|
||||||
|
f = \{} -> 42
|
||||||
|
|
||||||
|
f {}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
42,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
when {} is
|
||||||
|
{} -> 42
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
42,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn one_element_tag() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : [ Pair Int ]
|
||||||
|
x = Pair 2
|
||||||
|
|
||||||
|
0x3
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
3,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_tag_union() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Maybe a : [ Nothing, Just a ]
|
||||||
|
|
||||||
|
x : Maybe (Maybe a)
|
||||||
|
x = Just (Just 41)
|
||||||
|
|
||||||
|
5
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
5,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn unit_type() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Unit : [ Unit ]
|
||||||
|
|
||||||
|
v : Unit
|
||||||
|
v = Unit
|
||||||
|
|
||||||
|
1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
1,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_record_load() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Maybe a : [ Nothing, Just a ]
|
||||||
|
|
||||||
|
x = { a : { b : 0x5 } }
|
||||||
|
|
||||||
|
y = x.a
|
||||||
|
|
||||||
|
y.b
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
5,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_emit() {
|
||||||
|
let src = "42";
|
||||||
|
|
||||||
|
// Build the expr
|
||||||
|
let arena = Bump::new();
|
||||||
|
let (loc_expr, _output, _problems, subs, var, constraint, home, interns) = uniq_expr(src);
|
||||||
|
|
||||||
|
let mut unify_problems = Vec::new();
|
||||||
|
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
||||||
|
|
||||||
|
let context = Context::create();
|
||||||
|
let module = context.create_module("app");
|
||||||
|
let builder = context.create_builder();
|
||||||
|
let fpm = PassManager::create(&module);
|
||||||
|
|
||||||
|
roc_gen::llvm::build::add_passes(&fpm);
|
||||||
|
|
||||||
|
fpm.initialize();
|
||||||
|
|
||||||
|
// Compute main_fn_type before moving subs to Env
|
||||||
|
let layout = Layout::from_content(&arena, content, &subs, crate::helpers::eval::POINTER_SIZE)
|
||||||
|
.unwrap_or_else(|err| panic!("Code gen error in test: could not convert to layout. Err was {:?} and Subs were {:?}", err, subs));
|
||||||
|
|
||||||
|
let execution_engine =
|
||||||
|
module
|
||||||
|
.create_jit_execution_engine(OptimizationLevel::None)
|
||||||
|
.expect("Error creating JIT execution engine for test");
|
||||||
|
|
||||||
|
let ptr_bytes = execution_engine.get_target_data().get_pointer_byte_size(None);
|
||||||
|
let main_fn_type = basic_type_from_layout(&arena, &context, &layout, ptr_bytes)
|
||||||
|
.fn_type(&[], false);
|
||||||
|
let main_fn_name = "$Test.main";
|
||||||
|
|
||||||
|
// Compile and add all the Procs before adding main
|
||||||
|
let mut env = roc_gen::llvm::build::Env {
|
||||||
|
arena: &arena,
|
||||||
|
builder: &builder,
|
||||||
|
context: &context,
|
||||||
|
interns,
|
||||||
|
module: arena.alloc(module),
|
||||||
|
ptr_bytes
|
||||||
|
};
|
||||||
|
let mut procs = Procs::default();
|
||||||
|
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
||||||
|
|
||||||
|
// Populate Procs and get the low-level Expr from the canonical Expr
|
||||||
|
let main_body = Expr::new(&arena, &mut subs, loc_expr.value, &mut procs, home, &mut ident_ids, $crate::helpers::eval::POINTER_SIZE);
|
||||||
|
|
||||||
|
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
||||||
|
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
|
||||||
|
let mut headers = Vec::with_capacity(procs.len());
|
||||||
|
|
||||||
|
// Add all the Proc headers to the module.
|
||||||
|
// We have to do this in a separate pass first,
|
||||||
|
// because their bodies may reference each other.
|
||||||
|
for (symbol, opt_proc) in procs.as_map().into_iter() {
|
||||||
|
if let Some(proc) = opt_proc {
|
||||||
|
let (fn_val, arg_basic_types) = build_proc_header(&env, symbol, &proc);
|
||||||
|
|
||||||
|
headers.push((proc, fn_val, arg_basic_types));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build each proc using its header info.
|
||||||
|
for (proc, fn_val, arg_basic_types) in headers {
|
||||||
|
// NOTE: This is here to be uncommented in case verification fails.
|
||||||
|
// (This approach means we don't have to defensively clone name here.)
|
||||||
|
//
|
||||||
|
// println!("\n\nBuilding and then verifying function {}\n\n", name);
|
||||||
|
build_proc(&env, proc, &procs, fn_val, arg_basic_types);
|
||||||
|
|
||||||
|
if fn_val.verify(true) {
|
||||||
|
fpm.run_on(&fn_val);
|
||||||
|
} else {
|
||||||
|
// NOTE: If this fails, uncomment the above println to debug.
|
||||||
|
panic!("Non-main function failed LLVM verification. Uncomment the above println to debug!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add main to the module.
|
||||||
|
let main_fn = env.module.add_function(main_fn_name, main_fn_type, None);
|
||||||
|
|
||||||
|
main_fn.set_call_conventions($crate::helpers::eval::MAIN_CALLING_CONVENTION);
|
||||||
|
|
||||||
|
// Add main's body
|
||||||
|
let basic_block = context.append_basic_block(main_fn, "entry");
|
||||||
|
|
||||||
|
builder.position_at_end(basic_block);
|
||||||
|
|
||||||
|
let ret = roc_gen::llvm::build::build_expr(
|
||||||
|
&env,
|
||||||
|
&ImMap::default(),
|
||||||
|
main_fn,
|
||||||
|
&main_body,
|
||||||
|
&mut Procs::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
builder.build_return(Some(&ret));
|
||||||
|
|
||||||
|
// Uncomment this to see the module's un-optimized LLVM instruction output:
|
||||||
|
// env.module.print_to_stderr();
|
||||||
|
|
||||||
|
if main_fn.verify(true) {
|
||||||
|
fpm.run_on(&main_fn);
|
||||||
|
} else {
|
||||||
|
panic!("Function {} failed LLVM verification.", main_fn_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the module
|
||||||
|
if let Err(errors) = env.module.verify() {
|
||||||
|
panic!("Errors defining module: {:?}", errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uncomment this to see the module's optimized LLVM instruction output:
|
||||||
|
// env.module.print_to_stderr();
|
||||||
|
|
||||||
|
// Emit
|
||||||
|
Target::initialize_x86(&InitializationConfig::default());
|
||||||
|
|
||||||
|
let opt = OptimizationLevel::Default;
|
||||||
|
let reloc = RelocMode::Default;
|
||||||
|
let model = CodeModel::Default;
|
||||||
|
let target = Target::from_name("x86-64").unwrap();
|
||||||
|
let target_machine = target.create_target_machine(
|
||||||
|
&TargetTriple::create("x86_64-pc-linux-gnu"),
|
||||||
|
"x86-64",
|
||||||
|
"+avx2",
|
||||||
|
opt,
|
||||||
|
reloc,
|
||||||
|
model
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let buffer = target_machine.write_to_memory_buffer(&module, FileType::Assembly).unwrap();
|
||||||
|
|
||||||
|
let buffer_str = std::str::from_utf8(buffer).unwrap();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_emit_old() {
|
||||||
|
Target::initialize_x86(&InitializationConfig::default());
|
||||||
|
|
||||||
|
let opt = OptimizationLevel::Default;
|
||||||
|
let reloc = RelocMode::Default;
|
||||||
|
let model = CodeModel::Default;
|
||||||
|
let path = Path::new("./test.asm");
|
||||||
|
let target = Target::from_name("x86-64").unwrap();
|
||||||
|
let target_machine = target
|
||||||
|
.create_target_machine(
|
||||||
|
&TargetTriple::create("x86_64-pc-linux-gnu"),
|
||||||
|
"x86-64",
|
||||||
|
"+avx2",
|
||||||
|
opt,
|
||||||
|
reloc,
|
||||||
|
model,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let context = Context::create();
|
||||||
|
let module = context.create_module("my_module");
|
||||||
|
let void_type = context.void_type();
|
||||||
|
let fn_type = void_type.fn_type(&[], false);
|
||||||
|
|
||||||
|
module.add_function("my_fn", fn_type, None);
|
||||||
|
|
||||||
|
target_machine
|
||||||
|
.write_to_file(&module, FileType::Assembly, &path)
|
||||||
|
.expect("writing to file succeeded");
|
||||||
|
|
||||||
|
panic!("TODO remove this test");
|
||||||
|
}
|
||||||
|
}
|
33
Cargo.lock
generated
33
Cargo.lock
generated
|
@ -526,6 +526,32 @@ version = "0.6.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roc-cli"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"im",
|
||||||
|
"im-rc",
|
||||||
|
"inkwell",
|
||||||
|
"inlinable_string",
|
||||||
|
"roc_builtins",
|
||||||
|
"roc_can",
|
||||||
|
"roc_collections",
|
||||||
|
"roc_constrain",
|
||||||
|
"roc_gen",
|
||||||
|
"roc_module",
|
||||||
|
"roc_mono",
|
||||||
|
"roc_parse",
|
||||||
|
"roc_problem",
|
||||||
|
"roc_region",
|
||||||
|
"roc_solve",
|
||||||
|
"roc_types",
|
||||||
|
"roc_unify",
|
||||||
|
"roc_uniq",
|
||||||
|
"target-lexicon",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roc_builtins"
|
name = "roc_builtins"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -642,6 +668,7 @@ dependencies = [
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"roc_unify",
|
"roc_unify",
|
||||||
"roc_uniq",
|
"roc_uniq",
|
||||||
|
"target-lexicon",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -903,6 +930,12 @@ dependencies = [
|
||||||
"unicode-xid 0.2.0",
|
"unicode-xid 0.2.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "target-lexicon"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
|
|
@ -19,5 +19,7 @@ members = [
|
||||||
"compiler/load",
|
"compiler/load",
|
||||||
"compiler/gen",
|
"compiler/gen",
|
||||||
"vendor/ena",
|
"vendor/ena",
|
||||||
"vendor/pathfinding"
|
"vendor/pathfinding",
|
||||||
|
"cli"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
BIN
a.out
Executable file
BIN
a.out
Executable file
Binary file not shown.
|
@ -8,6 +8,50 @@ keywords = ["roc", "gui"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "A CLI for Roc"
|
description = "A CLI for Roc"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
default-run = "roc"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "roc"
|
||||||
|
path = "src/main.rs"
|
||||||
|
test = false
|
||||||
|
bench = false
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
roc = { path = "../", version = "0.1.0" }
|
roc_collections = { path = "../compiler/collections" }
|
||||||
|
roc_can = { path = "../compiler/can" }
|
||||||
|
roc_parse = { path = "../compiler/parse" }
|
||||||
|
roc_region = { path = "../compiler/region" }
|
||||||
|
roc_module = { path = "../compiler/module" }
|
||||||
|
roc_problem = { path = "../compiler/problem" }
|
||||||
|
roc_types = { path = "../compiler/types" }
|
||||||
|
roc_builtins = { path = "../compiler/builtins" }
|
||||||
|
roc_constrain = { path = "../compiler/constrain" }
|
||||||
|
roc_uniq = { path = "../compiler/uniq" }
|
||||||
|
roc_unify = { path = "../compiler/unify" }
|
||||||
|
roc_solve = { path = "../compiler/solve" }
|
||||||
|
roc_mono = { path = "../compiler/mono" }
|
||||||
|
roc_gen = { path = "../compiler/gen", version = "0.1.0" }
|
||||||
|
im = "14" # im and im-rc should always have the same version!
|
||||||
|
im-rc = "14" # im and im-rc should always have the same version!
|
||||||
|
bumpalo = { version = "3.2", features = ["collections"] }
|
||||||
|
inlinable_string = "0.1.0"
|
||||||
|
# NOTE: rtfeldman/inkwell is a fork of TheDan64/inkwell which does not change anything.
|
||||||
|
#
|
||||||
|
# The reason for this fork is that the way Inkwell is designed, you have to use
|
||||||
|
# a particular branch (e.g. "llvm8-0") in Cargo.toml. That would be fine, except that
|
||||||
|
# breaking changes get pushed directly to that branch, which breaks our build
|
||||||
|
# without warning.
|
||||||
|
#
|
||||||
|
# We tried referencing a specific rev on TheDan64/inkwell directly (instead of branch),
|
||||||
|
# but although that worked locally, it did not work on GitHub Actions. (After a few
|
||||||
|
# hours of investigation, gave up trying to figure out why.) So this is the workaround:
|
||||||
|
# having an immutable tag on the rtfeldman/inkwell fork which points to
|
||||||
|
# a particular "release" of Inkwell.
|
||||||
|
#
|
||||||
|
# When we want to update Inkwell, we can sync up rtfeldman/inkwell to the latest
|
||||||
|
# commit of TheDan64/inkwell, push a new tag which points to the latest commit,
|
||||||
|
# change the tag value in this Cargo.toml to point to that tag, and `cargo update`.
|
||||||
|
# This way, GitHub Actions works and nobody's builds get broken.
|
||||||
|
inkwell = { git = "https://github.com/rtfeldman/inkwell", tag = "llvm8-0.release2" }
|
||||||
|
target-lexicon = "0.10"
|
||||||
|
|
458
cli/src/helpers.rs
Normal file
458
cli/src/helpers.rs
Normal file
|
@ -0,0 +1,458 @@
|
||||||
|
use bumpalo::Bump;
|
||||||
|
use roc_builtins::unique::uniq_stdlib;
|
||||||
|
use roc_can::constraint::Constraint;
|
||||||
|
use roc_can::env::Env;
|
||||||
|
use roc_can::expected::Expected;
|
||||||
|
use roc_can::expr::{canonicalize_expr, Expr, Output};
|
||||||
|
use roc_can::operator;
|
||||||
|
use roc_can::scope::Scope;
|
||||||
|
use roc_collections::all::{ImMap, ImSet, MutMap, SendMap, SendSet};
|
||||||
|
use roc_constrain::expr::constrain_expr;
|
||||||
|
use roc_constrain::module::{constrain_imported_values, load_builtin_aliases, Import};
|
||||||
|
use roc_module::ident::Ident;
|
||||||
|
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, Symbol};
|
||||||
|
use roc_parse::ast::{self, Attempting};
|
||||||
|
use roc_parse::blankspace::space0_before;
|
||||||
|
use roc_parse::parser::{loc, Fail, Parser, State};
|
||||||
|
use roc_problem::can::Problem;
|
||||||
|
use roc_region::all::{Located, Region};
|
||||||
|
use roc_solve::solve;
|
||||||
|
use roc_types::subs::{Content, Subs, VarStore, Variable};
|
||||||
|
use roc_types::types::Type;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub fn test_home() -> ModuleId {
|
||||||
|
ModuleIds::default().get_or_insert(&"Test".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn infer_expr(
|
||||||
|
subs: Subs,
|
||||||
|
problems: &mut Vec<roc_types::types::Problem>,
|
||||||
|
constraint: &Constraint,
|
||||||
|
expr_var: Variable,
|
||||||
|
) -> (Content, Subs) {
|
||||||
|
let env = solve::Env {
|
||||||
|
aliases: MutMap::default(),
|
||||||
|
vars_by_symbol: SendMap::default(),
|
||||||
|
};
|
||||||
|
let (solved, _) = solve::run(&env, problems, subs, constraint);
|
||||||
|
|
||||||
|
let content = solved.inner().get_without_compacting(expr_var).content;
|
||||||
|
|
||||||
|
(content, solved.into_inner())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used in the with_larger_debug_stack() function, for tests that otherwise
|
||||||
|
/// run out of stack space in debug builds (but don't in --release builds)
|
||||||
|
#[allow(dead_code)]
|
||||||
|
const EXPANDED_STACK_SIZE: usize = 4 * 1024 * 1024;
|
||||||
|
|
||||||
|
/// Without this, some tests pass in `cargo test --release` but fail without
|
||||||
|
/// the --release flag because they run out of stack space. This increases
|
||||||
|
/// stack size for debug builds only, while leaving the stack space at the default
|
||||||
|
/// amount for release builds.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub fn with_larger_debug_stack<F>(run_test: F)
|
||||||
|
where
|
||||||
|
F: FnOnce() -> (),
|
||||||
|
F: Send,
|
||||||
|
F: 'static,
|
||||||
|
{
|
||||||
|
std::thread::Builder::new()
|
||||||
|
.stack_size(EXPANDED_STACK_SIZE)
|
||||||
|
.spawn(run_test)
|
||||||
|
.expect("Error while spawning expanded dev stack size thread")
|
||||||
|
.join()
|
||||||
|
.expect("Error while joining expanded dev stack size thread")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// In --release builds, don't increase the stack size. Run the test normally.
|
||||||
|
/// This way, we find out if any of our tests are blowing the stack even after
|
||||||
|
/// optimizations in release builds.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn with_larger_debug_stack<F>(run_test: F)
|
||||||
|
where
|
||||||
|
F: FnOnce() -> (),
|
||||||
|
F: Send,
|
||||||
|
F: 'static,
|
||||||
|
{
|
||||||
|
run_test()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn parse_with<'a>(arena: &'a Bump, input: &'a str) -> Result<ast::Expr<'a>, Fail> {
|
||||||
|
parse_loc_with(arena, input).map(|loc_expr| loc_expr.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn parse_loc_with<'a>(arena: &'a Bump, input: &'a str) -> Result<Located<ast::Expr<'a>>, Fail> {
|
||||||
|
let state = State::new(&input, Attempting::Module);
|
||||||
|
let parser = space0_before(loc(roc_parse::expr::expr(0)), 0);
|
||||||
|
let answer = parser.parse(&arena, state);
|
||||||
|
|
||||||
|
answer
|
||||||
|
.map(|(loc_expr, _)| loc_expr)
|
||||||
|
.map_err(|(fail, _)| fail)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn can_expr(expr_str: &str) -> CanExprOut {
|
||||||
|
can_expr_with(&Bump::new(), test_home(), expr_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn uniq_expr(
|
||||||
|
expr_str: &str,
|
||||||
|
) -> (
|
||||||
|
Located<Expr>,
|
||||||
|
Output,
|
||||||
|
Vec<Problem>,
|
||||||
|
Subs,
|
||||||
|
Variable,
|
||||||
|
Constraint,
|
||||||
|
ModuleId,
|
||||||
|
Interns,
|
||||||
|
) {
|
||||||
|
let declared_idents: &ImMap<Ident, (Symbol, Region)> = &ImMap::default();
|
||||||
|
|
||||||
|
uniq_expr_with(&Bump::new(), expr_str, declared_idents)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn uniq_expr_with(
|
||||||
|
arena: &Bump,
|
||||||
|
expr_str: &str,
|
||||||
|
declared_idents: &ImMap<Ident, (Symbol, Region)>,
|
||||||
|
) -> (
|
||||||
|
Located<Expr>,
|
||||||
|
Output,
|
||||||
|
Vec<Problem>,
|
||||||
|
Subs,
|
||||||
|
Variable,
|
||||||
|
Constraint,
|
||||||
|
ModuleId,
|
||||||
|
Interns,
|
||||||
|
) {
|
||||||
|
let home = test_home();
|
||||||
|
let CanExprOut {
|
||||||
|
loc_expr,
|
||||||
|
output,
|
||||||
|
problems,
|
||||||
|
var_store: old_var_store,
|
||||||
|
var,
|
||||||
|
interns,
|
||||||
|
..
|
||||||
|
} = can_expr_with(arena, home, expr_str);
|
||||||
|
|
||||||
|
// double check
|
||||||
|
let var_store = VarStore::new(old_var_store.fresh());
|
||||||
|
|
||||||
|
let expected2 = Expected::NoExpectation(Type::Variable(var));
|
||||||
|
let constraint = roc_constrain::uniq::constrain_declaration(
|
||||||
|
home,
|
||||||
|
&var_store,
|
||||||
|
Region::zero(),
|
||||||
|
&loc_expr,
|
||||||
|
declared_idents,
|
||||||
|
expected2,
|
||||||
|
);
|
||||||
|
|
||||||
|
let stdlib = uniq_stdlib();
|
||||||
|
|
||||||
|
let types = stdlib.types;
|
||||||
|
let imports: Vec<_> = types
|
||||||
|
.iter()
|
||||||
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
|
loc_symbol: Located::at(*region, *symbol),
|
||||||
|
solved_type: solved_type,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// load builtin values
|
||||||
|
|
||||||
|
// TODO what to do with those rigids?
|
||||||
|
let (_introduced_rigids, constraint) =
|
||||||
|
constrain_imported_values(imports, constraint, &var_store);
|
||||||
|
|
||||||
|
// load builtin types
|
||||||
|
let mut constraint = load_builtin_aliases(&stdlib.aliases, constraint, &var_store);
|
||||||
|
|
||||||
|
constraint.instantiate_aliases(&var_store);
|
||||||
|
|
||||||
|
let subs2 = Subs::new(var_store.into());
|
||||||
|
|
||||||
|
(
|
||||||
|
loc_expr, output, problems, subs2, var, constraint, home, interns,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CanExprOut {
|
||||||
|
pub loc_expr: Located<Expr>,
|
||||||
|
pub output: Output,
|
||||||
|
pub problems: Vec<Problem>,
|
||||||
|
pub home: ModuleId,
|
||||||
|
pub interns: Interns,
|
||||||
|
pub var_store: VarStore,
|
||||||
|
pub var: Variable,
|
||||||
|
pub constraint: Constraint,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut {
|
||||||
|
let loc_expr = parse_loc_with(&arena, expr_str).unwrap_or_else(|e| {
|
||||||
|
panic!(
|
||||||
|
"can_expr_with() got a parse error when attempting to canonicalize:\n\n{:?} {:?}",
|
||||||
|
expr_str, e
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let var_store = VarStore::default();
|
||||||
|
let var = var_store.fresh();
|
||||||
|
let expected = Expected::NoExpectation(Type::Variable(var));
|
||||||
|
let module_ids = ModuleIds::default();
|
||||||
|
|
||||||
|
// Desugar operators (convert them to Apply calls, taking into account
|
||||||
|
// operator precedence and associativity rules), before doing other canonicalization.
|
||||||
|
//
|
||||||
|
// If we did this *during* canonicalization, then each time we
|
||||||
|
// visited a BinOp node we'd recursively try to apply this to each of its nested
|
||||||
|
// operators, and then again on *their* nested operators, ultimately applying the
|
||||||
|
// rules multiple times unnecessarily.
|
||||||
|
let loc_expr = operator::desugar_expr(arena, &loc_expr);
|
||||||
|
|
||||||
|
let mut scope = Scope::new(home);
|
||||||
|
let dep_idents = IdentIds::exposed_builtins(0);
|
||||||
|
let mut env = Env::new(home, dep_idents, &module_ids, IdentIds::default());
|
||||||
|
let (loc_expr, output) = canonicalize_expr(
|
||||||
|
&mut env,
|
||||||
|
&var_store,
|
||||||
|
&mut scope,
|
||||||
|
Region::zero(),
|
||||||
|
&loc_expr.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
let constraint = constrain_expr(
|
||||||
|
&roc_constrain::expr::Env {
|
||||||
|
rigids: ImMap::default(),
|
||||||
|
home,
|
||||||
|
},
|
||||||
|
loc_expr.region,
|
||||||
|
&loc_expr.value,
|
||||||
|
expected,
|
||||||
|
);
|
||||||
|
|
||||||
|
let types = roc_builtins::std::types();
|
||||||
|
|
||||||
|
let imports: Vec<_> = types
|
||||||
|
.iter()
|
||||||
|
.map(|(symbol, (solved_type, region))| Import {
|
||||||
|
loc_symbol: Located::at(*region, *symbol),
|
||||||
|
solved_type: solved_type,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
//load builtin values
|
||||||
|
let (_introduced_rigids, constraint) =
|
||||||
|
constrain_imported_values(imports, constraint, &var_store);
|
||||||
|
|
||||||
|
// TODO determine what to do with those rigids
|
||||||
|
// for var in introduced_rigids {
|
||||||
|
// output.ftv.insert(var, format!("internal_{:?}", var).into());
|
||||||
|
// }
|
||||||
|
|
||||||
|
//load builtin types
|
||||||
|
let mut constraint =
|
||||||
|
load_builtin_aliases(&roc_builtins::std::aliases(), constraint, &var_store);
|
||||||
|
|
||||||
|
constraint.instantiate_aliases(&var_store);
|
||||||
|
|
||||||
|
let mut all_ident_ids = MutMap::default();
|
||||||
|
|
||||||
|
// When pretty printing types, we may need the exposed builtins,
|
||||||
|
// so include them in the Interns we'll ultimately return.
|
||||||
|
for (module_id, ident_ids) in IdentIds::exposed_builtins(0) {
|
||||||
|
all_ident_ids.insert(module_id, ident_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
all_ident_ids.insert(home, env.ident_ids);
|
||||||
|
|
||||||
|
let interns = Interns {
|
||||||
|
module_ids: env.module_ids.clone(),
|
||||||
|
all_ident_ids,
|
||||||
|
};
|
||||||
|
|
||||||
|
CanExprOut {
|
||||||
|
loc_expr,
|
||||||
|
output,
|
||||||
|
problems: env.problems,
|
||||||
|
home: env.home,
|
||||||
|
var_store,
|
||||||
|
interns,
|
||||||
|
var,
|
||||||
|
constraint,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn mut_map_from_pairs<K, V, I>(pairs: I) -> MutMap<K, V>
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = (K, V)>,
|
||||||
|
K: Hash + Eq,
|
||||||
|
{
|
||||||
|
let mut answer = MutMap::default();
|
||||||
|
|
||||||
|
for (key, value) in pairs {
|
||||||
|
answer.insert(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
answer
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn im_map_from_pairs<K, V, I>(pairs: I) -> ImMap<K, V>
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = (K, V)>,
|
||||||
|
K: Hash + Eq + Clone,
|
||||||
|
V: Clone,
|
||||||
|
{
|
||||||
|
let mut answer = ImMap::default();
|
||||||
|
|
||||||
|
for (key, value) in pairs {
|
||||||
|
answer.insert(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
answer
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn send_set_from<V, I>(elems: I) -> SendSet<V>
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = V>,
|
||||||
|
V: Hash + Eq + Clone,
|
||||||
|
{
|
||||||
|
let mut answer = SendSet::default();
|
||||||
|
|
||||||
|
for elem in elems {
|
||||||
|
answer.insert(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
answer
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn fixtures_dir<'a>() -> PathBuf {
|
||||||
|
Path::new("tests").join("fixtures").join("build")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn builtins_dir<'a>() -> PathBuf {
|
||||||
|
PathBuf::new().join("builtins")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check constraints
|
||||||
|
//
|
||||||
|
// Keep track of the used (in types or expectations) variables, and the declared variables (in
|
||||||
|
// flex_vars or rigid_vars fields of LetConstraint. These roc_collections should match: no duplicates
|
||||||
|
// and no variables that are used but not declared are allowed.
|
||||||
|
//
|
||||||
|
// There is one exception: the initial variable (that stores the type of the whole expression) is
|
||||||
|
// never declared, but is used.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn assert_correct_variable_usage(constraint: &Constraint) {
|
||||||
|
// variables declared in constraint (flex_vars or rigid_vars)
|
||||||
|
// and variables actually used in constraints
|
||||||
|
let (declared, used) = variable_usage(constraint);
|
||||||
|
|
||||||
|
let used: ImSet<Variable> = used.clone().into();
|
||||||
|
let mut decl: ImSet<Variable> = declared.rigid_vars.clone().into();
|
||||||
|
|
||||||
|
for var in declared.flex_vars.clone() {
|
||||||
|
decl.insert(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
let diff = used.clone().relative_complement(decl);
|
||||||
|
|
||||||
|
// NOTE: this checks whether we're using variables that are not declared. For recursive type
|
||||||
|
// definitions, their rigid types are declared twice, which is correct!
|
||||||
|
if !diff.is_empty() {
|
||||||
|
println!("VARIABLE USAGE PROBLEM");
|
||||||
|
|
||||||
|
println!("used: {:?}", &used);
|
||||||
|
println!("rigids: {:?}", &declared.rigid_vars);
|
||||||
|
println!("flexs: {:?}", &declared.flex_vars);
|
||||||
|
|
||||||
|
println!("difference: {:?}", &diff);
|
||||||
|
|
||||||
|
panic!("variable usage problem (see stdout for details)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct SeenVariables {
|
||||||
|
pub rigid_vars: Vec<Variable>,
|
||||||
|
pub flex_vars: Vec<Variable>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn variable_usage(con: &Constraint) -> (SeenVariables, Vec<Variable>) {
|
||||||
|
let mut declared = SeenVariables::default();
|
||||||
|
let mut used = ImSet::default();
|
||||||
|
variable_usage_help(con, &mut declared, &mut used);
|
||||||
|
|
||||||
|
used.remove(unsafe { &Variable::unsafe_test_debug_variable(1) });
|
||||||
|
|
||||||
|
let mut used_vec: Vec<Variable> = used.into_iter().collect();
|
||||||
|
used_vec.sort();
|
||||||
|
|
||||||
|
declared.rigid_vars.sort();
|
||||||
|
declared.flex_vars.sort();
|
||||||
|
|
||||||
|
(declared, used_vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn variable_usage_help(con: &Constraint, declared: &mut SeenVariables, used: &mut ImSet<Variable>) {
|
||||||
|
use Constraint::*;
|
||||||
|
|
||||||
|
match con {
|
||||||
|
True | SaveTheEnvironment => (),
|
||||||
|
Eq(tipe, expectation, _) => {
|
||||||
|
for v in tipe.variables() {
|
||||||
|
used.insert(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
for v in expectation.get_type_ref().variables() {
|
||||||
|
used.insert(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Lookup(_, expectation, _) => {
|
||||||
|
for v in expectation.get_type_ref().variables() {
|
||||||
|
used.insert(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Pattern(_, _, tipe, pexpectation) => {
|
||||||
|
for v in tipe.variables() {
|
||||||
|
used.insert(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
for v in pexpectation.get_type_ref().variables() {
|
||||||
|
used.insert(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Let(letcon) => {
|
||||||
|
declared.rigid_vars.extend(letcon.rigid_vars.clone());
|
||||||
|
declared.flex_vars.extend(letcon.flex_vars.clone());
|
||||||
|
|
||||||
|
variable_usage_help(&letcon.defs_constraint, declared, used);
|
||||||
|
variable_usage_help(&letcon.ret_constraint, declared, used);
|
||||||
|
}
|
||||||
|
And(constraints) => {
|
||||||
|
for sub in constraints {
|
||||||
|
variable_usage_help(sub, declared, used);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
268
cli/src/main.rs
268
cli/src/main.rs
|
@ -1,15 +1,32 @@
|
||||||
extern crate roc;
|
extern crate roc_gen;
|
||||||
|
|
||||||
use roc::eval::Evaluated::*;
|
use crate::helpers::{infer_expr, uniq_expr_with};
|
||||||
use roc::eval::{call, eval, Evaluated};
|
use bumpalo::Bump;
|
||||||
use roc::expr::Expr;
|
use inkwell::context::Context;
|
||||||
use roc::parse;
|
use inkwell::module::Linkage;
|
||||||
use roc::region::{Located, Region};
|
use inkwell::passes::PassManager;
|
||||||
|
use inkwell::types::BasicType;
|
||||||
|
use inkwell::OptimizationLevel;
|
||||||
|
use roc_collections::all::ImMap;
|
||||||
|
use roc_gen::llvm::build::{build_proc, build_proc_header, get_call_conventions};
|
||||||
|
use roc_gen::llvm::convert::basic_type_from_layout;
|
||||||
|
use roc_mono::expr::{Expr, Procs};
|
||||||
|
use roc_mono::layout::Layout;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
|
use inkwell::targets::{
|
||||||
|
CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetTriple,
|
||||||
|
};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
use std::path::Path;
|
||||||
|
use target_lexicon::Triple;
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
pub mod helpers;
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let now = SystemTime::now();
|
||||||
let argv = std::env::args().into_iter().collect::<Vec<String>>();
|
let argv = std::env::args().into_iter().collect::<Vec<String>>();
|
||||||
|
|
||||||
match argv.get(1) {
|
match argv.get(1) {
|
||||||
|
@ -19,9 +36,15 @@ fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
file.read_to_string(&mut contents)?;
|
file.read_to_string(&mut contents)?;
|
||||||
|
|
||||||
let expr = parse::parse_string(contents.as_str()).unwrap();
|
let dest_filename = Path::new(filename).with_extension("o");
|
||||||
|
|
||||||
process_task(eval(expr))
|
gen(contents.as_str(), Triple::host(), &dest_filename);
|
||||||
|
|
||||||
|
let end_time = now.elapsed().unwrap();
|
||||||
|
|
||||||
|
println!("Finished in {} ms\n", end_time.as_millis());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
println!("Usage: roc FILENAME.roc");
|
println!("Usage: roc FILENAME.roc");
|
||||||
|
@ -31,109 +54,158 @@ fn main() -> std::io::Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_task(evaluated: Evaluated) -> std::io::Result<()> {
|
fn gen(src: &str, target: Triple, dest_filename: &Path) {
|
||||||
match evaluated {
|
// Build the expr
|
||||||
EvalError(region, problem) => {
|
let arena = Bump::new();
|
||||||
println!(
|
|
||||||
"\n\u{001B}[4mruntime error\u{001B}[24m\n\n{} at {}\n",
|
|
||||||
format!("{}", problem),
|
|
||||||
format!("line {}, column {}", region.start_line, region.start_col)
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
let (loc_expr, _output, _problems, subs, var, constraint, home, interns) =
|
||||||
}
|
uniq_expr_with(&arena, src, &ImMap::default());
|
||||||
ApplyVariant(name, Some(mut vals)) => {
|
|
||||||
match name.as_str() {
|
let mut unify_problems = Vec::new();
|
||||||
"Echo" => {
|
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
||||||
// Extract the string from the Echo variant.
|
|
||||||
let string_to_be_displayed = match vals.pop() {
|
let context = Context::create();
|
||||||
Some(Str(payload)) => payload,
|
let module = context.create_module("app");
|
||||||
Some(EvalError(region, err)) => {
|
let builder = context.create_builder();
|
||||||
panic!(
|
let fpm = PassManager::create(&module);
|
||||||
"RUNTIME ERROR in Echo: {} at {}",
|
|
||||||
format!("{}", err),
|
roc_gen::llvm::build::add_passes(&fpm);
|
||||||
format!("line {}, column {}", region.start_line, region.start_col)
|
|
||||||
);
|
fpm.initialize();
|
||||||
}
|
|
||||||
Some(val) => {
|
// Compute main_fn_type before moving subs to Env
|
||||||
panic!("TYPE MISMATCH in Echo: {}", format!("{}", val));
|
let pointer_bytes = target.pointer_width().unwrap().bytes() as u32;
|
||||||
}
|
let layout = Layout::from_content(&arena, content, &subs, pointer_bytes)
|
||||||
None => {
|
.unwrap_or_else(|err| panic!("Code gen error in test: could not convert to layout. Err was {:?} and Subs were {:?}", err, subs));
|
||||||
panic!("TYPE MISMATCH in Echo: None");
|
|
||||||
}
|
let execution_engine = module
|
||||||
|
.create_jit_execution_engine(OptimizationLevel::None)
|
||||||
|
.expect("Error creating JIT execution engine for test");
|
||||||
|
|
||||||
|
let ptr_bytes = execution_engine
|
||||||
|
.get_target_data()
|
||||||
|
.get_pointer_byte_size(None);
|
||||||
|
let main_fn_type =
|
||||||
|
basic_type_from_layout(&arena, &context, &layout, ptr_bytes).fn_type(&[], false);
|
||||||
|
let main_fn_name = "$Test.main";
|
||||||
|
|
||||||
|
// Compile and add all the Procs before adding main
|
||||||
|
let mut env = roc_gen::llvm::build::Env {
|
||||||
|
arena: &arena,
|
||||||
|
builder: &builder,
|
||||||
|
context: &context,
|
||||||
|
interns,
|
||||||
|
module: arena.alloc(module),
|
||||||
|
ptr_bytes,
|
||||||
};
|
};
|
||||||
|
let mut procs = Procs::default();
|
||||||
|
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
||||||
|
|
||||||
// Print the string to the console, since that's what Echo does!
|
// Populate Procs and get the low-level Expr from the canonical Expr
|
||||||
println!("{}", string_to_be_displayed);
|
let main_body = Expr::new(
|
||||||
|
&arena,
|
||||||
|
&mut subs,
|
||||||
|
loc_expr.value,
|
||||||
|
&mut procs,
|
||||||
|
home,
|
||||||
|
&mut ident_ids,
|
||||||
|
pointer_bytes,
|
||||||
|
);
|
||||||
|
|
||||||
// Continue with the callback.
|
// Put this module's ident_ids back in the interns, so we can use them in env.
|
||||||
let callback = vals.pop().unwrap();
|
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
|
||||||
process_task(call(
|
let mut headers = Vec::with_capacity(procs.len());
|
||||||
Region {
|
|
||||||
start_line: 0,
|
|
||||||
start_col: 0,
|
|
||||||
end_line: 0,
|
|
||||||
end_col: 0,
|
|
||||||
},
|
|
||||||
callback,
|
|
||||||
vec![with_zero_loc(Expr::EmptyRecord)],
|
|
||||||
))
|
|
||||||
}
|
|
||||||
"Read" => {
|
|
||||||
// Read a line from from stdin, since that's what Read does!
|
|
||||||
let mut input = String::new();
|
|
||||||
|
|
||||||
io::stdin().read_line(&mut input)?;
|
// Add all the Proc headers to the module.
|
||||||
|
// We have to do this in a separate pass first,
|
||||||
|
// because their bodies may reference each other.
|
||||||
|
for (symbol, opt_proc) in procs.as_map().into_iter() {
|
||||||
|
if let Some(proc) = opt_proc {
|
||||||
|
let (fn_val, arg_basic_types) = build_proc_header(&env, symbol, &proc);
|
||||||
|
|
||||||
// Continue with the callback.
|
headers.push((proc, fn_val, arg_basic_types));
|
||||||
let callback = vals.pop().unwrap();
|
|
||||||
|
|
||||||
process_task(call(
|
|
||||||
Region {
|
|
||||||
start_line: 0,
|
|
||||||
start_col: 0,
|
|
||||||
end_line: 0,
|
|
||||||
end_col: 0,
|
|
||||||
},
|
|
||||||
callback,
|
|
||||||
vec![with_zero_loc(Expr::Str(input.trim().to_string()))],
|
|
||||||
))
|
|
||||||
}
|
|
||||||
"Success" => {
|
|
||||||
// We finished all our tasks. Great! No need to print anything.
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// We don't recognize this variant, so display it and exit.
|
|
||||||
display_val(ApplyVariant(name, Some(vals)));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
output => {
|
|
||||||
// We don't recognize this value, so display it and exit.
|
|
||||||
display_val(output);
|
|
||||||
|
|
||||||
Ok(())
|
// Build each proc using its header info.
|
||||||
|
for (proc, fn_val, arg_basic_types) in headers {
|
||||||
|
// NOTE: This is here to be uncommented in case verification fails.
|
||||||
|
// (This approach means we don't have to defensively clone name here.)
|
||||||
|
//
|
||||||
|
// println!("\n\nBuilding and then verifying function {}\n\n", name);
|
||||||
|
build_proc(&env, proc, &procs, fn_val, arg_basic_types);
|
||||||
|
|
||||||
|
if fn_val.verify(true) {
|
||||||
|
fpm.run_on(&fn_val);
|
||||||
|
} else {
|
||||||
|
// NOTE: If this fails, uncomment the above println to debug.
|
||||||
|
panic!(
|
||||||
|
"Non-main function failed LLVM verification. Uncomment the above println to debug!"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn with_zero_loc<T>(val: T) -> Located<T> {
|
// Add main to the module.
|
||||||
Located::new(
|
let cc = get_call_conventions(target.default_calling_convention().unwrap());
|
||||||
val,
|
let main_fn = env.module.add_function(main_fn_name, main_fn_type, None);
|
||||||
Region {
|
|
||||||
start_line: 0,
|
|
||||||
start_col: 0,
|
|
||||||
|
|
||||||
end_line: 0,
|
main_fn.set_call_conventions(cc);
|
||||||
end_col: 0,
|
main_fn.set_linkage(Linkage::External);
|
||||||
},
|
|
||||||
|
// Add main's body
|
||||||
|
let basic_block = context.append_basic_block(main_fn, "entry");
|
||||||
|
|
||||||
|
builder.position_at_end(basic_block);
|
||||||
|
|
||||||
|
let ret = roc_gen::llvm::build::build_expr(
|
||||||
|
&env,
|
||||||
|
&ImMap::default(),
|
||||||
|
main_fn,
|
||||||
|
&main_body,
|
||||||
|
&mut Procs::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
builder.build_return(Some(&ret));
|
||||||
|
|
||||||
|
// Uncomment this to see the module's un-optimized LLVM instruction output:
|
||||||
|
// env.module.print_to_stderr();
|
||||||
|
|
||||||
|
if main_fn.verify(true) {
|
||||||
|
fpm.run_on(&main_fn);
|
||||||
|
} else {
|
||||||
|
panic!("Function {} failed LLVM verification.", main_fn_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the module
|
||||||
|
if let Err(errors) = env.module.verify() {
|
||||||
|
panic!("Errors defining module: {:?}", errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uncomment this to see the module's optimized LLVM instruction output:
|
||||||
|
// env.module.print_to_stderr();
|
||||||
|
|
||||||
|
// Emit
|
||||||
|
Target::initialize_x86(&InitializationConfig::default());
|
||||||
|
|
||||||
|
let opt = OptimizationLevel::Default;
|
||||||
|
let reloc = RelocMode::Default;
|
||||||
|
let model = CodeModel::Default;
|
||||||
|
let target = Target::from_name("x86-64").unwrap();
|
||||||
|
let target_machine = target
|
||||||
|
.create_target_machine(
|
||||||
|
&TargetTriple::create("x86_64-pc-linux-gnu"),
|
||||||
|
"x86-64",
|
||||||
|
"+avx2",
|
||||||
|
opt,
|
||||||
|
reloc,
|
||||||
|
model,
|
||||||
)
|
)
|
||||||
}
|
.unwrap();
|
||||||
|
|
||||||
fn display_val(evaluated: Evaluated) {
|
target_machine
|
||||||
println!("\n\u{001B}[4mroc out\u{001B}[24m\n\n{}\n", evaluated);
|
.write_to_file(&env.module, FileType::Object, &dest_filename)
|
||||||
|
.expect("Writing .o file failed");
|
||||||
|
|
||||||
|
println!("\nSuccess! 🎉\n\n\t➡ {}\n", dest_filename.display());
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ inlinable_string = "0.1.0"
|
||||||
# change the tag value in this Cargo.toml to point to that tag, and `cargo update`.
|
# change the tag value in this Cargo.toml to point to that tag, and `cargo update`.
|
||||||
# This way, GitHub Actions works and nobody's builds get broken.
|
# This way, GitHub Actions works and nobody's builds get broken.
|
||||||
inkwell = { git = "https://github.com/rtfeldman/inkwell", tag = "llvm8-0.release2" }
|
inkwell = { git = "https://github.com/rtfeldman/inkwell", tag = "llvm8-0.release2" }
|
||||||
|
target-lexicon = "0.10"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
roc_can = { path = "../can" }
|
roc_can = { path = "../can" }
|
||||||
|
|
|
@ -16,6 +16,7 @@ use roc_collections::all::ImMap;
|
||||||
use roc_module::symbol::{Interns, Symbol};
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
use roc_mono::expr::{Expr, Proc, Procs};
|
use roc_mono::expr::{Expr, Proc, Procs};
|
||||||
use roc_mono::layout::{Builtin, Layout};
|
use roc_mono::layout::{Builtin, Layout};
|
||||||
|
use target_lexicon::CallingConvention;
|
||||||
|
|
||||||
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
||||||
/// output in debug builds, but we don't want it to print to stdout in release builds!
|
/// output in debug builds, but we don't want it to print to stdout in release builds!
|
||||||
|
@ -1297,3 +1298,17 @@ fn list_set<'a, 'ctx, 'env>(
|
||||||
ret_type.into(),
|
ret_type.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Translates a target_lexicon::Triple to a LLVM calling convention u32
|
||||||
|
/// as described in https://llvm.org/doxygen/namespacellvm_1_1CallingConv.html
|
||||||
|
pub fn get_call_conventions(cc: CallingConvention) -> u32 {
|
||||||
|
use CallingConvention::*;
|
||||||
|
|
||||||
|
// For now, we're returning 0 for the C calling convention on all of these.
|
||||||
|
// Not sure if we should be picking something more specific!
|
||||||
|
match cc {
|
||||||
|
SystemV => 0,
|
||||||
|
WasmBasicCAbi => 0,
|
||||||
|
WindowsFastcall => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
4
compiler/gen/test.asm
Normal file
4
compiler/gen/test.asm
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.text
|
||||||
|
.file "my_module"
|
||||||
|
|
||||||
|
.section ".note.GNU-stack","",@progbits
|
|
@ -17,6 +17,7 @@ mod gen_tags {
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
use inkwell::execution_engine::JitFunction;
|
use inkwell::execution_engine::JitFunction;
|
||||||
|
use inkwell::module::Linkage;
|
||||||
use inkwell::passes::PassManager;
|
use inkwell::passes::PassManager;
|
||||||
use inkwell::types::BasicType;
|
use inkwell::types::BasicType;
|
||||||
use inkwell::OptimizationLevel;
|
use inkwell::OptimizationLevel;
|
||||||
|
@ -28,8 +29,9 @@ mod gen_tags {
|
||||||
use roc_types::subs::Subs;
|
use roc_types::subs::Subs;
|
||||||
|
|
||||||
use inkwell::targets::{
|
use inkwell::targets::{
|
||||||
CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine, TargetTriple,
|
CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetTriple,
|
||||||
};
|
};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn applied_tag_nothing() {
|
fn applied_tag_nothing() {
|
||||||
|
@ -625,179 +627,4 @@ mod gen_tags {
|
||||||
i64
|
i64
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_emit() {
|
|
||||||
let src = "42";
|
|
||||||
|
|
||||||
// Build the expr
|
|
||||||
let arena = Bump::new();
|
|
||||||
let (loc_expr, _output, _problems, subs, var, constraint, home, interns) = uniq_expr(src);
|
|
||||||
|
|
||||||
let mut unify_problems = Vec::new();
|
|
||||||
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
|
||||||
|
|
||||||
let context = Context::create();
|
|
||||||
let module = context.create_module("app");
|
|
||||||
let builder = context.create_builder();
|
|
||||||
let fpm = PassManager::create(&module);
|
|
||||||
|
|
||||||
roc_gen::llvm::build::add_passes(&fpm);
|
|
||||||
|
|
||||||
fpm.initialize();
|
|
||||||
|
|
||||||
// Compute main_fn_type before moving subs to Env
|
|
||||||
let layout = Layout::from_content(&arena, content, &subs, crate::helpers::eval::POINTER_SIZE)
|
|
||||||
.unwrap_or_else(|err| panic!("Code gen error in test: could not convert to layout. Err was {:?} and Subs were {:?}", err, subs));
|
|
||||||
|
|
||||||
let execution_engine = module
|
|
||||||
.create_jit_execution_engine(OptimizationLevel::None)
|
|
||||||
.expect("Error creating JIT execution engine for test");
|
|
||||||
|
|
||||||
let ptr_bytes = execution_engine
|
|
||||||
.get_target_data()
|
|
||||||
.get_pointer_byte_size(None);
|
|
||||||
let main_fn_type =
|
|
||||||
basic_type_from_layout(&arena, &context, &layout, ptr_bytes).fn_type(&[], false);
|
|
||||||
let main_fn_name = "$Test.main";
|
|
||||||
|
|
||||||
// Compile and add all the Procs before adding main
|
|
||||||
let mut env = roc_gen::llvm::build::Env {
|
|
||||||
arena: &arena,
|
|
||||||
builder: &builder,
|
|
||||||
context: &context,
|
|
||||||
interns,
|
|
||||||
module: arena.alloc(module),
|
|
||||||
ptr_bytes,
|
|
||||||
};
|
|
||||||
let mut procs = Procs::default();
|
|
||||||
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
|
||||||
|
|
||||||
// Populate Procs and get the low-level Expr from the canonical Expr
|
|
||||||
let main_body = Expr::new(
|
|
||||||
&arena,
|
|
||||||
&mut subs,
|
|
||||||
loc_expr.value,
|
|
||||||
&mut procs,
|
|
||||||
home,
|
|
||||||
&mut ident_ids,
|
|
||||||
crate::helpers::eval::POINTER_SIZE,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
|
||||||
env.interns.all_ident_ids.insert(home, ident_ids);
|
|
||||||
|
|
||||||
let mut headers = Vec::with_capacity(procs.len());
|
|
||||||
|
|
||||||
// Add all the Proc headers to the module.
|
|
||||||
// We have to do this in a separate pass first,
|
|
||||||
// because their bodies may reference each other.
|
|
||||||
for (symbol, opt_proc) in procs.as_map().into_iter() {
|
|
||||||
if let Some(proc) = opt_proc {
|
|
||||||
let (fn_val, arg_basic_types) = build_proc_header(&env, symbol, &proc);
|
|
||||||
|
|
||||||
headers.push((proc, fn_val, arg_basic_types));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build each proc using its header info.
|
|
||||||
for (proc, fn_val, arg_basic_types) in headers {
|
|
||||||
// NOTE: This is here to be uncommented in case verification fails.
|
|
||||||
// (This approach means we don't have to defensively clone name here.)
|
|
||||||
//
|
|
||||||
// println!("\n\nBuilding and then verifying function {}\n\n", name);
|
|
||||||
build_proc(&env, proc, &procs, fn_val, arg_basic_types);
|
|
||||||
|
|
||||||
if fn_val.verify(true) {
|
|
||||||
fpm.run_on(&fn_val);
|
|
||||||
} else {
|
|
||||||
// NOTE: If this fails, uncomment the above println to debug.
|
|
||||||
panic!("Non-main function failed LLVM verification. Uncomment the above println to debug!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add main to the module.
|
|
||||||
let main_fn = env.module.add_function(main_fn_name, main_fn_type, None);
|
|
||||||
|
|
||||||
main_fn.set_call_conventions(crate::helpers::eval::MAIN_CALLING_CONVENTION);
|
|
||||||
|
|
||||||
// Add main's body
|
|
||||||
let basic_block = context.append_basic_block(main_fn, "entry");
|
|
||||||
|
|
||||||
builder.position_at_end(basic_block);
|
|
||||||
|
|
||||||
let ret = roc_gen::llvm::build::build_expr(
|
|
||||||
&env,
|
|
||||||
&ImMap::default(),
|
|
||||||
main_fn,
|
|
||||||
&main_body,
|
|
||||||
&mut Procs::default(),
|
|
||||||
);
|
|
||||||
|
|
||||||
builder.build_return(Some(&ret));
|
|
||||||
|
|
||||||
// Uncomment this to see the module's un-optimized LLVM instruction output:
|
|
||||||
// env.module.print_to_stderr();
|
|
||||||
|
|
||||||
if main_fn.verify(true) {
|
|
||||||
fpm.run_on(&main_fn);
|
|
||||||
} else {
|
|
||||||
panic!("Function {} failed LLVM verification.", main_fn_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the module
|
|
||||||
if let Err(errors) = env.module.verify() {
|
|
||||||
panic!("Errors defining module: {:?}", errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uncomment this to see the module's optimized LLVM instruction output:
|
|
||||||
// env.module.print_to_stderr();
|
|
||||||
|
|
||||||
// Emit
|
|
||||||
Target::initialize_x86(&InitializationConfig::default());
|
|
||||||
|
|
||||||
let opt = OptimizationLevel::Default;
|
|
||||||
let reloc = RelocMode::Default;
|
|
||||||
let model = CodeModel::Default;
|
|
||||||
let target = Target::from_name("x86-64").unwrap();
|
|
||||||
let target_machine = target
|
|
||||||
.create_target_machine(
|
|
||||||
&TargetTriple::create("x86_64-pc-linux-gnu"),
|
|
||||||
"x86-64",
|
|
||||||
"+avx2",
|
|
||||||
opt,
|
|
||||||
reloc,
|
|
||||||
model,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let buffer = target_machine
|
|
||||||
.write_to_memory_buffer(&env.module, FileType::Assembly)
|
|
||||||
.unwrap();
|
|
||||||
let buffer_str = std::str::from_utf8(buffer.as_slice()).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
buffer_str.trim(),
|
|
||||||
indoc!(
|
|
||||||
r#"
|
|
||||||
.text
|
|
||||||
.file "app"
|
|
||||||
.globl $Test.main
|
|
||||||
.p2align 4, 0x90
|
|
||||||
.type $Test.main,@function
|
|
||||||
$Test.main:
|
|
||||||
.cfi_startproc
|
|
||||||
movl $42, %eax
|
|
||||||
retq
|
|
||||||
.Lfunc_end0:
|
|
||||||
.size $Test.main, .Lfunc_end0-($Test.main)
|
|
||||||
.cfi_endproc
|
|
||||||
|
|
||||||
|
|
||||||
.section ".note.GNU-stack","",@progbits
|
|
||||||
"#
|
|
||||||
)
|
|
||||||
.trim()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,3 @@
|
||||||
// Pointer size on current system
|
|
||||||
pub const POINTER_SIZE: u32 = std::mem::size_of::<usize>() as u32;
|
|
||||||
|
|
||||||
// 0 is the C calling convention - see https://llvm.org/doxygen/namespacellvm_1_1CallingConv.html
|
|
||||||
pub const MAIN_CALLING_CONVENTION: u32 = 0;
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! assert_llvm_evals_to {
|
macro_rules! assert_llvm_evals_to {
|
||||||
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
|
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
|
||||||
|
@ -196,7 +190,134 @@ macro_rules! assert_opt_evals_to {
|
||||||
|
|
||||||
headers.push((proc, fn_val, arg_basic_types));
|
headers.push((proc, fn_val, arg_basic_types));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build each proc using its header info.
|
||||||
|
for (proc, fn_val, arg_basic_types) in headers {
|
||||||
|
// NOTE: This is here to be uncommented in case verification fails.
|
||||||
|
// (This approach means we don't have to defensively clone name here.)
|
||||||
|
//
|
||||||
|
// println!("\n\nBuilding and then verifying function {}\n\n", name);
|
||||||
|
build_proc(&env, proc, &procs, fn_val, arg_basic_types);
|
||||||
|
|
||||||
|
if fn_val.verify(true) {
|
||||||
|
fpm.run_on(&fn_val);
|
||||||
|
} else {
|
||||||
|
// NOTE: If this fails, uncomment the above println to debug.
|
||||||
|
panic!("Non-main function failed LLVM verification. Uncomment the above println to debug!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add main to the module.
|
||||||
|
let main_fn = env.module.add_function(main_fn_name, main_fn_type, None);
|
||||||
|
|
||||||
|
main_fn.set_call_conventions($crate::helpers::eval::MAIN_CALLING_CONVENTION);
|
||||||
|
|
||||||
|
// Add main's body
|
||||||
|
let basic_block = context.append_basic_block(main_fn, "entry");
|
||||||
|
|
||||||
|
builder.position_at_end(basic_block);
|
||||||
|
|
||||||
|
let ret = roc_gen::llvm::build::build_expr(
|
||||||
|
&env,
|
||||||
|
&ImMap::default(),
|
||||||
|
main_fn,
|
||||||
|
&main_body,
|
||||||
|
&mut Procs::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
builder.build_return(Some(&ret));
|
||||||
|
|
||||||
|
// Uncomment this to see the module's un-optimized LLVM instruction output:
|
||||||
|
// env.module.print_to_stderr();
|
||||||
|
|
||||||
|
if main_fn.verify(true) {
|
||||||
|
fpm.run_on(&main_fn);
|
||||||
|
} else {
|
||||||
|
panic!("Function {} failed LLVM verification.", main_fn_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the module
|
||||||
|
if let Err(errors) = env.module.verify() {
|
||||||
|
panic!("Errors defining module: {:?}", errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uncomment this to see the module's optimized LLVM instruction output:
|
||||||
|
// env.module.print_to_stderr();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let main: JitFunction<unsafe extern "C" fn() -> $ty> = execution_engine
|
||||||
|
.get_function(main_fn_name)
|
||||||
|
.ok()
|
||||||
|
.ok_or(format!("Unable to JIT compile `{}`", main_fn_name))
|
||||||
|
.expect("errored");
|
||||||
|
|
||||||
|
assert_eq!($transform(main.call()), $expected);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! emit_expr {
|
||||||
|
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let (loc_expr, _output, _problems, subs, var, constraint, home, interns) = uniq_expr($src);
|
||||||
|
|
||||||
|
let mut unify_problems = Vec::new();
|
||||||
|
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
||||||
|
|
||||||
|
let context = Context::create();
|
||||||
|
let module = context.create_module("app");
|
||||||
|
let builder = context.create_builder();
|
||||||
|
let fpm = PassManager::create(&module);
|
||||||
|
|
||||||
|
roc_gen::llvm::build::add_passes(&fpm);
|
||||||
|
|
||||||
|
fpm.initialize();
|
||||||
|
|
||||||
|
// Compute main_fn_type before moving subs to Env
|
||||||
|
let layout = Layout::from_content(&arena, content, &subs, $crate::helpers::eval::POINTER_SIZE)
|
||||||
|
.unwrap_or_else(|err| panic!("Code gen error in test: could not convert to layout. Err was {:?} and Subs were {:?}", err, subs));
|
||||||
|
|
||||||
|
let execution_engine =
|
||||||
|
module
|
||||||
|
.create_jit_execution_engine(OptimizationLevel::None)
|
||||||
|
.expect("Error creating JIT execution engine for test");
|
||||||
|
|
||||||
|
let ptr_bytes = execution_engine.get_target_data().get_pointer_byte_size(None);
|
||||||
|
let main_fn_type = basic_type_from_layout(&arena, &context, &layout, ptr_bytes)
|
||||||
|
.fn_type(&[], false);
|
||||||
|
let main_fn_name = "$Test.main";
|
||||||
|
|
||||||
|
// Compile and add all the Procs before adding main
|
||||||
|
let mut env = roc_gen::llvm::build::Env {
|
||||||
|
arena: &arena,
|
||||||
|
builder: &builder,
|
||||||
|
context: &context,
|
||||||
|
interns,
|
||||||
|
module: arena.alloc(module),
|
||||||
|
ptr_bytes
|
||||||
|
};
|
||||||
|
let mut procs = Procs::default();
|
||||||
|
let mut ident_ids = env.interns.all_ident_ids.remove(&home).unwrap();
|
||||||
|
|
||||||
|
// Populate Procs and get the low-level Expr from the canonical Expr
|
||||||
|
let main_body = Expr::new(&arena, &mut subs, loc_expr.value, &mut procs, home, &mut ident_ids, $crate::helpers::eval::POINTER_SIZE);
|
||||||
|
|
||||||
|
// Put this module's ident_ids back in the interns, so we can use them in Env.
|
||||||
|
env.interns.all_ident_ids.insert(home, ident_ids);
|
||||||
|
|
||||||
|
let mut headers = Vec::with_capacity(procs.len());
|
||||||
|
|
||||||
|
// Add all the Proc headers to the module.
|
||||||
|
// We have to do this in a separate pass first,
|
||||||
|
// because their bodies may reference each other.
|
||||||
|
for (symbol, opt_proc) in procs.as_map().into_iter() {
|
||||||
|
if let Some(proc) = opt_proc {
|
||||||
|
let (fn_val, arg_basic_types) = build_proc_header(&env, symbol, &proc);
|
||||||
|
|
||||||
|
headers.push((proc, fn_val, arg_basic_types));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build each proc using its header info.
|
// Build each proc using its header info.
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# Hello, World!
|
# Hello, World!
|
||||||
|
|
||||||
Right now, there is only one way to build Roc programs: the Rube Goldberg Build Process.
|
Right now, there is only one way to build Roc programs: the Rube Goldberg Build Process.
|
||||||
(In the future, it will be nicer. However, at the moment, that future nicer
|
(In the future, it will be nicer. At the moment, the nicer build system exists only
|
||||||
build system exists only in our imaginations...so for now, Rube Goldberg it is!)
|
in our imaginations...so Rube Goldberg it is!)
|
||||||
|
|
||||||
## Ingredients
|
## Ingredients
|
||||||
|
|
||||||
|
@ -12,10 +12,18 @@ build system exists only in our imaginations...so for now, Rube Goldberg it is!)
|
||||||
|
|
||||||
## Steps
|
## Steps
|
||||||
|
|
||||||
1. Compile the Roc source code into a `hello.o` file. The snippet at the end of this README will do that.
|
1. `cd` into `examples/helloworld/`
|
||||||
2. Run `gcc -shared hello.o -o libhello_from_roc.so` to generate `libhello_from_roc.so`. (This filename must begin with `lib` and end in `.so` or else `host.rs` won't be able to find it!)
|
2. Run `cargo run hello.roc` to compile the Roc source code into a `hello.o` file.
|
||||||
3. Run `rustc host.rs -L .` to generate the `hello` executable. (The `-L .` flag lets it look for `libhello_from_roc.so` in the current directory.)
|
3. Run `gcc -shared hello.o -o libhello_from_roc.so` to generate `libhello_from_roc.so`. (This filename must begin with `lib` and end in `.so` or else `host.rs` won't be able to find it!)
|
||||||
4. Run `./hello` to see the greeting!
|
4. Move `libhello_from_roc.so` onto the system library path, e.g. with `sudo mv libhello_from_roc.so /usr/lib/`
|
||||||
|
5. Run `rustc host.rs -o hello` to generate the `hello` executable.
|
||||||
|
6. Run `./hello` to see the greeting!
|
||||||
|
|
||||||
|
To run in release mode instead, do:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo run --release hello.roc
|
||||||
|
```
|
||||||
|
|
||||||
## Design Notes
|
## Design Notes
|
||||||
|
|
||||||
|
@ -54,7 +62,8 @@ would be to have the host precompiled into an object file (eliminating the
|
||||||
need for Roc authors to run `rustc` in this example) and for the Roc compiler
|
need for Roc authors to run `rustc` in this example) and for the Roc compiler
|
||||||
to not only generate the object file for the Roc file, but also to link it with
|
to not only generate the object file for the Roc file, but also to link it with
|
||||||
the host object file to produce an executable (eliminating the need for `gcc`)
|
the host object file to produce an executable (eliminating the need for `gcc`)
|
||||||
such that Roc application authors can concern themselves exclusively with Roc code.
|
such that Roc application authors can concern themselves exclusively with Roc code
|
||||||
|
and need only the Roc compiler to build and to execute it.
|
||||||
|
|
||||||
Of course, none of those niceties exist yet. But we'll get there!
|
Of course, none of those niceties exist yet. But we'll get there!
|
||||||
|
|
||||||
|
|
1
examples/helloworld/hello.roc
Normal file
1
examples/helloworld/hello.roc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
"Hello, World!"
|
BIN
examples/helloworld/host
Executable file
BIN
examples/helloworld/host
Executable file
Binary file not shown.
BIN
hello
Executable file
BIN
hello
Executable file
Binary file not shown.
24
hello.asm
Normal file
24
hello.asm
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
.text
|
||||||
|
.file "app"
|
||||||
|
.globl $Test.main
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type $Test.main,@function
|
||||||
|
$Test.main:
|
||||||
|
.cfi_startproc
|
||||||
|
pushq %rax
|
||||||
|
.cfi_def_cfa_offset 16
|
||||||
|
movl $14, %edi
|
||||||
|
callq malloc
|
||||||
|
movabsq $6278066737626506568, %rcx
|
||||||
|
movq %rcx, (%rax)
|
||||||
|
movl $1684828783, 8(%rax)
|
||||||
|
movw $33, 12(%rax)
|
||||||
|
popq %rcx
|
||||||
|
.cfi_def_cfa_offset 8
|
||||||
|
retq
|
||||||
|
.Lfunc_end0:
|
||||||
|
.size $Test.main, .Lfunc_end0-($Test.main)
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
|
||||||
|
.section ".note.GNU-stack","",@progbits
|
BIN
hello.o
Normal file
BIN
hello.o
Normal file
Binary file not shown.
BIN
hello.so
Executable file
BIN
hello.so
Executable file
Binary file not shown.
BIN
lib
Executable file
BIN
lib
Executable file
Binary file not shown.
32
out.asm
Normal file
32
out.asm
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
.text
|
||||||
|
.file "app"
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type .L_0,@function
|
||||||
|
.L_0:
|
||||||
|
.cfi_startproc
|
||||||
|
movq %rdi, %rax
|
||||||
|
movq %rdi, %rdx
|
||||||
|
retq
|
||||||
|
.Lfunc_end0:
|
||||||
|
.size .L_0, .Lfunc_end0-.L_0
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.globl $Test.main
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type $Test.main,@function
|
||||||
|
$Test.main:
|
||||||
|
.cfi_startproc
|
||||||
|
pushq %rax
|
||||||
|
.cfi_def_cfa_offset 16
|
||||||
|
movl $9, %edi
|
||||||
|
callq .L_0
|
||||||
|
imulq %rdx, %rax
|
||||||
|
popq %rcx
|
||||||
|
.cfi_def_cfa_offset 8
|
||||||
|
retq
|
||||||
|
.Lfunc_end1:
|
||||||
|
.size $Test.main, .Lfunc_end1-($Test.main)
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
|
||||||
|
.section ".note.GNU-stack","",@progbits
|
395
out2.asm
Normal file
395
out2.asm
Normal file
|
@ -0,0 +1,395 @@
|
||||||
|
00000000 7F45 jg 0x47
|
||||||
|
00000002 4C rex.wr
|
||||||
|
00000003 460201 add r8b,[rcx]
|
||||||
|
00000006 0100 add [rax],eax
|
||||||
|
00000008 0000 add [rax],al
|
||||||
|
0000000A 0000 add [rax],al
|
||||||
|
0000000C 0000 add [rax],al
|
||||||
|
0000000E 0000 add [rax],al
|
||||||
|
00000010 0100 add [rax],eax
|
||||||
|
00000012 3E0001 add [ds:rcx],al
|
||||||
|
00000015 0000 add [rax],al
|
||||||
|
00000017 0000 add [rax],al
|
||||||
|
00000019 0000 add [rax],al
|
||||||
|
0000001B 0000 add [rax],al
|
||||||
|
0000001D 0000 add [rax],al
|
||||||
|
0000001F 0000 add [rax],al
|
||||||
|
00000021 0000 add [rax],al
|
||||||
|
00000023 0000 add [rax],al
|
||||||
|
00000025 0000 add [rax],al
|
||||||
|
00000027 008001000000 add [rax+0x1],al
|
||||||
|
0000002D 0000 add [rax],al
|
||||||
|
0000002F 0000 add [rax],al
|
||||||
|
00000031 0000 add [rax],al
|
||||||
|
00000033 004000 add [rax+0x0],al
|
||||||
|
00000036 0000 add [rax],al
|
||||||
|
00000038 0000 add [rax],al
|
||||||
|
0000003A 400007 add [rdi],al
|
||||||
|
0000003D 0001 add [rcx],al
|
||||||
|
0000003F 004889 add [rax-0x77],cl
|
||||||
|
00000042 F8 clc
|
||||||
|
00000043 4889FA mov rdx,rdi
|
||||||
|
00000046 C3 ret
|
||||||
|
00000047 660F1F8400000000 nop word [rax+rax+0x0]
|
||||||
|
-00
|
||||||
|
00000050 50 push rax
|
||||||
|
00000051 BF09000000 mov edi,0x9
|
||||||
|
00000056 E8E5FFFFFF call 0x40
|
||||||
|
0000005B 4801D0 add rax,rdx
|
||||||
|
0000005E 59 pop rcx
|
||||||
|
0000005F C3 ret
|
||||||
|
00000060 1400 adc al,0x0
|
||||||
|
00000062 0000 add [rax],al
|
||||||
|
00000064 0000 add [rax],al
|
||||||
|
00000066 0000 add [rax],al
|
||||||
|
00000068 017A52 add [rdx+0x52],edi
|
||||||
|
0000006B 0001 add [rcx],al
|
||||||
|
0000006D 7810 js 0x7f
|
||||||
|
0000006F 011B add [rbx],ebx
|
||||||
|
00000071 0C07 or al,0x7
|
||||||
|
00000073 089001000010 or [rax+0x10000001],dl
|
||||||
|
00000079 0000 add [rax],al
|
||||||
|
0000007B 001C00 add [rax+rax],bl
|
||||||
|
0000007E 0000 add [rax],al
|
||||||
|
00000080 0000 add [rax],al
|
||||||
|
00000082 0000 add [rax],al
|
||||||
|
00000084 07 db 0x07
|
||||||
|
00000085 0000 add [rax],al
|
||||||
|
00000087 0000 add [rax],al
|
||||||
|
00000089 0000 add [rax],al
|
||||||
|
0000008B 0018 add [rax],bl
|
||||||
|
0000008D 0000 add [rax],al
|
||||||
|
0000008F 0030 add [rax],dh
|
||||||
|
00000091 0000 add [rax],al
|
||||||
|
00000093 0000 add [rax],al
|
||||||
|
00000095 0000 add [rax],al
|
||||||
|
00000097 0010 add [rax],dl
|
||||||
|
00000099 0000 add [rax],al
|
||||||
|
0000009B 0000 add [rax],al
|
||||||
|
0000009D 41 rex.b
|
||||||
|
0000009E 0E db 0x0e
|
||||||
|
0000009F 104E0E adc [rsi+0xe],cl
|
||||||
|
000000A2 0800 or [rax],al
|
||||||
|
000000A4 0000 add [rax],al
|
||||||
|
000000A6 0000 add [rax],al
|
||||||
|
000000A8 0000 add [rax],al
|
||||||
|
000000AA 0000 add [rax],al
|
||||||
|
000000AC 0000 add [rax],al
|
||||||
|
000000AE 0000 add [rax],al
|
||||||
|
000000B0 0000 add [rax],al
|
||||||
|
000000B2 0000 add [rax],al
|
||||||
|
000000B4 0000 add [rax],al
|
||||||
|
000000B6 0000 add [rax],al
|
||||||
|
000000B8 0000 add [rax],al
|
||||||
|
000000BA 0000 add [rax],al
|
||||||
|
000000BC 0000 add [rax],al
|
||||||
|
000000BE 0000 add [rax],al
|
||||||
|
000000C0 07 db 0x07
|
||||||
|
000000C1 0000 add [rax],al
|
||||||
|
000000C3 000400 add [rax+rax],al
|
||||||
|
000000C6 F1 int1
|
||||||
|
000000C7 FF00 inc dword [rax]
|
||||||
|
000000C9 0000 add [rax],al
|
||||||
|
000000CB 0000 add [rax],al
|
||||||
|
000000CD 0000 add [rax],al
|
||||||
|
000000CF 0000 add [rax],al
|
||||||
|
000000D1 0000 add [rax],al
|
||||||
|
000000D3 0000 add [rax],al
|
||||||
|
000000D5 0000 add [rax],al
|
||||||
|
000000D7 0000 add [rax],al
|
||||||
|
000000D9 0000 add [rax],al
|
||||||
|
000000DB 0003 add [rbx],al
|
||||||
|
000000DD 0002 add [rdx],al
|
||||||
|
000000DF 0000 add [rax],al
|
||||||
|
000000E1 0000 add [rax],al
|
||||||
|
000000E3 0000 add [rax],al
|
||||||
|
000000E5 0000 add [rax],al
|
||||||
|
000000E7 0000 add [rax],al
|
||||||
|
000000E9 0000 add [rax],al
|
||||||
|
000000EB 0000 add [rax],al
|
||||||
|
000000ED 0000 add [rax],al
|
||||||
|
000000EF 000B add [rbx],cl
|
||||||
|
000000F1 0000 add [rax],al
|
||||||
|
000000F3 0012 add [rdx],dl
|
||||||
|
000000F5 0002 add [rdx],al
|
||||||
|
000000F7 0010 add [rax],dl
|
||||||
|
000000F9 0000 add [rax],al
|
||||||
|
000000FB 0000 add [rax],al
|
||||||
|
000000FD 0000 add [rax],al
|
||||||
|
000000FF 0010 add [rax],dl
|
||||||
|
00000101 0000 add [rax],al
|
||||||
|
00000103 0000 add [rax],al
|
||||||
|
00000105 0000 add [rax],al
|
||||||
|
00000107 0020 add [rax],ah
|
||||||
|
00000109 0000 add [rax],al
|
||||||
|
0000010B 0000 add [rax],al
|
||||||
|
0000010D 0000 add [rax],al
|
||||||
|
0000010F 0002 add [rdx],al
|
||||||
|
00000111 0000 add [rax],al
|
||||||
|
00000113 0002 add [rdx],al
|
||||||
|
00000115 0000 add [rax],al
|
||||||
|
00000117 0000 add [rax],al
|
||||||
|
00000119 0000 add [rax],al
|
||||||
|
0000011B 0000 add [rax],al
|
||||||
|
0000011D 0000 add [rax],al
|
||||||
|
0000011F 003400 add [rax+rax],dh
|
||||||
|
00000122 0000 add [rax],al
|
||||||
|
00000124 0000 add [rax],al
|
||||||
|
00000126 0000 add [rax],al
|
||||||
|
00000128 0200 add al,[rax]
|
||||||
|
0000012A 0000 add [rax],al
|
||||||
|
0000012C 0200 add al,[rax]
|
||||||
|
0000012E 0000 add [rax],al
|
||||||
|
00000130 1000 adc [rax],al
|
||||||
|
00000132 0000 add [rax],al
|
||||||
|
00000134 0000 add [rax],al
|
||||||
|
00000136 0000 add [rax],al
|
||||||
|
00000138 002E add [rsi],ch
|
||||||
|
0000013A 7465 jz 0x1a1
|
||||||
|
0000013C 7874 js 0x1b2
|
||||||
|
0000013E 006170 add [rcx+0x70],ah
|
||||||
|
00000141 7000 jo 0x143
|
||||||
|
00000143 2454 and al,0x54
|
||||||
|
00000145 657374 gs jnc 0x1bc
|
||||||
|
00000148 2E6D cs insd
|
||||||
|
0000014A 61 db 0x61
|
||||||
|
0000014B 696E002E6E6F74 imul ebp,[rsi+0x0],dword 0x746f6e2e
|
||||||
|
00000152 65 gs
|
||||||
|
00000153 2E cs
|
||||||
|
00000154 47 rex.rxb
|
||||||
|
00000155 4E55 push rbp
|
||||||
|
00000157 2D73746163 sub eax,0x63617473
|
||||||
|
0000015C 6B002E imul eax,[rax],byte +0x2e
|
||||||
|
0000015F 7265 jc 0x1c6
|
||||||
|
00000161 6C insb
|
||||||
|
00000162 61 db 0x61
|
||||||
|
00000163 2E65685F667261 gs push qword 0x6172665f
|
||||||
|
0000016A 6D insd
|
||||||
|
0000016B 65002E add [gs:rsi],ch
|
||||||
|
0000016E 7374 jnc 0x1e4
|
||||||
|
00000170 7274 jc 0x1e6
|
||||||
|
00000172 61 db 0x61
|
||||||
|
00000173 62 db 0x62
|
||||||
|
00000174 002E add [rsi],ch
|
||||||
|
00000176 7379 jnc 0x1f1
|
||||||
|
00000178 6D insd
|
||||||
|
00000179 7461 jz 0x1dc
|
||||||
|
0000017B 62 db 0x62
|
||||||
|
0000017C 0000 add [rax],al
|
||||||
|
0000017E 0000 add [rax],al
|
||||||
|
00000180 0000 add [rax],al
|
||||||
|
00000182 0000 add [rax],al
|
||||||
|
00000184 0000 add [rax],al
|
||||||
|
00000186 0000 add [rax],al
|
||||||
|
00000188 0000 add [rax],al
|
||||||
|
0000018A 0000 add [rax],al
|
||||||
|
0000018C 0000 add [rax],al
|
||||||
|
0000018E 0000 add [rax],al
|
||||||
|
00000190 0000 add [rax],al
|
||||||
|
00000192 0000 add [rax],al
|
||||||
|
00000194 0000 add [rax],al
|
||||||
|
00000196 0000 add [rax],al
|
||||||
|
00000198 0000 add [rax],al
|
||||||
|
0000019A 0000 add [rax],al
|
||||||
|
0000019C 0000 add [rax],al
|
||||||
|
0000019E 0000 add [rax],al
|
||||||
|
000001A0 0000 add [rax],al
|
||||||
|
000001A2 0000 add [rax],al
|
||||||
|
000001A4 0000 add [rax],al
|
||||||
|
000001A6 0000 add [rax],al
|
||||||
|
000001A8 0000 add [rax],al
|
||||||
|
000001AA 0000 add [rax],al
|
||||||
|
000001AC 0000 add [rax],al
|
||||||
|
000001AE 0000 add [rax],al
|
||||||
|
000001B0 0000 add [rax],al
|
||||||
|
000001B2 0000 add [rax],al
|
||||||
|
000001B4 0000 add [rax],al
|
||||||
|
000001B6 0000 add [rax],al
|
||||||
|
000001B8 0000 add [rax],al
|
||||||
|
000001BA 0000 add [rax],al
|
||||||
|
000001BC 0000 add [rax],al
|
||||||
|
000001BE 0000 add [rax],al
|
||||||
|
000001C0 3500000003 xor eax,0x3000000
|
||||||
|
000001C5 0000 add [rax],al
|
||||||
|
000001C7 0000 add [rax],al
|
||||||
|
000001C9 0000 add [rax],al
|
||||||
|
000001CB 0000 add [rax],al
|
||||||
|
000001CD 0000 add [rax],al
|
||||||
|
000001CF 0000 add [rax],al
|
||||||
|
000001D1 0000 add [rax],al
|
||||||
|
000001D3 0000 add [rax],al
|
||||||
|
000001D5 0000 add [rax],al
|
||||||
|
000001D7 0038 add [rax],bh
|
||||||
|
000001D9 0100 add [rax],eax
|
||||||
|
000001DB 0000 add [rax],al
|
||||||
|
000001DD 0000 add [rax],al
|
||||||
|
000001DF 004500 add [rbp+0x0],al
|
||||||
|
000001E2 0000 add [rax],al
|
||||||
|
000001E4 0000 add [rax],al
|
||||||
|
000001E6 0000 add [rax],al
|
||||||
|
000001E8 0000 add [rax],al
|
||||||
|
000001EA 0000 add [rax],al
|
||||||
|
000001EC 0000 add [rax],al
|
||||||
|
000001EE 0000 add [rax],al
|
||||||
|
000001F0 0100 add [rax],eax
|
||||||
|
000001F2 0000 add [rax],al
|
||||||
|
000001F4 0000 add [rax],al
|
||||||
|
000001F6 0000 add [rax],al
|
||||||
|
000001F8 0000 add [rax],al
|
||||||
|
000001FA 0000 add [rax],al
|
||||||
|
000001FC 0000 add [rax],al
|
||||||
|
000001FE 0000 add [rax],al
|
||||||
|
00000200 0100 add [rax],eax
|
||||||
|
00000202 0000 add [rax],al
|
||||||
|
00000204 0100 add [rax],eax
|
||||||
|
00000206 0000 add [rax],al
|
||||||
|
00000208 06 db 0x06
|
||||||
|
00000209 0000 add [rax],al
|
||||||
|
0000020B 0000 add [rax],al
|
||||||
|
0000020D 0000 add [rax],al
|
||||||
|
0000020F 0000 add [rax],al
|
||||||
|
00000211 0000 add [rax],al
|
||||||
|
00000213 0000 add [rax],al
|
||||||
|
00000215 0000 add [rax],al
|
||||||
|
00000217 004000 add [rax+0x0],al
|
||||||
|
0000021A 0000 add [rax],al
|
||||||
|
0000021C 0000 add [rax],al
|
||||||
|
0000021E 0000 add [rax],al
|
||||||
|
00000220 2000 and [rax],al
|
||||||
|
00000222 0000 add [rax],al
|
||||||
|
00000224 0000 add [rax],al
|
||||||
|
00000226 0000 add [rax],al
|
||||||
|
00000228 0000 add [rax],al
|
||||||
|
0000022A 0000 add [rax],al
|
||||||
|
0000022C 0000 add [rax],al
|
||||||
|
0000022E 0000 add [rax],al
|
||||||
|
00000230 1000 adc [rax],al
|
||||||
|
00000232 0000 add [rax],al
|
||||||
|
00000234 0000 add [rax],al
|
||||||
|
00000236 0000 add [rax],al
|
||||||
|
00000238 0000 add [rax],al
|
||||||
|
0000023A 0000 add [rax],al
|
||||||
|
0000023C 0000 add [rax],al
|
||||||
|
0000023E 0000 add [rax],al
|
||||||
|
00000240 16 db 0x16
|
||||||
|
00000241 0000 add [rax],al
|
||||||
|
00000243 0001 add [rcx],al
|
||||||
|
00000245 0000 add [rax],al
|
||||||
|
00000247 0000 add [rax],al
|
||||||
|
00000249 0000 add [rax],al
|
||||||
|
0000024B 0000 add [rax],al
|
||||||
|
0000024D 0000 add [rax],al
|
||||||
|
0000024F 0000 add [rax],al
|
||||||
|
00000251 0000 add [rax],al
|
||||||
|
00000253 0000 add [rax],al
|
||||||
|
00000255 0000 add [rax],al
|
||||||
|
00000257 006000 add [rax+0x0],ah
|
||||||
|
0000025A 0000 add [rax],al
|
||||||
|
0000025C 0000 add [rax],al
|
||||||
|
0000025E 0000 add [rax],al
|
||||||
|
00000260 0000 add [rax],al
|
||||||
|
00000262 0000 add [rax],al
|
||||||
|
00000264 0000 add [rax],al
|
||||||
|
00000266 0000 add [rax],al
|
||||||
|
00000268 0000 add [rax],al
|
||||||
|
0000026A 0000 add [rax],al
|
||||||
|
0000026C 0000 add [rax],al
|
||||||
|
0000026E 0000 add [rax],al
|
||||||
|
00000270 0100 add [rax],eax
|
||||||
|
00000272 0000 add [rax],al
|
||||||
|
00000274 0000 add [rax],al
|
||||||
|
00000276 0000 add [rax],al
|
||||||
|
00000278 0000 add [rax],al
|
||||||
|
0000027A 0000 add [rax],al
|
||||||
|
0000027C 0000 add [rax],al
|
||||||
|
0000027E 0000 add [rax],al
|
||||||
|
00000280 2B00 sub eax,[rax]
|
||||||
|
00000282 0000 add [rax],al
|
||||||
|
00000284 0100 add [rax],eax
|
||||||
|
00000286 007002 add [rax+0x2],dh
|
||||||
|
00000289 0000 add [rax],al
|
||||||
|
0000028B 0000 add [rax],al
|
||||||
|
0000028D 0000 add [rax],al
|
||||||
|
0000028F 0000 add [rax],al
|
||||||
|
00000291 0000 add [rax],al
|
||||||
|
00000293 0000 add [rax],al
|
||||||
|
00000295 0000 add [rax],al
|
||||||
|
00000297 006000 add [rax+0x0],ah
|
||||||
|
0000029A 0000 add [rax],al
|
||||||
|
0000029C 0000 add [rax],al
|
||||||
|
0000029E 0000 add [rax],al
|
||||||
|
000002A0 480000 o64 add [rax],al
|
||||||
|
000002A3 0000 add [rax],al
|
||||||
|
000002A5 0000 add [rax],al
|
||||||
|
000002A7 0000 add [rax],al
|
||||||
|
000002A9 0000 add [rax],al
|
||||||
|
000002AB 0000 add [rax],al
|
||||||
|
000002AD 0000 add [rax],al
|
||||||
|
000002AF 0008 add [rax],cl
|
||||||
|
000002B1 0000 add [rax],al
|
||||||
|
000002B3 0000 add [rax],al
|
||||||
|
000002B5 0000 add [rax],al
|
||||||
|
000002B7 0000 add [rax],al
|
||||||
|
000002B9 0000 add [rax],al
|
||||||
|
000002BB 0000 add [rax],al
|
||||||
|
000002BD 0000 add [rax],al
|
||||||
|
000002BF 0026 add [rsi],ah
|
||||||
|
000002C1 0000 add [rax],al
|
||||||
|
000002C3 000400 add [rax+rax],al
|
||||||
|
000002C6 0000 add [rax],al
|
||||||
|
000002C8 0000 add [rax],al
|
||||||
|
000002CA 0000 add [rax],al
|
||||||
|
000002CC 0000 add [rax],al
|
||||||
|
000002CE 0000 add [rax],al
|
||||||
|
000002D0 0000 add [rax],al
|
||||||
|
000002D2 0000 add [rax],al
|
||||||
|
000002D4 0000 add [rax],al
|
||||||
|
000002D6 0000 add [rax],al
|
||||||
|
000002D8 0801 or [rcx],al
|
||||||
|
000002DA 0000 add [rax],al
|
||||||
|
000002DC 0000 add [rax],al
|
||||||
|
000002DE 0000 add [rax],al
|
||||||
|
000002E0 3000 xor [rax],al
|
||||||
|
000002E2 0000 add [rax],al
|
||||||
|
000002E4 0000 add [rax],al
|
||||||
|
000002E6 0000 add [rax],al
|
||||||
|
000002E8 06 db 0x06
|
||||||
|
000002E9 0000 add [rax],al
|
||||||
|
000002EB 000400 add [rax+rax],al
|
||||||
|
000002EE 0000 add [rax],al
|
||||||
|
000002F0 0800 or [rax],al
|
||||||
|
000002F2 0000 add [rax],al
|
||||||
|
000002F4 0000 add [rax],al
|
||||||
|
000002F6 0000 add [rax],al
|
||||||
|
000002F8 1800 sbb [rax],al
|
||||||
|
000002FA 0000 add [rax],al
|
||||||
|
000002FC 0000 add [rax],al
|
||||||
|
000002FE 0000 add [rax],al
|
||||||
|
00000300 3D00000002 cmp eax,0x2000000
|
||||||
|
00000305 0000 add [rax],al
|
||||||
|
00000307 0000 add [rax],al
|
||||||
|
00000309 0000 add [rax],al
|
||||||
|
0000030B 0000 add [rax],al
|
||||||
|
0000030D 0000 add [rax],al
|
||||||
|
0000030F 0000 add [rax],al
|
||||||
|
00000311 0000 add [rax],al
|
||||||
|
00000313 0000 add [rax],al
|
||||||
|
00000315 0000 add [rax],al
|
||||||
|
00000317 00A800000000 add [rax+0x0],ch
|
||||||
|
0000031D 0000 add [rax],al
|
||||||
|
0000031F 006000 add [rax+0x0],ah
|
||||||
|
00000322 0000 add [rax],al
|
||||||
|
00000324 0000 add [rax],al
|
||||||
|
00000326 0000 add [rax],al
|
||||||
|
00000328 0100 add [rax],eax
|
||||||
|
0000032A 0000 add [rax],al
|
||||||
|
0000032C 0300 add eax,[rax]
|
||||||
|
0000032E 0000 add [rax],al
|
||||||
|
00000330 0800 or [rax],al
|
||||||
|
00000332 0000 add [rax],al
|
||||||
|
00000334 0000 add [rax],al
|
||||||
|
00000336 0000 add [rax],al
|
||||||
|
00000338 1800 sbb [rax],al
|
||||||
|
0000033A 0000 add [rax],al
|
||||||
|
0000033C 0000 add [rax],al
|
||||||
|
0000033E 0000 add [rax],al
|
BIN
out2.o
Normal file
BIN
out2.o
Normal file
Binary file not shown.
BIN
rust
Executable file
BIN
rust
Executable file
Binary file not shown.
13
rust.rs
Normal file
13
rust.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
pub fn foo(x: i64) -> (i64, i64) {
|
||||||
|
return (x, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn test_main() -> i64 {
|
||||||
|
let record = foo(0x9);
|
||||||
|
|
||||||
|
record.0 * record.1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
test_main();
|
||||||
|
}
|
315
rust.s
Normal file
315
rust.s
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
.text
|
||||||
|
.file "rust.7rcbfp3g-cgu.0"
|
||||||
|
.section .text._ZN3std2rt10lang_start17h10ea254a893e0692E,"ax",@progbits
|
||||||
|
.hidden _ZN3std2rt10lang_start17h10ea254a893e0692E
|
||||||
|
.globl _ZN3std2rt10lang_start17h10ea254a893e0692E
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type _ZN3std2rt10lang_start17h10ea254a893e0692E,@function
|
||||||
|
_ZN3std2rt10lang_start17h10ea254a893e0692E:
|
||||||
|
.cfi_startproc
|
||||||
|
subq $40, %rsp
|
||||||
|
.cfi_def_cfa_offset 48
|
||||||
|
leaq .L__unnamed_1(%rip), %rax
|
||||||
|
movq %rdi, 32(%rsp)
|
||||||
|
leaq 32(%rsp), %rcx
|
||||||
|
movq %rcx, %rdi
|
||||||
|
movq %rsi, 24(%rsp)
|
||||||
|
movq %rax, %rsi
|
||||||
|
movq 24(%rsp), %rax
|
||||||
|
movq %rdx, 16(%rsp)
|
||||||
|
movq %rax, %rdx
|
||||||
|
movq 16(%rsp), %rcx
|
||||||
|
callq *_ZN3std2rt19lang_start_internal17h9cf8802361ad86c2E@GOTPCREL(%rip)
|
||||||
|
movq %rax, 8(%rsp)
|
||||||
|
movq 8(%rsp), %rax
|
||||||
|
addq $40, %rsp
|
||||||
|
.cfi_def_cfa_offset 8
|
||||||
|
retq
|
||||||
|
.Lfunc_end0:
|
||||||
|
.size _ZN3std2rt10lang_start17h10ea254a893e0692E, .Lfunc_end0-_ZN3std2rt10lang_start17h10ea254a893e0692E
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.section ".text._ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17haa4f2d7d298b0acfE","ax",@progbits
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type _ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17haa4f2d7d298b0acfE,@function
|
||||||
|
_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17haa4f2d7d298b0acfE:
|
||||||
|
.cfi_startproc
|
||||||
|
pushq %rax
|
||||||
|
.cfi_def_cfa_offset 16
|
||||||
|
callq *(%rdi)
|
||||||
|
callq _ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h4c1d7168636eac2bE
|
||||||
|
movl %eax, 4(%rsp)
|
||||||
|
movl 4(%rsp), %eax
|
||||||
|
popq %rcx
|
||||||
|
.cfi_def_cfa_offset 8
|
||||||
|
retq
|
||||||
|
.Lfunc_end1:
|
||||||
|
.size _ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17haa4f2d7d298b0acfE, .Lfunc_end1-_ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17haa4f2d7d298b0acfE
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.section .text._ZN3std3sys4unix7process14process_common8ExitCode6as_i3217hafc7a17b3af818e6E,"ax",@progbits
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type _ZN3std3sys4unix7process14process_common8ExitCode6as_i3217hafc7a17b3af818e6E,@function
|
||||||
|
_ZN3std3sys4unix7process14process_common8ExitCode6as_i3217hafc7a17b3af818e6E:
|
||||||
|
.cfi_startproc
|
||||||
|
movzbl (%rdi), %eax
|
||||||
|
retq
|
||||||
|
.Lfunc_end2:
|
||||||
|
.size _ZN3std3sys4unix7process14process_common8ExitCode6as_i3217hafc7a17b3af818e6E, .Lfunc_end2-_ZN3std3sys4unix7process14process_common8ExitCode6as_i3217hafc7a17b3af818e6E
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.section ".text._ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h3c0881b3435f345aE","ax",@progbits
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type _ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h3c0881b3435f345aE,@function
|
||||||
|
_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h3c0881b3435f345aE:
|
||||||
|
.cfi_startproc
|
||||||
|
subq $24, %rsp
|
||||||
|
.cfi_def_cfa_offset 32
|
||||||
|
movq (%rdi), %rdi
|
||||||
|
callq _ZN4core3ops8function6FnOnce9call_once17h95777eb19c893e7cE
|
||||||
|
movl %eax, 12(%rsp)
|
||||||
|
movl 12(%rsp), %eax
|
||||||
|
addq $24, %rsp
|
||||||
|
.cfi_def_cfa_offset 8
|
||||||
|
retq
|
||||||
|
.Lfunc_end3:
|
||||||
|
.size _ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h3c0881b3435f345aE, .Lfunc_end3-_ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h3c0881b3435f345aE
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.section .text._ZN4core3ops8function6FnOnce9call_once17h95777eb19c893e7cE,"ax",@progbits
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type _ZN4core3ops8function6FnOnce9call_once17h95777eb19c893e7cE,@function
|
||||||
|
_ZN4core3ops8function6FnOnce9call_once17h95777eb19c893e7cE:
|
||||||
|
.Lfunc_begin0:
|
||||||
|
.cfi_startproc
|
||||||
|
.cfi_personality 155, DW.ref.rust_eh_personality
|
||||||
|
.cfi_lsda 27, .Lexception0
|
||||||
|
subq $40, %rsp
|
||||||
|
.cfi_def_cfa_offset 48
|
||||||
|
movq %rdi, 8(%rsp)
|
||||||
|
.Ltmp0:
|
||||||
|
leaq 8(%rsp), %rdi
|
||||||
|
callq _ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17haa4f2d7d298b0acfE
|
||||||
|
.Ltmp1:
|
||||||
|
movl %eax, 4(%rsp)
|
||||||
|
jmp .LBB4_1
|
||||||
|
.LBB4_1:
|
||||||
|
jmp .LBB4_2
|
||||||
|
.LBB4_2:
|
||||||
|
movl 4(%rsp), %eax
|
||||||
|
addq $40, %rsp
|
||||||
|
.cfi_def_cfa_offset 8
|
||||||
|
retq
|
||||||
|
.LBB4_3:
|
||||||
|
.cfi_def_cfa_offset 48
|
||||||
|
jmp .LBB4_4
|
||||||
|
.LBB4_4:
|
||||||
|
movq 24(%rsp), %rdi
|
||||||
|
callq _Unwind_Resume@PLT
|
||||||
|
ud2
|
||||||
|
.LBB4_5:
|
||||||
|
.Ltmp2:
|
||||||
|
movq %rax, 24(%rsp)
|
||||||
|
movl %edx, 32(%rsp)
|
||||||
|
jmp .LBB4_3
|
||||||
|
.Lfunc_end4:
|
||||||
|
.size _ZN4core3ops8function6FnOnce9call_once17h95777eb19c893e7cE, .Lfunc_end4-_ZN4core3ops8function6FnOnce9call_once17h95777eb19c893e7cE
|
||||||
|
.cfi_endproc
|
||||||
|
.section .gcc_except_table,"a",@progbits
|
||||||
|
.p2align 2
|
||||||
|
GCC_except_table4:
|
||||||
|
.Lexception0:
|
||||||
|
.byte 255
|
||||||
|
.byte 255
|
||||||
|
.byte 1
|
||||||
|
.uleb128 .Lcst_end0-.Lcst_begin0
|
||||||
|
.Lcst_begin0:
|
||||||
|
.uleb128 .Ltmp0-.Lfunc_begin0
|
||||||
|
.uleb128 .Ltmp1-.Ltmp0
|
||||||
|
.uleb128 .Ltmp2-.Lfunc_begin0
|
||||||
|
.byte 0
|
||||||
|
.uleb128 .Ltmp1-.Lfunc_begin0
|
||||||
|
.uleb128 .Lfunc_end4-.Ltmp1
|
||||||
|
.byte 0
|
||||||
|
.byte 0
|
||||||
|
.Lcst_end0:
|
||||||
|
.p2align 2
|
||||||
|
|
||||||
|
.section .text._ZN4core3ptr13drop_in_place17h5ea43678993f7f74E,"ax",@progbits
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type _ZN4core3ptr13drop_in_place17h5ea43678993f7f74E,@function
|
||||||
|
_ZN4core3ptr13drop_in_place17h5ea43678993f7f74E:
|
||||||
|
.cfi_startproc
|
||||||
|
retq
|
||||||
|
.Lfunc_end5:
|
||||||
|
.size _ZN4core3ptr13drop_in_place17h5ea43678993f7f74E, .Lfunc_end5-_ZN4core3ptr13drop_in_place17h5ea43678993f7f74E
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.section ".text._ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h4c1d7168636eac2bE","ax",@progbits
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type _ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h4c1d7168636eac2bE,@function
|
||||||
|
_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h4c1d7168636eac2bE:
|
||||||
|
.cfi_startproc
|
||||||
|
pushq %rax
|
||||||
|
.cfi_def_cfa_offset 16
|
||||||
|
xorl %edi, %edi
|
||||||
|
callq _ZN68_$LT$std..process..ExitCode$u20$as$u20$std..process..Termination$GT$6report17h4641d8c7c31fa834E
|
||||||
|
movl %eax, 4(%rsp)
|
||||||
|
movl 4(%rsp), %eax
|
||||||
|
popq %rcx
|
||||||
|
.cfi_def_cfa_offset 8
|
||||||
|
retq
|
||||||
|
.Lfunc_end6:
|
||||||
|
.size _ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h4c1d7168636eac2bE, .Lfunc_end6-_ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17h4c1d7168636eac2bE
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.section ".text._ZN68_$LT$std..process..ExitCode$u20$as$u20$std..process..Termination$GT$6report17h4641d8c7c31fa834E","ax",@progbits
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type _ZN68_$LT$std..process..ExitCode$u20$as$u20$std..process..Termination$GT$6report17h4641d8c7c31fa834E,@function
|
||||||
|
_ZN68_$LT$std..process..ExitCode$u20$as$u20$std..process..Termination$GT$6report17h4641d8c7c31fa834E:
|
||||||
|
.cfi_startproc
|
||||||
|
pushq %rax
|
||||||
|
.cfi_def_cfa_offset 16
|
||||||
|
movb %dil, 7(%rsp)
|
||||||
|
leaq 7(%rsp), %rdi
|
||||||
|
callq _ZN3std3sys4unix7process14process_common8ExitCode6as_i3217hafc7a17b3af818e6E
|
||||||
|
movl %eax, (%rsp)
|
||||||
|
movl (%rsp), %eax
|
||||||
|
popq %rcx
|
||||||
|
.cfi_def_cfa_offset 8
|
||||||
|
retq
|
||||||
|
.Lfunc_end7:
|
||||||
|
.size _ZN68_$LT$std..process..ExitCode$u20$as$u20$std..process..Termination$GT$6report17h4641d8c7c31fa834E, .Lfunc_end7-_ZN68_$LT$std..process..ExitCode$u20$as$u20$std..process..Termination$GT$6report17h4641d8c7c31fa834E
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.section .text._ZN4rust3foo17h24346e1203f74a2dE,"ax",@progbits
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type _ZN4rust3foo17h24346e1203f74a2dE,@function
|
||||||
|
_ZN4rust3foo17h24346e1203f74a2dE:
|
||||||
|
.cfi_startproc
|
||||||
|
subq $16, %rsp
|
||||||
|
.cfi_def_cfa_offset 24
|
||||||
|
movq %rdi, (%rsp)
|
||||||
|
movq %rdi, 8(%rsp)
|
||||||
|
movq (%rsp), %rax
|
||||||
|
movq 8(%rsp), %rdx
|
||||||
|
addq $16, %rsp
|
||||||
|
.cfi_def_cfa_offset 8
|
||||||
|
retq
|
||||||
|
.Lfunc_end8:
|
||||||
|
.size _ZN4rust3foo17h24346e1203f74a2dE, .Lfunc_end8-_ZN4rust3foo17h24346e1203f74a2dE
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.section .text._ZN4rust9test_main17h45325f9e1ca54b4bE,"ax",@progbits
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type _ZN4rust9test_main17h45325f9e1ca54b4bE,@function
|
||||||
|
_ZN4rust9test_main17h45325f9e1ca54b4bE:
|
||||||
|
.cfi_startproc
|
||||||
|
subq $24, %rsp
|
||||||
|
.cfi_def_cfa_offset 32
|
||||||
|
movl $9, %edi
|
||||||
|
callq _ZN4rust3foo17h24346e1203f74a2dE
|
||||||
|
movq %rax, 16(%rsp)
|
||||||
|
movq %rdx, 8(%rsp)
|
||||||
|
movq 16(%rsp), %rax
|
||||||
|
movq 8(%rsp), %rcx
|
||||||
|
imulq %rcx, %rax
|
||||||
|
seto %dl
|
||||||
|
testb $1, %dl
|
||||||
|
movq %rax, (%rsp)
|
||||||
|
jne .LBB9_3
|
||||||
|
movq (%rsp), %rax
|
||||||
|
addq $24, %rsp
|
||||||
|
.cfi_def_cfa_offset 8
|
||||||
|
retq
|
||||||
|
.LBB9_3:
|
||||||
|
.cfi_def_cfa_offset 32
|
||||||
|
leaq str.0(%rip), %rdi
|
||||||
|
leaq .L__unnamed_2(%rip), %rdx
|
||||||
|
movq _ZN4core9panicking5panic17hcdc9f0ba8d71d265E@GOTPCREL(%rip), %rax
|
||||||
|
movl $33, %esi
|
||||||
|
callq *%rax
|
||||||
|
ud2
|
||||||
|
.Lfunc_end9:
|
||||||
|
.size _ZN4rust9test_main17h45325f9e1ca54b4bE, .Lfunc_end9-_ZN4rust9test_main17h45325f9e1ca54b4bE
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.section .text._ZN4rust4main17h523dcf5432fcfd88E,"ax",@progbits
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type _ZN4rust4main17h523dcf5432fcfd88E,@function
|
||||||
|
_ZN4rust4main17h523dcf5432fcfd88E:
|
||||||
|
.cfi_startproc
|
||||||
|
pushq %rax
|
||||||
|
.cfi_def_cfa_offset 16
|
||||||
|
callq _ZN4rust9test_main17h45325f9e1ca54b4bE
|
||||||
|
popq %rax
|
||||||
|
.cfi_def_cfa_offset 8
|
||||||
|
retq
|
||||||
|
.Lfunc_end10:
|
||||||
|
.size _ZN4rust4main17h523dcf5432fcfd88E, .Lfunc_end10-_ZN4rust4main17h523dcf5432fcfd88E
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.section .text.main,"ax",@progbits
|
||||||
|
.globl main
|
||||||
|
.p2align 4, 0x90
|
||||||
|
.type main,@function
|
||||||
|
main:
|
||||||
|
.cfi_startproc
|
||||||
|
pushq %rax
|
||||||
|
.cfi_def_cfa_offset 16
|
||||||
|
movslq %edi, %rax
|
||||||
|
leaq _ZN4rust4main17h523dcf5432fcfd88E(%rip), %rdi
|
||||||
|
movq %rsi, (%rsp)
|
||||||
|
movq %rax, %rsi
|
||||||
|
movq (%rsp), %rdx
|
||||||
|
callq _ZN3std2rt10lang_start17h10ea254a893e0692E
|
||||||
|
popq %rcx
|
||||||
|
.cfi_def_cfa_offset 8
|
||||||
|
retq
|
||||||
|
.Lfunc_end11:
|
||||||
|
.size main, .Lfunc_end11-main
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
.type .L__unnamed_1,@object
|
||||||
|
.section .data.rel.ro..L__unnamed_1,"aw",@progbits
|
||||||
|
.p2align 3
|
||||||
|
.L__unnamed_1:
|
||||||
|
.quad _ZN4core3ptr13drop_in_place17h5ea43678993f7f74E
|
||||||
|
.quad 8
|
||||||
|
.quad 8
|
||||||
|
.quad _ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17haa4f2d7d298b0acfE
|
||||||
|
.quad _ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17haa4f2d7d298b0acfE
|
||||||
|
.quad _ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h3c0881b3435f345aE
|
||||||
|
.size .L__unnamed_1, 48
|
||||||
|
|
||||||
|
.type .L__unnamed_3,@object
|
||||||
|
.section .rodata..L__unnamed_3,"a",@progbits
|
||||||
|
.L__unnamed_3:
|
||||||
|
.ascii "rust.rs"
|
||||||
|
.size .L__unnamed_3, 7
|
||||||
|
|
||||||
|
.type .L__unnamed_2,@object
|
||||||
|
.section .data.rel.ro..L__unnamed_2,"aw",@progbits
|
||||||
|
.p2align 3
|
||||||
|
.L__unnamed_2:
|
||||||
|
.quad .L__unnamed_3
|
||||||
|
.asciz "\007\000\000\000\000\000\000\000\b\000\000\000\005\000\000"
|
||||||
|
.size .L__unnamed_2, 24
|
||||||
|
|
||||||
|
.type str.0,@object
|
||||||
|
.section .rodata.str.0,"a",@progbits
|
||||||
|
.p2align 4
|
||||||
|
str.0:
|
||||||
|
.ascii "attempt to multiply with overflow"
|
||||||
|
.size str.0, 33
|
||||||
|
|
||||||
|
.hidden DW.ref.rust_eh_personality
|
||||||
|
.weak DW.ref.rust_eh_personality
|
||||||
|
.section .data.DW.ref.rust_eh_personality,"aGw",@progbits,DW.ref.rust_eh_personality,comdat
|
||||||
|
.p2align 3
|
||||||
|
.type DW.ref.rust_eh_personality,@object
|
||||||
|
.size DW.ref.rust_eh_personality, 8
|
||||||
|
DW.ref.rust_eh_personality:
|
||||||
|
.quad rust_eh_personality
|
||||||
|
|
||||||
|
.section ".note.GNU-stack","",@progbits
|
Loading…
Add table
Add a link
Reference in a new issue