301 lines · plain
1// Check that the wide integer emulation produces the same result as wide2// calculations. Emulate i16 ops with i8 ops.3 4// RUN: mlir-opt %s --test-arith-emulate-wide-int="widest-int-supported=8" \5// RUN: --convert-vector-to-scf --convert-scf-to-cf --convert-cf-to-llvm \6// RUN: --convert-vector-to-llvm --convert-func-to-llvm --convert-arith-to-llvm \7// RUN: --reconcile-unrealized-casts | \8// RUN: mlir-runner -e entry -entry-point-result=void \9// RUN: --shared-libs="%mlir_c_runner_utils,%mlir_runner_utils" | \10// RUN: FileCheck %s11 12// CHECK-NOT: Mismatch13 14//===----------------------------------------------------------------------===//15// Common Utility Functions16//===----------------------------------------------------------------------===//17 18// Prints both binary op operands and the first result. If the second result19// does not match, prints the second result and a 'Mismatch' message.20func.func @check_results(%lhs : i16, %rhs : i16, %res0 : i16, %res1 : i16) -> () {21 %vec_zero = arith.constant dense<0> : vector<2xi16>22 %ins0 = vector.insert %lhs, %vec_zero[0] : i16 into vector<2xi16>23 %operands = vector.insert %rhs, %ins0[1] : i16 into vector<2xi16>24 vector.print %operands : vector<2xi16>25 vector.print %res0 : i1626 %mismatch = arith.cmpi ne, %res0, %res1 : i1627 scf.if %mismatch -> () {28 vector.print %res1 : i1629 vector.print str "Mismatch\n"30 }31 return32}33 34func.func @xorshift(%i : i16) -> (i16) {35 %cst8 = arith.constant 8 : i1636 %shifted = arith.shrui %i, %cst8 : i1637 %res = arith.xori %i, %shifted : i1638 return %res : i1639}40 41// Returns a hash of the input number. This is used we want to sample a bunch42// of i16 inputs with close to uniform distribution but without fixed offsets43// between each sample.44func.func @xhash(%i : i16) -> (i16) {45 %pattern = arith.constant 21845 : i16 // Alternating ones and zeros.46 %prime = arith.constant 25867 : i16 // Large i16 prime.47 %xi = func.call @xorshift(%i) : (i16) -> (i16)48 %inner = arith.muli %xi, %pattern : i1649 %xinner = func.call @xorshift(%inner) : (i16) -> (i16)50 %res = arith.muli %xinner, %prime : i1651 return %res : i1652}53 54//===----------------------------------------------------------------------===//55// Test arith.addi56//===----------------------------------------------------------------------===//57 58// Ops in this function will be emulated using i8 ops.59func.func @emulate_addi(%lhs : i16, %rhs : i16) -> (i16) {60 %res = arith.addi %lhs, %rhs : i1661 return %res : i1662}63 64// Performs both wide and emulated `arith.muli`, and checks that the results65// match.66func.func @check_addi(%lhs : i16, %rhs : i16) -> () {67 %wide = arith.addi %lhs, %rhs : i1668 %emulated = func.call @emulate_addi(%lhs, %rhs) : (i16, i16) -> (i16)69 func.call @check_results(%lhs, %rhs, %wide, %emulated) : (i16, i16, i16, i16) -> ()70 return71}72 73// Checks that `arith.addi` is emulated properly by sampling the input space.74// In total, this test function checks 500 * 500 = 250k input pairs.75func.func @test_addi() -> () {76 %idx0 = arith.constant 0 : index77 %idx1 = arith.constant 1 : index78 %idx500 = arith.constant 500 : index79 80 %cst0 = arith.constant 0 : i1681 %cst1 = arith.constant 1 : i1682 83 scf.for %lhs_idx = %idx0 to %idx500 step %idx1 iter_args(%lhs = %cst0) -> (i16) {84 %arg_lhs = func.call @xhash(%lhs) : (i16) -> (i16)85 86 scf.for %rhs_idx = %idx0 to %idx500 step %idx1 iter_args(%rhs = %cst0) -> (i16) {87 %arg_rhs = func.call @xhash(%rhs) : (i16) -> (i16)88 func.call @check_addi(%arg_lhs, %arg_rhs) : (i16, i16) -> ()89 90 %rhs_next = arith.addi %rhs, %cst1 : i1691 scf.yield %rhs_next : i1692 }93 94 %lhs_next = arith.addi %lhs, %cst1 : i1695 scf.yield %lhs_next : i1696 }97 98 return99}100 101//===----------------------------------------------------------------------===//102// Test arith.muli103//===----------------------------------------------------------------------===//104 105// Ops in this function will be emulated using i8 ops.106func.func @emulate_muli(%lhs : i16, %rhs : i16) -> (i16) {107 %res = arith.muli %lhs, %rhs : i16108 return %res : i16109}110 111// Performs both wide and emulated `arith.muli`, and checks that the results112// match.113func.func @check_muli(%lhs : i16, %rhs : i16) -> () {114 %wide = arith.muli %lhs, %rhs : i16115 %emulated = func.call @emulate_muli(%lhs, %rhs) : (i16, i16) -> (i16)116 func.call @check_results(%lhs, %rhs, %wide, %emulated) : (i16, i16, i16, i16) -> ()117 return118}119 120// Checks that `arith.muli` is emulated properly by sampling the input space.121// In total, this test function checks 500 * 500 = 250k input pairs.122func.func @test_muli() -> () {123 %idx0 = arith.constant 0 : index124 %idx1 = arith.constant 1 : index125 %idx500 = arith.constant 500 : index126 127 %cst0 = arith.constant 0 : i16128 %cst1 = arith.constant 1 : i16129 130 scf.for %lhs_idx = %idx0 to %idx500 step %idx1 iter_args(%lhs = %cst0) -> (i16) {131 %arg_lhs = func.call @xhash(%lhs) : (i16) -> (i16)132 133 scf.for %rhs_idx = %idx0 to %idx500 step %idx1 iter_args(%rhs = %cst0) -> (i16) {134 %arg_rhs = func.call @xhash(%rhs) : (i16) -> (i16)135 func.call @check_muli(%arg_lhs, %arg_rhs) : (i16, i16) -> ()136 137 %rhs_next = arith.addi %rhs, %cst1 : i16138 scf.yield %rhs_next : i16139 }140 141 %lhs_next = arith.addi %lhs, %cst1 : i16142 scf.yield %lhs_next : i16143 }144 145 return146}147 148//===----------------------------------------------------------------------===//149// Test arith.shli150//===----------------------------------------------------------------------===//151 152// Ops in this function will be emulated using i8 ops.153func.func @emulate_shli(%lhs : i16, %rhs : i16) -> (i16) {154 %res = arith.shli %lhs, %rhs : i16155 return %res : i16156}157 158// Performs both wide and emulated `arith.shli`, and checks that the results159// match.160func.func @check_shli(%lhs : i16, %rhs : i16) -> () {161 %wide = arith.shli %lhs, %rhs : i16162 %emulated = func.call @emulate_shli(%lhs, %rhs) : (i16, i16) -> (i16)163 func.call @check_results(%lhs, %rhs, %wide, %emulated) : (i16, i16, i16, i16) -> ()164 return165}166 167// Checks that `arith.shli` is emulated properly by sampling the input space.168// Checks all valid shift amounts for i16: 0 to 15.169// In total, this test function checks 100 * 16 = 1.6k input pairs.170func.func @test_shli() -> () {171 %idx0 = arith.constant 0 : index172 %idx1 = arith.constant 1 : index173 %idx16 = arith.constant 16 : index174 %idx100 = arith.constant 100 : index175 176 %cst0 = arith.constant 0 : i16177 %cst1 = arith.constant 1 : i16178 179 scf.for %lhs_idx = %idx0 to %idx100 step %idx1 iter_args(%lhs = %cst0) -> (i16) {180 %arg_lhs = func.call @xhash(%lhs) : (i16) -> (i16)181 182 scf.for %rhs_idx = %idx0 to %idx16 step %idx1 iter_args(%rhs = %cst0) -> (i16) {183 func.call @check_shli(%arg_lhs, %rhs) : (i16, i16) -> ()184 %rhs_next = arith.addi %rhs, %cst1 : i16185 scf.yield %rhs_next : i16186 }187 188 %lhs_next = arith.addi %lhs, %cst1 : i16189 scf.yield %lhs_next : i16190 }191 192 return193}194 195//===----------------------------------------------------------------------===//196// Test arith.shrsi197//===----------------------------------------------------------------------===//198 199// Ops in this function will be emulated using i8 ops.200func.func @emulate_shrsi(%lhs : i16, %rhs : i16) -> (i16) {201 %res = arith.shrsi %lhs, %rhs : i16202 return %res : i16203}204 205// Performs both wide and emulated `arith.shrsi`, and checks that the results206// match.207func.func @check_shrsi(%lhs : i16, %rhs : i16) -> () {208 %wide = arith.shrsi %lhs, %rhs : i16209 %emulated = func.call @emulate_shrsi(%lhs, %rhs) : (i16, i16) -> (i16)210 func.call @check_results(%lhs, %rhs, %wide, %emulated) : (i16, i16, i16, i16) -> ()211 return212}213 214// Checks that `arith.shrus` is emulated properly by sampling the input space.215// Checks all valid shift amounts for i16: 0 to 15.216// In total, this test function checks 100 * 16 = 1.6k input pairs.217func.func @test_shrsi() -> () {218 %idx0 = arith.constant 0 : index219 %idx1 = arith.constant 1 : index220 %idx16 = arith.constant 16 : index221 %idx100 = arith.constant 100 : index222 223 %cst0 = arith.constant 0 : i16224 %cst1 = arith.constant 1 : i16225 226 scf.for %lhs_idx = %idx0 to %idx100 step %idx1 iter_args(%lhs = %cst0) -> (i16) {227 %arg_lhs = func.call @xhash(%lhs) : (i16) -> (i16)228 229 scf.for %rhs_idx = %idx0 to %idx16 step %idx1 iter_args(%rhs = %cst0) -> (i16) {230 func.call @check_shrsi(%arg_lhs, %rhs) : (i16, i16) -> ()231 %rhs_next = arith.addi %rhs, %cst1 : i16232 scf.yield %rhs_next : i16233 }234 235 %lhs_next = arith.addi %lhs, %cst1 : i16236 scf.yield %lhs_next : i16237 }238 239 return240}241 242//===----------------------------------------------------------------------===//243// Test arith.shrui244//===----------------------------------------------------------------------===//245 246// Ops in this function will be emulated using i8 ops.247func.func @emulate_shrui(%lhs : i16, %rhs : i16) -> (i16) {248 %res = arith.shrui %lhs, %rhs : i16249 return %res : i16250}251 252// Performs both wide and emulated `arith.shrui`, and checks that the results253// match.254func.func @check_shrui(%lhs : i16, %rhs : i16) -> () {255 %wide = arith.shrui %lhs, %rhs : i16256 %emulated = func.call @emulate_shrui(%lhs, %rhs) : (i16, i16) -> (i16)257 func.call @check_results(%lhs, %rhs, %wide, %emulated) : (i16, i16, i16, i16) -> ()258 return259}260 261// Checks that `arith.shrui` is emulated properly by sampling the input space.262// Checks all valid shift amounts for i16: 0 to 15.263// In total, this test function checks 100 * 16 = 1.6k input pairs.264func.func @test_shrui() -> () {265 %idx0 = arith.constant 0 : index266 %idx1 = arith.constant 1 : index267 %idx16 = arith.constant 16 : index268 %idx100 = arith.constant 100 : index269 270 %cst0 = arith.constant 0 : i16271 %cst1 = arith.constant 1 : i16272 273 scf.for %lhs_idx = %idx0 to %idx100 step %idx1 iter_args(%lhs = %cst0) -> (i16) {274 %arg_lhs = func.call @xhash(%lhs) : (i16) -> (i16)275 276 scf.for %rhs_idx = %idx0 to %idx16 step %idx1 iter_args(%rhs = %cst0) -> (i16) {277 func.call @check_shrui(%arg_lhs, %rhs) : (i16, i16) -> ()278 %rhs_next = arith.addi %rhs, %cst1 : i16279 scf.yield %rhs_next : i16280 }281 282 %lhs_next = arith.addi %lhs, %cst1 : i16283 scf.yield %lhs_next : i16284 }285 286 return287}288 289//===----------------------------------------------------------------------===//290// Entry Point291//===----------------------------------------------------------------------===//292 293func.func @entry() {294 func.call @test_addi() : () -> ()295 func.call @test_muli() : () -> ()296 func.call @test_shli() : () -> ()297 func.call @test_shrsi() : () -> ()298 func.call @test_shrui() : () -> ()299 return300}301