Emulate the cpuid arch intrinsic

This commit is contained in:
bjorn3 2020-08-15 18:55:32 +02:00
parent 847cc7ab2a
commit c1a68b1386
5 changed files with 107 additions and 43 deletions

View file

@ -126,6 +126,8 @@ fn panic(_: u128) {
#[target_feature(enable = "sse2")]
unsafe fn test_simd() {
assert!(is_x86_feature_detected!("sse2"));
let x = _mm_setzero_si128();
let y = _mm_set1_epi16(7);
let or = _mm_or_si128(x, y);

View file

@ -1,27 +0,0 @@
From 7403e2998345ef0650fd50628d7098d4d1e88e5c Mon Sep 17 00:00:00 2001
From: bjorn3 <bjorn3@users.noreply.github.com>
Date: Sat, 6 Apr 2019 12:16:21 +0200
Subject: [PATCH] Remove usage of unsized locals
---
library/stdarch/crates/core_arch/src/x86/cpuid.rs | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/library/stdarch/crates/core_arch/src/x86/cpuid.rs b/library/stdarch/crates/core_arch/src/x86/cpuid.rs
index f313c42..ff952bc 100644
--- a/library/stdarch/crates/core_arch/src/x86/cpuid.rs
+++ b/library/stdarch/crates/core_arch/src/x86/cpuid.rs
@@ -84,6 +84,11 @@ pub unsafe fn __cpuid(leaf: u32) -> CpuidResult {
/// Does the host support the `cpuid` instruction?
#[inline]
pub fn has_cpuid() -> bool {
+ // __cpuid intrinsic is not yet implemented
+ #[cfg(target_feature = "cg_clif")] {
+ return false;
+ }
+
#[cfg(target_env = "sgx")]
{
false
--
2.20.1 (Apple Git-117)

View file

@ -681,37 +681,57 @@ fn trans_stmt<'tcx>(
use rustc_span::symbol::Symbol;
let LlvmInlineAsm {
asm,
outputs: _,
inputs: _,
outputs,
inputs,
} = &**asm;
let rustc_hir::LlvmInlineAsmInner {
asm: asm_code, // Name
outputs, // Vec<Name>
inputs, // Vec<Name>
outputs: output_names, // Vec<LlvmInlineAsmOutput>
inputs: input_names, // Vec<Name>
clobbers, // Vec<Name>
volatile, // bool
alignstack, // bool
dialect: _, // rustc_ast::ast::AsmDialect
dialect: _,
asm_str_style: _,
} = asm;
match &*asm_code.as_str() {
match asm_code.as_str().trim() {
"" => {
// Black box
}
cpuid if cpuid.contains("cpuid") => {
crate::trap::trap_unimplemented(
fx,
"__cpuid_count arch intrinsic is not supported",
);
"mov %rbx, %rsi\n cpuid\n xchg %rbx, %rsi" => {
assert_eq!(input_names, &[Symbol::intern("{eax}"), Symbol::intern("{ecx}")]);
assert_eq!(output_names.len(), 4);
for (i, c) in (&["={eax}", "={esi}", "={ecx}", "={edx}"]).iter().enumerate() {
assert_eq!(&output_names[i].constraint.as_str(), c);
assert!(!output_names[i].is_rw);
assert!(!output_names[i].is_indirect);
}
assert_eq!(clobbers, &[]);
assert!(!volatile);
assert!(!alignstack);
assert_eq!(inputs.len(), 2);
let leaf = trans_operand(fx, &inputs[0].1).load_scalar(fx); // %eax
let subleaf = trans_operand(fx, &inputs[1].1).load_scalar(fx); // %ecx
let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, subleaf);
assert_eq!(outputs.len(), 4);
trans_place(fx, outputs[0]).write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
trans_place(fx, outputs[1]).write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
trans_place(fx, outputs[2]).write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
trans_place(fx, outputs[3]).write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
}
"xgetbv" => {
assert_eq!(inputs, &[Symbol::intern("{ecx}")]);
assert_eq!(input_names, &[Symbol::intern("{ecx}")]);
assert_eq!(outputs.len(), 2);
assert_eq!(output_names.len(), 2);
for (i, c) in (&["={eax}", "={edx}"]).iter().enumerate() {
assert_eq!(&outputs[i].constraint.as_str(), c);
assert!(!outputs[i].is_rw);
assert!(!outputs[i].is_indirect);
assert_eq!(&output_names[i].constraint.as_str(), c);
assert!(!output_names[i].is_rw);
assert!(!output_names[i].is_indirect);
}
assert_eq!(clobbers, &[]);

67
src/intrinsics/cpuid.rs Normal file
View file

@ -0,0 +1,67 @@
use crate::prelude::*;
/// Emulates a subset of the cpuid call.
///
/// This emulates an intel cpu with sse and sse2 support, but which doesn't support anything else.
pub(crate) fn codegen_cpuid_call<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
leaf: Value,
_subleaf: Value,
) -> (Value, Value, Value, Value) {
let leaf_0 = fx.bcx.create_block();
let leaf_1 = fx.bcx.create_block();
let leaf_8000_0000 = fx.bcx.create_block();
let leaf_8000_0001 = fx.bcx.create_block();
let unsupported_leaf = fx.bcx.create_block();
let dest = fx.bcx.create_block();
let eax = fx.bcx.append_block_param(dest, types::I32);
let ebx = fx.bcx.append_block_param(dest, types::I32);
let ecx = fx.bcx.append_block_param(dest, types::I32);
let edx = fx.bcx.append_block_param(dest, types::I32);
let mut switch = cranelift_frontend::Switch::new();
switch.set_entry(0, leaf_0);
switch.set_entry(1, leaf_1);
switch.set_entry(0x8000_0000, leaf_8000_0000);
switch.set_entry(0x8000_0001, leaf_8000_0001);
switch.emit(&mut fx.bcx, leaf, unsupported_leaf);
fx.bcx.switch_to_block(leaf_0);
let max_basic_leaf = fx.bcx.ins().iconst(types::I32, 1);
let vend0 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"Genu")));
let vend2 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"ineI")));
let vend1 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"ntel")));
fx.bcx.ins().jump(dest, &[max_basic_leaf, vend0, vend1, vend2]);
fx.bcx.switch_to_block(leaf_1);
let cpu_signature = fx.bcx.ins().iconst(types::I32, 0);
let additional_information = fx.bcx.ins().iconst(types::I32, 0);
let ecx_features = fx.bcx.ins().iconst(
types::I32,
0,
);
let edx_features = fx.bcx.ins().iconst(
types::I32,
1 << 25 /* sse */ | 1 << 26 /* sse2 */,
);
fx.bcx.ins().jump(dest, &[cpu_signature, additional_information, ecx_features, edx_features]);
fx.bcx.switch_to_block(leaf_8000_0000);
let extended_max_basic_leaf = fx.bcx.ins().iconst(types::I32, 0);
let zero = fx.bcx.ins().iconst(types::I32, 0);
fx.bcx.ins().jump(dest, &[extended_max_basic_leaf, zero, zero, zero]);
fx.bcx.switch_to_block(leaf_8000_0001);
let zero = fx.bcx.ins().iconst(types::I32, 0);
let proc_info_ecx = fx.bcx.ins().iconst(types::I32, 0);
let proc_info_edx = fx.bcx.ins().iconst(types::I32, 0);
fx.bcx.ins().jump(dest, &[zero, zero, proc_info_ecx, proc_info_edx]);
fx.bcx.switch_to_block(unsupported_leaf);
crate::trap::trap_unreachable(fx, "__cpuid_count arch intrinsic doesn't yet support specified leaf");
fx.bcx.switch_to_block(dest);
(eax, ebx, ecx, edx)
}

View file

@ -1,6 +1,8 @@
mod cpuid;
mod llvm;
mod simd;
pub(crate) use cpuid::codegen_cpuid_call;
pub(crate) use llvm::codegen_llvm_intrinsic_call;
use crate::prelude::*;