source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1"
-[[package]]
-name = "autocfg"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
-
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-[[package]]
-name = "crc32fast"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
-dependencies = [
- "cfg-if",
-]
-
[[package]]
name = "fm"
version = "0.1.4"
[[package]]
name = "gccjit"
version = "1.0.0"
-source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e"
+source = "git+https://github.com/antoyo/gccjit.rs#0672b78d162d65b6f36ea4062947253affe9fdef"
dependencies = [
"gccjit_sys",
]
[[package]]
name = "gccjit_sys"
version = "0.0.1"
-source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e"
+source = "git+https://github.com/antoyo/gccjit.rs#0672b78d162d65b6f36ea4062947253affe9fdef"
dependencies = [
"libc 0.1.12",
]
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
- "libc 0.2.102",
+ "libc 0.2.112",
"wasi",
]
-[[package]]
-name = "hashbrown"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
-
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
- "libc 0.2.102",
-]
-
-[[package]]
-name = "indexmap"
-version = "1.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
-dependencies = [
- "autocfg",
- "hashbrown",
+ "libc 0.2.112",
]
[[package]]
dependencies = [
"fm",
"getopts",
- "libc 0.2.102",
+ "libc 0.2.112",
"num_cpus",
"termcolor",
"threadpool",
[[package]]
name = "libc"
-version = "0.2.102"
+version = "0.2.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
+checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
[[package]]
name = "memchr"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [
"hermit-abi",
- "libc 0.2.102",
-]
-
-[[package]]
-name = "object"
-version = "0.25.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7"
-dependencies = [
- "crc32fast",
- "indexmap",
- "memchr",
+ "libc 0.2.112",
]
[[package]]
name = "ppv-lite86"
-version = "0.2.10"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
[[package]]
name = "rand"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
dependencies = [
- "libc 0.2.102",
+ "libc 0.2.112",
"rand_chacha",
"rand_core",
"rand_hc",
"ar",
"gccjit",
"lang_tester",
- "object",
"target-lexicon",
"tempfile",
]
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
dependencies = [
"cfg-if",
- "libc 0.2.102",
+ "libc 0.2.112",
"rand",
"redox_syscall",
"remove_dir_all",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
dependencies = [
- "libc 0.2.102",
+ "libc 0.2.112",
]
[[package]]
ar = "0.8.0"
-[dependencies.object]
-version = "0.25.0"
-default-features = false
-features = ["read", "std", "write"] # We don't need WASM support.
-
[dev-dependencies]
lang_tester = "0.3.9"
tempfile = "3.1.0"
p loc->m_line
```
+To get the `rustc` command to run in `gdb`, add the `--verbose` flag to `cargo build`.
+
### How to use a custom-build rustc
* Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`).
#[test]
fn cell_allows_array_cycle() {
+diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
+index 3e00e0a..8e5663b 100644
+--- a/library/core/tests/slice.rs
++++ b/library/core/tests/slice.rs
+@@ -2108,6 +2108,7 @@ fn test_copy_within_panics_src_out_of_bounds() {
+ bytes.copy_within(usize::MAX..=usize::MAX, 0);
+ }
+
++/*
+ #[test]
+ fn test_is_sorted() {
+ let empty: [i32; 0] = [];
+@@ -2122,6 +2123,7 @@ fn test_is_sorted() {
+ assert!(!["c", "bb", "aaa"].is_sorted());
+ assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
+ }
++*/
+
+ #[test]
+ fn test_slice_run_destructors() {
-- 2.21.0 (Apple Git-122)
--- /dev/null
+From b1ae000f6da1abd3b8e9b80c40bc11c89b8ae93c Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Thu, 30 Dec 2021 16:54:40 +0100
+Subject: [PATCH] [core] Disable portable-simd test
+
+---
+ library/core/tests/lib.rs | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
+index ec70034..7cd9e21 100644
+--- a/library/core/tests/lib.rs
++++ b/library/core/tests/lib.rs
+@@ -121,7 +121,6 @@ mod pattern;
+ mod pin;
+ mod ptr;
+ mod result;
+-mod simd;
+ mod slice;
+ mod str;
+ mod str_lossy;
+--
+2.26.2.7.g19db9cfb68
+
--- /dev/null
+From 0ffdd8eda8df364391c8ac6e1ce92c73ba9254d4 Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Fri, 3 Dec 2021 12:16:30 +0100
+Subject: [PATCH] Disable long running tests
+
+---
+ library/core/tests/slice.rs | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
+index 2c8f00a..44847ee 100644
+--- a/library/core/tests/slice.rs
++++ b/library/core/tests/slice.rs
+@@ -2332,7 +2332,8 @@ macro_rules! empty_max_mut {
+ };
+ }
+
++/*
+ #[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations)
+ take_tests! {
+ slice: &[(); usize::MAX], method: take,
+ (take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]),
+@@ -2345,3 +2347,4 @@ take_tests! {
+ (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
+ (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
+ }
++*/
+--
+2.26.2.7.g19db9cfb68
+
-nightly-2021-09-28
+nightly-2021-12-30
// Rust asm! and GCC Extended Asm semantics differ substantially.
//
-// 1. Rust asm operands go along as one list of operands. Operands themselves indicate
-// if they're "in" or "out". "In" and "out" operands can interleave. One operand can be
+// 1. Rust asm operands go along as one list of operands. Operands themselves indicate
+// if they're "in" or "out". "In" and "out" operands can interleave. One operand can be
// both "in" and "out" (`inout(reg)`).
//
-// GCC asm has two different lists for "in" and "out" operands. In terms of gccjit,
-// this means that all "out" operands must go before "in" operands. "In" and "out" operands
+// GCC asm has two different lists for "in" and "out" operands. In terms of gccjit,
+// this means that all "out" operands must go before "in" operands. "In" and "out" operands
// cannot interleave.
//
-// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important
+// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important
// because the asm template refers to operands by index.
//
// Mapping from Rust to GCC index would be 1-1 if it wasn't for...
//
-// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes.
-// Contrary, Rust expresses clobbers through "out" operands that aren't tied to
+// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes.
+// Contrary, Rust expresses clobbers through "out" operands that aren't tied to
// a variable (`_`), and such "clobbers" do have index.
//
-// 4. Furthermore, GCC Extended Asm does not support explicit register constraints
-// (like `out("eax")`) directly, offering so-called "local register variables"
-// as a workaround. These variables need to be declared and initialized *before*
-// the Extended Asm block but *after* normal local variables
+// 4. Furthermore, GCC Extended Asm does not support explicit register constraints
+// (like `out("eax")`) directly, offering so-called "local register variables"
+// as a workaround. These variables need to be declared and initialized *before*
+// the Extended Asm block but *after* normal local variables
// (see comment in `codegen_inline_asm` for explanation).
//
-// With that in mind, let's see how we translate Rust syntax to GCC
+// With that in mind, let's see how we translate Rust syntax to GCC
// (from now on, `CC` stands for "constraint code"):
//
// * `out(reg_class) var` -> translated to output operand: `"=CC"(var)`
//
// * `out("explicit register") _` -> not translated to any operands, register is simply added to clobbers list
//
-// * `inout(reg_class) in_var => out_var` -> translated to two operands:
+// * `inout(reg_class) in_var => out_var` -> translated to two operands:
// output: `"=CC"(in_var)`
-// input: `"num"(out_var)` where num is the GCC index
+// input: `"num"(out_var)` where num is the GCC index
// of the corresponding output operand
//
-// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`,
+// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`,
// where "tmp" is a temporary unused variable
//
-// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above
-// with `"r"(var)` constraint,
+// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above
+// with `"r"(var)` constraint,
// and one register variable assigned to the desired register.
-//
const ATT_SYNTAX_INS: &str = ".att_syntax noprefix\n\t";
const INTEL_SYNTAX_INS: &str = "\n\t.intel_syntax noprefix";
let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
let intel_dialect = is_x86 && !options.contains(InlineAsmOptions::ATT_SYNTAX);
- // GCC index of an output operand equals its position in the array
+ // GCC index of an output operand equals its position in the array
let mut outputs = vec![];
// GCC index of an input operand equals its position in the array
let mut constants_len = 0;
// There are rules we must adhere to if we want GCC to do the right thing:
- //
+ //
// * Every local variable that the asm block uses as an output must be declared *before*
- // the asm block.
+ // the asm block.
// * There must be no instructions whatsoever between the register variables and the asm.
//
// Therefore, the backend must generate the instructions strictly in this order:
// We also must make sure that no input operands are emitted before output operands.
//
// This is why we work in passes, first emitting local vars, then local register vars.
- // Also, we don't emit any asm operands immediately; we save them to
+ // Also, we don't emit any asm operands immediately; we save them to
// the one of the buffers to be emitted later.
// 1. Normal variables (and saving operands to buffers).
(Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx, false)),
// When `reg` is a class and not an explicit register but the out place is not specified,
// we need to create an unused output variable to assign the output to. This var
- // needs to be of a type that's "compatible" with the register class, but specific type
+ // needs to be of a type that's "compatible" with the register class, but specific type
// doesn't matter.
(Constraint(constraint), None) => (constraint, dummy_output_type(self.cx, reg.reg_class())),
(Register(_), Some(_)) => {
let tmp_var = self.current_func().new_local(None, ty, "output_register");
outputs.push(AsmOutOperand {
- constraint,
+ constraint,
rust_idx,
late,
readwrite: false,
InlineAsmOperandRef::In { reg, value } => {
if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
- inputs.push(AsmInOperand {
- constraint: Cow::Borrowed(constraint),
- rust_idx,
+ inputs.push(AsmInOperand {
+ constraint: Cow::Borrowed(constraint),
+ rust_idx,
val: value.immediate()
});
- }
+ }
else {
// left for the next pass
continue
InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
constraint
- }
+ }
else {
// left for the next pass
continue
// Rustc frontend guarantees that input and output types are "compatible",
// so we can just use input var's type for the output variable.
//
- // This decision is also backed by the fact that LLVM needs in and out
- // values to be of *exactly the same type*, not just "compatible".
+ // This decision is also backed by the fact that LLVM needs in and out
+ // values to be of *exactly the same type*, not just "compatible".
// I'm not sure if GCC is so picky too, but better safe than sorry.
let ty = in_value.layout.gcc_type(self.cx, false);
let tmp_var = self.current_func().new_local(None, ty, "output_register");
// If the out_place is None (i.e `inout(reg) _` syntax was used), we translate
- // it to one "readwrite (+) output variable", otherwise we translate it to two
+ // it to one "readwrite (+) output variable", otherwise we translate it to two
// "out and tied in" vars as described above.
let readwrite = out_place.is_none();
outputs.push(AsmOutOperand {
- constraint,
+ constraint,
rust_idx,
late,
readwrite,
- tmp_var,
+ tmp_var,
out_place,
});
let constraint = Cow::Owned(out_gcc_idx.to_string());
inputs.push(AsmInOperand {
- constraint,
- rust_idx,
+ constraint,
+ rust_idx,
val: in_value.immediate()
});
}
if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
let out_place = if let Some(place) = place {
place
- }
+ }
else {
// processed in the previous pass
continue
tmp_var.set_register_name(reg_name);
outputs.push(AsmOutOperand {
- constraint: "r".into(),
+ constraint: "r".into(),
rust_idx,
late,
readwrite: false,
reg_var.set_register_name(reg_name);
self.llbb().add_assignment(None, reg_var, value.immediate());
- inputs.push(AsmInOperand {
- constraint: "r".into(),
- rust_idx,
+ inputs.push(AsmInOperand {
+ constraint: "r".into(),
+ rust_idx,
val: reg_var.to_rvalue()
});
}
// `inout("explicit register") in_var => out_var`
InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
- let out_place = if let Some(place) = out_place {
- place
- }
- else {
- // processed in the previous pass
- continue
- };
-
// See explanation in the first pass.
let ty = in_value.layout.gcc_type(self.cx, false);
let tmp_var = self.current_func().new_local(None, ty, "output_register");
tmp_var.set_register_name(reg_name);
outputs.push(AsmOutOperand {
- constraint: "r".into(),
+ constraint: "r".into(),
rust_idx,
late,
readwrite: false,
tmp_var,
- out_place: Some(out_place)
+ out_place,
});
let constraint = Cow::Owned((outputs.len() - 1).to_string());
- inputs.push(AsmInOperand {
- constraint,
+ inputs.push(AsmInOperand {
+ constraint,
rust_idx,
val: in_value.immediate()
});
// processed in the previous pass
}
- InlineAsmOperandRef::Const { .. }
- | InlineAsmOperandRef::SymFn { .. }
+ InlineAsmOperandRef::Const { .. }
+ | InlineAsmOperandRef::SymFn { .. }
| InlineAsmOperandRef::SymStatic { .. } => {
// processed in the previous pass
}
if !intel_dialect {
template_str.push_str(INTEL_SYNTAX_INS);
}
-
+
// 4. Generate Extended Asm block
let block = self.llbb();
}
if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) {
- // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient
+ // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient
// on all architectures. For instance, what about FP stack?
extended_asm.add_clobber("cc");
}
self.call(self.type_void(), builtin_unreachable, &[], None);
}
- // Write results to outputs.
+ // Write results to outputs.
//
// We need to do this because:
- // 1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases
+ // 1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases
// (especially with current `rustc_backend_ssa` API).
// 2. Not every output operand has an `out_place`, and it's required by `add_output_operand`.
//
// generates `out_place = tmp_var;` assignments if out_place exists.
for op in &outputs {
if let Some(place) = op.out_place {
- OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place);
+ OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place);
}
}
-use std::fs;
+use std::{env, fs};
use gccjit::OutputKind;
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
let _timer = cgcx
.prof
.generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name);
- match &*module.name {
- "std_example.7rcbfp3g-cgu.15" => {
- println!("Dumping reproducer {}", module.name);
- let _ = fs::create_dir("/tmp/reproducers");
- // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by
- // transmuting an rvalue to an lvalue.
- // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue
- context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name));
- println!("Dumped reproducer {}", module.name);
- },
- _ => (),
+ if env::var("CG_GCCJIT_DUMP_MODULE_NAMES").as_deref() == Ok("1") {
+ println!("Module {}", module.name);
+ }
+ if env::var("CG_GCCJIT_DUMP_MODULE").as_deref() == Ok(&module.name) {
+ println!("Dumping reproducer {}", module.name);
+ let _ = fs::create_dir("/tmp/reproducers");
+ // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by
+ // transmuting an rvalue to an lvalue.
+ // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue
+ context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name));
+ println!("Dumped reproducer {}", module.name);
}
context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str"));
}
for arg in &tcx.sess.opts.cg.llvm_args {
context.add_command_line_option(arg);
}
+ // NOTE: an optimization (https://github.com/rust-lang/rustc_codegen_gcc/issues/53).
context.add_command_line_option("-fno-semantic-interposition");
+ // NOTE: Rust relies on LLVM not doing TBAA (https://github.com/rust-lang/unsafe-code-guidelines/issues/292).
+ context.add_command_line_option("-fno-strict-aliasing");
if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") {
context.set_dump_code_on_compile(true);
}
fn check_ptr_call<'b>(&mut self, _typ: &str, func_ptr: RValue<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> {
let mut all_args_match = true;
let mut param_types = vec![];
- let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr");
+ let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr");
for (index, arg) in args.iter().enumerate().take(gcc_func.get_param_count()) {
let param = gcc_func.get_param_type(index);
if param != arg.get_type() {
// gccjit requires to use the result of functions, even when it's not used.
// That's why we assign the result to a local or call add_eval().
- let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr");
+ let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr");
let mut return_type = gcc_func.get_return_type();
let current_block = self.current_block.borrow().expect("block");
let void_type = self.context.new_type::<()>();
}
fn and(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
- // FIXME(antoyo): hack by putting the result in a variable to workaround this bug:
- // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498
if a.get_type() != b.get_type() {
b = self.context.new_cast(None, b, a.get_type());
}
- let res = self.current_func().new_local(None, b.get_type(), "andResult");
- self.llbb().add_assignment(None, res, a & b);
- res.to_rvalue()
+ a & b
}
- fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
- // FIXME(antoyo): hack by putting the result in a variable to workaround this bug:
- // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498
- let res = self.current_func().new_local(None, b.get_type(), "orResult");
- self.llbb().add_assignment(None, res, a | b);
- res.to_rvalue()
+ fn or(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
+ if a.get_type() != b.get_type() {
+ b = self.context.new_cast(None, b, a.get_type());
+ }
+ a | b
}
fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
}
fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
- // TODO(antoyo): use new_unary_op()?
- self.cx.context.new_rvalue_from_long(a.get_type(), 0) - a
+ self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a)
}
fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
let atomic_load = self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes()));
let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
- let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile();
+ let volatile_const_void_ptr_type = self.context.new_type::<()>()
+ .make_const()
+ .make_volatile()
+ .make_pointer();
let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type);
self.context.new_call(None, atomic_load, &[ptr, ordering])
}
// TODO(antoyo): handle alignment.
let atomic_store = self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes()));
let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
- let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile();
+ let volatile_const_void_ptr_type = self.context.new_type::<()>()
+ .make_volatile()
+ .make_pointer();
let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type);
// FIXME(antoyo): fix libgccjit to allow comparing an integer type with an aligned integer type because
assert_eq!(idx as usize as u64, idx);
let value = ptr.dereference(None).to_rvalue();
- if value_type.is_array().is_some() {
+ if value_type.dyncast_array().is_some() {
let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
let element = self.context.new_array_access(None, value, index);
element.get_address(None)
}
- else if let Some(vector_type) = value_type.is_vector() {
+ else if let Some(vector_type) = value_type.dyncast_vector() {
let array_type = vector_type.get_element_type().make_pointer();
let array = self.bitcast(ptr, array_type);
let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
fn sext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
// TODO(antoyo): check that it indeed sign extend the value.
- if dest_ty.is_vector().is_some() {
+ if dest_ty.dyncast_vector().is_some() {
// TODO(antoyo): nothing to do as it is only for LLVM?
return value;
}
let right_type = rhs.get_type();
if left_type != right_type {
// NOTE: because libgccjit cannot compare function pointers.
- if left_type.is_function_ptr_type().is_some() && right_type.is_function_ptr_type().is_some() {
+ if left_type.dyncast_function_ptr_type().is_some() && right_type.dyncast_function_ptr_type().is_some() {
lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer());
rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer());
}
assert_eq!(idx as usize as u64, idx);
let value_type = aggregate_value.get_type();
- if value_type.is_array().is_some() {
+ if value_type.dyncast_array().is_some() {
let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
let element = self.context.new_array_access(None, aggregate_value, index);
element.get_address(None)
}
- else if value_type.is_vector().is_some() {
+ else if value_type.dyncast_vector().is_some() {
panic!();
}
else if let Some(pointer_type) = value_type.get_pointee() {
let value_type = aggregate_value.get_type();
let lvalue =
- if value_type.is_array().is_some() {
+ if value_type.dyncast_array().is_some() {
let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
self.context.new_array_access(None, aggregate_value, index)
}
- else if value_type.is_vector().is_some() {
+ else if value_type.dyncast_vector().is_some() {
panic!();
}
else if let Some(pointer_type) = value_type.get_pointee() {
use std::convert::TryFrom;
-use std::convert::TryInto;
use gccjit::LValue;
use gccjit::{Block, CType, RValue, Type, ToRValue};
let string = self.context.new_string_literal(&*string);
let sym = self.generate_local_symbol_name("str");
let global = self.declare_private_global(&sym, self.val_ty(string));
- global.global_set_initializer_value(string);
+ global.global_set_initializer_rvalue(string);
global
// TODO(antoyo): set linkage.
}
bytes.iter()
.map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))
.collect();
- context.new_rvalue_from_array(None, typ, &elements)
+ context.new_array_constructor(None, typ, &elements)
}
pub fn type_is_pointer<'gcc>(typ: Type<'gcc>) -> bool {
}
fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> {
- let num64: Result<i64, _> = num.try_into();
- if let Ok(num) = num64 {
- // FIXME(antoyo): workaround for a bug where libgccjit is expecting a constant.
- // The operations >> 64 and | low are making the normal case a non-constant.
- return self.context.new_rvalue_from_long(typ, num as i64);
- }
-
if num >> 64 != 0 {
// FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()?
let low = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64);
// TODO(antoyo): cache the type? It's anonymous, so probably not.
let typ = self.type_struct(&fields, packed);
let struct_type = typ.is_struct().expect("struct type");
- self.context.new_rvalue_from_struct(None, struct_type, values)
+ self.context.new_struct_constructor(None, struct_type.as_type(), None, values)
}
fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64> {
pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> {
if value.get_type() == self.bool_type.make_pointer() {
if let Some(pointee) = typ.get_pointee() {
- if pointee.is_vector().is_some() {
+ if pointee.dyncast_vector().is_some() {
panic!()
}
}
impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> {
- if let Some(global_value) = self.const_globals.borrow().get(&cv) {
- // TODO(antoyo): upgrade alignment.
- return *global_value;
+ // TODO(antoyo): implement a proper rvalue comparison in libgccjit instead of doing the
+ // following:
+ for (value, variable) in &*self.const_globals.borrow() {
+ if format!("{:?}", value) == format!("{:?}", cv) {
+ // TODO(antoyo): upgrade alignment.
+ return *variable;
+ }
}
let global_value = self.static_addr_of_mut(cv, align, kind);
// TODO(antoyo): set global constant.
else {
value
};
- global.global_set_initializer_value(value);
+ global.global_set_initializer_rvalue(value);
// As an optimization, all shared statics which do not have interior
// mutability are placed into read-only memory.
};
// FIXME(antoyo): I think the name coming from generate_local_symbol_name() above cannot be used
// globally.
- global.global_set_initializer_value(cv);
+ global.global_set_initializer_rvalue(cv);
// TODO(antoyo): set unnamed address.
global.get_address(None)
}
real_name.push_str(&sym);
let global2 = cx.define_global(&real_name, llty, is_tls, attrs.link_section);
// TODO(antoyo): set linkage.
- global2.global_set_initializer_value(global1.get_address(None));
+ global2.global_set_initializer_rvalue(global1.get_address(None));
// TODO(antoyo): use global_set_initializer() when it will work.
global2
}
use std::cell::{Cell, RefCell};
-use gccjit::{
- Block,
- Context,
- CType,
- Function,
- FunctionType,
- LValue,
- RValue,
- Struct,
- Type,
-};
+use gccjit::{Block, CType, Context, Function, FunctionType, LValue, RValue, Struct, Type};
use rustc_codegen_ssa::base::wants_msvc_seh;
use rustc_codegen_ssa::traits::{
BackendTypes,
let value =
if result_type.is_signed(self.cx) {
- self.context.new_bitcast(None, value, typ)
+ self.context.new_cast(None, value, typ)
}
else {
value
},
};
- self.context.new_bitcast(None, result, result_type)
+ self.context.new_cast(None, result, result_type)
}
fn count_leading_zeroes(&self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> {
let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low);
let not_low_and_not_high = not_low & not_high;
let index = not_high + not_low_and_not_high;
+ // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in
+ // gcc.
+ // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the
+ // compilation stage.
+ let index = self.context.new_cast(None, index, self.i32_type);
let res = self.context.new_array_access(None, result, index);
let arg =
if result_type.is_signed(self.cx) {
let new_type = result_type.to_unsigned(self.cx);
- self.context.new_bitcast(None, arg, new_type)
+ self.context.new_cast(None, arg, new_type)
}
else {
arg
let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high);
let not_low_and_not_high = not_low & not_high;
let index = not_low + not_low_and_not_high;
+ // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in
+ // gcc.
+ // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the
+ // compilation stage.
+ let index = self.context.new_cast(None, index, self.i32_type);
let res = self.context.new_array_access(None, result, index);
- return self.context.new_bitcast(None, res, result_type);
+ return self.context.new_cast(None, res, result_type);
}
else {
unimplemented!("count_trailing_zeroes for {:?}", arg_type);
arg
};
let res = self.context.new_call(None, count_trailing_zeroes, &[arg]);
- self.context.new_bitcast(None, res, result_type)
+ self.context.new_cast(None, res, result_type)
}
fn int_width(&self, typ: Type<'gcc>) -> i64 {
let value =
if result_type.is_signed(self.cx) {
- self.context.new_bitcast(None, value, value_type)
+ self.context.new_cast(None, value, value_type)
}
else {
value
let low = self.context.new_cast(None, value, self.cx.ulonglong_type);
let low = self.context.new_call(None, popcount, &[low]);
let res = high + low;
- return self.context.new_bitcast(None, res, result_type);
+ return self.context.new_cast(None, res, result_type);
}
// First step.
let value = left + right;
if value_type.is_u8(&self.cx) {
- return self.context.new_bitcast(None, value, result_type);
+ return self.context.new_cast(None, value, result_type);
}
// Fourth step.
let value = left + right;
if value_type.is_u16(&self.cx) {
- return self.context.new_bitcast(None, value, result_type);
+ return self.context.new_cast(None, value, result_type);
}
// Fifth step.
let value = left + right;
if value_type.is_u32(&self.cx) {
- return self.context.new_bitcast(None, value, result_type);
+ return self.context.new_cast(None, value, result_type);
}
// Sixth step.
let right = shifted & mask;
let value = left + right;
- self.context.new_bitcast(None, value, result_type)
+ self.context.new_cast(None, value, result_type)
}
// Algorithm from: https://blog.regehr.org/archives/1063
let target_cpu = target_cpu(tcx.sess);
let res = codegen_crate(self.clone(), tcx, target_cpu.to_string(), metadata, need_metadata_module);
- rustc_symbol_mangling::test::report_symbol_names(tcx);
-
Box::new(res)
}
if typ.is_integral() {
TypeKind::Integer
}
- else if typ.is_vector().is_some() {
+ else if typ.dyncast_vector().is_some() {
TypeKind::Vector
}
else {
}
fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> {
- if let Some(typ) = ty.is_array() {
+ if let Some(typ) = ty.dyncast_array() {
typ
}
- else if let Some(vector_type) = ty.is_vector() {
+ else if let Some(vector_type) = ty.dyncast_vector() {
vector_type.get_element_type()
}
else if let Some(typ) = ty.get_pointee() {
// Run-time:
// status: 0
+#![feature(asm_const, asm_sym)]
+
+use std::arch::{asm, global_asm};
+
global_asm!("
.global add_asm
add_asm:
fn add_asm(a: i64, b: i64) -> i64;
}
+pub unsafe fn mem_cpy(dst: *mut u8, src: *const u8, len: usize) {
+ asm!(
+ "rep movsb",
+ inout("rdi") dst => _,
+ inout("rsi") src => _,
+ inout("rcx") len => _,
+ options(preserves_flags, nostack)
+ );
+}
+
fn main() {
unsafe {
asm!("nop");
}
assert_eq!(x, 43);
- // check inout(reg_class) x
+ // check inout(reg_class) x
let mut x: u64 = 42;
unsafe {
asm!("add {0}, {0}",
- inout(reg) x
+ inout(reg) x
);
}
assert_eq!(x, 84);
let mut x: u64 = 42;
unsafe {
asm!("add r11, r11",
- inout("r11") x
+ inout("r11") x
);
}
assert_eq!(x, 84);
assert_eq!(res, 7);
assert_eq!(rem, 2);
- // check const
+ // check const
let mut x: u64 = 42;
unsafe {
asm!("add {}, {}",
inout(reg) x,
- const 1
+ const 1
);
}
assert_eq!(x, 43);
assert_eq!(x, 42);
assert_eq!(unsafe { add_asm(40, 2) }, 42);
+
+ let array1 = [1u8, 2, 3];
+ let mut array2 = [0u8, 0, 0];
+ unsafe {
+ mem_cpy(array2.as_mut_ptr(), array1.as_ptr(), 3);
+ }
+ assert_eq!(array1, array2);
}