| Artem Belevich | cb8f632 | 2017-10-24 20:31:44 +0000 | [diff] [blame] | 1 | # This test generates all variants of load/store instructions and verifies that |
| 2 | # LLVM generates correct PTX for them. |
| 3 | |
| 4 | # RUN: python %s > %t.ll |
| 5 | # RUN: llc < %t.ll -march=nvptx64 -mcpu=sm_30 | FileCheck -check-prefixes=CHECK,CHECK_P64 %t.ll |
| 6 | # RUN: llc < %t.ll -march=nvptx -mcpu=sm_30 | FileCheck -check-prefixes=CHECK,CHECK_P32 %t.ll |
| 7 | |
| Serge Guelton | 4a27478 | 2019-01-03 14:11:33 +0000 | [diff] [blame] | 8 | from __future__ import print_function |
| 9 | |
| Artem Belevich | cb8f632 | 2017-10-24 20:31:44 +0000 | [diff] [blame] | 10 | from itertools import product |
| 11 | from string import Template |
| 12 | |
| 13 | llvm_type_to_ptx_type = { |
| 14 | "i8": "u8", |
| 15 | "i16": "u16", |
| 16 | "i32": "u32", |
| 17 | "i64": "u64", |
| 18 | "half": "b16", |
| 19 | "<2 x half>": "b32", |
| 20 | "float": "f32", |
| 21 | "double": "f64" |
| 22 | } |
| 23 | |
| 24 | llvm_type_to_ptx_reg = { |
| 25 | "i8": "r", |
| 26 | "i16": "r", |
| 27 | "i32": "r", |
| 28 | "i64": "rd", |
| 29 | "half": "h", |
| 30 | "<2 x half>": "hh", |
| 31 | "float": "f", |
| 32 | "double": "fd" |
| 33 | } |
| 34 | |
| 35 | addrspace_id = { |
| 36 | "": 0, |
| 37 | ".global": 1, |
| 38 | ".shared": 3, |
| 39 | ".const": 4, |
| 40 | ".local": 5, |
| 41 | ".param": 101 |
| 42 | } |
| 43 | |
| 44 | |
| 45 | def gen_load_tests(): |
| 46 | load_template = """ |
| 47 | define ${type} @ld${_volatile}${_space}.${ptx_type}(${type} addrspace(${asid})* %ptr) { |
| 48 | ; CHECK_P32: ld${_volatile}${_volatile_as}.${ptx_type} %${ptx_reg}{{[0-9]+}}, [%r{{[0-9]+}}] |
| 49 | ; CHECK_P64: ld${_volatile}${_volatile_as}.${ptx_type} %${ptx_reg}{{[0-9]+}}, [%rd{{[0-9]+}}] |
| 50 | ; CHECK: ret |
| 51 | %p = ${generic_ptr} |
| 52 | %a = load ${volatile} ${type}, ${type}* %p |
| 53 | ret ${type} %a |
| 54 | } |
| 55 | """ |
| 56 | for op_type, volatile, space in product( |
| 57 | ["i8", "i16", "i32", "i64", "half", "float", "double", "<2 x half>"], |
| 58 | [True, False], # volatile |
| 59 | ["", ".shared", ".global", ".const", ".local", ".param"]): |
| 60 | |
| 61 | # Volatile is only supported for global, shared and generic. |
| 62 | if volatile and not space in ["", ".global", ".shared"]: |
| 63 | continue |
| 64 | |
| 65 | # Volatile is only supported for global, shared and generic. |
| 66 | # All other volatile accesses are done in generic AS. |
| 67 | if volatile and not space in ["", ".global", ".shared"]: |
| 68 | volatile_as = "" |
| 69 | else: |
| 70 | volatile_as = space |
| 71 | |
| 72 | params = { |
| 73 | "type": op_type, |
| 74 | "volatile": "volatile" if volatile else "", |
| 75 | "_volatile": ".volatile" if volatile else "", |
| 76 | "_volatile_as": volatile_as, |
| 77 | "_space": space, |
| 78 | "ptx_reg": llvm_type_to_ptx_reg[op_type], |
| 79 | "ptx_type": llvm_type_to_ptx_type[op_type], |
| 80 | "asid": addrspace_id[space], |
| 81 | } |
| 82 | |
| 83 | # LLVM does not accept "addrspacecast Type* addrspace(0) to Type*", so we |
| 84 | # need to avoid it for generic pointer tests. |
| 85 | if space: |
| 86 | generic_ptr_template = ("addrspacecast ${type} addrspace(${asid})* %ptr " |
| 87 | "to ${type}*") |
| 88 | else: |
| 89 | generic_ptr_template = "select i1 true, ${type}* %ptr, ${type}* %ptr" |
| 90 | params["generic_ptr"] = Template(generic_ptr_template).substitute(params) |
| 91 | |
| 92 | print(Template(load_template).substitute(params)) |
| 93 | |
| 94 | |
| 95 | def main(): |
| 96 | gen_load_tests() |
| 97 | |
| 98 | |
| 99 | main() |