From 7d5343a6700581e318189dcd74567b348bd7f68d Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 21 Mar 2018 21:49:22 +0100 Subject: [PATCH 1/6] implement minmax intrinsics --- src/librustc_llvm/ffi.rs | 3 +++ src/librustc_trans/builder.rs | 13 +++++++++++++ src/librustc_trans/intrinsic.rs | 2 ++ src/librustc_typeck/check/intrinsic.rs | 3 ++- src/rustllvm/RustWrapper.cpp | 9 +++++++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 403fe4731f118..09ff35667139c 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1247,6 +1247,9 @@ extern "C" { IsNaN: bool) -> ValueRef; + pub fn LLVMRustBuildMinNum(B: BuilderRef, LHS: ValueRef, LHS: ValueRef) -> ValueRef; + pub fn LLVMRustBuildMaxNum(B: BuilderRef, LHS: ValueRef, LHS: ValueRef) -> ValueRef; + pub fn LLVMBuildIsNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) -> ValueRef; pub fn LLVMBuildIsNotNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) -> ValueRef; pub fn LLVMBuildPtrDiff(B: BuilderRef, diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 5e2d32b359698..b5271b25b630c 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -917,6 +917,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + pub fn minnum(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("minnum"); + unsafe { + llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) + } + } + pub fn maxnum(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { + self.count_insn("maxnum"); + unsafe { + llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs) + } + } + pub fn select(&self, cond: ValueRef, then_val: ValueRef, else_val: ValueRef) -> ValueRef { self.count_insn("select"); unsafe { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 2be29c0836075..5c67f8091141b 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -1432,6 +1432,8 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, simd_and: TyUint, TyInt => and; simd_or: TyUint, TyInt => or; simd_xor: TyUint, TyInt => xor; + simd_fmax: TyFloat => maxnum; + simd_fmin: TyFloat => minnum; } span_bug!(span, "unknown SIMD intrinsic"); } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index da37cec31cf44..377e3a891840f 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -355,7 +355,8 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } "simd_add" | "simd_sub" | "simd_mul" | "simd_rem" | "simd_div" | "simd_shl" | "simd_shr" | - "simd_and" | "simd_or" | "simd_xor" => { + "simd_and" | "simd_or" | "simd_xor" | + "simd_fmin" | "simd_fmax" => { (1, vec![param(0), param(0)], param(0)) } "simd_insert" => (2, vec![param(0), tcx.types.u32, param(1)], param(0)), diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index e815d151aeba9..627827105cbb2 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1500,3 +1500,12 @@ LLVMBuildExactUDiv(LLVMBuilderRef B, LLVMValueRef LHS, return wrap(unwrap(B)->CreateExactUDiv(unwrap(LHS), unwrap(RHS), Name)); } #endif + +extern "C" LLVMValueRef +LLVMRustBuildMinNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { + return wrap(unwrap(B)->CreateMinNum(unwrap(LHS),unwrap(RHS))); +} +extern "C" LLVMValueRef +LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { + return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS),unwrap(RHS))); +} From d2cd57c8ff2116c2120da2668cee4ff2bf28315c Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 22 Mar 2018 09:49:46 +0100 Subject: [PATCH 2/6] add tests --- .../codegen/simd-intrinsic-float-minmax.rs | 40 ++++++++++++++ .../run-fail/simd-intrinsic-float-minmax.rs | 55 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 src/test/codegen/simd-intrinsic-float-minmax.rs create mode 100644 src/test/run-fail/simd-intrinsic-float-minmax.rs diff --git a/src/test/codegen/simd-intrinsic-float-minmax.rs b/src/test/codegen/simd-intrinsic-float-minmax.rs new file mode 100644 index 0000000000000..bebb4d379830e --- /dev/null +++ b/src/test/codegen/simd-intrinsic-float-minmax.rs @@ -0,0 +1,40 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +#![feature(repr_simd, platform_intrinsics)] +#[allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fmin(x: T, y: T) -> T; + fn simd_fmax(x: T, y: T) -> T; +} + +// CHECK-LABEL: @fmin +#[no_mangle] +pub unsafe fn fmin(a: f32x4, b: f32x4) -> f32x4 { + // CHECK: call <4 x float> @llvm.minnum.v4f32 + simd_fmin(a, b) +} + +// FIXME(49261) +// // CHECK-LABEL: @fmax +// #[no_mangle] +// pub unsafe fn fmax(a: f32x4, b: f32x4) -> f32x4 { +// // CHECK: call <4 x float> @llvm.maxnum.v4f32 +// simd_fmax(a, b) +// } diff --git a/src/test/run-fail/simd-intrinsic-float-minmax.rs b/src/test/run-fail/simd-intrinsic-float-minmax.rs new file mode 100644 index 0000000000000..32ee569d8fad7 --- /dev/null +++ b/src/test/run-fail/simd-intrinsic-float-minmax.rs @@ -0,0 +1,55 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-emscripten + +// Test that the simd_f{min,max} intrinsics produce the correct results. + +#![feature(repr_simd, platform_intrinsics)] +#[allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fmin(x: T, y: T) -> T; + fn simd_fmax(x: T, y: T) -> T; +} + +fn main() { + let x = f32x4(1.0, 2.0, 3.0, 4.0); + let y = f32x4(2.0, 1.0, 4.0, 3.0); + let nan = ::std::f32::NAN; + let n = f32x4(nan, nan, nan, nan); + + unsafe { + let min0 = simd_fmin(x, y); + let min1 = simd_fmin(y, x); + assert_eq!(min0, min1); + let e = f32x4(1.0, 1.0, 3.0, 3.0); + assert_eq!(min0, e); + let minn = simd_fmin(x, n); + assert_eq!(minn, x); + let minn = simd_fmin(y, n); + assert_eq!(minn, y); + + // FIXME(49261) + let max0 = simd_fmax(x, y); + let max1 = simd_fmax(y, x); + assert_eq!(max0, max1); + let e = f32x4(2.0, 2.0, 4.0, 4.0); + assert_eq!(max0, e); + let maxn = simd_fmax(x, n); + assert_eq!(maxn, x); + let maxn = simd_fmax(y, n); + assert_eq!(maxn, y); + } +} From 066c2ec9baac1be5e884e48813a542de8f5d64b0 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 22 Mar 2018 14:48:58 +0100 Subject: [PATCH 3/6] require llvm 6 --- src/librustc_trans/builder.rs | 8 ++++++-- src/rustllvm/RustWrapper.cpp | 11 +++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index b5271b25b630c..241ee8a48283a 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -920,13 +920,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn minnum(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { self.count_insn("minnum"); unsafe { - llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) + let instr = llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs); + bug!("LLVMRustBuildMinNum is not available in LLVM version < 6.0"); + instr } } pub fn maxnum(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { self.count_insn("maxnum"); unsafe { - llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs) + let instr = llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs); + bug!("LLVMRustBuildMaxNum is not available in LLVM version < 6.0"); + instr } } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 627827105cbb2..1b35f0adda645 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1501,6 +1501,7 @@ LLVMBuildExactUDiv(LLVMBuilderRef B, LLVMValueRef LHS, } #endif +#if LLVM_VERSION_GE(6, 0) extern "C" LLVMValueRef LLVMRustBuildMinNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { return wrap(unwrap(B)->CreateMinNum(unwrap(LHS),unwrap(RHS))); @@ -1509,3 +1510,13 @@ extern "C" LLVMValueRef LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS),unwrap(RHS))); } +#else +extern "C" LLVMValueRef +LLVMRustBuildMinNum(LLVMBuilderRef, LLVMValueRef, LLVMValueRef) { + return nullptr; +} +extern "C" LLVMValueRef +LLVMRustBuildMaxNum(LLVMBuilderRef, LLVMValueRef, LLVMValueRef) { + return nullptr; +} +#endif From 1841f40d2164c56dc286cef7a2e0d1bf091837f7 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 22 Mar 2018 16:28:11 +0100 Subject: [PATCH 4/6] properly handle the case when LLVM does not have min/maxnum --- src/librustc_trans/builder.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 241ee8a48283a..db803ca8209d9 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -921,7 +921,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.count_insn("minnum"); unsafe { let instr = llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs); - bug!("LLVMRustBuildMinNum is not available in LLVM version < 6.0"); + if instr.is_null() { + bug!("LLVMRustBuildMinNum is not available in LLVM version < 6.0"); + } instr } } @@ -929,7 +931,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.count_insn("maxnum"); unsafe { let instr = llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs); - bug!("LLVMRustBuildMaxNum is not available in LLVM version < 6.0"); + if instr.is_null() { + bug!("LLVMRustBuildMaxNum is not available in LLVM version < 6.0"); + } instr } } From 48fd903eae4b6b95c76f206c3c7f648aaf4f664d Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 22 Mar 2018 18:01:35 +0100 Subject: [PATCH 5/6] set min-llvm-version 6.0, ignore-emscripten --- src/test/codegen/simd-intrinsic-float-minmax.rs | 3 +++ src/test/run-fail/simd-intrinsic-float-minmax.rs | 1 + 2 files changed, 4 insertions(+) diff --git a/src/test/codegen/simd-intrinsic-float-minmax.rs b/src/test/codegen/simd-intrinsic-float-minmax.rs index bebb4d379830e..8ad3ad762c281 100644 --- a/src/test/codegen/simd-intrinsic-float-minmax.rs +++ b/src/test/codegen/simd-intrinsic-float-minmax.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-emscripten +// min-llvm-version 6.0 + // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] diff --git a/src/test/run-fail/simd-intrinsic-float-minmax.rs b/src/test/run-fail/simd-intrinsic-float-minmax.rs index 32ee569d8fad7..fad8fa48bc34f 100644 --- a/src/test/run-fail/simd-intrinsic-float-minmax.rs +++ b/src/test/run-fail/simd-intrinsic-float-minmax.rs @@ -9,6 +9,7 @@ // except according to those terms. // ignore-emscripten +// min-llvm-version 6.0 // Test that the simd_f{min,max} intrinsics produce the correct results. From 56aaf344c444943f3c9cefe9d88ed27b43f0a731 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Mon, 26 Mar 2018 10:18:36 +0200 Subject: [PATCH 6/6] fix tests --- src/test/codegen/simd-intrinsic-float-minmax.rs | 4 ++-- src/test/run-fail/simd-intrinsic-float-minmax.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/codegen/simd-intrinsic-float-minmax.rs b/src/test/codegen/simd-intrinsic-float-minmax.rs index 8ad3ad762c281..6663b841808f1 100644 --- a/src/test/codegen/simd-intrinsic-float-minmax.rs +++ b/src/test/codegen/simd-intrinsic-float-minmax.rs @@ -35,9 +35,9 @@ pub unsafe fn fmin(a: f32x4, b: f32x4) -> f32x4 { } // FIXME(49261) -// // CHECK-LABEL: @fmax +// // C_HECK-LABEL: @fmax // #[no_mangle] // pub unsafe fn fmax(a: f32x4, b: f32x4) -> f32x4 { -// // CHECK: call <4 x float> @llvm.maxnum.v4f32 +// // C_HECK: call <4 x float> @llvm.maxnum.v4f32 // simd_fmax(a, b) // } diff --git a/src/test/run-fail/simd-intrinsic-float-minmax.rs b/src/test/run-fail/simd-intrinsic-float-minmax.rs index fad8fa48bc34f..f4fb8e12250b5 100644 --- a/src/test/run-fail/simd-intrinsic-float-minmax.rs +++ b/src/test/run-fail/simd-intrinsic-float-minmax.rs @@ -10,6 +10,7 @@ // ignore-emscripten // min-llvm-version 6.0 +// error-pattern: panicked // Test that the simd_f{min,max} intrinsics produce the correct results.