about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJorge Aparicio <japaricious@gmail.com>2016-12-22 16:24:29 -0500
committerJorge Aparicio <japaricious@gmail.com>2016-12-26 21:06:23 -0500
commit18d49288d546efaceab7c4c6d71a868b575bd00f (patch)
tree9df84415f9655febf4372df9ad2a0a6bdaf511e0
parentb7e5148bbd95062ae8c5e018dec8fd44a8028e0d (diff)
PTX support
- `--emit=asm --target=nvptx64-nvidia-cuda` can be used to turn a crate
  into a PTX module (a `.s` file).

- intrinsics like `__syncthreads` and `blockIdx.x` are exposed as
  `"platform-intrinsics"`.

- "cabi" has been implemented for the nvptx and nvptx64 architectures.
  i.e. `extern "C"` works.

- a new ABI, `"ptx-kernel"`. That can be used to generate "global"
  functions. Example: `extern "ptx-kernel" fn kernel() { .. }`. All
  other functions are "device" functions.
-rw-r--r--src/bootstrap/native.rs2
-rw-r--r--src/etc/platform-intrinsics/nvptx/cuda.json13
-rw-r--r--src/etc/platform-intrinsics/nvptx/info.json7
-rw-r--r--src/etc/platform-intrinsics/nvptx/sreg.json90
-rw-r--r--src/librustc_llvm/build.rs2
-rw-r--r--src/librustc_llvm/ffi.rs1
-rw-r--r--src/librustc_llvm/lib.rs5
-rw-r--r--src/librustc_platform_intrinsics/lib.rs3
-rw-r--r--src/librustc_platform_intrinsics/nvptx.rs92
-rw-r--r--src/librustc_trans/abi.rs5
-rw-r--r--src/librustc_trans/cabi_nvptx.rs53
-rw-r--r--src/librustc_trans/cabi_nvptx64.rs53
-rw-r--r--src/librustc_trans/lib.rs2
-rw-r--r--src/libsyntax/abi.rs2
-rw-r--r--src/libsyntax/feature_gate.rs17
15 files changed, 344 insertions, 3 deletions
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 09dbd9f8220..80f27a5ab67 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -81,7 +81,7 @@ pub fn llvm(build: &Build, target: &str) {
        .profile(profile)
        .define("LLVM_ENABLE_ASSERTIONS", assertions)
        .define("LLVM_TARGETS_TO_BUILD",
-               "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc")
+               "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX")
        .define("LLVM_INCLUDE_EXAMPLES", "OFF")
        .define("LLVM_INCLUDE_TESTS", "OFF")
        .define("LLVM_INCLUDE_DOCS", "OFF")
diff --git a/src/etc/platform-intrinsics/nvptx/cuda.json b/src/etc/platform-intrinsics/nvptx/cuda.json
new file mode 100644
index 00000000000..1beaaeb5d87
--- /dev/null
+++ b/src/etc/platform-intrinsics/nvptx/cuda.json
@@ -0,0 +1,13 @@
+{
+    "intrinsic_prefix": "_",
+    "llvm_prefix": "llvm.cuda.",
+    "intrinsics": [
+        {
+            "intrinsic": "syncthreads",
+            "width": ["0"],
+            "llvm": "syncthreads",
+            "ret": "V",
+            "args": []
+        }
+    ]
+}
diff --git a/src/etc/platform-intrinsics/nvptx/info.json b/src/etc/platform-intrinsics/nvptx/info.json
new file mode 100644
index 00000000000..80332c54e04
--- /dev/null
+++ b/src/etc/platform-intrinsics/nvptx/info.json
@@ -0,0 +1,7 @@
+{
+  "platform": "nvptx",
+  "number_info": {
+    "signed": {}
+  },
+  "width_info": {}
+}
diff --git a/src/etc/platform-intrinsics/nvptx/sreg.json b/src/etc/platform-intrinsics/nvptx/sreg.json
new file mode 100644
index 00000000000..33d97f26946
--- /dev/null
+++ b/src/etc/platform-intrinsics/nvptx/sreg.json
@@ -0,0 +1,90 @@
+{
+    "intrinsic_prefix": "_",
+    "llvm_prefix": "llvm.nvvm.read.ptx.sreg.",
+    "intrinsics": [
+        {
+            "intrinsic": "block_dim_x",
+            "width": ["0"],
+            "llvm": "ntid.x",
+            "ret": "S32",
+            "args": []
+        },
+        {
+            "intrinsic": "block_dim_y",
+            "width": ["0"],
+            "llvm": "ntid.y",
+            "ret": "S32",
+            "args": []
+        },
+        {
+            "intrinsic": "block_dim_z",
+            "width": ["0"],
+            "llvm": "ntid.z",
+            "ret": "S32",
+            "args": []
+        },
+        {
+            "intrinsic": "block_idx_x",
+            "width": ["0"],
+            "llvm": "ctaid.x",
+            "ret": "S32",
+            "args": []
+        },
+        {
+            "intrinsic": "block_idx_y",
+            "width": ["0"],
+            "llvm": "ctaid.y",
+            "ret": "S32",
+            "args": []
+        },
+        {
+            "intrinsic": "block_idx_z",
+            "width": ["0"],
+            "llvm": "ctaid.z",
+            "ret": "S32",
+            "args": []
+        },
+        {
+            "intrinsic": "grid_dim_x",
+            "width": ["0"],
+            "llvm": "nctaid.x",
+            "ret": "S32",
+            "args": []
+        },
+        {
+            "intrinsic": "grid_dim_y",
+            "width": ["0"],
+            "llvm": "nctaid.y",
+            "ret": "S32",
+            "args": []
+        },
+        {
+            "intrinsic": "grid_dim_z",
+            "width": ["0"],
+            "llvm": "nctaid.z",
+            "ret": "S32",
+            "args": []
+        },
+        {
+            "intrinsic": "thread_idx_x",
+            "width": ["0"],
+            "llvm": "tid.x",
+            "ret": "S32",
+            "args": []
+        },
+        {
+            "intrinsic": "thread_idx_y",
+            "width": ["0"],
+            "llvm": "tid.y",
+            "ret": "S32",
+            "args": []
+        },
+        {
+            "intrinsic": "thread_idx_z",
+            "width": ["0"],
+            "llvm": "tid.z",
+            "ret": "S32",
+            "args": []
+        }
+    ]
+}
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index e681a81cf0c..2ee4cc49435 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -96,7 +96,7 @@ fn main() {
 
     let optional_components =
         ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430",
-         "sparc"];
+         "sparc", "nvptx"];
 
     // FIXME: surely we don't need all these components, right? Stuff like mcjit
     //        or interpreter the compiler itself never uses.
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index f3dbac7ce68..334a1dbdec1 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -42,6 +42,7 @@ pub enum CallConv {
     X86StdcallCallConv = 64,
     X86FastcallCallConv = 65,
     ArmAapcsCallConv = 67,
+    PtxKernel = 71,
     X86_64_SysV = 78,
     X86_64_Win64 = 79,
     X86_VectorCall = 80,
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 69709f72b8b..679e9c17a8b 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -377,6 +377,11 @@ pub fn initialize_available_targets() {
                  LLVMInitializeSparcTargetMC,
                  LLVMInitializeSparcAsmPrinter,
                  LLVMInitializeSparcAsmParser);
+    init_target!(llvm_component = "nvptx",
+                 LLVMInitializeNVPTXTargetInfo,
+                 LLVMInitializeNVPTXTarget,
+                 LLVMInitializeNVPTXTargetMC,
+                 LLVMInitializeNVPTXAsmPrinter);
 }
 
 pub fn last_error() -> Option<String> {
diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs
index 6fe1f0c2b9c..e814050e960 100644
--- a/src/librustc_platform_intrinsics/lib.rs
+++ b/src/librustc_platform_intrinsics/lib.rs
@@ -95,6 +95,7 @@ static VOID: Type = Type::Void;
 mod x86;
 mod arm;
 mod aarch64;
+mod nvptx;
 
 impl Intrinsic {
     pub fn find(name: &str) -> Option<Intrinsic> {
@@ -104,6 +105,8 @@ impl Intrinsic {
             arm::find(name)
         } else if name.starts_with("aarch64_") {
             aarch64::find(name)
+        } else if name.starts_with("nvptx_") {
+            nvptx::find(name)
         } else {
             None
         }
diff --git a/src/librustc_platform_intrinsics/nvptx.rs b/src/librustc_platform_intrinsics/nvptx.rs
new file mode 100644
index 00000000000..82408723ebe
--- /dev/null
+++ b/src/librustc_platform_intrinsics/nvptx.rs
@@ -0,0 +1,92 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// DO NOT EDIT: autogenerated by etc/platform-intrinsics/generator.py
+// ignore-tidy-linelength
+
+#![allow(unused_imports)]
+
+use {Intrinsic, Type};
+use IntrinsicDef::Named;
+
+// The default inlining settings trigger a pathological behaviour in
+// LLVM, which causes makes compilation very slow. See #28273.
+#[inline(never)]
+pub fn find(name: &str) -> Option<Intrinsic> {
+    if !name.starts_with("nvptx") { return None }
+    Some(match &name["nvptx".len()..] {
+        "_syncthreads" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::VOID,
+            definition: Named("llvm.cuda.syncthreads")
+        },
+        "_block_dim_x" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::I32,
+            definition: Named("llvm.nvvm.read.ptx.sreg.ntid.x")
+        },
+        "_block_dim_y" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::I32,
+            definition: Named("llvm.nvvm.read.ptx.sreg.ntid.y")
+        },
+        "_block_dim_z" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::I32,
+            definition: Named("llvm.nvvm.read.ptx.sreg.ntid.z")
+        },
+        "_block_idx_x" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::I32,
+            definition: Named("llvm.nvvm.read.ptx.sreg.ctaid.x")
+        },
+        "_block_idx_y" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::I32,
+            definition: Named("llvm.nvvm.read.ptx.sreg.ctaid.y")
+        },
+        "_block_idx_z" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::I32,
+            definition: Named("llvm.nvvm.read.ptx.sreg.ctaid.z")
+        },
+        "_grid_dim_x" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::I32,
+            definition: Named("llvm.nvvm.read.ptx.sreg.nctaid.x")
+        },
+        "_grid_dim_y" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::I32,
+            definition: Named("llvm.nvvm.read.ptx.sreg.nctaid.y")
+        },
+        "_grid_dim_z" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::I32,
+            definition: Named("llvm.nvvm.read.ptx.sreg.nctaid.z")
+        },
+        "_thread_idx_x" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::I32,
+            definition: Named("llvm.nvvm.read.ptx.sreg.tid.x")
+        },
+        "_thread_idx_y" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::I32,
+            definition: Named("llvm.nvvm.read.ptx.sreg.tid.y")
+        },
+        "_thread_idx_z" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+            output: &::I32,
+            definition: Named("llvm.nvvm.read.ptx.sreg.tid.z")
+        },
+        _ => return None,
+    })
+}
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 9c4246e079b..81e4b4d1f21 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -25,6 +25,8 @@ use cabi_mips64;
 use cabi_asmjs;
 use cabi_msp430;
 use cabi_sparc;
+use cabi_nvptx;
+use cabi_nvptx64;
 use machine::{llalign_of_min, llsize_of, llsize_of_alloc};
 use type_::Type;
 use type_of;
@@ -353,6 +355,7 @@ impl FnType {
             Win64 => llvm::X86_64_Win64,
             SysV64 => llvm::X86_64_SysV,
             Aapcs => llvm::ArmAapcsCallConv,
+            PtxKernel => llvm::PtxKernel,
 
             // These API constants ought to be more specific...
             Cdecl => llvm::CCallConv,
@@ -608,6 +611,8 @@ impl FnType {
             "wasm32" => cabi_asmjs::compute_abi_info(ccx, self),
             "msp430" => cabi_msp430::compute_abi_info(ccx, self),
             "sparc" => cabi_sparc::compute_abi_info(ccx, self),
+            "nvptx" => cabi_nvptx::compute_abi_info(ccx, self),
+            "nvptx64" => cabi_nvptx64::compute_abi_info(ccx, self),
             a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
         }
 
diff --git a/src/librustc_trans/cabi_nvptx.rs b/src/librustc_trans/cabi_nvptx.rs
new file mode 100644
index 00000000000..5ece19f764a
--- /dev/null
+++ b/src/librustc_trans/cabi_nvptx.rs
@@ -0,0 +1,53 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Reference: PTX Writer's Guide to Interoperability
+// http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
+
+#![allow(non_upper_case_globals)]
+
+use llvm::Struct;
+
+use abi::{self, ArgType, FnType};
+use context::CrateContext;
+use type_::Type;
+
+fn ty_size(ty: Type) -> usize {
+    abi::ty_size(ty, 4)
+}
+
+fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+    if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 {
+        ret.make_indirect(ccx);
+    } else {
+        ret.extend_integer_width_to(32);
+    }
+}
+
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
+    if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 {
+        arg.make_indirect(ccx);
+    } else {
+        arg.extend_integer_width_to(32);
+    }
+}
+
+pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(ccx, &mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg_ty(ccx, arg);
+    }
+}
diff --git a/src/librustc_trans/cabi_nvptx64.rs b/src/librustc_trans/cabi_nvptx64.rs
new file mode 100644
index 00000000000..880c6cfd7a8
--- /dev/null
+++ b/src/librustc_trans/cabi_nvptx64.rs
@@ -0,0 +1,53 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Reference: PTX Writer's Guide to Interoperability
+// http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
+
+#![allow(non_upper_case_globals)]
+
+use llvm::Struct;
+
+use abi::{self, ArgType, FnType};
+use context::CrateContext;
+use type_::Type;
+
+fn ty_size(ty: Type) -> usize {
+    abi::ty_size(ty, 8)
+}
+
+fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+    if ret.ty.kind() == Struct && ty_size(ret.ty) > 64 {
+        ret.make_indirect(ccx);
+    } else {
+        ret.extend_integer_width_to(64);
+    }
+}
+
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
+    if arg.ty.kind() == Struct && ty_size(arg.ty) > 64 {
+        arg.make_indirect(ccx);
+    } else {
+        arg.extend_integer_width_to(64);
+    }
+}
+
+pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(ccx, &mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg_ty(ccx, arg);
+    }
+}
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 3a8eef131a2..0d3e1853f01 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -103,6 +103,8 @@ mod cabi_asmjs;
 mod cabi_mips;
 mod cabi_mips64;
 mod cabi_msp430;
+mod cabi_nvptx;
+mod cabi_nvptx64;
 mod cabi_powerpc;
 mod cabi_powerpc64;
 mod cabi_s390x;
diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs
index a39cac8db99..0cc62fb43a5 100644
--- a/src/libsyntax/abi.rs
+++ b/src/libsyntax/abi.rs
@@ -41,6 +41,7 @@ pub enum Abi {
     Aapcs,
     Win64,
     SysV64,
+    PtxKernel,
 
     // Multiplatform / generic ABIs
     Rust,
@@ -82,6 +83,7 @@ const AbiDatas: &'static [AbiData] = &[
     AbiData {abi: Abi::Aapcs, name: "aapcs", generic: false },
     AbiData {abi: Abi::Win64, name: "win64", generic: false },
     AbiData {abi: Abi::SysV64, name: "sysv64", generic: false },
+    AbiData {abi: Abi::PtxKernel, name: "ptx-kernel", generic: false },
 
     // Cross-platform ABIs
     AbiData {abi: Abi::Rust, name: "Rust", generic: true },
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index e04cc11f15e..625af803458 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -318,6 +318,9 @@ declare_features! (
 
     // Allow safe suggestions for potential type conversions.
     (active, safe_suggestion, "1.0.0", Some(37384)),
+
+    // `extern "ptx-*" fn()`
+    (active, abi_ptx, "1.15.0", None),
 );
 
 declare_features! (
@@ -986,7 +989,19 @@ impl<'a> PostExpansionVisitor<'a> {
                 gate_feature_post!(&self, abi_sysv64, span,
                                    "sysv64 ABI is experimental and subject to change");
             },
-            _ => {}
+            Abi::PtxKernel => {
+                gate_feature_post!(&self, abi_ptx, span,
+                                   "PTX ABIs are experimental and subject to change");
+            }
+            // Stable
+            Abi::Cdecl |
+            Abi::Stdcall |
+            Abi::Fastcall |
+            Abi::Aapcs |
+            Abi::Win64 |
+            Abi::Rust |
+            Abi::C |
+            Abi::System => {}
         }
     }
 }