1use rucc_base::float::Format;
23use rucc_session::{GnucVersion, OptLevel, Options, Pic, Std};
24use rucc_target::{Arch, Env, Os, TargetInfo, Triple};
25use rucc_tuple::{self as tuple};
26
27pub const BUILT_IN: &str = "<built-in>";
29
30pub const COMMAND_LINE: &str = "<command-line>";
32
33#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct Timestamp {
40 pub date: String,
42 pub time: String,
44}
45
46impl Timestamp {
47 pub fn now() -> Timestamp {
52 let seconds = match std::env::var("SOURCE_DATE_EPOCH").ok().and_then(|v| v.parse().ok()) {
53 Some(fixed) => fixed,
54 None => std::time::SystemTime::now()
55 .duration_since(std::time::UNIX_EPOCH)
56 .map_or(0, |d| d.as_secs() as i64),
57 };
58 Timestamp::from_unix(seconds)
59 }
60
61 pub fn from_unix(seconds: i64) -> Timestamp {
66 let days = seconds.div_euclid(86_400);
67 let rest = seconds.rem_euclid(86_400);
68 let (year, month, day) = civil_from_days(days);
69 const MONTHS: [&str; 12] =
70 ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
71 let name = MONTHS[(month - 1) as usize];
72 Timestamp {
73 date: format!("{name} {day:2} {year}"),
74 time: format!("{:02}:{:02}:{:02}", rest / 3600, (rest / 60) % 60, rest % 60),
75 }
76 }
77}
78
79fn civil_from_days(days: i64) -> (i64, u32, u32) {
85 let shifted = days + 719_468;
88 let era = shifted.div_euclid(146_097);
89 let day_of_era = shifted.rem_euclid(146_097);
90 let year_of_era =
91 (day_of_era - day_of_era / 1460 + day_of_era / 36_524 - day_of_era / 146_096) / 365;
92 let year = year_of_era + era * 400;
93 let day_of_year = day_of_era - (365 * year_of_era + year_of_era / 4 - year_of_era / 100);
94 let marched = (5 * day_of_year + 2) / 153;
95 let day = (day_of_year - (153 * marched + 2) / 5 + 1) as u32;
96 let month = if marched < 10 { marched + 3 } else { marched - 9 } as u32;
97 (year + i64::from(month <= 2), month, day)
98}
99
100#[derive(Debug, Clone, PartialEq, Eq)]
102pub struct Predef {
103 pub std: Std,
105 pub gnu_extensions: bool,
108 pub gnu89_inline: bool,
112 pub gnuc: GnucVersion,
114 pub opt_level: OptLevel,
116 pub hosted: bool,
118 pub pic: Pic,
121 pub timestamp: Timestamp,
123 pub glibc_minor: Option<u32>,
129 pub defines: Vec<String>,
131 pub undefines: Vec<String>,
133}
134
135impl Predef {
136 pub fn new() -> Predef {
138 Predef {
139 std: Std::default(),
140 gnu_extensions: true,
141 gnu89_inline: false,
142 gnuc: GnucVersion::default(),
143 opt_level: OptLevel::O0,
144 hosted: true,
145 pic: Pic::Executable,
146 timestamp: Timestamp::now(),
147 glibc_minor: None,
148 defines: Vec::new(),
149 undefines: Vec::new(),
150 }
151 }
152}
153
154impl Predef {
155 pub fn for_options(opts: &Options) -> Predef {
161 Predef {
162 std: opts.std,
163 gnu_extensions: opts.gnu_extensions,
164 gnu89_inline: opts.gnu89_inline,
165 gnuc: opts.gnuc,
166 opt_level: opts.opt_level,
167 hosted: opts.hosted,
168 pic: opts.pic,
169 timestamp: Timestamp::now(),
170 glibc_minor: opts.glibc_minor,
171 defines: opts.defines.clone(),
172 undefines: opts.undefines.clone(),
173 }
174 }
175}
176
177impl Default for Predef {
178 fn default() -> Predef {
179 Predef::new()
180 }
181}
182
183struct Defs {
185 text: String,
186}
187
188impl Defs {
189 fn new() -> Defs {
190 Defs { text: String::new() }
191 }
192
193 fn set(&mut self, name: &str, value: &str) {
195 self.text.push_str("#define ");
196 self.text.push_str(name);
197 self.text.push(' ');
198 self.text.push_str(value);
199 self.text.push('\n');
200 }
201
202 fn flag(&mut self, name: &str) {
204 self.set(name, "1");
205 }
206
207 fn set_if(&mut self, when: bool, name: &str, value: &str) {
208 if when {
209 self.set(name, value);
210 }
211 }
212
213 fn flag_if(&mut self, when: bool, name: &str) {
214 if when {
215 self.flag(name);
216 }
217 }
218}
219
220pub(crate) fn built_in(target: &TargetInfo, opts: &Predef) -> String {
222 let mut d = Defs::new();
223 identity(&mut d, target, opts);
224 d.set("__DATE__", &format!("\"{}\"", opts.timestamp.date));
228 d.set("__TIME__", &format!("\"{}\"", opts.timestamp.time));
229 dialect(&mut d, opts);
230 optimization(&mut d, opts);
231 platform(&mut d, target, opts);
232 sizes(&mut d, target);
233 integers(&mut d, target);
234 floats(&mut d, target);
235 atomics(&mut d, target);
236 d.text
237}
238
239pub(crate) fn command_line(opts: &Predef) -> String {
245 let mut d = Defs::new();
246 for define in &opts.defines {
247 match define.split_once('=') {
248 Some((name, value)) => d.set(name, value),
249 None => d.flag(define),
252 }
253 }
254 for name in &opts.undefines {
255 d.text.push_str("#undef ");
256 d.text.push_str(name);
257 d.text.push('\n');
258 }
259 d.text
260}
261
262fn identity(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
264 d.flag("__rucc__");
265 d.set("__rucc_version__", "\"0.1.0\"");
266 d.set("__rucc_major__", "0");
267 d.set("__rucc_minor__", "1");
268 d.set("__rucc_patchlevel__", "0");
269 d.set("__GNUC__", &opts.gnuc.major.to_string());
271 d.set("__GNUC_MINOR__", &opts.gnuc.minor.to_string());
272 d.set("__GNUC_PATCHLEVEL__", &opts.gnuc.patch.to_string());
273 d.set("__VERSION__", "\"rucc 0.1.0\"");
274 let gnu_inline = opts.gnu89_inline || opts.std == Std::C89;
283 d.flag_if(gnu_inline, "__GNUC_GNU_INLINE__");
284 d.flag_if(!gnu_inline, "__GNUC_STDC_INLINE__");
285 d.set("__GNUC_EXECUTION_CHARSET_NAME", "\"UTF-8\"");
290 let wide = if target.wchar_width == 16 { "\"UTF-16LE\"" } else { "\"UTF-32LE\"" };
291 d.set("__GNUC_WIDE_EXECUTION_CHARSET_NAME", wide);
292 d.set("__GXX_ABI_VERSION", "1021");
297}
298
299fn dialect(d: &mut Defs, opts: &Predef) {
301 d.flag("__STDC__");
302 d.set_if(opts.hosted, "__STDC_HOSTED__", "1");
303 d.set_if(!opts.hosted, "__STDC_HOSTED__", "0");
304 if let Some(version) = opts.std.stdc_version() {
305 d.set("__STDC_VERSION__", version);
306 }
307 d.flag_if(!opts.gnu_extensions, "__STRICT_ANSI__");
310 d.flag("__STDC_UTF_16__");
311 d.flag("__STDC_UTF_32__");
312 d.flag("__STDC_IEC_559__");
313 d.flag("__STDC_IEC_559_COMPLEX__");
314 d.set("__STDC_IEC_60559_BFP__", "201404L");
325 d.set("__STDC_IEC_60559_COMPLEX__", "201404L");
334 d.set("__STDC_ISO_10646__", "201706L");
335 d.set_if(opts.std == Std::C23, "__CHAR8_TYPE__", "unsigned char");
341 if opts.std.has_c11() {
353 d.flag("__STDC_NO_ATOMICS__");
354 d.flag("__STDC_NO_THREADS__");
355 d.flag("__STDC_NO_COMPLEX__");
356 }
357 d.set("__STDC_EMBED_NOT_FOUND__", "0");
362 d.set("__STDC_EMBED_FOUND__", "1");
363 d.set("__STDC_EMBED_EMPTY__", "2");
364}
365
366fn atomics(d: &mut Defs, target: &TargetInfo) {
378 d.set("__ATOMIC_RELAXED", "0");
379 d.set("__ATOMIC_CONSUME", "1");
380 d.set("__ATOMIC_ACQUIRE", "2");
381 d.set("__ATOMIC_RELEASE", "3");
382 d.set("__ATOMIC_ACQ_REL", "4");
383 d.set("__ATOMIC_SEQ_CST", "5");
384 let llong = if target.pointer_width == 64 { "2" } else { "1" };
387 for name in [
388 "BOOL", "CHAR", "CHAR8_T", "CHAR16_T", "CHAR32_T", "WCHAR_T", "SHORT", "INT", "LONG",
389 "POINTER",
390 ] {
391 d.set(&format!("__GCC_ATOMIC_{name}_LOCK_FREE"), "2");
392 }
393 d.set("__GCC_ATOMIC_LLONG_LOCK_FREE", llong);
397 d.set("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", "1");
398 for width in [1, 2, 4, 8] {
402 d.flag(&format!("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_{width}"));
403 }
404 if target.tuple.arch() == tuple::Arch::X86_64 {
409 d.set("__ATOMIC_HLE_ACQUIRE", "65536");
410 d.set("__ATOMIC_HLE_RELEASE", "131072");
411 }
412}
413
414fn optimization(d: &mut Defs, opts: &Predef) {
416 d.flag_if(opts.opt_level.runs_optimizer(), "__OPTIMIZE__");
417 d.flag_if(opts.opt_level.is_size(), "__OPTIMIZE_SIZE__");
418 d.flag_if(!opts.opt_level.runs_optimizer(), "__NO_INLINE__");
421 d.set("__FINITE_MATH_ONLY__", "0");
427}
428
429fn platform(d: &mut Defs, target: &TargetInfo, opts: &Predef) {
431 let Some(triple) = Triple::from_tuple(target.tuple) else {
437 return;
438 };
439 match triple.arch {
440 Arch::X86_64 => {
441 d.flag("__x86_64__");
442 d.flag("__x86_64");
443 d.flag("__amd64__");
444 d.flag("__amd64");
445 d.flag("__SSE__");
446 d.flag("__SSE2__");
447 d.flag("__MMX__");
448 d.flag("__SSE_MATH__");
449 d.flag("__SSE2_MATH__");
450 d.flag("__k8");
451 d.flag("__k8__");
452 d.flag("__FXSR__");
455 d.flag("__code_model_small__");
456 d.flag("__MMX_WITH_SSE__");
461 }
462 Arch::Aarch64 => {
463 d.flag("__aarch64__");
464 d.flag("__AARCH64EL__");
465 d.set("__ARM_ARCH", "8");
466 d.set("__ARM_ARCH_PROFILE", "'A'");
467 d.set("__ARM_64BIT_STATE", "1");
468 d.set("__ARM_ALIGN_MAX_PWR", "28");
469 d.set("__ARM_FP", "0xe");
470 d.set("__ARM_NEON", "1");
471 d.set("__ARM_FEATURE_UNALIGNED", "1");
472 d.set("__ARM_PCS_AAPCS64", "1");
473 }
474 Arch::Riscv64 => {
475 d.flag("__riscv");
476 d.set("__riscv_xlen", "64");
477 d.set("__riscv_flen", "64");
478 d.flag("__riscv_float_abi_double");
479 d.flag("__riscv_muldiv");
480 d.flag("__riscv_atomic");
481 d.flag("__riscv_compressed");
482 d.set("__riscv_cmodel_medlow", "1");
483 }
484 }
485 match triple.os {
486 Os::Linux => {
487 d.flag("__linux__");
488 d.flag("__linux");
489 d.flag("__unix__");
490 d.flag("__unix");
491 d.flag("__gnu_linux__");
492 d.flag("__ELF__");
493 if opts.gnu_extensions {
496 d.flag("linux");
497 d.flag("unix");
498 }
499 }
500 Os::Darwin => {
501 d.flag("__APPLE__");
502 d.flag("__MACH__");
503 d.flag("__unix__");
504 d.flag("__unix");
505 d.set("__APPLE_CC__", "6000");
506 d.set("__DYNAMIC__", "1");
507 if triple.arch == Arch::Aarch64 {
508 d.flag("__arm64__");
513 d.flag("__arm64");
514 }
515 if opts.gnu_extensions {
516 d.flag("unix");
517 }
518 }
519 Os::Windows => {
520 d.flag("_WIN32");
521 d.flag("__WIN32__");
522 d.flag("_WIN64");
523 d.flag("__WIN64__");
524 d.flag("__MINGW32__");
525 windows_spellings(d, opts);
526 }
527 Os::None => {
528 d.flag("__ELF__");
531 }
532 }
533 match triple.env {
534 Env::Musl => d.flag("__musl__"),
535 Env::Gnu | Env::None | Env::Msvc => {}
536 }
537 if let Some(minor) = opts.glibc_minor {
549 d.set("__GLIBC_MINOR__", &minor.to_string());
550 }
551 if target.long_width == 64 && target.pointer_width == 64 {
554 d.flag("__LP64__");
555 d.flag("_LP64");
556 }
557 d.set("__USER_LABEL_PREFIX__", if triple.os == Os::Darwin { "_" } else { "" });
564 d.set("__REGISTER_PREFIX__", "");
568
569 if !matches!(triple.os, Os::Windows) {
578 d.set("__PIC__", "2");
579 d.set("__pic__", "2");
580 if opts.pic == Pic::Executable {
581 d.set("__PIE__", "2");
582 d.set("__pie__", "2");
583 }
584 }
585}
586
587fn windows_spellings(d: &mut Defs, opts: &Predef) {
606 for name in ["cdecl", "stdcall", "fastcall", "thiscall"] {
607 d.set(&format!("__{name}"), &format!("__attribute__((__{name}__))"));
608 if opts.gnu_extensions {
611 d.set(&format!("_{name}"), &format!("__attribute__((__{name}__))"));
612 }
613 }
614 d.set("__declspec(x)", "__attribute__((x))");
615}
616
617fn sizes(d: &mut Defs, target: &TargetInfo) {
619 let pointer = target.pointer_width / 8;
620 d.set("__GCC_CONSTRUCTIVE_SIZE", "64");
625 d.set("__GCC_DESTRUCTIVE_SIZE", "64");
626 let long = target.long_width / 8;
627 let long_double = target.long_double_width / 8;
628 d.set("__CHAR_BIT__", "8");
629 d.set("__SIZEOF_SHORT__", "2");
630 d.set("__SIZEOF_INT__", "4");
631 d.set("__SIZEOF_LONG__", &long.to_string());
632 d.set("__SIZEOF_LONG_LONG__", "8");
633 d.set("__SIZEOF_INT128__", "16");
634 d.set("__SIZEOF_FLOAT__", "4");
635 d.set("__SIZEOF_DOUBLE__", "8");
636 d.set("__SIZEOF_LONG_DOUBLE__", &long_double.to_string());
637 d.set("__SIZEOF_POINTER__", &pointer.to_string());
638 d.set("__SIZEOF_SIZE_T__", &pointer.to_string());
639 d.set("__SIZEOF_PTRDIFF_T__", &pointer.to_string());
640 d.set("__SIZEOF_WCHAR_T__", &wchar(target).size.to_string());
641 d.set("__SIZEOF_WINT_T__", "4");
642 d.set("__BIGGEST_ALIGNMENT__", "16");
643 d.set("__ORDER_LITTLE_ENDIAN__", "1234");
647 d.set("__ORDER_BIG_ENDIAN__", "4321");
648 d.set("__ORDER_PDP_ENDIAN__", "3412");
649 let order =
650 if target.little_endian { "__ORDER_LITTLE_ENDIAN__" } else { "__ORDER_BIG_ENDIAN__" };
651 d.set("__BYTE_ORDER__", order);
652 d.set("__FLOAT_WORD_ORDER__", order);
653 d.flag_if(!target.char_is_signed, "__CHAR_UNSIGNED__");
654}
655
656struct Wchar {
658 spelling: &'static str,
660 size: u32,
662 max: &'static str,
664 min: &'static str,
666}
667
668fn wchar(target: &TargetInfo) -> Wchar {
678 match (target.wchar_width, target.wchar_is_signed) {
679 (16, false) => Wchar { spelling: "short unsigned int", size: 2, max: "0xffff", min: "0" },
680 (16, true) => Wchar { spelling: "short int", size: 2, max: "0x7fff", min: "(-32767 - 1)" },
681 (_, false) => Wchar { spelling: "unsigned int", size: 4, max: "0xffffffffU", min: "0U" },
682 (_, true) => {
683 Wchar { spelling: "int", size: 4, max: "0x7fffffff", min: "(-__WCHAR_MAX__ - 1)" }
684 }
685 }
686}
687
688struct Wint {
690 spelling: &'static str,
692 max: &'static str,
694 min: &'static str,
696 width: u32,
698}
699
700fn wint(target: &TargetInfo) -> Wint {
707 match target.tuple.os() {
708 tuple::Os::Windows => {
709 Wint { spelling: "short unsigned int", max: "0xffff", min: "0", width: 16 }
710 }
711 os if os.is_darwin() => {
712 Wint { spelling: "int", max: "0x7fffffff", min: "(-__WINT_MAX__ - 1)", width: 32 }
713 }
714 _ => Wint { spelling: "unsigned int", max: "0xffffffffU", min: "0U", width: 32 },
715 }
716}
717
718fn integers(d: &mut Defs, target: &TargetInfo) {
720 let lp64 = target.long_width == 64;
724 let wide = if lp64 { "long int" } else { "long long int" };
725 let wide_unsigned = if lp64 { "long unsigned int" } else { "long long unsigned int" };
726 let wide_suffix = if lp64 { "L" } else { "LL" };
727 let wide_max = format!("0x7fffffffffffffff{wide_suffix}");
728 let wide_umax = format!("0xffffffffffffffffU{wide_suffix}");
729
730 d.set("__SCHAR_MAX__", "0x7f");
731 d.set("__SHRT_MAX__", "0x7fff");
732 d.set("__INT_MAX__", "0x7fffffff");
733 d.set("__LONG_MAX__", if lp64 { "0x7fffffffffffffffL" } else { "0x7fffffffL" });
734 d.set("__LONG_LONG_MAX__", "0x7fffffffffffffffLL");
735 d.set("__INTMAX_MAX__", &wide_max);
736 d.set("__UINTMAX_MAX__", &wide_umax);
737 d.set("__SIZE_MAX__", &wide_umax);
738 d.set("__PTRDIFF_MAX__", &wide_max);
739 d.set("__INTPTR_MAX__", &wide_max);
740 d.set("__UINTPTR_MAX__", &wide_umax);
741 d.set("__SIG_ATOMIC_MAX__", "0x7fffffff");
742 d.set("__SIG_ATOMIC_MIN__", "(-__SIG_ATOMIC_MAX__ - 1)");
743 d.set("__BITINT_MAXWIDTH__", "128");
750
751 let wchar = wchar(target);
752 d.set("__WCHAR_TYPE__", wchar.spelling);
753 d.set("__WCHAR_MAX__", wchar.max);
754 d.set("__WCHAR_MIN__", wchar.min);
755 let wint = wint(target);
756 d.set("__WINT_TYPE__", wint.spelling);
757 d.set("__WINT_MAX__", wint.max);
758 d.set("__WINT_MIN__", wint.min);
759 d.set("__SIZE_TYPE__", wide_unsigned);
760 d.set("__PTRDIFF_TYPE__", wide);
761 d.set("__INTMAX_TYPE__", wide);
762 d.set("__UINTMAX_TYPE__", wide_unsigned);
763 d.set("__INTPTR_TYPE__", wide);
764 d.set("__UINTPTR_TYPE__", wide_unsigned);
765 d.set("__SIG_ATOMIC_TYPE__", "int");
766 d.set("__CHAR16_TYPE__", "short unsigned int");
767 d.set("__CHAR32_TYPE__", "unsigned int");
768 d.set("__INTMAX_C(c)", &format!("c ## {wide_suffix}"));
769 d.set("__UINTMAX_C(c)", &format!("c ## U{wide_suffix}"));
770
771 exact(d, 8, "signed char", "unsigned char", "0x7f", "0xff", "");
773 exact(d, 16, "short int", "short unsigned int", "0x7fff", "0xffff", "");
774 exact(d, 32, "int", "unsigned int", "0x7fffffff", "0xffffffffU", "");
777 exact(d, 64, wide, wide_unsigned, &wide_max, &wide_umax, wide_suffix);
778
779 let fast_is_wide = target.tuple.arch() == tuple::Arch::X86_64
790 && lp64
791 && target.tuple.env() != tuple::Env::Musl;
792 let fast_middle = if fast_is_wide { wide } else { "int" };
793 d.set("__INT_FAST8_TYPE__", "signed char");
794 d.set("__UINT_FAST8_TYPE__", "unsigned char");
795 d.set("__INT_FAST8_MAX__", "0x7f");
796 d.set("__UINT_FAST8_MAX__", "0xff");
797 for width in [16, 32] {
798 let unsigned = if fast_middle == "int" { "unsigned int" } else { wide_unsigned };
799 let max = if fast_middle == "int" { "0x7fffffff" } else { wide_max.as_str() };
800 let umax = if fast_middle == "int" { "0xffffffffU" } else { wide_umax.as_str() };
801 d.set(&format!("__INT_FAST{width}_TYPE__"), fast_middle);
802 d.set(&format!("__UINT_FAST{width}_TYPE__"), unsigned);
803 d.set(&format!("__INT_FAST{width}_MAX__"), max);
804 d.set(&format!("__UINT_FAST{width}_MAX__"), umax);
805 }
806 d.set("__INT_FAST64_TYPE__", wide);
807 d.set("__UINT_FAST64_TYPE__", wide_unsigned);
808 d.set("__INT_FAST64_MAX__", &wide_max);
809 d.set("__UINT_FAST64_MAX__", &wide_umax);
810
811 widths(d, target, &wchar, &wint, if fast_is_wide { 64 } else { 32 });
812}
813
814fn widths(d: &mut Defs, target: &TargetInfo, wchar: &Wchar, wint: &Wint, fast_middle: u32) {
825 let pointer = target.pointer_width;
826 d.set("__SCHAR_WIDTH__", "8");
827 d.set("__SHRT_WIDTH__", "16");
828 d.set("__INT_WIDTH__", "32");
829 d.set("__LONG_WIDTH__", &target.long_width.to_string());
830 d.set("__LONG_LONG_WIDTH__", "64");
831 d.set("__INTMAX_WIDTH__", "64");
832 d.set("__INTPTR_WIDTH__", &pointer.to_string());
833 d.set("__PTRDIFF_WIDTH__", &pointer.to_string());
834 d.set("__SIZE_WIDTH__", &pointer.to_string());
835 d.set("__SIG_ATOMIC_WIDTH__", "32");
836 d.set("__WCHAR_WIDTH__", &(wchar.size * 8).to_string());
837 d.set("__WINT_WIDTH__", &wint.width.to_string());
838 for width in [8, 16, 32, 64] {
839 d.set(&format!("__INT_LEAST{width}_WIDTH__"), &width.to_string());
840 }
841 d.set("__INT_FAST8_WIDTH__", "8");
842 d.set("__INT_FAST16_WIDTH__", &fast_middle.to_string());
843 d.set("__INT_FAST32_WIDTH__", &fast_middle.to_string());
844 d.set("__INT_FAST64_WIDTH__", "64");
845}
846
847fn exact(
849 d: &mut Defs,
850 width: u32,
851 signed: &str,
852 unsigned: &str,
853 max: &str,
854 umax: &str,
855 width_suffix: &str,
859) {
860 d.set(&format!("__INT{width}_TYPE__"), signed);
861 d.set(&format!("__UINT{width}_TYPE__"), unsigned);
862 d.set(&format!("__INT{width}_MAX__"), max);
863 d.set(&format!("__UINT{width}_MAX__"), umax);
864 d.set(&format!("__INT_LEAST{width}_TYPE__"), signed);
865 d.set(&format!("__UINT_LEAST{width}_TYPE__"), unsigned);
866 d.set(&format!("__INT_LEAST{width}_MAX__"), max);
867 d.set(&format!("__UINT_LEAST{width}_MAX__"), umax);
868 let unsigned_after_promotion = width >= 32;
878 let u = if unsigned_after_promotion { "U" } else { "" };
879 if width_suffix.is_empty() && u.is_empty() {
880 d.set(&format!("__INT{width}_C(c)"), "c");
881 d.set(&format!("__UINT{width}_C(c)"), "c");
882 } else if width_suffix.is_empty() {
883 d.set(&format!("__INT{width}_C(c)"), "c");
884 d.set(&format!("__UINT{width}_C(c)"), &format!("c ## {u}"));
885 } else {
886 d.set(&format!("__INT{width}_C(c)"), &format!("c ## {width_suffix}"));
887 d.set(&format!("__UINT{width}_C(c)"), &format!("c ## {u}{width_suffix}"));
888 }
889}
890
891struct Characteristics {
897 mant_dig: &'static str,
898 dig: &'static str,
899 min_exp: &'static str,
900 min_10_exp: &'static str,
901 max_exp: &'static str,
902 max_10_exp: &'static str,
903 decimal_dig: &'static str,
904 max: &'static str,
905 norm_max: &'static str,
914 min: &'static str,
915 epsilon: &'static str,
916 denorm_min: &'static str,
917 is_iec_60559: &'static str,
921}
922
923const HALF: Characteristics = Characteristics {
925 mant_dig: "11",
926 dig: "3",
927 min_exp: "(-13)",
928 min_10_exp: "(-4)",
929 max_exp: "16",
930 max_10_exp: "4",
931 decimal_dig: "5",
932 max: "6.55040000000000000000000000000000000e+4",
933 norm_max: "6.55040000000000000000000000000000000e+4",
934 min: "6.10351562500000000000000000000000000e-5",
935 epsilon: "9.76562500000000000000000000000000000e-4",
936 denorm_min: "5.96046447753906250000000000000000000e-8",
937 is_iec_60559: "1",
938};
939
940const BFLOAT16: Characteristics = Characteristics {
942 mant_dig: "8",
943 dig: "2",
944 min_exp: "(-125)",
945 min_10_exp: "(-37)",
946 max_exp: "128",
947 max_10_exp: "38",
948 decimal_dig: "4",
949 max: "3.38953138925153547590470800371487867e+38",
950 norm_max: "3.38953138925153547590470800371487867e+38",
951 min: "1.17549435082228750796873653722224568e-38",
952 epsilon: "7.81250000000000000000000000000000000e-3",
953 denorm_min: "9.18354961579912115600575419704879436e-41",
954 is_iec_60559: "0",
955};
956
957const SINGLE: Characteristics = Characteristics {
959 mant_dig: "24",
960 dig: "6",
961 min_exp: "(-125)",
962 min_10_exp: "(-37)",
963 max_exp: "128",
964 max_10_exp: "38",
965 decimal_dig: "9",
966 max: "3.40282346638528859811704183484516925e+38",
967 norm_max: "3.40282346638528859811704183484516925e+38",
968 min: "1.17549435082228750796873653722224568e-38",
969 epsilon: "1.19209289550781250000000000000000000e-7",
970 denorm_min: "1.40129846432481707092372958328991613e-45",
971 is_iec_60559: "1",
972};
973
974const DOUBLE: Characteristics = Characteristics {
977 mant_dig: "53",
978 dig: "15",
979 min_exp: "(-1021)",
980 min_10_exp: "(-307)",
981 max_exp: "1024",
982 max_10_exp: "308",
983 decimal_dig: "17",
984 max: "1.79769313486231570814527423731704357e+308",
985 norm_max: "1.79769313486231570814527423731704357e+308",
986 min: "2.22507385850720138309023271733240406e-308",
987 epsilon: "2.22044604925031308084726333618164062e-16",
988 denorm_min: "4.94065645841246544176568792868221372e-324",
989 is_iec_60559: "1",
990};
991
992const X87: Characteristics = Characteristics {
994 mant_dig: "64",
995 dig: "18",
996 min_exp: "(-16381)",
997 min_10_exp: "(-4931)",
998 max_exp: "16384",
999 max_10_exp: "4932",
1000 decimal_dig: "21",
1001 max: "1.18973149535723176502126385303097021e+4932",
1002 norm_max: "1.18973149535723176502126385303097021e+4932",
1003 min: "3.36210314311209350626267781732175260e-4932",
1004 epsilon: "1.08420217248550443400745280086994171e-19",
1005 denorm_min: "3.64519953188247460252840593361941982e-4951",
1006 is_iec_60559: "1",
1007};
1008
1009const QUAD: Characteristics = Characteristics {
1012 mant_dig: "113",
1013 dig: "33",
1014 min_exp: "(-16381)",
1015 min_10_exp: "(-4931)",
1016 max_exp: "16384",
1017 max_10_exp: "4932",
1018 decimal_dig: "36",
1019 max: "1.18973149535723176508575932662800702e+4932",
1020 norm_max: "1.18973149535723176508575932662800702e+4932",
1021 min: "3.36210314311209350626267781732175260e-4932",
1022 epsilon: "1.92592994438723585305597794258492732e-34",
1023 denorm_min: "6.47517511943802511092443895822764655e-4966",
1024 is_iec_60559: "1",
1025};
1026
1027const DOUBLE_DOUBLE: Characteristics = Characteristics {
1043 mant_dig: "106",
1044 dig: "31",
1045 min_exp: "(-968)",
1046 min_10_exp: "(-291)",
1047 max_exp: "1024",
1048 max_10_exp: "308",
1049 decimal_dig: "33",
1050 max: "1.79769313486231580793728971405301e+308",
1051 norm_max: "8.98846567431157953864652595394501e+307",
1052 min: "2.00416836000897277799610805135016e-292",
1053 epsilon: "4.94065645841246544176568792868221e-324",
1054 denorm_min: "4.94065645841246544176568792868221e-324",
1055 is_iec_60559: "0",
1056};
1057
1058const fn characteristics(format: Format) -> &'static Characteristics {
1061 match format {
1062 Format::Half => &HALF,
1063 Format::BFloat16 => &BFLOAT16,
1064 Format::Single => &SINGLE,
1065 Format::Double => &DOUBLE,
1066 Format::X87Extended => &X87,
1067 Format::Quad => &QUAD,
1068 Format::DoubleDouble => &DOUBLE_DOUBLE,
1069 }
1070}
1071
1072fn floats(d: &mut Defs, target: &TargetInfo) {
1088 d.set("__FLT_RADIX__", "2");
1089 d.set("__GCC_IEC_559", "2");
1097 d.set("__GCC_IEC_559_COMPLEX", "2");
1098 d.set("__FLT_EVAL_METHOD__", "0");
1103 d.set("__FLT_EVAL_METHOD_C99__", "0");
1104 d.set("__FLT_EVAL_METHOD_TS_18661_3__", "0");
1105
1106 family(d, "FLT", &SINGLE, |value| format!("{value}F"));
1107 family(d, "DBL", &DOUBLE, |value| format!("((double){value}L)"));
1110 family(d, "LDBL", characteristics(target.long_double_format), |value| format!("{value}L"));
1111
1112 if target.has_float16 {
1117 family(d, "FLT16", &HALF, |value| format!("{value}F16"));
1118 }
1119 family(d, "FLT32", &SINGLE, |value| format!("{value}F32"));
1120 family(d, "FLT64", &DOUBLE, |value| format!("{value}F64"));
1121 if target.has_float128 {
1122 family(d, "FLT128", &QUAD, |value| format!("{value}F128"));
1123 }
1124 family(d, "FLT32X", &DOUBLE, |value| format!("{value}F32x"));
1125 if let Some(format) = target.float64x_format {
1129 family(d, "FLT64X", characteristics(format), |value| format!("{value}F64x"));
1130 }
1131
1132 d.set("__DECIMAL_DIG__", characteristics(target.long_double_format).decimal_dig);
1137}
1138
1139fn family(d: &mut Defs, prefix: &str, c: &Characteristics, write: impl Fn(&str) -> String) {
1144 d.set(&format!("__{prefix}_MANT_DIG__"), c.mant_dig);
1145 d.set(&format!("__{prefix}_DIG__"), c.dig);
1146 d.set(&format!("__{prefix}_MIN_EXP__"), c.min_exp);
1147 d.set(&format!("__{prefix}_MIN_10_EXP__"), c.min_10_exp);
1148 d.set(&format!("__{prefix}_MAX_EXP__"), c.max_exp);
1149 d.set(&format!("__{prefix}_MAX_10_EXP__"), c.max_10_exp);
1150 d.set(&format!("__{prefix}_DECIMAL_DIG__"), c.decimal_dig);
1151 d.set(&format!("__{prefix}_MAX__"), &write(c.max));
1152 d.set(&format!("__{prefix}_NORM_MAX__"), &write(c.norm_max));
1153 d.set(&format!("__{prefix}_MIN__"), &write(c.min));
1154 d.set(&format!("__{prefix}_EPSILON__"), &write(c.epsilon));
1155 d.set(&format!("__{prefix}_DENORM_MIN__"), &write(c.denorm_min));
1156 d.set(&format!("__{prefix}_IS_IEC_60559__"), c.is_iec_60559);
1157 d.set(&format!("__{prefix}_HAS_DENORM__"), "1");
1158 d.set(&format!("__{prefix}_HAS_INFINITY__"), "1");
1159 d.set(&format!("__{prefix}_HAS_QUIET_NAN__"), "1");
1160}
1161
1162#[cfg(test)]
1163mod tests {
1164 use rucc_target::Triple;
1165
1166 use super::*;
1167
1168 fn set_for(triple: &str) -> String {
1169 let triple: Triple = triple.parse().expect("a triple the compiler supports");
1170 built_in(&TargetInfo::new(triple), &Predef::new())
1171 }
1172
1173 fn set_for_tuple(tuple: &str) -> String {
1175 let target = TargetInfo::for_tuple(tuple.parse().expect("a row in the target table"));
1176 built_in(&target, &Predef::new())
1177 }
1178
1179 fn has(text: &str, line: &str) -> bool {
1180 text.lines().any(|l| l == line)
1181 }
1182
1183 #[test]
1184 fn the_set_is_driven_by_the_target_rather_than_by_the_host() {
1185 let x86 = set_for("x86_64-unknown-linux-gnu");
1186 let arm = set_for("aarch64-unknown-linux-gnu");
1187 assert!(has(&x86, "#define __x86_64__ 1"));
1188 assert!(!has(&x86, "#define __aarch64__ 1"));
1189 assert!(has(&arm, "#define __aarch64__ 1"));
1190 assert!(!has(&arm, "#define __x86_64__ 1"));
1191 assert!(has(&x86, "#define __linux__ 1") && has(&arm, "#define __linux__ 1"));
1192 }
1193
1194 #[test]
1195 fn windows_is_the_target_that_makes_long_thirty_two_bits() {
1196 let windows = set_for("x86_64-pc-windows-msvc");
1197 let linux = set_for("x86_64-unknown-linux-gnu");
1198 assert!(has(&windows, "#define __SIZEOF_LONG__ 4"));
1199 assert!(has(&windows, "#define __SIZE_TYPE__ long long unsigned int"));
1200 assert!(has(&windows, "#define __INT64_TYPE__ long long int"));
1201 assert!(!has(&windows, "#define __LP64__ 1"));
1202 assert!(has(&linux, "#define __SIZEOF_LONG__ 8"));
1203 assert!(has(&linux, "#define __SIZE_TYPE__ long unsigned int"));
1204 assert!(has(&linux, "#define __INT64_TYPE__ long int"));
1205 assert!(has(&linux, "#define __LP64__ 1"));
1206 }
1207
1208 #[test]
1209 fn windows_spells_a_calling_convention_and_an_attribute_as_macros() {
1210 let windows = set_for("x86_64-pc-windows-gnu");
1213 assert!(has(&windows, "#define __cdecl __attribute__((__cdecl__))"));
1214 assert!(has(&windows, "#define __stdcall __attribute__((__stdcall__))"));
1215 assert!(has(&windows, "#define __fastcall __attribute__((__fastcall__))"));
1216 assert!(has(&windows, "#define __thiscall __attribute__((__thiscall__))"));
1217 assert!(has(&windows, "#define _cdecl __attribute__((__cdecl__))"));
1218 assert!(has(&windows, "#define __declspec(x) __attribute__((x))"));
1219 let linux = set_for("x86_64-unknown-linux-gnu");
1220 assert!(!has(&linux, "#define __cdecl __attribute__((__cdecl__))"));
1221 assert!(!has(&linux, "#define __declspec(x) __attribute__((x))"));
1222 }
1223
1224 #[test]
1225 fn a_strict_mode_keeps_the_spellings_that_are_not_the_implementations_to_take() {
1226 let mut opts = Predef::new();
1229 opts.gnu_extensions = false;
1230 let triple: Triple = "x86_64-pc-windows-gnu".parse().expect("a triple");
1231 let strict = built_in(&TargetInfo::new(triple), &opts);
1232 assert!(has(&strict, "#define __cdecl __attribute__((__cdecl__))"));
1233 assert!(!has(&strict, "#define _cdecl __attribute__((__cdecl__))"));
1234 }
1235
1236 #[test]
1237 fn wchar_t_is_the_type_that_divides_the_targets() {
1238 assert!(has(&set_for("x86_64-unknown-linux-gnu"), "#define __WCHAR_TYPE__ int"));
1240 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __WCHAR_TYPE__ unsigned int"));
1241 let windows = set_for("x86_64-pc-windows-msvc");
1242 assert!(has(&windows, "#define __WCHAR_TYPE__ short unsigned int"));
1243 assert!(has(&windows, "#define __SIZEOF_WCHAR_T__ 2"));
1244 }
1245
1246 #[test]
1247 fn apple_spells_the_architecture_its_own_way_and_its_headers_only_know_that_spelling() {
1248 let darwin = set_for("aarch64-apple-darwin");
1251 assert!(has(&darwin, "#define __arm64__ 1"));
1252 assert!(has(&darwin, "#define __arm64 1"));
1253 assert!(has(&darwin, "#define __aarch64__ 1"), "the portable spelling stays too");
1254 let linux = set_for("aarch64-unknown-linux-gnu");
1255 assert!(!has(&linux, "#define __arm64__ 1"), "Apple's spelling is Apple's alone");
1256 assert!(!has(&set_for("x86_64-apple-darwin"), "#define __arm64__ 1"));
1257 }
1258
1259 #[test]
1260 fn every_limit_is_spelled_in_hexadecimal_the_way_gcc_spells_it() {
1261 let linux = set_for("x86_64-unknown-linux-gnu");
1268 for line in [
1269 "#define __SCHAR_MAX__ 0x7f",
1270 "#define __SHRT_MAX__ 0x7fff",
1271 "#define __INT_MAX__ 0x7fffffff",
1272 "#define __LONG_MAX__ 0x7fffffffffffffffL",
1273 "#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL",
1274 "#define __INTMAX_MAX__ 0x7fffffffffffffffL",
1275 "#define __UINTMAX_MAX__ 0xffffffffffffffffUL",
1276 "#define __SIZE_MAX__ 0xffffffffffffffffUL",
1277 "#define __PTRDIFF_MAX__ 0x7fffffffffffffffL",
1278 "#define __SIG_ATOMIC_MAX__ 0x7fffffff",
1279 "#define __INT8_MAX__ 0x7f",
1280 "#define __UINT8_MAX__ 0xff",
1281 "#define __INT16_MAX__ 0x7fff",
1282 "#define __UINT16_MAX__ 0xffff",
1283 "#define __INT32_MAX__ 0x7fffffff",
1284 "#define __UINT32_MAX__ 0xffffffffU",
1285 "#define __INT64_MAX__ 0x7fffffffffffffffL",
1286 "#define __UINT64_MAX__ 0xffffffffffffffffUL",
1287 "#define __INT_FAST8_MAX__ 0x7f",
1288 "#define __UINT_FAST8_MAX__ 0xff",
1289 ] {
1290 assert!(has(&linux, line), "{line}");
1291 }
1292 let windows = set_for("x86_64-pc-windows-msvc");
1295 assert!(has(&windows, "#define __LONG_MAX__ 0x7fffffffL"));
1296 assert!(has(&windows, "#define __INTMAX_MAX__ 0x7fffffffffffffffLL"));
1297 assert!(has(&windows, "#define __UINTMAX_MAX__ 0xffffffffffffffffULL"));
1298 }
1299
1300 #[test]
1301 fn wint_t_does_not_follow_wchar_t() {
1302 let darwin = set_for("aarch64-apple-darwin");
1304 assert!(has(&darwin, "#define __WINT_TYPE__ int"));
1305 assert!(has(&darwin, "#define __WINT_MAX__ 0x7fffffff"));
1306 assert!(has(&darwin, "#define __WCHAR_TYPE__ int"));
1307 let linux = set_for("aarch64-unknown-linux-gnu");
1308 assert!(has(&linux, "#define __WINT_TYPE__ unsigned int"));
1309 assert!(has(&linux, "#define __WINT_MAX__ 0xffffffffU"));
1310 assert!(has(&linux, "#define __WCHAR_TYPE__ unsigned int"), "and wchar_t is its own");
1311 assert!(has(
1312 &set_for("x86_64-pc-windows-msvc"),
1313 "#define __WINT_TYPE__ short unsigned int"
1314 ));
1315 }
1316
1317 #[test]
1318 fn the_widths_say_what_the_type_holds_and_follow_the_target_that_changes_it() {
1319 let linux = set_for("x86_64-unknown-linux-gnu");
1323 assert_eq!(linux.lines().filter(|line| line.contains("_WIDTH__")).count(), 20);
1324 assert!(has(&linux, "#define __LONG_WIDTH__ 64"));
1325 assert!(has(&linux, "#define __SIZE_WIDTH__ 64"));
1326 assert!(has(&linux, "#define __WCHAR_WIDTH__ 32"));
1327 assert!(has(&linux, "#define __INT_LEAST16_WIDTH__ 16"));
1328 assert!(has(&linux, "#define __INT_FAST16_WIDTH__ 64"));
1331 assert!(has(&set_for("x86_64-unknown-linux-musl"), "#define __INT_FAST16_WIDTH__ 32"));
1332 let windows = set_for("x86_64-pc-windows-msvc");
1335 assert!(has(&windows, "#define __LONG_WIDTH__ 32"));
1336 assert!(has(&windows, "#define __WINT_WIDTH__ 16"));
1337 assert!(has(&windows, "#define __SIZE_WIDTH__ 64"));
1338 assert!(has(&windows, "#define __INTMAX_WIDTH__ 64"));
1339 }
1340
1341 #[test]
1342 fn a_constant_maker_gets_the_suffix_its_width_needs_and_no_other() {
1343 let linux = set_for("x86_64-unknown-linux-gnu");
1347 assert!(has(&linux, "#define __INT32_C(c) c"));
1348 assert!(has(&linux, "#define __UINT32_C(c) c ## U"));
1349 assert!(has(&linux, "#define __INT16_C(c) c"));
1350 assert!(has(&linux, "#define __UINT16_C(c) c"));
1353 assert!(has(&linux, "#define __UINT8_C(c) c"));
1354 assert!(has(&linux, "#define __INT64_C(c) c ## L"));
1356 assert!(has(&linux, "#define __UINT64_C(c) c ## UL"));
1357 let windows = set_for("x86_64-pc-windows-msvc");
1359 assert!(has(&windows, "#define __INT64_C(c) c ## LL"));
1360 assert!(has(&windows, "#define __UINT64_C(c) c ## ULL"));
1361 }
1362
1363 #[test]
1364 fn the_symbol_prefix_is_defined_everywhere_including_where_it_is_empty() {
1365 for triple in
1370 ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
1371 {
1372 assert!(has(&set_for(triple), "#define __USER_LABEL_PREFIX__ "), "{triple}");
1373 }
1374 assert!(has(&set_for("aarch64-apple-darwin"), "#define __USER_LABEL_PREFIX__ _"));
1376 }
1377
1378 #[test]
1382 fn the_toolchain_macros_gcc_defines_are_defined_with_gccs_values() {
1383 let linux = set_for("x86_64-unknown-linux-gnu");
1384 for line in [
1385 "#define __GNUC_EXECUTION_CHARSET_NAME \"UTF-8\"",
1386 "#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-32LE\"",
1387 "#define __GXX_ABI_VERSION 1021",
1388 "#define __REGISTER_PREFIX__ ",
1389 "#define __FINITE_MATH_ONLY__ 0",
1390 "#define __GCC_IEC_559 2",
1391 "#define __GCC_IEC_559_COMPLEX 2",
1392 "#define __GCC_CONSTRUCTIVE_SIZE 64",
1393 "#define __GCC_DESTRUCTIVE_SIZE 64",
1394 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1",
1395 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1",
1396 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1",
1397 "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1",
1398 "#define __ATOMIC_HLE_ACQUIRE 65536",
1399 "#define __ATOMIC_HLE_RELEASE 131072",
1400 "#define __FXSR__ 1",
1401 "#define __MMX_WITH_SSE__ 1",
1402 "#define __code_model_small__ 1",
1403 ] {
1404 assert!(has(&linux, line), "{line}");
1405 }
1406 let arm = set_for("aarch64-unknown-linux-gnu");
1408 for name in ["__ATOMIC_HLE_ACQUIRE", "__FXSR__", "__MMX_WITH_SSE__", "__code_model_small__"]
1409 {
1410 assert!(!arm.contains(name), "{name}");
1411 }
1412 assert!(has(&arm, "#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1"));
1413 let windows = set_for("x86_64-pc-windows-msvc");
1415 assert!(has(&windows, "#define __GNUC_WIDE_EXECUTION_CHARSET_NAME \"UTF-16LE\""));
1416 }
1417
1418 #[test]
1419 fn the_memory_orders_are_there_even_without_atomics() {
1420 let linux = set_for("x86_64-unknown-linux-gnu");
1425 assert!(has(&linux, "#define __ATOMIC_RELAXED 0"));
1426 assert!(has(&linux, "#define __ATOMIC_SEQ_CST 5"));
1427 assert!(has(&linux, "#define __STDC_NO_ATOMICS__ 1"), "and we still have no _Atomic");
1428 assert!(has(&linux, "#define __GCC_ATOMIC_INT_LOCK_FREE 2"));
1429 assert!(has(&linux, "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2"));
1430 assert!(has(&set_for("x86_64-pc-windows-msvc"), "#define __GCC_ATOMIC_LLONG_LOCK_FREE 2"));
1431 }
1432
1433 #[test]
1434 fn long_double_is_three_types_and_the_macros_say_which() {
1435 assert!(has(&set_for("x86_64-unknown-linux-gnu"), "#define __LDBL_MANT_DIG__ 64"));
1436 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __LDBL_MANT_DIG__ 113"));
1437 assert!(has(&set_for("aarch64-apple-darwin"), "#define __LDBL_MANT_DIG__ 53"));
1438 }
1439
1440 #[test]
1441 fn the_extended_floating_types_have_the_limits_their_formats_have() {
1442 let linux = set_for("x86_64-unknown-linux-gnu");
1445 assert!(has(&linux, "#define __FLT16_MANT_DIG__ 11"));
1446 assert!(has(&linux, "#define __FLT32_MANT_DIG__ 24"));
1447 assert!(has(&linux, "#define __FLT64_MANT_DIG__ 53"));
1448 assert!(has(&linux, "#define __FLT128_MANT_DIG__ 113"));
1449 assert!(has(&linux, "#define __FLT32X_MANT_DIG__ 53"));
1450 assert!(has(&linux, "#define __FLT16_MAX__ 6.55040000000000000000000000000000000e+4F16"));
1453 assert!(has(
1454 &linux,
1455 "#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x"
1456 ));
1457 assert!(!linux.contains("__FLT128X_"));
1460 }
1461
1462 #[test]
1463 fn the_family_for_a_named_type_is_written_where_the_type_is_and_nowhere_else() {
1464 let has_family = |target: &str, prefix: &str| {
1469 set_for_tuple(target).contains(&format!("#define __{prefix}_MANT_DIG__ "))
1470 };
1471 assert!(has_family("x86_64-linux-gnu", "FLT16"));
1472 assert!(has_family("aarch64-linux-gnu", "FLT16"));
1473 assert!(has_family("riscv64-linux-gnu", "FLT16"));
1474 assert!(!has_family("i686-linux-gnu", "FLT16"));
1475 assert!(!has_family("s390x-linux-gnu", "FLT16"));
1476 assert!(!has_family("armv7-linux-gnueabihf", "FLT16"));
1477
1478 assert!(has_family("i686-linux-gnu", "FLT128"));
1479 assert!(has_family("s390x-linux-gnu", "FLT128"));
1480 assert!(!has_family("armv7-linux-gnueabihf", "FLT128"));
1481
1482 let arm = set_for_tuple("armv7-linux-gnueabihf");
1485 for prefix in ["FLT", "DBL", "LDBL", "FLT32", "FLT64", "FLT32X"] {
1486 assert!(arm.contains(&format!("#define __{prefix}_MANT_DIG__ ")), "__{prefix}_");
1487 }
1488 assert!(!arm.contains("__FLT64X_"));
1489 }
1490
1491 #[test]
1492 fn float64x_keeps_the_width_that_long_double_loses_on_apple() {
1493 let linux = set_for("x86_64-unknown-linux-gnu");
1496 assert!(has(&linux, "#define __FLT64X_MANT_DIG__ 64"));
1497 assert!(has(&linux, "#define __LDBL_MANT_DIG__ 64"));
1498 let mac = set_for("aarch64-apple-darwin");
1499 assert!(has(&mac, "#define __FLT64X_MANT_DIG__ 113"));
1500 assert!(has(&mac, "#define __LDBL_MANT_DIG__ 53"));
1501 let windows = set_for("x86_64-pc-windows-msvc");
1502 assert!(has(&windows, "#define __FLT64X_MANT_DIG__ 64"));
1503 assert!(has(&windows, "#define __LDBL_MANT_DIG__ 53"));
1504 }
1505
1506 #[test]
1507 fn the_largest_value_of_an_ieee_format_is_also_its_largest_normal_one() {
1508 let linux = set_for("x86_64-unknown-linux-gnu");
1512 for prefix in ["FLT", "DBL", "LDBL", "FLT16", "FLT32", "FLT64", "FLT128", "FLT32X"] {
1513 let value = |suffix: &str| {
1514 let name = format!("#define __{prefix}_{suffix}__ ");
1515 let line = linux
1516 .lines()
1517 .find(|line| line.starts_with(&name))
1518 .unwrap_or_else(|| panic!("__{prefix}_{suffix}__ is defined"));
1519 line[name.len()..].to_owned()
1520 };
1521 assert_eq!(value("MAX"), value("NORM_MAX"), "__{prefix}_NORM_MAX__");
1522 }
1523 }
1524
1525 #[test]
1526 fn the_double_double_is_the_row_where_the_largest_value_is_not_the_largest_normal_one() {
1527 let c = characteristics(Format::DoubleDouble);
1532 assert_ne!(c.max, c.norm_max);
1533 assert!(c.norm_max.starts_with("8.98846567431157953864652595394501e+307"));
1537 assert!(c.max.starts_with("1.7976931348623158"));
1538 assert_eq!(c.epsilon, c.denorm_min);
1542 for format in [Format::Half, Format::Single, Format::Double, Format::X87Extended] {
1543 assert_ne!(characteristics(format).epsilon, characteristics(format).denorm_min);
1544 }
1545 assert_eq!(c.is_iec_60559, "0");
1547 }
1548
1549 #[test]
1550 fn the_widest_bit_int_is_said_in_every_dialect() {
1551 let mut opts = Predef::new();
1555 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1556 assert!(has(&built_in(&target, &opts), "#define __BITINT_MAXWIDTH__ 128"));
1557 opts.std = Std::C17;
1558 assert!(has(&built_in(&target, &opts), "#define __BITINT_MAXWIDTH__ 128"));
1559 }
1560
1561 #[test]
1562 fn char_signedness_is_recorded_only_when_it_is_unsigned() {
1563 assert!(has(&set_for("aarch64-unknown-linux-gnu"), "#define __CHAR_UNSIGNED__ 1"));
1565 assert!(!has(&set_for("x86_64-unknown-linux-gnu"), "#define __CHAR_UNSIGNED__ 1"));
1566 }
1567
1568 #[test]
1569 fn the_dialect_decides_the_standard_macros() {
1570 let mut opts = Predef::new();
1571 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1572 assert!(has(&built_in(&target, &opts), "#define __STDC_VERSION__ 202311L"));
1573 assert!(!has(&built_in(&target, &opts), "#define __STRICT_ANSI__ 1"));
1574 assert!(has(&built_in(&target, &opts), "#define linux 1"));
1575
1576 opts.gnu_extensions = false;
1577 assert!(has(&built_in(&target, &opts), "#define __STRICT_ANSI__ 1"));
1578 assert!(!has(&built_in(&target, &opts), "#define linux 1"), "not a reserved name");
1579
1580 opts.std = Std::C89;
1581 let c89 = built_in(&target, &opts);
1582 assert!(!c89.contains("__STDC_VERSION__"), "C89 does not define it at all");
1583 assert!(has(&c89, "#define __STDC__ 1"));
1584 }
1585
1586 #[test]
1589 fn the_only_things_claimed_missing_are_the_ones_that_are_missing() {
1590 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1591 let opts = Predef::new();
1592 let set = built_in(&target, &opts);
1593 assert!(has(&set, "#define __STDC_NO_ATOMICS__ 1"), "there is no stdatomic.h to include");
1594 assert!(has(&set, "#define __STDC_NO_THREADS__ 1"), "nor a threads.h");
1595 assert!(has(&set, "#define __STDC_NO_COMPLEX__ 1"), "the arithmetic is not lowered");
1596 assert!(!set.contains("__STDC_NO_VLA__"), "variable length arrays work");
1597 }
1598
1599 #[test]
1603 fn the_type_behind_char8_t_is_defined_in_c23_and_in_no_dialect_before_it() {
1604 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1605 let mut opts = Predef::new();
1606 assert!(has(&built_in(&target, &opts), "#define __CHAR8_TYPE__ unsigned char"));
1607
1608 for older in [Std::C17, Std::C11, Std::C99, Std::C89] {
1609 opts.std = older;
1610 assert!(!built_in(&target, &opts).contains("__CHAR8_TYPE__"), "{older:?}");
1611 }
1612 }
1613
1614 #[test]
1619 fn the_ieee_annex_macro_carries_the_value_glibcs_own_header_writes() {
1620 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1621 let mut opts = Predef::new();
1622 for std in [Std::C23, Std::C17, Std::C11, Std::C99, Std::C89] {
1623 opts.std = std;
1624 let set = built_in(&target, &opts);
1625 assert!(has(&set, "#define __STDC_IEC_60559_BFP__ 201404L"), "{std:?}");
1626 assert!(has(&set, "#define __STDC_IEC_60559_COMPLEX__ 201404L"), "{std:?}");
1627 assert!(has(&set, "#define __GCC_IEC_559 2"), "{std:?}");
1629 assert!(has(&set, "#define __GCC_IEC_559_COMPLEX 2"), "{std:?}");
1630 }
1631 }
1632
1633 #[test]
1634 fn the_optimizer_level_is_visible_to_the_preprocessor() {
1635 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1636 let mut opts = Predef::new();
1637 assert!(has(&built_in(&target, &opts), "#define __NO_INLINE__ 1"));
1638 assert!(!built_in(&target, &opts).contains("__OPTIMIZE__"));
1639
1640 opts.opt_level = OptLevel::O2;
1641 assert!(has(&built_in(&target, &opts), "#define __OPTIMIZE__ 1"));
1642 assert!(!built_in(&target, &opts).contains("__OPTIMIZE_SIZE__"));
1643
1644 opts.opt_level = OptLevel::Os;
1645 assert!(has(&built_in(&target, &opts), "#define __OPTIMIZE_SIZE__ 1"));
1646 }
1647
1648 #[test]
1649 fn a_command_line_define_with_no_value_is_one() {
1650 let mut opts = Predef::new();
1651 opts.defines = vec!["FOO".to_owned(), "BAR=2".to_owned(), "F(x)=x + 1".to_owned()];
1652 opts.undefines = vec!["__linux__".to_owned()];
1653 let text = command_line(&opts);
1654 assert!(has(&text, "#define FOO 1"));
1655 assert!(has(&text, "#define BAR 2"));
1656 assert!(has(&text, "#define F(x) x + 1"));
1657 assert!(text.trim_end().ends_with("#undef __linux__"));
1659 }
1660
1661 #[test]
1662 fn no_command_line_macros_is_no_file_at_all() {
1663 assert!(command_line(&Predef::new()).is_empty());
1664 }
1665
1666 #[test]
1667 fn a_date_is_spelled_the_way_the_standard_fixes() {
1668 let epoch = Timestamp::from_unix(0);
1670 assert_eq!(epoch.date, "Jan 1 1970");
1671 assert_eq!(epoch.time, "00:00:00");
1672 let leap = Timestamp::from_unix(1_709_164_800);
1673 assert_eq!(leap.date, "Feb 29 2024", "2024 is a leap year");
1674 let late = Timestamp::from_unix(1_735_689_599);
1675 assert_eq!(late.date, "Dec 31 2024");
1676 assert_eq!(late.time, "23:59:59");
1677 }
1678
1679 #[test]
1680 fn a_date_before_the_epoch_still_comes_out_right() {
1681 assert_eq!(Timestamp::from_unix(-1).date, "Dec 31 1969");
1684 assert_eq!(Timestamp::from_unix(-1).time, "23:59:59");
1685 }
1686
1687 #[test]
1688 fn the_gnuc_version_is_a_knob_rather_than_a_constant() {
1689 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1690 let mut opts = Predef::new();
1691 assert!(has(&built_in(&target, &opts), "#define __GNUC__ 7"));
1692 opts.gnuc = GnucVersion { major: 15, minor: 1, patch: 0 };
1693 assert!(has(&built_in(&target, &opts), "#define __GNUC__ 15"));
1694 assert!(has(&built_in(&target, &opts), "#define __GNUC_MINOR__ 1"));
1695 }
1696
1697 #[test]
1704 fn one_of_the_two_inline_macros_is_defined_and_three_things_can_pick_which() {
1705 let target = TargetInfo::new("x86_64-unknown-linux-gnu".parse().unwrap());
1706 let gnu = "#define __GNUC_GNU_INLINE__ 1";
1707 let stdc = "#define __GNUC_STDC_INLINE__ 1";
1708
1709 let mut opts = Predef::new();
1710 assert!(has(&built_in(&target, &opts), stdc));
1711 assert!(!has(&built_in(&target, &opts), gnu));
1712
1713 opts.gnu89_inline = true;
1714 assert!(has(&built_in(&target, &opts), gnu));
1715 assert!(!has(&built_in(&target, &opts), stdc));
1716
1717 let mut opts = Predef::new();
1719 opts.std = Std::C89;
1720 assert!(has(&built_in(&target, &opts), gnu));
1721 assert!(!has(&built_in(&target, &opts), stdc));
1722 }
1723
1724 #[test]
1725 fn musl_and_glibc_disagree_about_the_fast_types_on_the_same_processor() {
1726 let gnu = set_for("x86_64-unknown-linux-gnu");
1731 let musl = set_for("x86_64-unknown-linux-musl");
1732 assert!(has(&gnu, "#define __INT_FAST16_TYPE__ long int"));
1733 assert!(has(&gnu, "#define __INT_FAST32_TYPE__ long int"));
1734 assert!(has(&gnu, "#define __UINT_FAST16_TYPE__ long unsigned int"));
1735 assert!(has(&musl, "#define __INT_FAST16_TYPE__ int"));
1736 assert!(has(&musl, "#define __INT_FAST32_TYPE__ int"));
1737 assert!(has(&musl, "#define __UINT_FAST16_TYPE__ unsigned int"));
1738 assert!(has(&gnu, "#define __INT_FAST16_MAX__ 0x7fffffffffffffffL"));
1741 assert!(has(&musl, "#define __INT_FAST16_MAX__ 0x7fffffff"));
1742 assert!(has(&musl, "#define __UINT_FAST16_MAX__ 0xffffffffU"));
1743 }
1744
1745 #[test]
1746 fn the_libc_only_moves_the_two_fast_types_it_is_allowed_to_move() {
1747 let gnu = set_for("x86_64-unknown-linux-gnu");
1750 let musl = set_for("x86_64-unknown-linux-musl");
1751 for line in [
1752 "#define __INT_FAST8_TYPE__ signed char",
1753 "#define __INT_FAST64_TYPE__ long int",
1754 "#define __INT64_TYPE__ long int",
1755 "#define __SIZE_TYPE__ long unsigned int",
1756 "#define __SIZEOF_LONG__ 8",
1757 "#define __LP64__ 1",
1758 ] {
1759 assert!(has(&gnu, line), "glibc lost {line}");
1760 assert!(has(&musl, line), "musl lost {line}");
1761 }
1762 }
1763
1764 #[test]
1765 fn a_non_x86_target_has_int_sized_fast_types_whatever_the_libc() {
1766 let arm_gnu = set_for("aarch64-unknown-linux-gnu");
1769 let arm_musl = set_for("aarch64-unknown-linux-musl");
1770 assert!(has(&arm_gnu, "#define __INT_FAST16_TYPE__ int"));
1771 assert!(has(&arm_musl, "#define __INT_FAST16_TYPE__ int"));
1772 }
1773}