User-defined Migration Rules

Intel® DPC++ Compatibility Tool uses migration rules to migrate CUDA* code to SYCL* code. There are three categories of migration rules used by the tool:

  • Default migration rules. A set of built-in migration rules used by the Intel® DPC++ Compatibility Tool for all migrations.

  • Optional predefined migration rules. A set of predefined migration rules that can optionally be used for migration. Available predefined migration rules are in the extensions/opt_rules folder on the installation path of the Intel® DPC++ Compatibility Tool.

  • User-defined migration rules. Custom migration rules defined by the user. User-defined migration rules extend the migration capability of the Intel® DPC++ Compatibility Tool and can target the migration of specific CUDA syntax to SYCL syntax.

Specify Migration Rule Files

To specify a predefined or user-defined migration rule file for use in migration, use the –rule-file command line option with your migration command.

The –rule-file option can be used multiple times with a single command to specify multiple migration rule files. For example:

dpct sample.cu --rule-file=rule_file1.YAML --rule-file=rule_file2.YAML

See the Command Line Options Reference for additional information.

Write User-defined Migration Rules

Migration rules are specified in YAML files. To define a rule, use the following <key>: <value> pairs:

Key

Value

Description

Rule

String value

Required. Specifies the unique name of the rule.

Priority

Takeover | Default | Fallback

Required. Specifies the priority of the rule: Takeover > Default > Fallback. When there are rule conflicts, the rule with higher priority will take precedence.

Kind

Macro | API

Required. Specifies the rule type:

  • A Macro type rule is used to migrate macros.

  • An API type rule is used to migrate function calls.

In

String value

Specifies the target macro or function name in the input source code.

Out

String value

Required. Specifies the target macro or function call format in the output source code.

Includes

List of header files

Required. Specifies the header files which should be included in the output source code. The value can be an empty list.

A single rule file may contain multiple migration rules.

For example, the following user-defined migration rule file defines two rules:

---                                                    # [YAML syntax] Begin the document
- Rule: rule_forceinline                               # [Required] Unique rule name
  Kind: Macro                                          # [Required] Type of rule [Macro | API]
  Priority: Takeover                                   # [Required] Rule priority  [Takeover | Default | Fallback]
  In: __forceinline__                                  # [Required] Target macro name in the input source code
  Out: inline                                          # [Required] Migrated name of the macro in output source code
  Includes: ["header1.h", "\"header2.h\""]             # [Required] List of header file names which the new macro depends on, can be an empty list
- Rule: rule_foo                                       # [YAML syntax] "-" Denotes the start of another rule
  Kind: API
  Priority: Takeover
  In: foo                                              # [Required] Target function name in the input source code
  Out: $type_name_of($2) *new_ptr = bar($deref($1))    # [Required] Format form of migrated result in output source code
  Includes: ["<header3>"]
...                                                    # [YAML syntax] End the document
  • The first rule migrates __forceinline__ in the input source code to inline in the output source code.

  • The second rule migrates any function call foo(…) in the input source code to a function called bar(…) in output source code.

Grammar for Out Key in a User-defined API Migration Rule

To describe the value format for the Out key in a migration rule of Kind: API, use the following Backus-Naur form grammar:

OutValue::= Token | Token OutValue       # OutValue is the value for the “out” key
Token::= AnyString | Keyword             # AnyString is a string provided by the user
Keyword::= ArgIndex
   | $queue                              # Represents the queue string
   | $context                            # Represents the context string
   | $device                             # Represents the device string
   | $deref(ArgIndex)                    # The dereferenced value of the argument
   | $type_name_of(ArgIndex)             # The type name of the argument
   | $deref_type(ArgIndex)               # The dereferenced type name of the argument
   | $addr_of(ArgIndex)                  # The address of the argument
ArgIndex::= $Int                         # Int should be a greater than zero integer

The following scenario describes how the tool makes use of a user-defined migration rule that uses this grammar to migrate code.

Consider the following user-defined API migration rule:

- Rule: rule_foo
  Kind: API
  Priority: Takeover
  In: foo
  Out: $type_name_of($2) new_ptr = bar($deref($1), $3)
  Includes: [“<header3>”]

If the input source code contains a function call that matches the rule, the tool parses the value of the In and Out keys and builds a keyword mapping between the input and output source code. For example, with input source code:

int *ptr, *ptr2;
foo(ptr, ptr2, 30);

The tool creates the following mapping:

Keyword

Input Source Code Match

Migration Result

$1

Ptr

ptr

$2

ptr2

ptr2

$3

30

30

$type_name_of($2)

N/A

int*

$deref($1)

N/A

*ptr

Using this mapping, the tool migrates the input source code into the following output source code:

int *ptr, *ptr2;
int * new_ptr = bar(*ptr, 30);