mirror of
https://github.com/elwrcl/intel-hard-graphics.git
synced 2026-11-01 03:18:02 +03:00
init
This commit is contained in:
12511 files changed
+6156641
No files matched your search
@@ -0,0 +1,43 @@
|
||||
-- BFI seems available on Gfx9, need to fix the emission code for that.
|
||||
if devinfo.verx10 < 110 then
|
||||
error("BFI instruction requires Gfx11+")
|
||||
end
|
||||
|
||||
function BFI_simulation(a, b, c, d)
|
||||
local width = a & 0x1F
|
||||
local offset = b & 0x1F
|
||||
local mask = ((1 << width) - 1) << offset
|
||||
return ((c << offset) & mask) | (d & ~mask)
|
||||
end
|
||||
|
||||
function BFI(a, b, c, d)
|
||||
local r = execute {
|
||||
data = { [0] = a, b, c, d },
|
||||
src = [[
|
||||
@id r9
|
||||
@mov r11 0
|
||||
@mov r12 1
|
||||
@mov r13 2
|
||||
@mov r14 3
|
||||
|
||||
@read r1 r11
|
||||
@read r2 r12
|
||||
@read r3 r13
|
||||
@read r4 r14
|
||||
|
||||
bfi1 (8) r5 r1 r2 {A@1}
|
||||
bfi2 (8) r6 r5 r3 r4 {A@1}
|
||||
|
||||
@write r9 r6
|
||||
@eot
|
||||
]],
|
||||
}
|
||||
return r[0]
|
||||
end
|
||||
|
||||
function Hex(v) return string.format("0x%08x", v) end
|
||||
|
||||
local a, b, c, d = 12, 12, 0xAAAAAAAA, 0xBBBBBBBB
|
||||
|
||||
print("calculated", Hex(BFI(a, b, c, d)))
|
||||
print("expected", Hex(BFI_simulation(a, b, c, d)))
|
||||
@@ -0,0 +1,62 @@
|
||||
if not devinfo.has_bfloat16 then
|
||||
error("BF16 not supported in this platform.")
|
||||
end
|
||||
|
||||
local r = execute {
|
||||
src=[[
|
||||
@id r3
|
||||
|
||||
mov (8) r4:f r3 {A@1}
|
||||
mov (8) r5:f r4.1<0>:f {A@1}
|
||||
|
||||
// Converting F to unpacked BF works, but as will be
|
||||
// illustrated, is not very useful.
|
||||
|
||||
mov (8) r10<2>:bf r4:f {A@1}
|
||||
|
||||
// With exception of DPAS, instructions need to have at
|
||||
// least one non-BF operand and the operands must be packed.
|
||||
|
||||
mov (8) r11:uw r10<2>:uw {A@1} // Pack it!
|
||||
add (8) r12:bf r11:bf r4:f {A@1}
|
||||
|
||||
// Converting F to packed BF doesn't work, so add the value
|
||||
// to -0.0f instead. This will preserve the NaN. Note +0.0f
|
||||
// would not work since it doesn't preserve -0.0f!
|
||||
|
||||
mov (8) r20 0x80000000 {A@1} // -0.0f.
|
||||
add (8) r21:bf r4:f r20:f {A@1} // F -> BF.
|
||||
|
||||
// Converting BF to F doesn't work, so for a packed source,
|
||||
// shift-left the bits to expand it into an UD instead.
|
||||
|
||||
shl (8) r30 r21:uw 16:uw {A@1} // BF -> F.
|
||||
|
||||
mad (8) r40:bf r12:bf r21:bf r5:f {A@1}
|
||||
add (8) r41:bf r40:bf r30:f {A@1}
|
||||
|
||||
shl (8) r42 r41:uw 16:uw {A@1} // BF -> F.
|
||||
|
||||
mov (8) r43 r42:f {A@1}
|
||||
@write r3 r43
|
||||
|
||||
@eot
|
||||
]]
|
||||
}
|
||||
|
||||
expected = {[0] = 0, 4, 8, 12, 16, 20, 24, 28}
|
||||
|
||||
print("result")
|
||||
dump(r, 8)
|
||||
|
||||
print("expected")
|
||||
dump(expected, 8)
|
||||
|
||||
for i=0,7 do
|
||||
if r[i] ~= expected[i] then
|
||||
print("FAIL")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
print("OK")
|
||||
@@ -0,0 +1,43 @@
|
||||
--[[
|
||||
|
||||
Execute the example from the Dot Product 4 Accumulate
|
||||
instruction as seen in the PRM.
|
||||
|
||||
mov (1) r1.0:d 0x0102037F:d
|
||||
// (char4)(0x1,0x2,0x3,0x7F)
|
||||
mov (1) r2.0:d 50:d
|
||||
dp4a (1) r3.0:d r2:d r1:d r1:d
|
||||
// r3.0 = 50 + (0x1*0x1 + 0x2*0x2 + 0x3*0x3 + 0x7F*0x7F)
|
||||
// = 50 + (1 + 4 + 9 + 16129)
|
||||
// = 16193
|
||||
|
||||
--]]
|
||||
|
||||
if devinfo.ver < 12 then
|
||||
error("DP4A instruction requires Gfx12+")
|
||||
end
|
||||
|
||||
function DP4A(a, b, c)
|
||||
local r = c
|
||||
for i = 1, 4 do
|
||||
r = r + a[i] * b[i]
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
local r = execute {
|
||||
src = [[
|
||||
@id r9
|
||||
|
||||
@mov r1 0x0102037F
|
||||
@mov r2 50
|
||||
|
||||
dp4a (8) r3 r2 r1 r1 {A@1}
|
||||
|
||||
@write r9 r3
|
||||
@eot
|
||||
]],
|
||||
}
|
||||
|
||||
print("expected", DP4A({1,2,3,0x7F}, {1,2,3,0x7F}, 50))
|
||||
print("calculated", r[0])
|
||||
@@ -0,0 +1,67 @@
|
||||
if not devinfo.has_dpas then
|
||||
error("DPAS not supported in this platform.")
|
||||
end
|
||||
|
||||
if not devinfo.has_bfloat16 then
|
||||
error("BF16 not supported in this platform.")
|
||||
end
|
||||
|
||||
local gen = require("mod/gen")
|
||||
local matrix = require("mod/matrix")
|
||||
|
||||
-- Similar to the constants used for VK_KHR_cooperative_matrix.
|
||||
local M = 8
|
||||
local N = devinfo.ver >= 20 and 16 or 8
|
||||
local K = 16
|
||||
|
||||
local one_bf = 0x3f80
|
||||
|
||||
local A = matrix.new(M, K, one_bf)
|
||||
local B = matrix.new_diag(K, N, one_bf)
|
||||
local C = matrix.new(M, N, 0)
|
||||
|
||||
-- Note: when tinkering with values, use set() method to set
|
||||
-- values, e.g.
|
||||
--
|
||||
-- A:set(0, 2, 0x4000)
|
||||
|
||||
-- Calculate A * B + C. A and B are BF values, C and the result
|
||||
-- are F values.
|
||||
local buf = execute {
|
||||
src =
|
||||
[[]]
|
||||
.. gen.mov_grf("bf", 10, A:to_row_major())
|
||||
|
||||
-- For `src1`, the source representing the B matrix, DPAS expects
|
||||
-- the values to be in a layout that looks like an "interleaved"
|
||||
-- row major. Elements from `packing_factor` rows are packed
|
||||
-- together.
|
||||
--
|
||||
-- See mod/matrix.lua for details on that format.
|
||||
--
|
||||
.. gen.mov_grf("bf", 20, B:to_interleaved_row_major(2))
|
||||
|
||||
.. gen.mov_grf("f", 30, C:to_row_major())
|
||||
|
||||
.. (devinfo.ver >= 20 and [[
|
||||
|
||||
dpas.8x8 (16) r40:f r30:f r20:bf r10:bf {A@1,$1}
|
||||
@syncnop
|
||||
|
||||
]] or [[
|
||||
|
||||
dpas.8x8 (8) r40:f r30:f r20:bf r10:bf {A@1,$1}
|
||||
@syncnop
|
||||
|
||||
]])
|
||||
|
||||
.. gen.write_grfs(40, 8)
|
||||
.. [[
|
||||
|
||||
@eot
|
||||
|
||||
]],
|
||||
}
|
||||
|
||||
local r = matrix.from_row_major_buffer(M, N, buf)
|
||||
r:print("0x%08x")
|
||||
@@ -0,0 +1,63 @@
|
||||
if not devinfo.has_dpas then
|
||||
error("DPAS not supported in this platform.")
|
||||
end
|
||||
|
||||
local gen = require("mod/gen")
|
||||
local matrix = require("mod/matrix")
|
||||
|
||||
-- Similar to the constants used for VK_KHR_cooperative_matrix.
|
||||
local M = 8
|
||||
local N = devinfo.ver >= 20 and 16 or 8
|
||||
local K = 16
|
||||
|
||||
local one_hf = 0x3c00
|
||||
|
||||
local A = matrix.new(M, K, one_hf)
|
||||
local B = matrix.new_diag(K, N, one_hf)
|
||||
local C = matrix.new(M, N, 0)
|
||||
|
||||
-- Note: when tinkering with values, use set() method to set
|
||||
-- values, e.g.
|
||||
--
|
||||
-- A:set(0, 2, 0x4000)
|
||||
|
||||
-- Calculate A * B + C. A and B are HF values, C and the result
|
||||
-- are F values.
|
||||
local buf = execute {
|
||||
src =
|
||||
[[]]
|
||||
.. gen.mov_grf("hf", 10, A:to_row_major())
|
||||
|
||||
-- For `src1`, the source representing the B matrix, DPAS expects
|
||||
-- the values to be in a layout that looks like an "interleaved"
|
||||
-- row major. Elements from `packing_factor` rows are packed
|
||||
-- together.
|
||||
--
|
||||
-- See mod/matrix.lua for details on that format.
|
||||
--
|
||||
.. gen.mov_grf("hf", 20, B:to_interleaved_row_major(2))
|
||||
|
||||
.. gen.mov_grf("f", 30, C:to_row_major())
|
||||
|
||||
.. (devinfo.ver >= 20 and [[
|
||||
|
||||
dpas.8x8 (16) r40:f r30:f r20:hf r10:hf {A@1,$1}
|
||||
@syncnop
|
||||
|
||||
]] or [[
|
||||
|
||||
dpas.8x8 (8) r40:f r30:f r20:hf r10:hf {A@1,$1}
|
||||
@syncnop
|
||||
|
||||
]])
|
||||
|
||||
.. gen.write_grfs(40, 8)
|
||||
.. [[
|
||||
|
||||
@eot
|
||||
|
||||
]],
|
||||
}
|
||||
|
||||
local r = matrix.from_row_major_buffer(M, N, buf)
|
||||
r:print("0x%08x")
|
||||
@@ -0,0 +1,61 @@
|
||||
if not devinfo.has_dpas then
|
||||
error("DPAS not supported in this platform.")
|
||||
end
|
||||
|
||||
local gen = require("mod/gen")
|
||||
local matrix = require("mod/matrix")
|
||||
|
||||
-- Similar to the constants used for VK_KHR_cooperative_matrix.
|
||||
local M = 8
|
||||
local N = devinfo.ver >= 20 and 16 or 8
|
||||
local K = 32
|
||||
|
||||
local A = matrix.new(M, K, 1)
|
||||
local B = matrix.new_diag(K, N, 1)
|
||||
local C = matrix.new(M, N, 0)
|
||||
|
||||
-- Note: when tinkering with values, use set() method to set
|
||||
-- values, e.g.
|
||||
--
|
||||
-- A:set(0, 2, 0x2)
|
||||
|
||||
-- Calculate A * B + C. A and B are UB values, C and the result
|
||||
-- are UD values.
|
||||
local buf = execute {
|
||||
src =
|
||||
[[]]
|
||||
.. gen.mov_grf("ub", 10, A:to_row_major())
|
||||
|
||||
-- For `src1`, the source representing the B matrix, DPAS expects
|
||||
-- the values to be in a layout that looks like an "interleaved"
|
||||
-- row major. Elements from `packing_factor` rows are packed
|
||||
-- together.
|
||||
--
|
||||
-- See mod/matrix.lua for details on that format.
|
||||
--
|
||||
.. gen.mov_grf("ub", 20, B:to_interleaved_row_major(4))
|
||||
|
||||
.. gen.mov_grf("ud", 30, C:to_row_major())
|
||||
|
||||
.. (devinfo.ver >= 20 and [[
|
||||
|
||||
dpas.8x8 (16) r40:ud r30:ud r20:ub r10:ub {A@1,$1}
|
||||
@syncnop
|
||||
|
||||
]] or [[
|
||||
|
||||
dpas.8x8 (8) r40:ud r30:ud r20:ub r10:ub {A@1,$1}
|
||||
@syncnop
|
||||
|
||||
]])
|
||||
|
||||
.. gen.write_grfs(40, 8)
|
||||
.. [[
|
||||
|
||||
@eot
|
||||
|
||||
]],
|
||||
}
|
||||
|
||||
r = matrix.from_row_major_buffer(M, N, buf)
|
||||
r:print()
|
||||
@@ -0,0 +1,73 @@
|
||||
-- Xe3 adds a new ARF to store scalar values. It supports only a limited
|
||||
-- set of operations.
|
||||
|
||||
if devinfo.ver < 30 then
|
||||
error("Scalar register requires Gfx30+")
|
||||
end
|
||||
|
||||
local r = execute {
|
||||
src=[[
|
||||
// The new scalar register s0 has 32 bytes.
|
||||
//
|
||||
// Only MOV can have scalar as destination. Offsets in scalar
|
||||
// must be aligned to word boundary. This non-overlapping MOVs
|
||||
// will fill the first 16 bytes.
|
||||
|
||||
mov (1) s0.0:uw 0x1111:uw
|
||||
|
||||
mov (1) r2:uw 0x2222:uw
|
||||
mov (1) s0.2:uw r2<0>:uw {I@1}
|
||||
|
||||
mov (1) s0.4:ud 0x33333333:ud {I@1}
|
||||
|
||||
mov (4) r4:uw 0x4444:uw
|
||||
mov (1) s0.8:uq r4<0>:uq {I@1}
|
||||
|
||||
|
||||
// Scalar content can be broadcasted back into GRFs.
|
||||
|
||||
// Scalar subregister numbers are byte offsets in gen syntax.
|
||||
mov (16) r20:ud s0.0<0>:ud
|
||||
mov (16) r32:ud s0.4<0>:ud
|
||||
mov (16) r96:ud s0.8<0>:ud
|
||||
mov (16) r64:ud s0.12<0>:ud
|
||||
|
||||
|
||||
// Scalar can store a list of register numbers to be used as source for
|
||||
// SEND. Note the scalar will contain the hex value for r11 and r20.
|
||||
// And the scalar register is indexed as bytes in the send source.
|
||||
|
||||
mov (16) r11:ud 0x30000000:ud
|
||||
mov (1) s0.16:ud 0x0000140b:ud {I@1}
|
||||
|
||||
send.ugm (16) null r[s0.16] null:0 0x00000000 0x04000504 {I@1,$1}
|
||||
|
||||
|
||||
// A larger SEND, note that registers for the payload don't need to be
|
||||
// contiguous, the hardware will gather them together.
|
||||
|
||||
add (16) r11:ud r11:ud 0x4:ud {A@1,$1.src}
|
||||
mov (1) s0.16:ud 0x4060200b:ud
|
||||
|
||||
send.ugm (16) null r[s0.16] null:0 0x00000000 0x08002504 {I@1,$1}
|
||||
|
||||
@eot
|
||||
]]
|
||||
}
|
||||
|
||||
expected = {[0] = 0x22221111, 0x33333333, 0x44444444, 0x44444444}
|
||||
|
||||
print("result")
|
||||
dump(r, 4)
|
||||
|
||||
print("expected")
|
||||
dump(expected, 4)
|
||||
|
||||
for i=0,3 do
|
||||
if r[i] ~= expected[i] then
|
||||
print("FAIL")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
print("OK")
|
||||
@@ -0,0 +1,18 @@
|
||||
-- Example from the help message.
|
||||
|
||||
local r = execute {
|
||||
data={ [42] = 0x100 },
|
||||
src=[[
|
||||
@mov r1 42
|
||||
@read r2 r1
|
||||
|
||||
@id r3
|
||||
|
||||
add (8) r4 r2 r3 {A@1}
|
||||
|
||||
@write r3 r4
|
||||
@eot
|
||||
]]
|
||||
}
|
||||
|
||||
dump(r, 4)
|
||||
@@ -0,0 +1,337 @@
|
||||
-- Copyright © 2025 Intel Corporation
|
||||
-- SPDX-License-Identifier: MIT
|
||||
|
||||
local HELP_MESSAGE = [[
|
||||
Matrix Multiplication using DPAS
|
||||
|
||||
Usage: executor matmul.lua FORMAT A_FILE B_FILE [C_FILE]
|
||||
|
||||
Perform matrix multiplication D = A * B + C using DPAS instruction.
|
||||
If C is not provided, will be equivalent to all zeros.
|
||||
|
||||
Input files have values separated by spaces, with the rows
|
||||
separated by newlines. Values are expected to be valid for
|
||||
the format, e.g. if a matrix should contain UB (unsigned byte),
|
||||
values should be between 0-255. Float-pointing data is
|
||||
expected to be in "raw" form as hexadecimal values.
|
||||
|
||||
Matrices smaller than the maximum dimensions will be automatically
|
||||
zero-padded to the required size for DPAS computation.
|
||||
|
||||
Maximum dimensions are limited by data format and hardware version.
|
||||
|
||||
Gfx20+
|
||||
- HF/F: A max 8x16, B max 16x16, C/D max 8x16
|
||||
- BF/F: A max 8x16, B max 16x16, C/D max 8x16
|
||||
- UB/UD: A max 8x32, B max 32x16, C/D max 8x16
|
||||
|
||||
Gfx125
|
||||
- HF/F: A max 8x16, B max 16x8, C/D max 8x8
|
||||
- BF/F: A max 8x16, B max 16x8, C/D max 8x8
|
||||
- UB/UD: A max 8x32, B max 32x8, C/D max 8x8
|
||||
|
||||
If `octave` is installed, it will be used to verify the results.
|
||||
]]
|
||||
|
||||
-- TODO: Change this program to load matrix data from memory
|
||||
-- instead of setting data as immediates in the shader code.
|
||||
|
||||
if not devinfo.has_dpas then
|
||||
print("DPAS not supported on this platform.")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local verify_results = false
|
||||
do
|
||||
local handle = io.popen("which octave 2>/dev/null")
|
||||
local octave_path = handle:read("*a")
|
||||
handle:close()
|
||||
verify_results = octave_path and #octave_path > 0
|
||||
end
|
||||
|
||||
local gen = require("mod/gen")
|
||||
local matrix = require("mod/matrix")
|
||||
local fp = require("mod/fp")
|
||||
|
||||
local format_ab, format_cd, a_file, b_file, c_file
|
||||
|
||||
for i = 1, #arg do
|
||||
if arg[i] == "--help" or arg[i] == "-h" then
|
||||
print(HELP_MESSAGE)
|
||||
os.exit(0)
|
||||
elseif not format_ab then
|
||||
local format = arg[i]:lower()
|
||||
format_ab = format:sub(1, format:find("/") - 1)
|
||||
format_cd = format:sub(format:find("/") + 1)
|
||||
elseif not a_file then a_file = arg[i]
|
||||
elseif not b_file then b_file = arg[i]
|
||||
elseif not c_file then c_file = arg[i]
|
||||
end
|
||||
end
|
||||
|
||||
if not format_ab or not format_cd or not a_file or not b_file then
|
||||
print("Usage: executor matmul.lua FORMAT A_FILE B_FILE [C_FILE]")
|
||||
print("Use --help for more information")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
if not ((format_ab == "hf" and format_cd == "f") or
|
||||
(format_ab == "bf" and format_cd == "f") or
|
||||
(format_ab == "ub" and format_cd == "ud")) then
|
||||
print("Error: format must be 'hf/f', 'bf/f', or 'ub/ud', got '" .. format_ab .. "/" .. format_cd .. "'")
|
||||
print("Use --help for more information")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local function read_matrix(m, filename, max_rows, max_cols)
|
||||
local file = io.open(filename, "r")
|
||||
if not file then
|
||||
error("Failed to open file: " .. filename)
|
||||
end
|
||||
|
||||
-- Read entire file content first
|
||||
local raw_content = file:read("*all")
|
||||
file:close()
|
||||
|
||||
local rows_data = {}
|
||||
local cols = nil
|
||||
|
||||
-- Parse from the raw content string
|
||||
for line in raw_content:gmatch("[^\r\n]+") do
|
||||
local row = {}
|
||||
for val in line:gmatch("%S+") do
|
||||
local num = tonumber(val)
|
||||
if not num then
|
||||
error(string.format(
|
||||
"Error reading matrix from '%s': invalid number in row %d: " .. val,
|
||||
filename, #rows_data + 1))
|
||||
end
|
||||
|
||||
table.insert(row, num)
|
||||
end
|
||||
|
||||
if #row > 0 then
|
||||
if cols == nil then
|
||||
cols = #row
|
||||
elseif #row ~= cols then
|
||||
error(string.format(
|
||||
"Error reading matrix from %s: inconsistent number of columns (%d) in row %d",
|
||||
filename, #row, #rows_data + 1))
|
||||
end
|
||||
table.insert(rows_data, row)
|
||||
end
|
||||
end
|
||||
|
||||
local rows = #rows_data
|
||||
|
||||
if rows > max_rows then
|
||||
error(string.format(
|
||||
"Error reading matrix from %s: too many rows (%d), maximum is %d",
|
||||
filename, rows, max_rows))
|
||||
end
|
||||
|
||||
if cols > max_cols then
|
||||
error(string.format(
|
||||
"Error reading matrix from %s: too many columns (%d), maximum is %d",
|
||||
filename, cols, max_cols))
|
||||
end
|
||||
|
||||
for i = 1, rows do
|
||||
for j = 1, cols do
|
||||
-- Matrix indices are zero indexed.
|
||||
m:set(i-1, j-1, rows_data[i][j])
|
||||
end
|
||||
end
|
||||
|
||||
return rows, cols, raw_content
|
||||
end
|
||||
|
||||
local exec_size = devinfo.ver >= 20 and 16 or 8
|
||||
local packing_factor
|
||||
|
||||
if format_ab == "hf" or format_ab == "bf" then
|
||||
packing_factor = 2
|
||||
elseif format_ab == "ub" then
|
||||
packing_factor = 4
|
||||
end
|
||||
|
||||
local max_a = { rows = 8, cols = packing_factor * 8 }
|
||||
local max_b = { rows = packing_factor * 8, cols = exec_size }
|
||||
local max_c = { rows = 8, cols = exec_size }
|
||||
|
||||
local a = matrix.new(max_a.rows, max_a.cols, 0)
|
||||
local b = matrix.new(max_b.rows, max_b.cols, 0)
|
||||
local c = matrix.new(max_c.rows, max_c.cols, 0)
|
||||
|
||||
local actual_a_rows, actual_a_cols, a_raw_content = read_matrix(a, a_file, max_a.rows, max_a.cols)
|
||||
local actual_b_rows, actual_b_cols, b_raw_content = read_matrix(b, b_file, max_b.rows, max_b.cols)
|
||||
|
||||
if actual_a_cols ~= actual_b_rows then
|
||||
error(string.format(
|
||||
"Matrix dimension mismatch: A is %dx%d, B is %dx%d. A columns (%d) must equal B rows (%d)",
|
||||
actual_a_rows, actual_a_cols, actual_b_rows, actual_b_cols, actual_a_cols, actual_b_rows))
|
||||
end
|
||||
|
||||
local actual_c_rows, actual_c_cols, c_raw_content
|
||||
if c_file then
|
||||
actual_c_rows, actual_c_cols, c_raw_content = read_matrix(c, c_file, max_c.rows, max_c.cols)
|
||||
if actual_a_rows ~= actual_c_rows or actual_b_cols ~= actual_c_cols then
|
||||
error(string.format(
|
||||
"Matrix dimension mismatch: A*B would be %dx%d, but C is %dx%d",
|
||||
actual_a_rows, actual_b_cols, actual_c_rows, actual_c_cols))
|
||||
end
|
||||
else
|
||||
-- C defaults to zeros with dimensions matching A*B result
|
||||
actual_c_rows, actual_c_cols = actual_a_rows, actual_b_cols
|
||||
c_raw_content = nil
|
||||
end
|
||||
|
||||
local exec_size = c.cols
|
||||
|
||||
local encode = function(m, fmt)
|
||||
local f = nil
|
||||
if fmt == "hf" then f = fp.encode_f16
|
||||
elseif fmt == "bf" then f = fp.encode_bf16
|
||||
elseif fmt == "f" then f = fp.encode_f32
|
||||
end
|
||||
|
||||
if f then
|
||||
m:apply(f)
|
||||
end
|
||||
end
|
||||
|
||||
encode(a, format_ab)
|
||||
encode(b, format_ab)
|
||||
encode(c, format_cd)
|
||||
|
||||
local buf = execute {
|
||||
src =
|
||||
[[]]
|
||||
.. gen.mov_grf(format_ab, 10, a:to_row_major())
|
||||
.. gen.mov_grf(format_ab, 20, b:to_interleaved_row_major(packing_factor))
|
||||
.. gen.mov_grf(format_cd, 30, c:to_row_major())
|
||||
.. string.format([[
|
||||
|
||||
dpas.8x8 (%d) r40:%s r30:%s r20:%s r10:%s {A@1,$1}
|
||||
@syncnop
|
||||
|
||||
]], exec_size, format_cd, format_cd, format_ab, format_ab)
|
||||
.. gen.write_grfs(40, 8)
|
||||
.. [[
|
||||
@eot
|
||||
]],
|
||||
}
|
||||
|
||||
local d = matrix.from_row_major_buffer(8, exec_size, buf)
|
||||
|
||||
local d_print_fmt = nil
|
||||
if string.find(format_cd, "f") then
|
||||
d_print_fmt = "%.6f"
|
||||
|
||||
local f = nil
|
||||
if format_cd == "hf" then f = fp.decode_f16
|
||||
elseif format_cd == "bf" then f = fp.decode_bf16
|
||||
elseif format_cd == "f" then f = fp.decode_f32
|
||||
else
|
||||
error("unsupported float format")
|
||||
end
|
||||
|
||||
d:apply(f)
|
||||
end
|
||||
|
||||
-- Just consider the actual rows, same as C matrix.
|
||||
d:print_submatrix(actual_c_rows, actual_c_cols, d_print_fmt)
|
||||
|
||||
--
|
||||
-- VERIFICATION USING OCTAVE.
|
||||
--
|
||||
|
||||
if verify_results then
|
||||
local function save_matrix_to_temp(m, rows, cols)
|
||||
local filename = os.tmpname()
|
||||
local file = io.open(filename, "w")
|
||||
for i = 0, rows - 1 do
|
||||
local row = {}
|
||||
for j = 0, cols - 1 do
|
||||
table.insert(row, tostring(m:get(i, j)))
|
||||
end
|
||||
file:write(table.concat(row, " ") .. "\n")
|
||||
end
|
||||
file:close()
|
||||
return filename
|
||||
end
|
||||
|
||||
local function save_raw_content_to_temp(raw_content)
|
||||
local filename = os.tmpname()
|
||||
local file = io.open(filename, "w")
|
||||
file:write(raw_content)
|
||||
file:close()
|
||||
return filename
|
||||
end
|
||||
|
||||
-- Save A and B raw contents to temp files for Octave
|
||||
local a_for_octave = save_raw_content_to_temp(a_raw_content)
|
||||
local b_for_octave = save_raw_content_to_temp(b_raw_content)
|
||||
local d_for_octave = save_matrix_to_temp(d, actual_c_rows, actual_c_cols)
|
||||
|
||||
local c_load, c_for_octave
|
||||
if c_raw_content then
|
||||
c_for_octave = save_raw_content_to_temp(c_raw_content)
|
||||
c_load = string.format("C = single(dlmread('%s'));", c_for_octave)
|
||||
else
|
||||
c_load = string.format("C = single(zeros(%d, %d));", actual_c_rows, actual_c_cols)
|
||||
end
|
||||
|
||||
local tolerance = (format_cd == "f") and "1e-3" or "1e-6"
|
||||
|
||||
-- TODO: Currently values are rounded to what fits in F (32-bit), but for
|
||||
-- better results we should have a way to round them to precision based on
|
||||
-- format, and handle HF and BF16. Octave doesn't support those types
|
||||
-- natively. See https://github.com/higham/chop for Matlab version of this.
|
||||
|
||||
local octave_script = string.format([[
|
||||
A = single(dlmread('%s'));
|
||||
B = single(dlmread('%s'));
|
||||
%s
|
||||
D = single(dlmread('%s'));
|
||||
|
||||
D_expected = A * B + C;
|
||||
|
||||
%% Use relative tolerance for better comparison across different magnitudes.
|
||||
max_val = max(abs(D_expected(:)));
|
||||
tol = max_val * %s;
|
||||
|
||||
if all(all(abs(D_expected - D) < tol))
|
||||
exit(0);
|
||||
else
|
||||
disp('MISMATCH!');
|
||||
disp('Octave result:');
|
||||
disp(D_expected);
|
||||
disp('DPAS result:');
|
||||
disp(D);
|
||||
exit(1);
|
||||
endif
|
||||
]], a_for_octave, b_for_octave, c_load, d_for_octave, tolerance)
|
||||
|
||||
local exit_code = os.execute(
|
||||
[[octave --quiet --no-gui --eval "]]
|
||||
.. octave_script ..
|
||||
[[" 2>&1]])
|
||||
|
||||
-- Clean up temporary files
|
||||
os.remove(a_for_octave)
|
||||
os.remove(b_for_octave)
|
||||
if c_for_octave then
|
||||
os.remove(c_for_octave)
|
||||
end
|
||||
os.remove(d_for_octave)
|
||||
|
||||
if exit_code then
|
||||
print("\nMatches Octave.")
|
||||
else
|
||||
print("\nMISMATCH with Octave!")
|
||||
os.exit(1)
|
||||
end
|
||||
else
|
||||
print("\nNOTE: Install `octave` to verify the results.")
|
||||
end
|
||||
@@ -0,0 +1,128 @@
|
||||
-- Copyright © 2025 Intel Corporation
|
||||
-- SPDX-License-Identifier: MIT
|
||||
--
|
||||
-- Encode and decode floating point types.
|
||||
--
|
||||
-- Just enough to get basic usage of the examples. If this get serious might
|
||||
-- be a good idea to implement it using the existing Mesa routines and exposing
|
||||
-- as part of executor API.
|
||||
|
||||
local M = {}
|
||||
|
||||
M.decode_float = function(bits, mantissa_bits, exponent_bits, bias)
|
||||
local total_bits = 1 + exponent_bits + mantissa_bits
|
||||
|
||||
local sign_mask = 1 << (total_bits - 1)
|
||||
local exponent_mask = ((1 << exponent_bits) - 1) << mantissa_bits
|
||||
local mantissa_mask = (1 << mantissa_bits) - 1
|
||||
|
||||
local sign = (bits & sign_mask) ~= 0
|
||||
local exponent = (bits & exponent_mask) >> mantissa_bits
|
||||
local mantissa = bits & mantissa_mask
|
||||
|
||||
if exponent == 0 then
|
||||
if mantissa == 0 then
|
||||
return sign and "-0.0" or "0.0"
|
||||
else
|
||||
-- Subnormal number. They don't have implicit leading 1, so
|
||||
-- the number corresponds to "0.mantissa * 2^(1-bias)".
|
||||
local value = mantissa / (1 << mantissa_bits)
|
||||
value = value * (2 ^ (1 - bias))
|
||||
if sign then value = -value end
|
||||
return string.format("%.17g", value)
|
||||
end
|
||||
elseif exponent == (1 << exponent_bits) - 1 then
|
||||
if mantissa == 0 then
|
||||
return sign and "-inf" or "inf"
|
||||
else
|
||||
return "nan"
|
||||
end
|
||||
else
|
||||
-- Normal numbers have implicit leading 1, so the
|
||||
-- number corresponds to "1.mantissa * 2^(exponent-bias)".
|
||||
local value = 1.0 + (mantissa / (1 << mantissa_bits))
|
||||
value = value * (2 ^ (exponent - bias))
|
||||
if sign then value = -value end
|
||||
return string.format("%.17g", value)
|
||||
end
|
||||
end
|
||||
|
||||
M.decode_f32 = function(bits)
|
||||
return M.decode_float(bits, 23, 8, 127)
|
||||
end
|
||||
|
||||
M.decode_f16 = function(bits)
|
||||
return M.decode_float(bits, 10, 5, 15)
|
||||
end
|
||||
|
||||
M.decode_bf16 = function(bits)
|
||||
return M.decode_float(bits, 7, 8, 127)
|
||||
end
|
||||
|
||||
M.encode_float = function(value_str, mantissa_bits, exponent_bits, bias)
|
||||
local value = tonumber(value_str)
|
||||
if not value then
|
||||
return nil
|
||||
end
|
||||
|
||||
local total_bits = 1 + exponent_bits + mantissa_bits
|
||||
local max_exponent = (1 << exponent_bits) - 1
|
||||
|
||||
local sign_bit = value < 0 and (1 << (total_bits - 1)) or 0
|
||||
local signed_inf = sign_bit | max_exponent << mantissa_bits
|
||||
|
||||
-- Handle various special cases first: signed zero, NaN, Inf/-Inf.
|
||||
if value == 0.0 then
|
||||
return sign_bit
|
||||
elseif value ~= value then
|
||||
return (1 << (total_bits - 1)) | (max_exponent << mantissa_bits) | 1
|
||||
elseif value == math.huge or value == -math.huge then
|
||||
return signed_inf
|
||||
end
|
||||
|
||||
-- Do math with the absolute value from now on.
|
||||
if sign_bit ~= 0 then value = -value end
|
||||
|
||||
local exponent = math.floor(math.log(value) / math.log(2))
|
||||
|
||||
local mantissa_value = value / (2 ^ exponent) - 1.0
|
||||
|
||||
exponent = exponent + bias
|
||||
|
||||
if exponent <= 0 then
|
||||
-- Subnormal: no implicit leading 1, use minimum exponent
|
||||
mantissa_value = value / (2 ^ (1 - bias))
|
||||
exponent = 0
|
||||
elseif exponent >= max_exponent then
|
||||
-- Value too large to represent.
|
||||
return signed_inf
|
||||
end
|
||||
|
||||
local mantissa = math.floor(mantissa_value * (1 << mantissa_bits) + 0.5)
|
||||
|
||||
if mantissa >= (1 << mantissa_bits) then
|
||||
-- Rounding caused mantissa to overflow, increment exponent.
|
||||
mantissa = 0
|
||||
exponent = exponent + 1
|
||||
if exponent >= max_exponent then
|
||||
-- Value too large to represent.
|
||||
return signed_inf
|
||||
end
|
||||
end
|
||||
|
||||
return sign_bit | (exponent << mantissa_bits) | mantissa
|
||||
end
|
||||
|
||||
M.encode_f32 = function(value_str)
|
||||
return M.encode_float(value_str, 23, 8, 127)
|
||||
end
|
||||
|
||||
M.encode_f16 = function(value_str)
|
||||
return M.encode_float(value_str, 10, 5, 15)
|
||||
end
|
||||
|
||||
M.encode_bf16 = function(value_str)
|
||||
return M.encode_float(value_str, 7, 8, 127)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,64 @@
|
||||
-- Copyright © 2025 Intel Corporation
|
||||
-- SPDX-License-Identifier: MIT
|
||||
|
||||
local M = {}
|
||||
|
||||
local GRF_SLOTS = devinfo.ver >= 20 and 16 or 8
|
||||
|
||||
local mov_ub = function(grf, values)
|
||||
local s = ""
|
||||
for i = 1, #values, 4 do
|
||||
local b0 = values[i] or 0
|
||||
local b1 = values[i+1] or 0
|
||||
local b2 = values[i+2] or 0
|
||||
local b3 = values[i+3] or 0
|
||||
local packed = b0 + (b1 * 2^8) + (b2 * 2^16) + (b3 * 2^24)
|
||||
local dword_idx = (i-1) // 4
|
||||
local nr = dword_idx // GRF_SLOTS
|
||||
local off = dword_idx % GRF_SLOTS
|
||||
s = s .. string.format("mov (1) r%d.%d 0x%x {A@1}\n", grf + nr, off, packed)
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
M.mov_grf = function(fmt, grf, values)
|
||||
if fmt == "ub" then
|
||||
return mov_ub(grf, values)
|
||||
end
|
||||
|
||||
local packing = 0
|
||||
local dst_type = fmt
|
||||
local imm_type = fmt
|
||||
if fmt == "hf" then packing = 2
|
||||
elseif fmt == "bf" then packing = 2; dst_type = "uw"; imm_type = "uw"
|
||||
elseif fmt == "f" then packing = 1
|
||||
elseif fmt == "ud" then packing = 1
|
||||
else
|
||||
error("unsupported format")
|
||||
end
|
||||
|
||||
local s = ""
|
||||
|
||||
for i, v in ipairs(values) do
|
||||
nr = (i-1) // (GRF_SLOTS * packing)
|
||||
off = (i-1) % (GRF_SLOTS * packing)
|
||||
s = s .. string.format("mov (1) r%d.%d:%s 0x%x:%s {A@1}\n",
|
||||
grf + nr, off, dst_type, v, imm_type)
|
||||
end
|
||||
|
||||
return s
|
||||
end
|
||||
|
||||
M.write_grfs = function(grf, count)
|
||||
local s = "@id r126\n"
|
||||
local width = devinfo.ver >= 20 and 16 or 8
|
||||
for i = 1, count do
|
||||
s = s .. string.format([[
|
||||
@write r126 r%d
|
||||
add (%d) r126 r126 %d {A@1}
|
||||
]], grf + i - 1, width, GRF_SLOTS)
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,151 @@
|
||||
-- Copyright © 2025 Intel Corporation
|
||||
-- SPDX-License-Identifier: MIT
|
||||
|
||||
local M = {}
|
||||
|
||||
local Matrix = {}
|
||||
Matrix.__index = Matrix
|
||||
|
||||
Matrix.get = function(self, i, j)
|
||||
if i < 0 or i >= self.rows or j < 0 or j >= self.cols then
|
||||
error(string.format("Index out of bounds in get(): i=%d j=%d (size %dx%d)",
|
||||
i, j, self.rows, self.cols))
|
||||
end
|
||||
return self.data[i][j]
|
||||
end
|
||||
|
||||
Matrix.set = function(self, i, j, value)
|
||||
if i < 0 or i >= self.rows or j < 0 or j >= self.cols then
|
||||
error(string.format("Index out of bounds in set(): i=%d j=%d (size %dx%d)",
|
||||
i, j, self.rows, self.cols))
|
||||
end
|
||||
self.data[i][j] = value
|
||||
end
|
||||
|
||||
Matrix.print_submatrix = function(self, rows, cols, fmt)
|
||||
local fmt = fmt or "%4u"
|
||||
print(string.format("# %dx%d matrix", rows, cols))
|
||||
io.write("[\n")
|
||||
for i = 0, rows - 1 do
|
||||
for j = 0, cols - 1 do
|
||||
io.write(string.format(fmt, self.data[i][j]))
|
||||
if j < cols - 1 then io.write(" ") end
|
||||
end
|
||||
io.write("\n")
|
||||
end
|
||||
io.write("]\n")
|
||||
end
|
||||
|
||||
Matrix.print = function(self, fmt)
|
||||
self:print_submatrix(self.rows, self.cols, fmt)
|
||||
end
|
||||
|
||||
-- "Interleaved" row major is like row major except that
|
||||
-- elements from `packing_factor` rows are packed together.
|
||||
--
|
||||
-- So, for a 4x4 matrix with packing factor 2
|
||||
--
|
||||
-- [ 1 2 3 4
|
||||
-- 5 6 7 8
|
||||
-- 9 a b c
|
||||
-- d e f 0 ]
|
||||
--
|
||||
-- in regular row major the sequence
|
||||
--
|
||||
-- [ 1 2 3 4 5 6 7 8 9 a b c d e f 0 ]
|
||||
--
|
||||
-- while in "interleaved" row major
|
||||
--
|
||||
-- [ 1 5 2 6 3 7 4 8 9 d a e b f c 0 ]
|
||||
--
|
||||
-- This is used by `src1` of DPAS instruction.
|
||||
--
|
||||
Matrix.to_interleaved_row_major = function(self, packing_factor)
|
||||
local result = {}
|
||||
for row = 0, self.rows-1 do
|
||||
for col = 0, self.cols-1 do
|
||||
local v = self.data[row][col]
|
||||
local idx = (row // packing_factor) * (self.cols * packing_factor) +
|
||||
col * packing_factor +
|
||||
row % packing_factor
|
||||
-- The +1 is for 1-based arrays in Lua.
|
||||
result[idx+1] = v
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
Matrix.to_row_major = function(self)
|
||||
local result = {}
|
||||
for i = 0, self.rows - 1 do
|
||||
for j = 0, self.cols - 1 do
|
||||
local idx = i * self.cols + j
|
||||
-- The +1 is for 1-based arrays in Lua.
|
||||
result[idx+1] = self.data[i][j]
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
M.new = function(rows, cols, default)
|
||||
local self = setmetatable({}, Matrix)
|
||||
self.rows = rows
|
||||
self.cols = cols
|
||||
self.data = {}
|
||||
|
||||
for i = 0, rows - 1 do
|
||||
self.data[i] = {}
|
||||
for j = 0, cols - 1 do
|
||||
self.data[i][j] = default or 0
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
M.new_diag = function(rows, cols, value)
|
||||
cols = cols or rows -- If cols not provided, use rows (square matrix)
|
||||
local self = M.new(rows, cols, 0)
|
||||
local min_dim = math.min(rows, cols)
|
||||
for i = 0, min_dim - 1 do
|
||||
self.data[i][i] = value
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
M.from_row_major = function(rows, cols, data)
|
||||
local self = M.new(rows, cols)
|
||||
|
||||
for i = 0, rows - 1 do
|
||||
for j = 0, cols - 1 do
|
||||
local idx = i * cols + j + 1
|
||||
self.data[i][j] = data[idx] or 0
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-- Like above but assume data is 0-indexed like a memory buffer.
|
||||
M.from_row_major_buffer = function(rows, cols, data)
|
||||
local self = M.new(rows, cols)
|
||||
|
||||
for i = 0, rows - 1 do
|
||||
for j = 0, cols - 1 do
|
||||
local idx = i * cols + j
|
||||
self.data[i][j] = data[idx] or 0
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
Matrix.apply = function(self, func)
|
||||
for i = 0, self.rows - 1 do
|
||||
for j = 0, self.cols - 1 do
|
||||
self.data[i][j] = func(self.data[i][j])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,6 @@
|
||||
execute {
|
||||
src = [[
|
||||
nop (8)
|
||||
@eot
|
||||
]],
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
if devinfo.ver < 20 then
|
||||
error("SRND instruction requires Gfx20+")
|
||||
end
|
||||
|
||||
local r = execute {
|
||||
src = [[
|
||||
@id r1
|
||||
|
||||
// Prepare F32 input data in r2
|
||||
mov (8) r2.0 0x00000000 {A@1} // 0.0f
|
||||
mov (8) r2.1 0x80000000 {A@1} // -0.0f
|
||||
mov (8) r2.2 0x7f7fffff {A@1} // FLT_MAX
|
||||
mov (8) r2.3 0xff7fffff {A@1} // -FLT_MAX
|
||||
mov (8) r2.4 0x00800000 {A@1} // smallest normal
|
||||
mov (8) r2.5 0x7fc00000 {A@1} // NaN
|
||||
mov (8) r2.6 0x7f800000 {A@1} // +inf
|
||||
mov (8) r2.7 0xff800000 {A@1} // -inf
|
||||
|
||||
mov (8) r3<2>:uw 42:uw {A@1}
|
||||
|
||||
// Stochastic rounding: F32 -> HF16 using r3 as random, packed
|
||||
(W) srnd (8) r4<2>:hf r2:f r3:f {A@1}
|
||||
|
||||
// Convert back to F32 for checking, using supported regioning
|
||||
mov (8) r5:f r4<2>:hf {A@1}
|
||||
|
||||
@write r1 r5
|
||||
|
||||
@eot
|
||||
]],
|
||||
}
|
||||
|
||||
print("result")
|
||||
dump(r, 8)
|
||||
|
||||
print("expected")
|
||||
expected = {
|
||||
[0] = 0x00000000,
|
||||
0x80000000,
|
||||
0x7f800000, -- FLT_MAX rounds to +inf in HF16
|
||||
0xff800000, -- -FLT_MAX rounds to -inf in HF16
|
||||
0x00000000, -- smallest F32 normal rounds to zero in HF16
|
||||
0x7fc00000,
|
||||
0x7f800000,
|
||||
0xff800000
|
||||
}
|
||||
|
||||
dump(expected, 8)
|
||||
|
||||
for i=0,7 do
|
||||
if r[i] ~= expected[i] then
|
||||
print("FAIL at index", i, string.format("got 0x%08x expected 0x%08x", r[i], expected[i]))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
print("OK")
|
||||
@@ -0,0 +1,64 @@
|
||||
if devinfo.ver < 20 then
|
||||
error("SRND instruction requires Gfx20+")
|
||||
end
|
||||
|
||||
F32_VALUE = 0x3F8016F0 -- 1.0007
|
||||
-- F32_VALUE = 0x3F8009D5 -- 1.0003
|
||||
F16_ROUNDED_UP = 0x3C01 -- 1.001
|
||||
F16_ROUNDED_DOWN = 0x3C00 -- 1.000
|
||||
N = 16 * 4
|
||||
|
||||
math.randomseed(os.time())
|
||||
local random_data = {}
|
||||
for i = 0, N-1 do
|
||||
random_data[i] = math.random(1 << 32) - 1
|
||||
end
|
||||
|
||||
src = [[
|
||||
@id r10
|
||||
@mov r20 ]] .. F32_VALUE .. [[
|
||||
|
||||
]]
|
||||
|
||||
for i = 0, (N/16)-1 do
|
||||
src = src .. [[
|
||||
@read r30 r10
|
||||
@mov r40 0
|
||||
(W) srnd (16) r40<2>:hf r20:f r30:f {A@1}
|
||||
|
||||
// Change r30 to r40 to see the random values.
|
||||
@write r10 r40
|
||||
add (16) r10 r10 0x10 {A@1}
|
||||
]]
|
||||
end
|
||||
|
||||
src = src .. [[
|
||||
@eot
|
||||
]]
|
||||
|
||||
|
||||
local r = execute {
|
||||
data = random_data,
|
||||
src = src,
|
||||
}
|
||||
|
||||
up = 0
|
||||
down = 0
|
||||
invalid = 0
|
||||
|
||||
for i = 0, N-1 do
|
||||
if r[i] == F16_ROUNDED_UP then
|
||||
up = up + 1
|
||||
elseif r[i] == F16_ROUNDED_DOWN then
|
||||
down = down + 1
|
||||
else
|
||||
invalid = invalid + 1
|
||||
end
|
||||
end
|
||||
|
||||
dump(r, N)
|
||||
|
||||
print()
|
||||
print("rounded up ", up/N, "%")
|
||||
print("rounded down ", down/N, "%")
|
||||
print("invalid ", invalid/N, "%")
|
||||
@@ -0,0 +1,51 @@
|
||||
-- Illustrates executor parsing of structured control flow without having to
|
||||
-- spell out JIP/UIP for IF/ELSE/ENDIF. WHILE still needs an explicit JIP,
|
||||
-- but the common structured branch labels are inferred automatically.
|
||||
|
||||
local src = [[
|
||||
@id r1
|
||||
@mov r2 0
|
||||
@mov r3 0
|
||||
@mov r4 0
|
||||
|
||||
LOOP:
|
||||
// First conditional: 0 < 1, so this takes the then-path.
|
||||
cmp (1) (lt)f0.0 null:d r4<0>:d 1:d {A@1}
|
||||
(f0.0) if(1)
|
||||
add (1) r2 r2<0> 1
|
||||
else(1)
|
||||
add (1) r2 r2<0> 2
|
||||
endif(1)
|
||||
|
||||
// Second conditional: 0 < 0 is false, so this takes the else-path.
|
||||
cmp (1) (lt)f0.0 null:d r4<0>:d 0:d {A@1}
|
||||
(f0.0) if(1)
|
||||
add (1) r2 r2<0> 4
|
||||
else(1)
|
||||
add (1) r2 r2<0> 8
|
||||
endif(1)
|
||||
|
||||
add (1) r3 r3<0> 1
|
||||
cmp (1) (lt)f0.0 null:d r3<0>:d 2:d {A@1}
|
||||
// WHILE still needs an explicit loop-start label for its JIP back-edge.
|
||||
(f0.0) while(1) jip:LOOP
|
||||
|
||||
@write r1 r2
|
||||
@eot
|
||||
]]
|
||||
|
||||
local r = execute { src = src }
|
||||
|
||||
local expected = {[0] = 18}
|
||||
|
||||
print("result")
|
||||
dump(r, 1)
|
||||
|
||||
print("expected")
|
||||
dump(expected, 1)
|
||||
|
||||
if r[0] ~= expected[0] then
|
||||
error(string.format("got %u expected %u", r[0], expected[0]))
|
||||
end
|
||||
|
||||
print("OK")
|
||||
@@ -0,0 +1,20 @@
|
||||
local data = {}
|
||||
for i = 0, 8-1 do
|
||||
data[i] = i * 4
|
||||
end
|
||||
|
||||
local r = execute {
|
||||
data = data,
|
||||
src = [[
|
||||
@id r1
|
||||
@read r3 r1
|
||||
|
||||
add (8) r3 r3 0x100
|
||||
|
||||
@write r1 r3
|
||||
|
||||
@eot
|
||||
]],
|
||||
}
|
||||
|
||||
dump(r, 8)
|
||||
Executable
+179
@@ -0,0 +1,179 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
if ! command -v executor &> /dev/null; then
|
||||
echo "ERROR: executor command not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
executor matmul.lua UB/UD \
|
||||
<(cat <<EOF
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
||||
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
||||
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
||||
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
||||
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
||||
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
||||
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
|
||||
EOF
|
||||
) \
|
||||
<(cat <<EOF
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
||||
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
||||
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
||||
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
||||
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
||||
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
||||
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
||||
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
||||
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
||||
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
||||
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
||||
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
||||
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
|
||||
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
||||
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
||||
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
|
||||
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
||||
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
||||
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
||||
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
||||
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
||||
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
||||
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
||||
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
|
||||
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
||||
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
|
||||
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
|
||||
EOF
|
||||
)
|
||||
|
||||
executor matmul.lua HF/F \
|
||||
<(cat <<EOF
|
||||
0.25 1.75 2.00 3.50 4.00 5.00 6.00 7.00 8.00 9.00 10.00 11.00 12.00 13.00 14.00 15.00
|
||||
16.00 17.00 18.00 19.00 20.00 21.00 22.75 23.00 24.00 25.00 26.00 27.00 28.00 29.00 30.00 31.00
|
||||
32.00 33.00 34.00 35.00 36.00 37.00 38.00 39.00 40.00 41.00 42.00 43.00 44.00 45.25 46.00 47.00
|
||||
48.00 49.00 50.00 51.00 52.00 53.00 54.00 55.00 56.00 57.00 58.00 59.00 60.00 61.00 62.00 63.00
|
||||
64.00 65.00 66.00 67.00 68.00 69.00 70.00 71.00 72.00 73.00 74.00 75.00 76.00 77.00 78.00 79.00
|
||||
80.00 81.00 82.00 83.00 84.00 85.00 86.00 87.00 88.00 89.00 90.00 91.00 92.00 93.00 94.00 95.00
|
||||
96.00 97.00 98.00 99.00 100.0 101.0 102.0 103.0 104.0 105.0 106.0 107.0 108.0 109.0 110.0 111.0
|
||||
112.00 113.0 114.0 115.0 116.0 117.0 118.0 119.0 120.0 121.0 122.0 123.0 124.0 125.0 126.0 127.0
|
||||
EOF
|
||||
) \
|
||||
<(cat <<EOF
|
||||
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.25 10.00 11.00 12.00 13.00 14.00 15.00
|
||||
16.00 17.00 18.00 19.00 20.00 21.00 22.00 23.00 24.00 25.00 26.00 27.00 28.00 29.00 30.00 31.00
|
||||
32.00 33.00 34.00 35.00 36.00 37.00 38.00 39.00 40.00 41.00 42.00 43.00 44.00 45.00 46.00 47.00
|
||||
48.00 49.00 50.00 51.00 52.00 53.00 54.00 55.00 56.00 57.00 58.00 59.00 60.00 61.00 62.00 63.00
|
||||
64.00 65.00 66.00 67.00 68.00 69.00 70.00 71.00 72.00 73.00 74.75 75.00 76.00 77.00 78.00 79.00
|
||||
80.00 81.00 82.00 83.00 84.00 85.00 86.00 87.00 88.00 89.00 90.00 91.00 92.00 93.00 94.00 95.00
|
||||
96.00 97.00 98.00 99.00 100.0 101.0 102.0 103.0 104.0 105.0 106.0 107.0 108.0 109.0 110.0 111.0
|
||||
112.00 113.0 114.0 115.0 116.0 117.0 118.0 119.0 120.0 121.0 122.0 123.0 124.0 125.0 126.0 127.0
|
||||
128.00 129.0 130.0 131.0 132.0 133.0 134.0 135.0 136.0 137.0 138.0 139.0 140.0 141.0 142.0 143.0
|
||||
144.00 145.0 146.0 147.0 148.0 149.0 150.0 151.0 152.0 153.0 154.0 155.0 156.0 157.0 158.0 159.0
|
||||
160.00 161.0 162.0 163.0 164.0 165.0 166.0 167.0 168.0 169.0 170.0 171.0 172.0 173.0 174.0 175.0
|
||||
176.00 177.0 178.0 179.0 180.0 181.0 182.0 183.0 184.0 185.0 186.0 187.0 188.0 189.0 190.0 191.0
|
||||
192.00 193.0 194.0 195.0 196.0 197.0 198.0 199.0 200.0 201.0 202.0 203.0 204.0 205.0 206.0 207.0
|
||||
208.00 209.0 210.0 211.0 212.0 213.0 214.0 215.0 216.0 217.0 218.0 219.0 220.0 221.0 222.0 223.0
|
||||
224.00 225.0 226.0 227.0 228.0 229.0 230.0 231.0 232.0 233.0 234.0 235.0 236.0 237.0 238.0 239.0
|
||||
240.00 241.0 242.0 243.0 244.0 245.0 246.0 247.0 248.0 249.0 250.0 251.0 252.0 253.0 254.0 255.0
|
||||
EOF
|
||||
)
|
||||
|
||||
executor matmul.lua UB/UD \
|
||||
<(cat <<EOF
|
||||
0 1 2 3 4 5 6 7
|
||||
8 9 10 11 12 13 14 15
|
||||
16 17 18 19 20 21 22 23
|
||||
24 25 26 27 28 29 30 31
|
||||
EOF
|
||||
) \
|
||||
<(cat <<EOF
|
||||
1 1 1 1 1 1 1 1 1 1 1 1
|
||||
1 1 1 1 1 1 1 1 1 1 1 1
|
||||
1 1 1 1 1 1 1 1 1 1 1 1
|
||||
1 1 1 1 1 1 1 1 1 1 1 1
|
||||
1 1 1 1 1 1 1 1 1 1 1 1
|
||||
1 1 1 1 1 1 1 1 1 1 1 1
|
||||
1 1 1 1 1 1 1 1 1 1 1 1
|
||||
1 1 1 1 1 1 1 1 1 1 1 1
|
||||
EOF
|
||||
)
|
||||
|
||||
executor matmul.lua HF/F \
|
||||
<(cat <<EOF
|
||||
0.25 1.00 2.75 3.00 4.25
|
||||
5.00 6.75 7.00 8.50 9.00
|
||||
10.25 11.00 12.75 13.00 14.25
|
||||
EOF
|
||||
) \
|
||||
<(cat <<EOF
|
||||
0.0 1.25 2.0 3.75 4.0 5.75
|
||||
6.0 7.25 8.0 9.50 10.0 11.25
|
||||
12.0 13.75 14.0 15.75 16.0 17.25
|
||||
18.0 19.50 20.0 21.25 22.0 23.75
|
||||
24.0 25.75 26.0 27.25 28.0 29.50
|
||||
EOF
|
||||
)
|
||||
|
||||
executor matmul.lua UB/UD <(echo "22") <(echo "1")
|
||||
|
||||
executor matmul.lua BF/F \
|
||||
<(cat <<EOF
|
||||
0.25 1.75 2.00 3.50 4.00 5.00 6.00 7.00 8.00 9.00 10.00 11.00 12.00 13.00 14.00 15.00
|
||||
16.00 17.00 18.00 19.00 20.00 21.00 22.75 23.00 24.00 25.00 26.00 27.00 28.00 29.00 30.00 31.00
|
||||
32.00 33.00 34.00 35.00 36.00 37.00 38.00 39.00 40.00 41.00 42.00 43.00 44.00 45.25 46.00 47.00
|
||||
48.00 49.00 50.00 51.00 52.00 53.00 54.00 55.00 56.00 57.00 58.00 59.00 60.00 61.00 62.00 63.00
|
||||
64.00 65.00 66.00 67.00 68.00 69.00 70.00 71.00 72.00 73.00 74.00 75.00 76.00 77.00 78.00 79.00
|
||||
80.00 81.00 82.00 83.00 84.00 85.00 86.00 87.00 88.00 89.00 90.00 91.00 92.00 93.00 94.00 95.00
|
||||
96.00 97.00 98.00 99.00 100.0 101.0 102.0 103.0 104.0 105.0 106.0 107.0 108.0 109.0 110.0 111.0
|
||||
112.00 113.0 114.0 115.0 116.0 117.0 118.0 119.0 120.0 121.0 122.0 123.0 124.0 125.0 126.0 127.0
|
||||
EOF
|
||||
) \
|
||||
<(cat <<EOF
|
||||
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.25 10.00 11.00 12.00 13.00 14.00 15.00
|
||||
16.00 17.00 18.00 19.00 20.00 21.00 22.00 23.00 24.00 25.00 26.00 27.00 28.00 29.00 30.00 31.00
|
||||
32.00 33.00 34.00 35.00 36.00 37.00 38.00 39.00 40.00 41.00 42.00 43.00 44.00 45.00 46.00 47.00
|
||||
48.00 49.00 50.00 51.00 52.00 53.00 54.00 55.00 56.00 57.00 58.00 59.00 60.00 61.00 62.00 63.00
|
||||
64.00 65.00 66.00 67.00 68.00 69.00 70.00 71.00 72.00 73.00 74.75 75.00 76.00 77.00 78.00 79.00
|
||||
80.00 81.00 82.00 83.00 84.00 85.00 86.00 87.00 88.00 89.00 90.00 91.00 92.00 93.00 94.00 95.00
|
||||
96.00 97.00 98.00 99.00 100.0 101.0 102.0 103.0 104.0 105.0 106.0 107.0 108.0 109.0 110.0 111.0
|
||||
112.00 113.0 114.0 115.0 116.0 117.0 118.0 119.0 120.0 121.0 122.0 123.0 124.0 125.0 126.0 127.0
|
||||
128.00 129.0 130.0 131.0 132.0 133.0 134.0 135.0 136.0 137.0 138.0 139.0 140.0 141.0 142.0 143.0
|
||||
144.00 145.0 146.0 147.0 148.0 149.0 150.0 151.0 152.0 153.0 154.0 155.0 156.0 157.0 158.0 159.0
|
||||
160.00 161.0 162.0 163.0 164.0 165.0 166.0 167.0 168.0 169.0 170.0 171.0 172.0 173.0 174.0 175.0
|
||||
176.00 177.0 178.0 179.0 180.0 181.0 182.0 183.0 184.0 185.0 186.0 187.0 188.0 189.0 190.0 191.0
|
||||
192.00 193.0 194.0 195.0 196.0 197.0 198.0 199.0 200.0 201.0 202.0 203.0 204.0 205.0 206.0 207.0
|
||||
208.00 209.0 210.0 211.0 212.0 213.0 214.0 215.0 216.0 217.0 218.0 219.0 220.0 221.0 222.0 223.0
|
||||
224.00 225.0 226.0 227.0 228.0 229.0 230.0 231.0 232.0 233.0 234.0 235.0 236.0 237.0 238.0 239.0
|
||||
240.00 241.0 242.0 243.0 244.0 245.0 246.0 247.0 248.0 249.0 250.0 251.0 252.0 253.0 254.0 255.0
|
||||
EOF
|
||||
)
|
||||
|
||||
executor matmul.lua BF/F \
|
||||
<(cat <<EOF
|
||||
1.25 2.75 3.00 4.25
|
||||
5.00 6.75 7.50 8.00
|
||||
9.25 10.00 11.75 12.25
|
||||
EOF
|
||||
) \
|
||||
<(cat <<EOF
|
||||
2.0 1.25 3.75 2.0 1.0
|
||||
1.0 3.00 2.00 1.50 3.0
|
||||
3.75 2.00 1.00 3.00 2.0
|
||||
2.0 1.25 3.00 2.00 1.75
|
||||
EOF
|
||||
)
|
||||
|
||||
echo ""
|
||||
echo "All tests passed!"
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright © 2024 Intel Corporation
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef EXECUTOR_H
|
||||
#define EXECUTOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "intel/dev/intel_device_info.h"
|
||||
#include "intel/isl/isl.h"
|
||||
#include "perf/intel_perf.h"
|
||||
#include "perf/intel_perf_query.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t size;
|
||||
uint32_t handle;
|
||||
void *map;
|
||||
void *cursor;
|
||||
uint64_t addr;
|
||||
} executor_bo;
|
||||
|
||||
typedef struct {
|
||||
void *mem_ctx;
|
||||
|
||||
struct intel_device_info *devinfo;
|
||||
struct isl_device *isl_dev;
|
||||
int fd;
|
||||
|
||||
struct {
|
||||
uint32_t ctx_id;
|
||||
} i915;
|
||||
|
||||
struct {
|
||||
uint32_t vm_id;
|
||||
uint32_t queue_id;
|
||||
} xe;
|
||||
|
||||
struct {
|
||||
executor_bo batch;
|
||||
executor_bo extra;
|
||||
executor_bo data;
|
||||
executor_bo perf;
|
||||
} bo;
|
||||
|
||||
bool perf_enabled;
|
||||
|
||||
struct {
|
||||
struct intel_perf_context *ctx;
|
||||
struct intel_perf_query_object *obj;
|
||||
} perf_query;
|
||||
|
||||
uint64_t batch_start;
|
||||
} executor_context;
|
||||
|
||||
typedef struct {
|
||||
const char *original_src;
|
||||
|
||||
void *kernel_bin;
|
||||
uint32_t kernel_size;
|
||||
} executor_params;
|
||||
|
||||
typedef struct {
|
||||
uint64_t offset;
|
||||
} executor_address;
|
||||
|
||||
__attribute__((unused)) static uint64_t
|
||||
executor_combine_address(void *data, void *location,
|
||||
executor_address address, uint32_t delta)
|
||||
{
|
||||
return address.offset + delta;
|
||||
}
|
||||
|
||||
executor_address executor_address_of_ptr(executor_bo *bo, void *ptr);
|
||||
|
||||
void *executor_alloc_bytes(executor_bo *bo, uint32_t size);
|
||||
void *executor_alloc_bytes_aligned(executor_bo *bo, uint32_t size, uint32_t alignment);
|
||||
|
||||
void failf(const char *fmt, ...) PRINTFLIKE(1, 2);
|
||||
|
||||
const char *executor_apply_macros(executor_context *ec, const char *original_src);
|
||||
|
||||
#ifdef genX
|
||||
# include "executor_genx.h"
|
||||
#else
|
||||
# define genX(x) gfx9_##x
|
||||
# include "executor_genx.h"
|
||||
# undef genX
|
||||
# define genX(x) gfx11_##x
|
||||
# include "executor_genx.h"
|
||||
# undef genX
|
||||
# define genX(x) gfx12_##x
|
||||
# include "executor_genx.h"
|
||||
# undef genX
|
||||
# define genX(x) gfx125_##x
|
||||
# include "executor_genx.h"
|
||||
# undef genX
|
||||
# define genX(x) gfx20_##x
|
||||
# include "executor_genx.h"
|
||||
# undef genX
|
||||
# define genX(x) gfx30_##x
|
||||
# include "executor_genx.h"
|
||||
# undef genX
|
||||
#endif
|
||||
|
||||
#endif /* EXECUTOR_H */
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright © 2024 Intel Corporation
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "executor.h"
|
||||
|
||||
#ifdef HAVE_VALGRIND
|
||||
#include <valgrind.h>
|
||||
#include <memcheck.h>
|
||||
#define VG(x) x
|
||||
#else
|
||||
#define VG(x) ((void)0)
|
||||
#endif
|
||||
|
||||
#define __gen_address_type executor_address
|
||||
#define __gen_combine_address executor_combine_address
|
||||
#define __gen_user_data void
|
||||
|
||||
#include "intel/genxml/gen_macros.h"
|
||||
#include "intel/genxml/genX_pack.h"
|
||||
|
||||
#define __executor_cmd_length(cmd) cmd ## _length
|
||||
#define __executor_cmd_header(cmd) cmd ## _header
|
||||
#define __executor_cmd_pack(cmd) cmd ## _pack
|
||||
|
||||
#define executor_batch_emit(cmd, name) \
|
||||
for (struct cmd name = { __executor_cmd_header(cmd) }, \
|
||||
*_dst = executor_alloc_bytes(&ec->bo.batch, __executor_cmd_length(cmd) * 4); \
|
||||
__builtin_expect(_dst != NULL, 1); \
|
||||
({ __executor_cmd_pack(cmd)(0, _dst, &name); \
|
||||
VG(VALGRIND_CHECK_MEM_IS_DEFINED(_dst, __executor_cmd_length(cmd) * 4)); \
|
||||
_dst = NULL; \
|
||||
}))
|
||||
|
||||
static void
|
||||
emit_pipe_control(executor_context *ec)
|
||||
{
|
||||
executor_batch_emit(GENX(PIPE_CONTROL), pc) {
|
||||
#if GFX_VER >= 12
|
||||
pc.HDCPipelineFlushEnable = true;
|
||||
#endif
|
||||
pc.PipeControlFlushEnable = true;
|
||||
pc.CommandStreamerStallEnable = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
genX(emit_perf_stall)(executor_context *ec)
|
||||
{
|
||||
executor_batch_emit(GENX(PIPE_CONTROL), pc) {
|
||||
#if GFX_VER >= 12
|
||||
pc.HDCPipelineFlushEnable = true;
|
||||
#endif
|
||||
pc.PipeControlFlushEnable = true;
|
||||
pc.CommandStreamerStallEnable = true;
|
||||
pc.StallAtPixelScoreboard = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
genX(emit_mi_report_perf_count)(executor_context *ec, executor_bo *bo,
|
||||
uint32_t offset_in_bytes,
|
||||
uint32_t report_id)
|
||||
{
|
||||
executor_batch_emit(GENX(MI_REPORT_PERF_COUNT), mi_rpc) {
|
||||
mi_rpc.MemoryAddress = (executor_address){bo->addr + offset_in_bytes};
|
||||
mi_rpc.ReportID = report_id;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
genX(store_register_mem)(executor_context *ec, executor_bo *bo,
|
||||
uint32_t reg, uint32_t reg_size,
|
||||
uint32_t offset_in_bytes)
|
||||
{
|
||||
assert(reg_size == 4 || reg_size == 8);
|
||||
|
||||
for (uint32_t i = 0; i < reg_size; i += 4) {
|
||||
executor_batch_emit(GENX(MI_STORE_REGISTER_MEM), srm) {
|
||||
srm.RegisterAddress = reg + i;
|
||||
srm.MemoryAddress = (executor_address){bo->addr + offset_in_bytes + i};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
emit_state_base_address(executor_context *ec, uint32_t mocs)
|
||||
{
|
||||
/* Use the full address for everything. */
|
||||
const executor_address base_address = {0};
|
||||
const uint32_t size = (1 << 20) - 1;
|
||||
|
||||
executor_batch_emit(GENX(STATE_BASE_ADDRESS), sba) {
|
||||
sba.GeneralStateBaseAddress = base_address;
|
||||
sba.GeneralStateBaseAddressModifyEnable = true;
|
||||
sba.GeneralStateBufferSize = size;
|
||||
sba.GeneralStateBufferSizeModifyEnable = true;
|
||||
sba.GeneralStateMOCS = mocs;
|
||||
|
||||
sba.DynamicStateBaseAddress = base_address;
|
||||
sba.DynamicStateBaseAddressModifyEnable = true;
|
||||
sba.DynamicStateBufferSize = size;
|
||||
sba.DynamicStateBufferSizeModifyEnable = true;
|
||||
sba.DynamicStateMOCS = mocs;
|
||||
|
||||
sba.InstructionBaseAddress = base_address;
|
||||
sba.InstructionBaseAddressModifyEnable = true;
|
||||
sba.InstructionBufferSize = size;
|
||||
sba.InstructionBuffersizeModifyEnable = true;
|
||||
sba.InstructionMOCS = mocs;
|
||||
|
||||
sba.IndirectObjectBaseAddress = base_address;
|
||||
sba.IndirectObjectBaseAddressModifyEnable = true;
|
||||
sba.IndirectObjectBufferSize = size;
|
||||
sba.IndirectObjectBufferSizeModifyEnable = true;
|
||||
sba.IndirectObjectMOCS = mocs;
|
||||
|
||||
sba.SurfaceStateMOCS = mocs;
|
||||
sba.StatelessDataPortAccessMOCS = mocs;
|
||||
|
||||
#if GFX_VER >= 11
|
||||
sba.BindlessSamplerStateMOCS = mocs;
|
||||
#endif
|
||||
sba.BindlessSurfaceStateMOCS = mocs;
|
||||
|
||||
#if GFX_VERx10 >= 125
|
||||
sba.L1CacheControl = L1CC_WB;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
executor_perf_begin(executor_context *ec)
|
||||
{
|
||||
if (!intel_perf_begin_query(ec->perf_query.ctx, ec->perf_query.obj))
|
||||
failf("failed to begin OA performance query");
|
||||
}
|
||||
|
||||
static void
|
||||
executor_perf_end(executor_context *ec)
|
||||
{
|
||||
intel_perf_end_query(ec->perf_query.ctx, ec->perf_query.obj);
|
||||
}
|
||||
|
||||
void
|
||||
genX(emit_execute)(executor_context *ec, const executor_params *params)
|
||||
{
|
||||
uint32_t *kernel = executor_alloc_bytes(&ec->bo.extra, params->kernel_size);
|
||||
memcpy(kernel, params->kernel_bin, params->kernel_size);
|
||||
executor_address kernel_addr = executor_address_of_ptr(&ec->bo.extra, kernel);
|
||||
|
||||
/* TODO: Let SIMD be a parameter. */
|
||||
|
||||
struct GENX(INTERFACE_DESCRIPTOR_DATA) desc = {
|
||||
.KernelStartPointer = kernel_addr.offset,
|
||||
.NumberofThreadsinGPGPUThreadGroup = 1,
|
||||
};
|
||||
|
||||
void *b = executor_alloc_bytes_aligned(&ec->bo.batch, 0, 256);
|
||||
ec->batch_start = executor_address_of_ptr(&ec->bo.batch, b).offset;
|
||||
|
||||
emit_pipe_control(ec);
|
||||
|
||||
#if GFX_VERx10 < 200
|
||||
executor_batch_emit(GENX(PIPELINE_SELECT), ps) {
|
||||
ps.PipelineSelection = GPGPU;
|
||||
ps.MaskBits = 0x3;
|
||||
}
|
||||
emit_pipe_control(ec);
|
||||
#endif
|
||||
|
||||
const uint32_t mocs = isl_mocs(ec->isl_dev, 0, false);
|
||||
|
||||
emit_state_base_address(ec, mocs);
|
||||
|
||||
#if GFX_VERx10 >= 125
|
||||
executor_batch_emit(GENX(STATE_COMPUTE_MODE), cm) {
|
||||
cm.Mask1 = 0xffff;
|
||||
#if GFX_VERx10 >= 200
|
||||
cm.Mask2 = 0xffff;
|
||||
#endif
|
||||
}
|
||||
|
||||
executor_batch_emit(GENX(CFE_STATE), cfe) {
|
||||
cfe.MaximumNumberofThreads = 64;
|
||||
}
|
||||
#else
|
||||
executor_batch_emit(GENX(MEDIA_VFE_STATE), vfe) {
|
||||
vfe.NumberofURBEntries = 2;
|
||||
vfe.MaximumNumberofThreads = 64;
|
||||
}
|
||||
#endif
|
||||
|
||||
emit_pipe_control(ec);
|
||||
|
||||
#if GFX_VERx10 >= 125
|
||||
struct GENX(COMPUTE_WALKER_BODY) body = {
|
||||
#if GFX_VERx10 >= 200
|
||||
.SIMDSize = 1,
|
||||
.MessageSIMD = 1,
|
||||
#endif
|
||||
.ThreadGroupIDXDimension = 1,
|
||||
.ThreadGroupIDYDimension = 1,
|
||||
.ThreadGroupIDZDimension = 1,
|
||||
.ExecutionMask = 0xFFFFFFFF,
|
||||
.PostSync.MOCS = mocs,
|
||||
.InterfaceDescriptor = desc,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if GFX_VERx10 >= 125
|
||||
if (ec->perf_enabled)
|
||||
executor_perf_begin(ec);
|
||||
|
||||
executor_batch_emit(GENX(COMPUTE_WALKER), cw) {
|
||||
cw.body = body;
|
||||
};
|
||||
|
||||
if (ec->perf_enabled)
|
||||
executor_perf_end(ec);
|
||||
#else
|
||||
uint32_t *idd = executor_alloc_bytes_aligned(&ec->bo.extra, 8 * 4, 256);
|
||||
GENX(INTERFACE_DESCRIPTOR_DATA_pack)(NULL, idd, &desc);
|
||||
|
||||
executor_address idd_addr = executor_address_of_ptr(&ec->bo.extra, idd);
|
||||
|
||||
executor_batch_emit(GENX(MEDIA_INTERFACE_DESCRIPTOR_LOAD), load) {
|
||||
load.InterfaceDescriptorDataStartAddress = idd_addr.offset,
|
||||
load.InterfaceDescriptorTotalLength = 8 * 4;
|
||||
}
|
||||
|
||||
if (ec->perf_enabled)
|
||||
executor_perf_begin(ec);
|
||||
|
||||
executor_batch_emit(GENX(GPGPU_WALKER), gw) {
|
||||
gw.ThreadGroupIDXDimension = 1;
|
||||
gw.ThreadGroupIDYDimension = 1;
|
||||
gw.ThreadGroupIDZDimension = 1;
|
||||
gw.RightExecutionMask = 0xFFFFFFFF;
|
||||
gw.BottomExecutionMask = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
executor_batch_emit(GENX(MEDIA_STATE_FLUSH), msf);
|
||||
|
||||
if (ec->perf_enabled)
|
||||
executor_perf_end(ec);
|
||||
#endif
|
||||
|
||||
emit_pipe_control(ec);
|
||||
|
||||
executor_batch_emit(GENX(MI_BATCH_BUFFER_END), end);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright © 2024 Intel Corporation
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef EXECUTOR_H
|
||||
#error This file must be included via executor.h
|
||||
#endif
|
||||
|
||||
void genX(emit_execute)(executor_context *ec, const executor_params *params);
|
||||
void genX(emit_perf_stall)(executor_context *ec);
|
||||
void genX(emit_mi_report_perf_count)(executor_context *ec, executor_bo *bo,
|
||||
uint32_t offset_in_bytes,
|
||||
uint32_t report_id);
|
||||
void genX(store_register_mem)(executor_context *ec, executor_bo *bo,
|
||||
uint32_t reg, uint32_t reg_size,
|
||||
uint32_t offset_in_bytes);
|
||||
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Copyright © 2024 Intel Corporation
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "util/ralloc.h"
|
||||
|
||||
#include "executor.h"
|
||||
|
||||
static bool
|
||||
startswith(const char *prefix, const char *s)
|
||||
{
|
||||
return !strncmp(prefix, s, strlen(prefix));
|
||||
}
|
||||
|
||||
static char *
|
||||
skip_prefix(char *prefix, char *start)
|
||||
{
|
||||
assert(startswith(prefix, start));
|
||||
char *c = start += strlen(prefix);
|
||||
return c;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_comment(const char *c)
|
||||
{
|
||||
assert(c);
|
||||
return c[0] && c[0] == '/' && c[1] == '/';
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char **args;
|
||||
int count;
|
||||
} parse_args_result;
|
||||
|
||||
static parse_args_result
|
||||
parse_args(void *mem_ctx, char *c)
|
||||
{
|
||||
parse_args_result r = {0};
|
||||
|
||||
while (*c) {
|
||||
/* Skip spaces. */
|
||||
while (*c && isspace(*c))
|
||||
c++;
|
||||
|
||||
if (!*c || is_comment(c))
|
||||
break;
|
||||
|
||||
char *start = c;
|
||||
while (*c && !isspace(*c) && !is_comment(c))
|
||||
c++;
|
||||
r.args = reralloc_array_size(mem_ctx, r.args, sizeof(char *), r.count + 1);
|
||||
r.args[r.count++] = ralloc_strndup(mem_ctx, start, c - start);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
executor_macro_mov(executor_context *ec, char **src, char *line)
|
||||
{
|
||||
char *c = skip_prefix("@mov", line);
|
||||
parse_args_result r = parse_args(ec->mem_ctx, c);
|
||||
|
||||
if (r.count != 2)
|
||||
failf("@mov needs 2 arguments, found %d\n", r.count);
|
||||
|
||||
const char *reg = r.args[0];
|
||||
char *value = r.args[1];
|
||||
const unsigned width = ec->devinfo->ver >= 20 ? 16 : 8;
|
||||
|
||||
if (strchr(value, '.')) {
|
||||
union {
|
||||
float f;
|
||||
uint32_t u;
|
||||
} val;
|
||||
|
||||
val.f = strtof(value, NULL);
|
||||
ralloc_asprintf_append(src,
|
||||
"mov (%u) %s:f 0x%08x:f\n",
|
||||
width, reg, val.u);
|
||||
} else {
|
||||
for (char *x = value; *x; x++)
|
||||
*x = tolower(*x);
|
||||
|
||||
ralloc_asprintf_append(src,
|
||||
"mov (%u) %s %s\n",
|
||||
width, reg, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
executor_macro_syncnop(executor_context *ec, char **src, char *line)
|
||||
{
|
||||
switch (ec->devinfo->verx10) {
|
||||
case 90:
|
||||
case 110: {
|
||||
/* Not needed. */
|
||||
break;
|
||||
}
|
||||
|
||||
case 120: {
|
||||
ralloc_strcat(src,
|
||||
"(W) sync.nop (8) null {@1,$1.dst}\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case 125:
|
||||
case 200:
|
||||
case 300: {
|
||||
ralloc_strcat(src,
|
||||
"(W) sync.nop (8) null {A@1,$1.dst}\n");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE("invalid gfx version");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
executor_macro_eot(executor_context *ec, char **src, char *line)
|
||||
{
|
||||
switch (ec->devinfo->verx10) {
|
||||
case 90:
|
||||
case 110: {
|
||||
ralloc_strcat(src,
|
||||
"(W) mov (8) r127 r0\n"
|
||||
"(W) send.ts (8) null r127:1 null:0 0x00000000 0x82000010 {EOT}\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case 120: {
|
||||
ralloc_strcat(src,
|
||||
"(W) mov (8) r127 r0\n"
|
||||
"(W) send.ts (8) null r127:1 null:0 0x00000000 0x02000000 {@1,EOT}\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case 125: {
|
||||
ralloc_strcat(src,
|
||||
"(W) mov (8) r127 r0\n"
|
||||
"(W) send.gtwy (8) null r127:1 null:0 0x00000000 0x02000000 {A@1,EOT}\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case 200:
|
||||
case 300: {
|
||||
ralloc_strcat(src,
|
||||
"(W) mov (16) r127 r0\n"
|
||||
"(W) send.gtwy (16) null r127:1 null:0 0x00000000 0x02000000 {I@1,EOT}\n");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE("invalid gfx version");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
executor_macro_id(executor_context *ec, char **src, char *line)
|
||||
{
|
||||
char *c = skip_prefix("@id", line);
|
||||
parse_args_result r = parse_args(ec->mem_ctx, c);
|
||||
|
||||
if (r.count != 1)
|
||||
failf("@id needs 1 argument, found %d\n", r.count);
|
||||
|
||||
const char *reg = r.args[0];
|
||||
|
||||
switch (ec->devinfo->verx10) {
|
||||
case 90:
|
||||
case 110:
|
||||
case 120: {
|
||||
ralloc_asprintf_append(src,
|
||||
"(W) mov (8) r127:uw 0x76543210:v\n"
|
||||
"(W) mov (8) %s r127:uw {@1}\n",
|
||||
reg);
|
||||
break;
|
||||
}
|
||||
|
||||
case 125: {
|
||||
ralloc_asprintf_append(src,
|
||||
"(W) mov (8) r127:uw 0x76543210:v\n"
|
||||
"(W) mov (8) %s r127:uw {A@1}\n",
|
||||
reg);
|
||||
break;
|
||||
}
|
||||
|
||||
case 200:
|
||||
case 300: {
|
||||
ralloc_asprintf_append(src,
|
||||
"(W) mov (8) r127:uw 0x76543210:v\n"
|
||||
"(W) add (8) r127.8:uw r127:uw 8:uw {A@1}\n"
|
||||
"(W) mov (16) %s r127:uw {A@1}\n",
|
||||
reg);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE("invalid gfx version");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
executor_macro_write(executor_context *ec, char **src, char *line)
|
||||
{
|
||||
char *c = skip_prefix("@write", line);
|
||||
parse_args_result r = parse_args(ec->mem_ctx, c);
|
||||
|
||||
if (r.count != 2)
|
||||
failf("@write needs 2 arguments, found %d\n", r.count);
|
||||
|
||||
const char *offset_reg = r.args[0];
|
||||
const char *data_reg = r.args[1];
|
||||
|
||||
assert(ec->bo.data.addr <= 0xFFFFFFFF);
|
||||
uint32_t base_addr = ec->bo.data.addr;
|
||||
|
||||
switch (ec->devinfo->verx10) {
|
||||
case 90:
|
||||
case 110:
|
||||
case 120: {
|
||||
const char *send_op = ec->devinfo->verx10 < 120 ? "sends.hdc1" : "send.hdc1";
|
||||
ralloc_asprintf_append(src,
|
||||
"mul (8) r127 %s 0x4:uw {@1}\n"
|
||||
"add (8) r127 r127 0x%08x {@1}\n"
|
||||
"%s (8) null r127:1 %s:1 0x00000040 0x02026efd {@1,$1}\n",
|
||||
offset_reg, base_addr, send_op, data_reg);
|
||||
executor_macro_syncnop(ec, src, "@syncnop");
|
||||
break;
|
||||
}
|
||||
|
||||
case 125: {
|
||||
ralloc_asprintf_append(src,
|
||||
"mul (8) r127 %s 0x4:uw {A@1}\n"
|
||||
"add (8) r127 r127 0x%08x {A@1}\n"
|
||||
"store.ugm.d32.a32 (8) null r127:1 %s:1 {A@1,$1}\n",
|
||||
offset_reg, base_addr, data_reg);
|
||||
executor_macro_syncnop(ec, src, "@syncnop");
|
||||
break;
|
||||
}
|
||||
|
||||
case 200:
|
||||
case 300: {
|
||||
ralloc_asprintf_append(src,
|
||||
"mul (16) r127 %s 0x4:uw {A@1}\n"
|
||||
"add (16) r127 r127 0x%08x {A@1}\n"
|
||||
"store.ugm.d32.a32 (16) null r127:1 %s:1 {A@1,$1}\n",
|
||||
offset_reg, base_addr, data_reg);
|
||||
executor_macro_syncnop(ec, src, "@syncnop");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE("invalid gfx version");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
executor_macro_read(executor_context *ec, char **src, char *line)
|
||||
{
|
||||
char *c = skip_prefix("@read", line);
|
||||
parse_args_result r = parse_args(ec->mem_ctx, c);
|
||||
|
||||
if (r.count != 2)
|
||||
failf("@read needs 2 arguments, found %d\n", r.count);
|
||||
|
||||
/* Order follows underlying SEND, destination first. */
|
||||
const char *data_reg = r.args[0];
|
||||
const char *offset_reg = r.args[1];
|
||||
|
||||
assert(ec->bo.data.addr <= 0xFFFFFFFF);
|
||||
uint32_t base_addr = ec->bo.data.addr;
|
||||
|
||||
switch (ec->devinfo->verx10) {
|
||||
case 90:
|
||||
case 110:
|
||||
case 120: {
|
||||
const char *send_op = ec->devinfo->verx10 < 120 ? "sends.hdc1" : "send.hdc1";
|
||||
ralloc_asprintf_append(src,
|
||||
"mul (8) r127 %s 0x4:uw {@1}\n"
|
||||
"add (8) r127 r127 0x%08x {@1}\n"
|
||||
"%s (8) %s r127:1 null:0 0x00000000 0x02106efd {@1,$1}\n",
|
||||
offset_reg, base_addr, send_op, data_reg);
|
||||
executor_macro_syncnop(ec, src, "@syncnop");
|
||||
break;
|
||||
}
|
||||
|
||||
case 125: {
|
||||
ralloc_asprintf_append(src,
|
||||
"mul (8) r127 %s 0x4:uw {A@1}\n"
|
||||
"add (8) r127 r127 0x%08x {A@1}\n"
|
||||
"load.ugm.d32.a32 (8) %s:1 r127:1 {A@1,$1}\n",
|
||||
offset_reg, base_addr, data_reg);
|
||||
executor_macro_syncnop(ec, src, "@syncnop");
|
||||
break;
|
||||
}
|
||||
|
||||
case 200:
|
||||
case 300: {
|
||||
ralloc_asprintf_append(src,
|
||||
"mul (16) r127 %s 0x4:uw {A@1}\n"
|
||||
"add (16) r127 r127 0x%08x {A@1}\n"
|
||||
"load.ugm.d32.a32 (16) %s:1 r127:1 {A@1,$1}\n",
|
||||
offset_reg, base_addr, data_reg);
|
||||
executor_macro_syncnop(ec, src, "@syncnop");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE("invalid gfx version");
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
find_macro_symbol(char *line)
|
||||
{
|
||||
char *c = line;
|
||||
while (isspace(*c)) c++;
|
||||
return *c == '@' ? c : NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
match_macro_name(const char *name, const char *line)
|
||||
{
|
||||
if (!startswith(name, line))
|
||||
return false;
|
||||
line += strlen(name);
|
||||
return !*line || isspace(*line) || is_comment(line);
|
||||
}
|
||||
|
||||
const char *
|
||||
executor_apply_macros(executor_context *ec, const char *original_src)
|
||||
{
|
||||
char *scratch = ralloc_strdup(ec->mem_ctx, original_src);
|
||||
|
||||
/* Create a ralloc'ed empty string so can call append to it later. */
|
||||
char *src = ralloc_strdup(ec->mem_ctx, "");
|
||||
|
||||
/* TODO: Create a @send macro for common combinations of MsgDesc. */
|
||||
static const struct {
|
||||
const char *name;
|
||||
void (*func)(executor_context *ec, char **output, char *line);
|
||||
} macros[] = {
|
||||
{ "@eot", executor_macro_eot },
|
||||
{ "@mov", executor_macro_mov },
|
||||
{ "@write", executor_macro_write },
|
||||
{ "@read", executor_macro_read },
|
||||
{ "@id", executor_macro_id },
|
||||
{ "@syncnop", executor_macro_syncnop },
|
||||
};
|
||||
|
||||
char *next = scratch;
|
||||
while (next) {
|
||||
char *line = next;
|
||||
char *end = line;
|
||||
|
||||
while (*end && *end != '\n') end++;
|
||||
next = *end ? end + 1 : NULL;
|
||||
*end = '\0';
|
||||
|
||||
char *macro = find_macro_symbol(line);
|
||||
if (!macro) {
|
||||
ralloc_asprintf_append(&src, "%s\n", line);
|
||||
} else {
|
||||
bool found = false;
|
||||
for (int i = 0; i < ARRAY_SIZE(macros); i++) {
|
||||
if (match_macro_name(macros[i].name, macro)) {
|
||||
macros[i].func(ec, &src, macro);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
failf("unsupported macro line: %s", macro);
|
||||
}
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,57 @@
|
||||
# Copyright © 2024 Intel Corporation
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
executor_flags = [
|
||||
no_override_init_args,
|
||||
sse2_args,
|
||||
]
|
||||
|
||||
executor_includes = [
|
||||
inc_include,
|
||||
inc_src,
|
||||
inc_intel,
|
||||
]
|
||||
|
||||
executor_hw_libs = []
|
||||
foreach v: ['90', '110', '120', '125', '200', '300']
|
||||
executor_hw_libs += static_library(
|
||||
'executor_hw_ver@0@'.format(v),
|
||||
['executor_genx.c', gen_xml_pack],
|
||||
include_directories: [executor_includes],
|
||||
c_args: [
|
||||
executor_flags,
|
||||
'-DGFX_VERx10=@0@'.format(v),
|
||||
],
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
dependencies: [
|
||||
dep_valgrind,
|
||||
idep_genxml,
|
||||
idep_intel_dev,
|
||||
],
|
||||
build_by_default : false,
|
||||
)
|
||||
endforeach
|
||||
|
||||
executor = executable(
|
||||
'executor',
|
||||
[
|
||||
'executor_main.c',
|
||||
'executor_macros.c',
|
||||
],
|
||||
dependencies: [
|
||||
dep_libdrm,
|
||||
dep_lua,
|
||||
dep_valgrind,
|
||||
idep_genxml,
|
||||
idep_intel_compiler_gen,
|
||||
idep_intel_decoder_gen,
|
||||
idep_intel_dev,
|
||||
idep_intel_perf,
|
||||
idep_libintel_common,
|
||||
],
|
||||
include_directories: [executor_includes],
|
||||
link_with: [executor_hw_libs],
|
||||
c_args: [executor_flags],
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
install: true
|
||||
)
|
||||
Reference in new issue
Block a user