Emulate the cpuid arch intrinsic
This commit is contained in:
parent
847cc7ab2a
commit
c1a68b1386
5 changed files with 107 additions and 43 deletions
|
@ -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);
|
||||
|
|
|
@ -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)
|
52
src/base.rs
52
src/base.rs
|
@ -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
67
src/intrinsics/cpuid.rs
Normal 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)
|
||||
}
|
|
@ -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::*;
|
||||
|
|
Loading…
Add table
Reference in a new issue