1 ## Notes about the PTX backend 2 3 Here is the Java source code for a kernel: 4 5 ```Java 6 public static void mandel(KernelContext kc, S32Array2D s32Array2D, S32Array pallette, float offsetx, float offsety, float scale) { 7 if (kc.x < kc.maxX) { 8 float width = s32Array2D.width(); 9 float height = s32Array2D.height(); 10 float x = ((kc.x % s32Array2D.width()) * scale - (scale / 2f * width)) / width + offsetx; 11 float y = ((kc.x / s32Array2D.width()) * scale - (scale / 2f * height)) / height + offsety; 12 float zx = x; 13 float zy = y; 14 float new_zx; 15 int colorIdx = 0; 16 while ((colorIdx < pallette.length()) && (((zx * zx) + (zy * zy)) < 4f)) { 17 new_zx = ((zx * zx) - (zy * zy)) + x; 18 zy = (2f * zx * zy) + y; 19 zx = new_zx; 20 colorIdx++; 21 } 22 int color = colorIdx < pallette.length() ? pallette.array(colorIdx) : 0; 23 s32Array2D.array(kc.x, color); 24 } 25 } 26 27 ``` 28 29 And here is the corresponding Babylon code model: 30 31 ``` 32 func @"mandel" @loc="39:5:file:/Users/grfrost/orahub/hat/examples/mandel/src/java/mandel/MandelCompute.java" 33 (%0 : hat.KernelContext, %1 : hat.buffer.S32Array2D, %2 : hat.buffer.S32Array, %3 : float, %4 : float, %5 : float)void -> { 34 %6 : Var<hat.KernelContext> = var %0 @"kc" ; 35 %7 : Var<hat.buffer.S32Array2D> = var %1 @"s32Array2D" ; 36 %8 : Var<hat.buffer.S32Array> = var %2 @"pallette" ; 37 %9 : Var<float> = var %3 @"offsetx" ; 38 %10 : Var<float> = var %4 @"offsety" ; 39 %11 : Var<float> = var %5 @"scale" ; 40 java.if 41 ()boolean -> { 42 %12 : hat.KernelContext = var.load %6 ; 43 %13 : int = field.load %12 @"hat.KernelContext::x()int" ; 44 %14 : hat.KernelContext = var.load %6 ; 45 %15 : int = field.load %14 @"hat.KernelContext::maxX()int" ; 46 %16 : boolean = lt %13 %15 ; 47 yield %16 ; 48 } 49 ()void -> { 50 %17 : hat.buffer.S32Array2D = var.load %7 ; 51 %18 : int = invoke %17 @"hat.buffer.S32Array2D::width()int" ; 52 %19 : float = conv %18 ; 53 %20 : Var<float> = var %19 @"width" ; 54 %21 : hat.buffer.S32Array2D = var.load %7 ; 55 %22 : int = invoke %21 @"hat.buffer.S32Array2D::height()int" ; 56 %23 : float = conv %22 ; 57 %24 : Var<float> = var %23 @"height" ; 58 %25 : hat.KernelContext = var.load %6 ; 59 %26 : int = field.load %25 @"hat.KernelContext::x()int" ; 60 %27 : hat.buffer.S32Array2D = var.load %7 ; 61 %28 : int = invoke %27 @"hat.buffer.S32Array2D::width()int" ; 62 %29 : int = mod %26 %28 ; 63 %30 : float = conv %29 ; 64 %31 : float = var.load %11 ; 65 %32 : float = mul %30 %31 ; 66 %33 : float = var.load %11 ; 67 %34 : float = constant @"2.0" ; 68 %35 : float = div %33 %34 ; 69 %36 : float = var.load %20 ; 70 %37 : float = mul %35 %36 ; 71 %38 : float = sub %32 %37 ; 72 %39 : float = var.load %20 ; 73 %40 : float = div %38 %39 ; 74 %41 : float = var.load %9 ; 75 %42 : float = add %40 %41 ; 76 %43 : Var<float> = var %42 @"x" ; 77 %44 : hat.KernelContext = var.load %6 ; 78 %45 : int = field.load %44 @"hat.KernelContext::x()int" ; 79 %46 : hat.buffer.S32Array2D = var.load %7 ; 80 %47 : int = invoke %46 @"hat.buffer.S32Array2D::width()int" ; 81 %48 : int = div %45 %47 ; 82 %49 : float = conv %48 ; 83 %50 : float = var.load %11 ; 84 %51 : float = mul %49 %50 ; 85 %52 : float = var.load %11 ; 86 %53 : float = constant @"2.0" ; 87 %54 : float = div %52 %53 ; 88 %55 : float = var.load %24 ; 89 %56 : float = mul %54 %55 ; 90 %57 : float = sub %51 %56 ; 91 %58 : float = var.load %24 ; 92 %59 : float = div %57 %58 ; 93 %60 : float = var.load %10 ; 94 %61 : float = add %59 %60 ; 95 %62 : Var<float> = var %61 @"y" ; 96 %63 : float = var.load %43 ; 97 %64 : Var<float> = var %63 @"zx" ; 98 %65 : float = var.load %62 ; 99 %66 : Var<float> = var %65 @"zy" ; 100 %67 : float = constant @"0.0" ; 101 %68 : Var<float> = var %67 @"new_zx" ; 102 %69 : int = constant @"0" ; 103 %70 : Var<int> = var %69 @"colorIdx" ; 104 java.while 105 ()boolean -> { 106 %71 : boolean = java.cand 107 ()boolean -> { 108 %72 : int = var.load %70 ; 109 %73 : hat.buffer.S32Array = var.load %8 ; 110 %74 : int = invoke %73 @"hat.buffer.S32Array::length()int" ; 111 %75 : boolean = lt %72 %74 ; 112 yield %75 ; 113 } 114 ()boolean -> { 115 %76 : float = var.load %64 ; 116 %77 : float = var.load %64 ; 117 %78 : float = mul %76 %77 ; 118 %79 : float = var.load %66 ; 119 %80 : float = var.load %66 ; 120 %81 : float = mul %79 %80 ; 121 %82 : float = add %78 %81 ; 122 %83 : float = constant @"4.0" ; 123 %84 : boolean = lt %82 %83 ; 124 yield %84 ; 125 }; 126 yield %71 ; 127 } 128 ()void -> { 129 %85 : float = var.load %64 ; 130 %86 : float = var.load %64 ; 131 %87 : float = mul %85 %86 ; 132 %88 : float = var.load %66 ; 133 %89 : float = var.load %66 ; 134 %90 : float = mul %88 %89 ; 135 %91 : float = sub %87 %90 ; 136 %92 : float = var.load %43 ; 137 %93 : float = add %91 %92 ; 138 var.store %68 %93 ; 139 %94 : float = constant @"2.0" ; 140 %95 : float = var.load %64 ; 141 %96 : float = mul %94 %95 ; 142 %97 : float = var.load %66 ; 143 %98 : float = mul %96 %97 ; 144 %99 : float = var.load %62 ; 145 %100 : float = add %98 %99 ; 146 var.store %66 %100 ; 147 %101 : float = var.load %68 ; 148 var.store %64 %101 ; 149 %102 : int = var.load %70 ; 150 %103 : int = constant @"1" ; 151 %104 : int = add %102 %103 ; 152 var.store %70 %104 ; 153 java.continue ; 154 }; 155 %105 : int = java.cexpression 156 ()boolean -> { 157 %106 : int = var.load %70 ; 158 %107 : hat.buffer.S32Array = var.load %8 ; 159 %108 : int = invoke %107 @"hat.buffer.S32Array::length()int" ; 160 %109 : boolean = lt %106 %108 ; 161 yield %109 ; 162 } 163 ()int -> { 164 %110 : hat.buffer.S32Array = var.load %8 ; 165 %111 : int = var.load %70 ; 166 %112 : long = conv %111 ; 167 %113 : int = invoke %110 %112 @"hat.buffer.S32Array::array(long)int" ; 168 yield %113 ; 169 } 170 ()int -> { 171 %114 : int = constant @"0" ; 172 yield %114 ; 173 }; 174 %115 : Var<int> = var %105 @"color" ; 175 %116 : hat.buffer.S32Array2D = var.load %7 ; 176 %117 : hat.KernelContext = var.load %6 ; 177 %118 : int = field.load %117 @"hat.KernelContext::x()int" ; 178 %119 : long = conv %118 ; 179 %120 : int = var.load %115 ; 180 invoke %116 %119 %120 @"hat.buffer.S32Array2D::array(long, int)void" ; 181 yield ; 182 } 183 ()void -> { 184 yield; 185 }; 186 return ; 187 }; 188 189 ``` 190 From the above we can generate C99 style CUDA code 191 192 193 Here is the Cuda C99 code generated 194 195 ```C 196 typedef struct KernelContext_s{ 197 int x; 198 int maxX; 199 }KernelContext_t; 200 201 typedef struct S32Array2D_s{ 202 int width; 203 int height; 204 int array[0]; 205 }S32Array2D_t; 206 207 typedef struct S32Array_s{ 208 int length; 209 int array[0]; 210 }S32Array_t; 211 212 213 extern "C" __global__ void mandel( 214 S32Array2D_t* s32Array2D, S32Array_t* pallette, float offsetx, float offsety, float scale 215 ){ 216 KernelContext_t kc; 217 kc.x=blockIdx.x*blockDim.x+threadIdx.x; 218 kc.maxX=gridDim.x*blockDim.x; 219 if(kc.x<kc.maxX){ 220 float width = (float)s32Array2D->width; 221 float height = (float)s32Array2D->height; 222 float x = ((float)(kc.x%s32Array2D->width)*scale-scale/2.0*width)/width+offsetx; 223 float y = ((float)(kc.x/s32Array2D->width)*scale-scale/2.0*height)/height+offsety; 224 float zx = x; 225 float zy = y; 226 float new_zx = 0.0; 227 int colorIdx = 0; 228 while(colorIdx<pallette->length && zx*zx+zy*zy<4.0){ 229 new_zx=zx*zx-zy*zy+x; 230 zy=2.0*zx*zy+y; 231 zx=new_zx; 232 colorIdx=colorIdx+1; 233 } 234 int color = colorIdx<pallette->length?pallette->array[(long)colorIdx]:0; 235 s32Array2D->array[(long)kc.x]=color; 236 } 237 return; 238 } 239 ``` 240 241 Which we can convert to ptx using the nvcc compiler (on a NVDIA platform) 242 243 `nvcc -ptx mandel.cu -o mandel.ptx` 244 245 ``` 246 // 247 // Generated by NVIDIA NVVM Compiler 248 // 249 // Compiler Build ID: CL-33191640 250 // Cuda compilation tools, release 12.2, V12.2.140 251 // Based on NVVM 7.0.1 252 // 253 254 .version 8.2 255 .target sm_52 256 .address_size 64 257 258 // .globl mandel 259 260 .visible .entry mandel( 261 .param .u64 mandel_param_0, 262 .param .u64 mandel_param_1, 263 .param .f32 mandel_param_2, 264 .param .f32 mandel_param_3, 265 .param .f32 mandel_param_4 266 ) 267 { 268 .reg .pred %p<9>; 269 .reg .f32 %f<29>; 270 .reg .b32 %r<24>; 271 .reg .f64 %fd<22>; 272 .reg .b64 %rd<9>; 273 274 275 ld.param.u64 %rd3, [mandel_param_0]; 276 ld.param.u64 %rd4, [mandel_param_1]; 277 ld.param.f32 %f13, [mandel_param_2]; 278 ld.param.f32 %f14, [mandel_param_3]; 279 ld.param.f32 %f15, [mandel_param_4]; 280 cvta.to.global.u64 %rd1, %rd4; 281 cvta.to.global.u64 %rd2, %rd3; 282 mov.u32 %r8, %ntid.x; 283 mov.u32 %r9, %ctaid.x; 284 mov.u32 %r10, %tid.x; 285 mad.lo.s32 %r1, %r9, %r8, %r10; 286 mov.u32 %r11, %nctaid.x; 287 mul.lo.s32 %r12, %r11, %r8; 288 setp.ge.s32 %p1, %r1, %r12; 289 @%p1 bra $L__BB0_7; 290 291 ld.global.u32 %r14, [%rd2]; 292 cvt.rn.f32.s32 %f16, %r14; 293 ld.global.u32 %r15, [%rd2+4]; 294 cvt.rn.f32.s32 %f17, %r15; 295 div.s32 %r16, %r1, %r14; 296 mul.lo.s32 %r17, %r16, %r14; 297 sub.s32 %r18, %r1, %r17; 298 cvt.rn.f32.s32 %f18, %r18; 299 mul.f32 %f19, %f18, %f15; 300 cvt.f64.f32 %fd2, %f19; 301 cvt.f64.f32 %fd3, %f15; 302 mul.f64 %fd4, %fd3, 0d3FE0000000000000; 303 cvt.f64.f32 %fd5, %f16; 304 mul.f64 %fd6, %fd4, %fd5; 305 sub.f64 %fd7, %fd2, %fd6; 306 div.rn.f64 %fd8, %fd7, %fd5; 307 cvt.f64.f32 %fd9, %f13; 308 add.f64 %fd10, %fd8, %fd9; 309 cvt.rn.f32.f64 %f1, %fd10; 310 cvt.rn.f32.s32 %f20, %r16; 311 mul.f32 %f21, %f20, %f15; 312 cvt.f64.f32 %fd11, %f21; 313 cvt.f64.f32 %fd12, %f17; 314 mul.f64 %fd13, %fd4, %fd12; 315 sub.f64 %fd14, %fd11, %fd13; 316 div.rn.f64 %fd15, %fd14, %fd12; 317 cvt.f64.f32 %fd16, %f14; 318 add.f64 %fd17, %fd15, %fd16; 319 cvt.rn.f32.f64 %f27, %fd17; 320 ld.global.u32 %r2, [%rd1]; 321 setp.lt.s32 %p2, %r2, 1; 322 mov.u32 %r23, 0; 323 mul.f32 %f26, %f1, %f1; 324 mul.f32 %f25, %f27, %f27; 325 add.f32 %f22, %f26, %f25; 326 setp.geu.f32 %p3, %f22, 0f40800000; 327 or.pred %p4, %p2, %p3; 328 mov.u32 %r22, %r23; 329 @%p4 bra $L__BB0_4; 330 331 cvt.f64.f32 %fd1, %f27; 332 mov.f32 %f28, %f1; 333 334 $L__BB0_3: 335 sub.f32 %f23, %f26, %f25; 336 add.f32 %f9, %f23, %f1; 337 cvt.f64.f32 %fd18, %f28; 338 add.f64 %fd19, %fd18, %fd18; 339 cvt.f64.f32 %fd20, %f27; 340 fma.rn.f64 %fd21, %fd19, %fd20, %fd1; 341 cvt.rn.f32.f64 %f27, %fd21; 342 add.s32 %r22, %r22, 1; 343 setp.lt.s32 %p5, %r22, %r2; 344 mul.f32 %f26, %f9, %f9; 345 mul.f32 %f25, %f27, %f27; 346 add.f32 %f24, %f26, %f25; 347 setp.lt.f32 %p6, %f24, 0f40800000; 348 and.pred %p7, %p5, %p6; 349 mov.f32 %f28, %f9; 350 @%p7 bra $L__BB0_3; 351 352 $L__BB0_4: 353 setp.ge.s32 %p8, %r22, %r2; 354 @%p8 bra $L__BB0_6; 355 356 mul.wide.s32 %rd5, %r22, 4; 357 add.s64 %rd6, %rd1, %rd5; 358 ld.global.u32 %r23, [%rd6+4]; 359 360 $L__BB0_6: 361 mul.wide.s32 %rd7, %r1, 4; 362 add.s64 %rd8, %rd2, %rd7; 363 st.global.u32 [%rd8+8], %r23; 364 365 $L__BB0_7: 366 ret; 367 368 } 369 ``` 370 But we would like to create the ptx directly from the babylon model, without being on an NVidia platform. Probably the lowered model 371 372 We will probably use the lowered babylon model 373 374 ``` 375 func @"mandel" @loc="39:5:file:/Users/grfrost/orahub/hat/examples/mandel/src/java/mandel/MandelCompute.java" 376 (%0 : hat.KernelContext, %1 : hat.buffer.S32Array2D, %2 : hat.buffer.S32Array, %3 : float, %4 : float, %5 : float)void -> { 377 %6 : Var<hat.KernelContext> = var %0 @"kc" ; 378 %7 : Var<hat.buffer.S32Array2D> = var %1 @"s32Array2D" ; 379 %8 : Var<hat.buffer.S32Array> = var %2 @"pallette" ; 380 %9 : Var<float> = var %3 @"offsetx" ; 381 %10 : Var<float> = var %4 @"offsety" ; 382 %11 : Var<float> = var %5 @"scale" ; 383 %12 : hat.KernelContext = var.load %6 ; 384 %13 : int = field.load %12 @"hat.KernelContext::x()int" ; 385 %14 : hat.KernelContext = var.load %6 ; 386 %15 : int = field.load %14 @"hat.KernelContext::maxX()int" ; 387 %16 : boolean = lt %13 %15 ; 388 cbranch %16 ^block_0 ^block_1; 389 390 ^block_0: 391 %17 : hat.buffer.S32Array2D = var.load %7 ; 392 %18 : int = invoke %17 @"hat.buffer.S32Array2D::width()int" ; 393 %19 : float = conv %18 ; 394 %20 : Var<float> = var %19 @"width" ; 395 %21 : hat.buffer.S32Array2D = var.load %7 ; 396 %22 : int = invoke %21 @"hat.buffer.S32Array2D::height()int" ; 397 %23 : float = conv %22 ; 398 %24 : Var<float> = var %23 @"height" ; 399 %25 : hat.KernelContext = var.load %6 ; 400 %26 : int = field.load %25 @"hat.KernelContext::x()int" ; 401 %27 : hat.buffer.S32Array2D = var.load %7 ; 402 %28 : int = invoke %27 @"hat.buffer.S32Array2D::width()int" ; 403 %29 : int = mod %26 %28 ; 404 %30 : float = conv %29 ; 405 %31 : float = var.load %11 ; 406 %32 : float = mul %30 %31 ; 407 %33 : float = var.load %11 ; 408 %34 : float = constant @"2.0" ; 409 %35 : float = div %33 %34 ; 410 %36 : float = var.load %20 ; 411 %37 : float = mul %35 %36 ; 412 %38 : float = sub %32 %37 ; 413 %39 : float = var.load %20 ; 414 %40 : float = div %38 %39 ; 415 %41 : float = var.load %9 ; 416 %42 : float = add %40 %41 ; 417 %43 : Var<float> = var %42 @"x" ; 418 %44 : hat.KernelContext = var.load %6 ; 419 %45 : int = field.load %44 @"hat.KernelContext::x()int" ; 420 %46 : hat.buffer.S32Array2D = var.load %7 ; 421 %47 : int = invoke %46 @"hat.buffer.S32Array2D::width()int" ; 422 %48 : int = div %45 %47 ; 423 %49 : float = conv %48 ; 424 %50 : float = var.load %11 ; 425 %51 : float = mul %49 %50 ; 426 %52 : float = var.load %11 ; 427 %53 : float = constant @"2.0" ; 428 %54 : float = div %52 %53 ; 429 %55 : float = var.load %24 ; 430 %56 : float = mul %54 %55 ; 431 %57 : float = sub %51 %56 ; 432 %58 : float = var.load %24 ; 433 %59 : float = div %57 %58 ; 434 %60 : float = var.load %10 ; 435 %61 : float = add %59 %60 ; 436 %62 : Var<float> = var %61 @"y" ; 437 %63 : float = var.load %43 ; 438 %64 : Var<float> = var %63 @"zx" ; 439 %65 : float = var.load %62 ; 440 %66 : Var<float> = var %65 @"zy" ; 441 %67 : float = constant @"0.0" ; 442 %68 : Var<float> = var %67 @"new_zx" ; 443 %69 : int = constant @"0" ; 444 %70 : Var<int> = var %69 @"colorIdx" ; 445 branch ^block_2; 446 447 ^block_2: 448 %71 : int = var.load %70 ; 449 %72 : hat.buffer.S32Array = var.load %8 ; 450 %73 : int = invoke %72 @"hat.buffer.S32Array::length()int" ; 451 %74 : boolean = lt %71 %73 ; 452 cbranch %74 ^block_3 ^block_4(%74); 453 454 ^block_3: 455 %75 : float = var.load %64 ; 456 %76 : float = var.load %64 ; 457 %77 : float = mul %75 %76 ; 458 %78 : float = var.load %66 ; 459 %79 : float = var.load %66 ; 460 %80 : float = mul %78 %79 ; 461 %81 : float = add %77 %80 ; 462 %82 : float = constant @"4.0" ; 463 %83 : boolean = lt %81 %82 ; 464 branch ^block_4(%83); 465 466 ^block_4(%84 : boolean): 467 cbranch %84 ^block_5 ^block_6; 468 469 ^block_5: 470 %85 : float = var.load %64 ; 471 %86 : float = var.load %64 ; 472 %87 : float = mul %85 %86 ; 473 %88 : float = var.load %66 ; 474 %89 : float = var.load %66 ; 475 %90 : float = mul %88 %89 ; 476 %91 : float = sub %87 %90 ; 477 %92 : float = var.load %43 ; 478 %93 : float = add %91 %92 ; 479 var.store %68 %93 ; 480 %94 : float = constant @"2.0" ; 481 %95 : float = var.load %64 ; 482 %96 : float = mul %94 %95 ; 483 %97 : float = var.load %66 ; 484 %98 : float = mul %96 %97 ; 485 %99 : float = var.load %62 ; 486 %100 : float = add %98 %99 ; 487 var.store %66 %100 ; 488 %101 : float = var.load %68 ; 489 var.store %64 %101 ; 490 %102 : int = var.load %70 ; 491 %103 : int = constant @"1" ; 492 %104 : int = add %102 %103 ; 493 var.store %70 %104 ; 494 branch ^block_2; 495 496 ^block_6: 497 %105 : int = var.load %70 ; 498 %106 : hat.buffer.S32Array = var.load %8 ; 499 %107 : int = invoke %106 @"hat.buffer.S32Array::length()int" ; 500 %108 : boolean = lt %105 %107 ; 501 cbranch %108 ^block_7 ^block_8; 502 503 ^block_7: 504 %109 : hat.buffer.S32Array = var.load %8 ; 505 %110 : int = var.load %70 ; 506 %111 : long = conv %110 ; 507 %112 : int = invoke %109 %111 @"hat.buffer.S32Array::array(long)int" ; 508 branch ^block_9(%112); 509 510 ^block_8: 511 %113 : int = constant @"0" ; 512 branch ^block_9(%113); 513 514 ^block_9(%114 : int): 515 %115 : Var<int> = var %114 @"color" ; 516 %116 : hat.buffer.S32Array2D = var.load %7 ; 517 %117 : hat.KernelContext = var.load %6 ; 518 %118 : int = field.load %117 @"hat.KernelContext::x()int" ; 519 %119 : long = conv %118 ; 520 %120 : int = var.load %115 ; 521 invoke %116 %119 %120 @"hat.buffer.S32Array2D::array(long, int)void" ; 522 branch ^block_10; 523 524 ^block_1: 525 branch ^block_10; 526 527 ^block_10: 528 return ; 529 }; 530 ``` 531