1*392622d0SMaksim Levental# RUN: %PYTHON %s pybind11 | FileCheck %s 2*392622d0SMaksim Levental# RUN: %PYTHON %s nanobind | FileCheck %s 39f3f6d7bSStella Laurenzo 4*392622d0SMaksim Leventalimport sys 59f3f6d7bSStella Laurenzofrom mlir.ir import * 6f22008edSArash Taheri-Dezfouliimport mlir.dialects.func as func 79f3f6d7bSStella Laurenzoimport mlir.dialects.python_test as test 869cc3cfbSmaximport mlir.dialects.tensor as tensor 9e0ca7e99Smaximport mlir.dialects.arith as arith 109f3f6d7bSStella Laurenzo 11*392622d0SMaksim Leventalif sys.argv[1] == "pybind11": 12*392622d0SMaksim Levental from mlir._mlir_libs._mlirPythonTestPybind11 import ( 13*392622d0SMaksim Levental TestAttr, 14*392622d0SMaksim Levental TestType, 15*392622d0SMaksim Levental TestTensorValue, 16*392622d0SMaksim Levental TestIntegerRankedTensorType, 17*392622d0SMaksim Levental ) 18*392622d0SMaksim Levental 19*392622d0SMaksim Levental test.register_python_test_dialect(get_dialect_registry(), use_nanobind=False) 20*392622d0SMaksim Leventalelif sys.argv[1] == "nanobind": 21*392622d0SMaksim Levental from mlir._mlir_libs._mlirPythonTestNanobind import ( 22*392622d0SMaksim Levental TestAttr, 23*392622d0SMaksim Levental TestType, 24*392622d0SMaksim Levental TestTensorValue, 25*392622d0SMaksim Levental TestIntegerRankedTensorType, 26*392622d0SMaksim Levental ) 27*392622d0SMaksim Levental 28*392622d0SMaksim Levental test.register_python_test_dialect(get_dialect_registry(), use_nanobind=True) 29*392622d0SMaksim Leventalelse: 30*392622d0SMaksim Levental raise ValueError("Expected pybind11 or nanobind as argument") 3117ec364bSMaksim Levental 32f9008e63STobias Hieta 339f3f6d7bSStella Laurenzodef run(f): 349f3f6d7bSStella Laurenzo print("\nTEST:", f.__name__) 359f3f6d7bSStella Laurenzo f() 3614c92070SAlex Zinenko return f 379f3f6d7bSStella Laurenzo 38f9008e63STobias Hieta 399f3f6d7bSStella Laurenzo# CHECK-LABEL: TEST: testAttributes 4014c92070SAlex Zinenko@run 419f3f6d7bSStella Laurenzodef testAttributes(): 420f9e6451SMehdi Amini with Context() as ctx, Location.unknown(): 439f3f6d7bSStella Laurenzo # 449f3f6d7bSStella Laurenzo # Check op construction with attributes. 459f3f6d7bSStella Laurenzo # 469f3f6d7bSStella Laurenzo 479f3f6d7bSStella Laurenzo i32 = IntegerType.get_signless(32) 489f3f6d7bSStella Laurenzo one = IntegerAttr.get(i32, 1) 499f3f6d7bSStella Laurenzo two = IntegerAttr.get(i32, 2) 509f3f6d7bSStella Laurenzo unit = UnitAttr.get() 519f3f6d7bSStella Laurenzo 522ab14dffSMaksim Levental # CHECK: python_test.attributed_op { 539f3f6d7bSStella Laurenzo # CHECK-DAG: mandatory_i32 = 1 : i32 549f3f6d7bSStella Laurenzo # CHECK-DAG: optional_i32 = 2 : i32 559f3f6d7bSStella Laurenzo # CHECK-DAG: unit 569f3f6d7bSStella Laurenzo # CHECK: } 579b79f50bSJeremy Furtek op = test.AttributedOp(one, optional_i32=two, unit=unit) 589f3f6d7bSStella Laurenzo print(f"{op}") 599f3f6d7bSStella Laurenzo 602ab14dffSMaksim Levental # CHECK: python_test.attributed_op { 619f3f6d7bSStella Laurenzo # CHECK: mandatory_i32 = 2 : i32 629f3f6d7bSStella Laurenzo # CHECK: } 639b79f50bSJeremy Furtek op2 = test.AttributedOp(two) 649f3f6d7bSStella Laurenzo print(f"{op2}") 659f3f6d7bSStella Laurenzo 669f3f6d7bSStella Laurenzo # 679f3f6d7bSStella Laurenzo # Check generic "attributes" access and mutation. 689f3f6d7bSStella Laurenzo # 699f3f6d7bSStella Laurenzo 709f3f6d7bSStella Laurenzo assert "additional" not in op.attributes 719f3f6d7bSStella Laurenzo 722ab14dffSMaksim Levental # CHECK: python_test.attributed_op { 739f3f6d7bSStella Laurenzo # CHECK-DAG: additional = 1 : i32 749f3f6d7bSStella Laurenzo # CHECK-DAG: mandatory_i32 = 2 : i32 759f3f6d7bSStella Laurenzo # CHECK: } 769f3f6d7bSStella Laurenzo op2.attributes["additional"] = one 779f3f6d7bSStella Laurenzo print(f"{op2}") 789f3f6d7bSStella Laurenzo 792ab14dffSMaksim Levental # CHECK: python_test.attributed_op { 809f3f6d7bSStella Laurenzo # CHECK-DAG: additional = 2 : i32 819f3f6d7bSStella Laurenzo # CHECK-DAG: mandatory_i32 = 2 : i32 829f3f6d7bSStella Laurenzo # CHECK: } 839f3f6d7bSStella Laurenzo op2.attributes["additional"] = two 849f3f6d7bSStella Laurenzo print(f"{op2}") 859f3f6d7bSStella Laurenzo 862ab14dffSMaksim Levental # CHECK: python_test.attributed_op { 879f3f6d7bSStella Laurenzo # CHECK-NOT: additional = 2 : i32 889f3f6d7bSStella Laurenzo # CHECK: mandatory_i32 = 2 : i32 899f3f6d7bSStella Laurenzo # CHECK: } 909f3f6d7bSStella Laurenzo del op2.attributes["additional"] 919f3f6d7bSStella Laurenzo print(f"{op2}") 929f3f6d7bSStella Laurenzo 939f3f6d7bSStella Laurenzo try: 949f3f6d7bSStella Laurenzo print(op.attributes["additional"]) 959f3f6d7bSStella Laurenzo except KeyError: 969f3f6d7bSStella Laurenzo pass 979f3f6d7bSStella Laurenzo else: 989f3f6d7bSStella Laurenzo assert False, "expected KeyError on unknown attribute key" 999f3f6d7bSStella Laurenzo 1009f3f6d7bSStella Laurenzo # 1019f3f6d7bSStella Laurenzo # Check accessors to defined attributes. 1029f3f6d7bSStella Laurenzo # 1039f3f6d7bSStella Laurenzo 1049f3f6d7bSStella Laurenzo # CHECK: Mandatory: 1 1059f3f6d7bSStella Laurenzo # CHECK: Optional: 2 1069f3f6d7bSStella Laurenzo # CHECK: Unit: True 1079f3f6d7bSStella Laurenzo print(f"Mandatory: {op.mandatory_i32.value}") 1089f3f6d7bSStella Laurenzo print(f"Optional: {op.optional_i32.value}") 1099f3f6d7bSStella Laurenzo print(f"Unit: {op.unit}") 1109f3f6d7bSStella Laurenzo 1119f3f6d7bSStella Laurenzo # CHECK: Mandatory: 2 1129f3f6d7bSStella Laurenzo # CHECK: Optional: None 1139f3f6d7bSStella Laurenzo # CHECK: Unit: False 1149f3f6d7bSStella Laurenzo print(f"Mandatory: {op2.mandatory_i32.value}") 1159f3f6d7bSStella Laurenzo print(f"Optional: {op2.optional_i32}") 1169f3f6d7bSStella Laurenzo print(f"Unit: {op2.unit}") 1179f3f6d7bSStella Laurenzo 1189f3f6d7bSStella Laurenzo # CHECK: Mandatory: 2 1199f3f6d7bSStella Laurenzo # CHECK: Optional: None 1209f3f6d7bSStella Laurenzo # CHECK: Unit: False 1219f3f6d7bSStella Laurenzo op.mandatory_i32 = two 1229f3f6d7bSStella Laurenzo op.optional_i32 = None 1239f3f6d7bSStella Laurenzo op.unit = False 1249f3f6d7bSStella Laurenzo print(f"Mandatory: {op.mandatory_i32.value}") 1259f3f6d7bSStella Laurenzo print(f"Optional: {op.optional_i32}") 1269f3f6d7bSStella Laurenzo print(f"Unit: {op.unit}") 1279f3f6d7bSStella Laurenzo assert "optional_i32" not in op.attributes 1289f3f6d7bSStella Laurenzo assert "unit" not in op.attributes 1299f3f6d7bSStella Laurenzo 1309f3f6d7bSStella Laurenzo try: 1319f3f6d7bSStella Laurenzo op.mandatory_i32 = None 1329f3f6d7bSStella Laurenzo except ValueError: 1339f3f6d7bSStella Laurenzo pass 1349f3f6d7bSStella Laurenzo else: 1359f3f6d7bSStella Laurenzo assert False, "expected ValueError on setting a mandatory attribute to None" 1369f3f6d7bSStella Laurenzo 1379f3f6d7bSStella Laurenzo # CHECK: Optional: 2 1389f3f6d7bSStella Laurenzo op.optional_i32 = two 1399f3f6d7bSStella Laurenzo print(f"Optional: {op.optional_i32.value}") 1409f3f6d7bSStella Laurenzo 1419f3f6d7bSStella Laurenzo # CHECK: Optional: None 1429f3f6d7bSStella Laurenzo del op.optional_i32 1439f3f6d7bSStella Laurenzo print(f"Optional: {op.optional_i32}") 1449f3f6d7bSStella Laurenzo 1459f3f6d7bSStella Laurenzo # CHECK: Unit: False 1469f3f6d7bSStella Laurenzo op.unit = None 1479f3f6d7bSStella Laurenzo print(f"Unit: {op.unit}") 1489f3f6d7bSStella Laurenzo assert "unit" not in op.attributes 1499f3f6d7bSStella Laurenzo 1509f3f6d7bSStella Laurenzo # CHECK: Unit: True 1519f3f6d7bSStella Laurenzo op.unit = True 1529f3f6d7bSStella Laurenzo print(f"Unit: {op.unit}") 1539f3f6d7bSStella Laurenzo 1549f3f6d7bSStella Laurenzo # CHECK: Unit: False 1559f3f6d7bSStella Laurenzo del op.unit 1569f3f6d7bSStella Laurenzo print(f"Unit: {op.unit}") 1579f3f6d7bSStella Laurenzo 158f9008e63STobias Hieta 159c606fefaSpengchao.hu# CHECK-LABEL: TEST: attrBuilder 160c606fefaSpengchao.hu@run 161c606fefaSpengchao.hudef attrBuilder(): 162c606fefaSpengchao.hu with Context() as ctx, Location.unknown(): 163ca23c933SIngo Müller # CHECK: python_test.attributes_op 164f9008e63STobias Hieta op = test.AttributesOp( 165ca23c933SIngo Müller # CHECK-DAG: x_affinemap = affine_map<() -> (2)> 166ca23c933SIngo Müller x_affinemap=AffineMap.get_constant(2), 167ca23c933SIngo Müller # CHECK-DAG: x_affinemaparr = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>] 168ca23c933SIngo Müller x_affinemaparr=[AffineMap.get_identity(3)], 169ca23c933SIngo Müller # CHECK-DAG: x_arr = [true, "x"] 170ca23c933SIngo Müller x_arr=[BoolAttr.get(True), StringAttr.get("x")], 171ca23c933SIngo Müller x_boolarr=[False, True], # CHECK-DAG: x_boolarr = [false, true] 172ca23c933SIngo Müller x_bool=True, # CHECK-DAG: x_bool = true 173ca23c933SIngo Müller x_dboolarr=[True, False], # CHECK-DAG: x_dboolarr = array<i1: true, false> 174ca23c933SIngo Müller x_df16arr=[21, 22], # CHECK-DAG: x_df16arr = array<i16: 21, 22> 175ca23c933SIngo Müller # CHECK-DAG: x_df32arr = array<f32: 2.300000e+01, 2.400000e+01> 176ca23c933SIngo Müller x_df32arr=[23, 24], 177ca23c933SIngo Müller # CHECK-DAG: x_df64arr = array<f64: 2.500000e+01, 2.600000e+01> 178ca23c933SIngo Müller x_df64arr=[25, 26], 179ca23c933SIngo Müller x_di32arr=[0, 1], # CHECK-DAG: x_di32arr = array<i32: 0, 1> 180ca23c933SIngo Müller # CHECK-DAG: x_di64arr = array<i64: 1, 2> 181ca23c933SIngo Müller x_di64arr=[1, 2], 182ca23c933SIngo Müller x_di8arr=[2, 3], # CHECK-DAG: x_di8arr = array<i8: 2, 3> 183ca23c933SIngo Müller # CHECK-DAG: x_dictarr = [{a = false}] 184ca23c933SIngo Müller x_dictarr=[{"a": BoolAttr.get(False)}], 185ca23c933SIngo Müller x_dict={"b": BoolAttr.get(True)}, # CHECK-DAG: x_dict = {b = true} 186ca23c933SIngo Müller x_f32=-2.25, # CHECK-DAG: x_f32 = -2.250000e+00 : f32 187ca23c933SIngo Müller # CHECK-DAG: x_f32arr = [2.000000e+00 : f32, 3.000000e+00 : f32] 188ca23c933SIngo Müller x_f32arr=[2.0, 3.0], 189ca23c933SIngo Müller x_f64=4.25, # CHECK-DAG: x_f64 = 4.250000e+00 : f64 190ca23c933SIngo Müller x_f64arr=[4.0, 8.0], # CHECK-DAG: x_f64arr = [4.000000e+00, 8.000000e+00] 19110ec0d20SYuanqiang Liu # CHECK-DAG: x_f64elems = dense<[8.000000e+00, 1.600000e+01]> : tensor<2xf64> 192ca23c933SIngo Müller x_f64elems=[8.0, 16.0], 193ca23c933SIngo Müller # CHECK-DAG: x_flatsymrefarr = [@symbol1, @symbol2] 194ca23c933SIngo Müller x_flatsymrefarr=["symbol1", "symbol2"], 195ca23c933SIngo Müller x_flatsymref="symbol3", # CHECK-DAG: x_flatsymref = @symbol3 196ca23c933SIngo Müller x_i1=0, # CHECK-DAG: x_i1 = false 197ca23c933SIngo Müller x_i16=42, # CHECK-DAG: x_i16 = 42 : i16 198ca23c933SIngo Müller x_i32=6, # CHECK-DAG: x_i32 = 6 : i32 199ca23c933SIngo Müller x_i32arr=[4, 5], # CHECK-DAG: x_i32arr = [4 : i32, 5 : i32] 2002ab14dffSMaksim Levental x_i32elems=[5, 6], # CHECK-DAG: x_i32elems = dense<[5, 6]> : tensor<2xi32> 201ca23c933SIngo Müller x_i64=9, # CHECK-DAG: x_i64 = 9 : i64 202ca23c933SIngo Müller x_i64arr=[7, 8], # CHECK-DAG: x_i64arr = [7, 8] 2032ab14dffSMaksim Levental x_i64elems=[8, 9], # CHECK-DAG: x_i64elems = dense<[8, 9]> : tensor<2xi64> 204ca23c933SIngo Müller x_i64svecarr=[10, 11], # CHECK-DAG: x_i64svecarr = [10, 11] 205ca23c933SIngo Müller x_i8=11, # CHECK-DAG: x_i8 = 11 : i8 206ca23c933SIngo Müller x_idx=10, # CHECK-DAG: x_idx = 10 : index 207ca23c933SIngo Müller # CHECK-DAG: x_idxelems = dense<[11, 12]> : tensor<2xindex> 208ca23c933SIngo Müller x_idxelems=[11, 12], 209ca23c933SIngo Müller # CHECK-DAG: x_idxlistarr = [{{\[}}13], [14, 15]] 210ca23c933SIngo Müller x_idxlistarr=[[13], [14, 15]], 211ca23c933SIngo Müller x_si1=-1, # CHECK-DAG: x_si1 = -1 : si1 212ca23c933SIngo Müller x_si16=-2, # CHECK-DAG: x_si16 = -2 : si16 213ca23c933SIngo Müller x_si32=-3, # CHECK-DAG: x_si32 = -3 : si32 214ca23c933SIngo Müller x_si64=-123, # CHECK-DAG: x_si64 = -123 : si64 215ca23c933SIngo Müller x_si8=-4, # CHECK-DAG: x_si8 = -4 : si8 216ca23c933SIngo Müller x_strarr=["hello", "world"], # CHECK-DAG: x_strarr = ["hello", "world"] 217ca23c933SIngo Müller x_str="hello world!", # CHECK-DAG: x_str = "hello world!" 218ca23c933SIngo Müller # CHECK-DAG: x_symrefarr = [@flatsym, @deep::@sym] 219ca23c933SIngo Müller x_symrefarr=["flatsym", ["deep", "sym"]], 220ca23c933SIngo Müller x_symref=["deep", "sym2"], # CHECK-DAG: x_symref = @deep::@sym2 221ca23c933SIngo Müller x_sym="symbol", # CHECK-DAG: x_sym = "symbol" 222ca23c933SIngo Müller x_typearr=[F32Type.get()], # CHECK-DAG: x_typearr = [f32] 223ca23c933SIngo Müller x_type=F64Type.get(), # CHECK-DAG: x_type = f64 224ca23c933SIngo Müller x_ui1=1, # CHECK-DAG: x_ui1 = 1 : ui1 225ca23c933SIngo Müller x_ui16=2, # CHECK-DAG: x_ui16 = 2 : ui16 226ca23c933SIngo Müller x_ui32=3, # CHECK-DAG: x_ui32 = 3 : ui32 227ca23c933SIngo Müller x_ui64=4, # CHECK-DAG: x_ui64 = 4 : ui64 228ca23c933SIngo Müller x_ui8=5, # CHECK-DAG: x_ui8 = 5 : ui8 229ca23c933SIngo Müller x_unit=True, # CHECK-DAG: x_unit 230f9008e63STobias Hieta ) 231ca23c933SIngo Müller op.verify() 232ca23c933SIngo Müller op.print(use_local_scope=True) 233c606fefaSpengchao.hu 23414c92070SAlex Zinenko 23514c92070SAlex Zinenko# CHECK-LABEL: TEST: inferReturnTypes 23614c92070SAlex Zinenko@run 23714c92070SAlex Zinenkodef inferReturnTypes(): 23814c92070SAlex Zinenko with Context() as ctx, Location.unknown(ctx): 23914c92070SAlex Zinenko module = Module.create() 24014c92070SAlex Zinenko with InsertionPoint(module.body): 2412995d29bSAlex Zinenko op = test.InferResultsOp() 24214c92070SAlex Zinenko dummy = test.DummyOp() 24314c92070SAlex Zinenko 24414c92070SAlex Zinenko # CHECK: [Type(i32), Type(i64)] 24514c92070SAlex Zinenko iface = InferTypeOpInterface(op) 24614c92070SAlex Zinenko print(iface.inferReturnTypes()) 24714c92070SAlex Zinenko 24814c92070SAlex Zinenko # CHECK: [Type(i32), Type(i64)] 24914c92070SAlex Zinenko iface_static = InferTypeOpInterface(test.InferResultsOp) 25014c92070SAlex Zinenko print(iface.inferReturnTypes()) 25114c92070SAlex Zinenko 25214c92070SAlex Zinenko assert isinstance(iface.opview, test.InferResultsOp) 25314c92070SAlex Zinenko assert iface.opview == iface.operation.opview 25414c92070SAlex Zinenko 25514c92070SAlex Zinenko try: 25614c92070SAlex Zinenko iface_static.opview 25714c92070SAlex Zinenko except TypeError: 25814c92070SAlex Zinenko pass 25914c92070SAlex Zinenko else: 260f9008e63STobias Hieta assert False, ( 261f9008e63STobias Hieta "not expected to be able to obtain an opview from a static" " interface" 262f9008e63STobias Hieta ) 26314c92070SAlex Zinenko 26414c92070SAlex Zinenko try: 26514c92070SAlex Zinenko InferTypeOpInterface(dummy) 26614c92070SAlex Zinenko except ValueError: 26714c92070SAlex Zinenko pass 26814c92070SAlex Zinenko else: 26914c92070SAlex Zinenko assert False, "not expected dummy op to implement the interface" 27014c92070SAlex Zinenko 27114c92070SAlex Zinenko try: 27214c92070SAlex Zinenko InferTypeOpInterface(test.DummyOp) 27314c92070SAlex Zinenko except ValueError: 27414c92070SAlex Zinenko pass 27514c92070SAlex Zinenko else: 27614c92070SAlex Zinenko assert False, "not expected dummy op class to implement the interface" 2772995d29bSAlex Zinenko 2782995d29bSAlex Zinenko 2792995d29bSAlex Zinenko# CHECK-LABEL: TEST: resultTypesDefinedByTraits 2802995d29bSAlex Zinenko@run 2812995d29bSAlex Zinenkodef resultTypesDefinedByTraits(): 2822995d29bSAlex Zinenko with Context() as ctx, Location.unknown(ctx): 2832995d29bSAlex Zinenko module = Module.create() 2842995d29bSAlex Zinenko with InsertionPoint(module.body): 2852995d29bSAlex Zinenko inferred = test.InferResultsOp() 2862995d29bSAlex Zinenko same = test.SameOperandAndResultTypeOp([inferred.results[0]]) 2872995d29bSAlex Zinenko # CHECK-COUNT-2: i32 2882995d29bSAlex Zinenko print(same.one.type) 2892995d29bSAlex Zinenko print(same.two.type) 2902995d29bSAlex Zinenko 2912995d29bSAlex Zinenko first_type_attr = test.FirstAttrDeriveTypeAttrOp( 292f9008e63STobias Hieta inferred.results[1], TypeAttr.get(IndexType.get()) 293f9008e63STobias Hieta ) 2942995d29bSAlex Zinenko # CHECK-COUNT-2: index 2952995d29bSAlex Zinenko print(first_type_attr.one.type) 2962995d29bSAlex Zinenko print(first_type_attr.two.type) 2972995d29bSAlex Zinenko 298f9008e63STobias Hieta first_attr = test.FirstAttrDeriveAttrOp(FloatAttr.get(F32Type.get(), 3.14)) 2992995d29bSAlex Zinenko # CHECK-COUNT-3: f32 3002995d29bSAlex Zinenko print(first_attr.one.type) 3012995d29bSAlex Zinenko print(first_attr.two.type) 3022995d29bSAlex Zinenko print(first_attr.three.type) 3032995d29bSAlex Zinenko 3042995d29bSAlex Zinenko implied = test.InferResultsImpliedOp() 3052995d29bSAlex Zinenko # CHECK: i32 3062995d29bSAlex Zinenko print(implied.integer.type) 3072995d29bSAlex Zinenko # CHECK: f64 3082995d29bSAlex Zinenko print(implied.flt.type) 3092995d29bSAlex Zinenko # CHECK: index 3102995d29bSAlex Zinenko print(implied.index.type) 31154c99842SMichal Terepeta 31254c99842SMichal Terepeta 31354c99842SMichal Terepeta# CHECK-LABEL: TEST: testOptionalOperandOp 31454c99842SMichal Terepeta@run 31554c99842SMichal Terepetadef testOptionalOperandOp(): 31654c99842SMichal Terepeta with Context() as ctx, Location.unknown(): 31754c99842SMichal Terepeta module = Module.create() 31854c99842SMichal Terepeta with InsertionPoint(module.body): 3199b79f50bSJeremy Furtek op1 = test.OptionalOperandOp() 32054c99842SMichal Terepeta # CHECK: op1.input is None: True 32154c99842SMichal Terepeta print(f"op1.input is None: {op1.input is None}") 32254c99842SMichal Terepeta 3239b79f50bSJeremy Furtek op2 = test.OptionalOperandOp(input=op1) 32454c99842SMichal Terepeta # CHECK: op2.input is None: False 32554c99842SMichal Terepeta print(f"op2.input is None: {op2.input is None}") 32689a92fb3SAlex Zinenko 32789a92fb3SAlex Zinenko 32889a92fb3SAlex Zinenko# CHECK-LABEL: TEST: testCustomAttribute 32989a92fb3SAlex Zinenko@run 33089a92fb3SAlex Zinenkodef testCustomAttribute(): 33193156458SMaksim Levental with Context() as ctx, Location.unknown(): 332*392622d0SMaksim Levental a = TestAttr.get() 33389a92fb3SAlex Zinenko # CHECK: #python_test.test_attr 33489a92fb3SAlex Zinenko print(a) 33589a92fb3SAlex Zinenko 33693156458SMaksim Levental # CHECK: python_test.custom_attributed_op { 33793156458SMaksim Levental # CHECK: #python_test.test_attr 33893156458SMaksim Levental # CHECK: } 33993156458SMaksim Levental op2 = test.CustomAttributedOp(a) 34093156458SMaksim Levental print(f"{op2}") 34193156458SMaksim Levental 34293156458SMaksim Levental # CHECK: #python_test.test_attr 34393156458SMaksim Levental print(f"{op2.test_attr}") 34493156458SMaksim Levental 34593156458SMaksim Levental # CHECK: TestAttr(#python_test.test_attr) 34693156458SMaksim Levental print(repr(op2.test_attr)) 34793156458SMaksim Levental 34889a92fb3SAlex Zinenko # The following cast must not assert. 349*392622d0SMaksim Levental b = TestAttr(a) 35089a92fb3SAlex Zinenko 35189a92fb3SAlex Zinenko unit = UnitAttr.get() 35289a92fb3SAlex Zinenko try: 353*392622d0SMaksim Levental TestAttr(unit) 35489a92fb3SAlex Zinenko except ValueError as e: 35589a92fb3SAlex Zinenko assert "Cannot cast attribute to TestAttr" in str(e) 35689a92fb3SAlex Zinenko else: 35789a92fb3SAlex Zinenko raise 35889a92fb3SAlex Zinenko 35922fea18eSAlex Zinenko # The following must trigger a TypeError from our adaptors and must not 36022fea18eSAlex Zinenko # crash. 36122fea18eSAlex Zinenko try: 362*392622d0SMaksim Levental TestAttr(42) 36322fea18eSAlex Zinenko except TypeError as e: 36422fea18eSAlex Zinenko assert "Expected an MLIR object" in str(e) 36522fea18eSAlex Zinenko else: 36622fea18eSAlex Zinenko raise 36722fea18eSAlex Zinenko 36889a92fb3SAlex Zinenko # The following must trigger a TypeError from pybind (therefore, not 36989a92fb3SAlex Zinenko # checking its message) and must not crash. 37089a92fb3SAlex Zinenko try: 371*392622d0SMaksim Levental TestAttr(42, 56) 37289a92fb3SAlex Zinenko except TypeError: 37389a92fb3SAlex Zinenko pass 37489a92fb3SAlex Zinenko else: 37589a92fb3SAlex Zinenko raise 37689a92fb3SAlex Zinenko 37789a92fb3SAlex Zinenko 37889a92fb3SAlex Zinenko@run 37989a92fb3SAlex Zinenkodef testCustomType(): 38089a92fb3SAlex Zinenko with Context() as ctx: 381*392622d0SMaksim Levental a = TestType.get() 38289a92fb3SAlex Zinenko # CHECK: !python_test.test_type 38389a92fb3SAlex Zinenko print(a) 38489a92fb3SAlex Zinenko 38589a92fb3SAlex Zinenko # The following cast must not assert. 386*392622d0SMaksim Levental b = TestType(a) 387d39a7844Smax # Instance custom types should have typeids 388d39a7844Smax assert isinstance(b.typeid, TypeID) 389d39a7844Smax # Subclasses of ir.Type should not have a static_typeid 390d39a7844Smax # CHECK: 'TestType' object has no attribute 'static_typeid' 391d39a7844Smax try: 392d39a7844Smax b.static_typeid 393d39a7844Smax except AttributeError as e: 394d39a7844Smax print(e) 39589a92fb3SAlex Zinenko 39689a92fb3SAlex Zinenko i8 = IntegerType.get_signless(8) 39789a92fb3SAlex Zinenko try: 398*392622d0SMaksim Levental TestType(i8) 39989a92fb3SAlex Zinenko except ValueError as e: 40089a92fb3SAlex Zinenko assert "Cannot cast type to TestType" in str(e) 40189a92fb3SAlex Zinenko else: 40289a92fb3SAlex Zinenko raise 40389a92fb3SAlex Zinenko 40422fea18eSAlex Zinenko # The following must trigger a TypeError from our adaptors and must not 40522fea18eSAlex Zinenko # crash. 40622fea18eSAlex Zinenko try: 407*392622d0SMaksim Levental TestType(42) 40822fea18eSAlex Zinenko except TypeError as e: 40922fea18eSAlex Zinenko assert "Expected an MLIR object" in str(e) 41022fea18eSAlex Zinenko else: 41122fea18eSAlex Zinenko raise 41222fea18eSAlex Zinenko 41389a92fb3SAlex Zinenko # The following must trigger a TypeError from pybind (therefore, not 41489a92fb3SAlex Zinenko # checking its message) and must not crash. 41589a92fb3SAlex Zinenko try: 416*392622d0SMaksim Levental TestType(42, 56) 41789a92fb3SAlex Zinenko except TypeError: 41889a92fb3SAlex Zinenko pass 41989a92fb3SAlex Zinenko else: 42089a92fb3SAlex Zinenko raise 42169cc3cfbSmax 42269cc3cfbSmax 42369cc3cfbSmax@run 42469cc3cfbSmax# CHECK-LABEL: TEST: testTensorValue 42569cc3cfbSmaxdef testTensorValue(): 42669cc3cfbSmax with Context() as ctx, Location.unknown(): 42769cc3cfbSmax i8 = IntegerType.get_signless(8) 42869cc3cfbSmax 429*392622d0SMaksim Levental class Tensor(TestTensorValue): 43069cc3cfbSmax def __str__(self): 43169cc3cfbSmax return super().__str__().replace("Value", "Tensor") 43269cc3cfbSmax 43369cc3cfbSmax module = Module.create() 43469cc3cfbSmax with InsertionPoint(module.body): 43569cc3cfbSmax t = tensor.EmptyOp([10, 10], i8).result 43669cc3cfbSmax 43769cc3cfbSmax # CHECK: Value(%{{.*}} = tensor.empty() : tensor<10x10xi8>) 43869cc3cfbSmax print(Value(t)) 43969cc3cfbSmax 44069cc3cfbSmax tt = Tensor(t) 44169cc3cfbSmax # CHECK: Tensor(%{{.*}} = tensor.empty() : tensor<10x10xi8>) 44269cc3cfbSmax print(tt) 44369cc3cfbSmax 44469cc3cfbSmax # CHECK: False 44569cc3cfbSmax print(tt.is_null()) 446f22008edSArash Taheri-Dezfouli 447d39a7844Smax # Classes of custom types that inherit from concrete types should have 448d39a7844Smax # static_typeid 449*392622d0SMaksim Levental assert isinstance(TestIntegerRankedTensorType.static_typeid, TypeID) 450d39a7844Smax # And it should be equal to the in-tree concrete type 451*392622d0SMaksim Levental assert TestIntegerRankedTensorType.static_typeid == t.type.typeid 452d39a7844Smax 4537c850867SMaksim Levental d = tensor.EmptyOp([1, 2, 3], IntegerType.get_signless(5)).result 4547c850867SMaksim Levental # CHECK: Value(%{{.*}} = tensor.empty() : tensor<1x2x3xi5>) 4557c850867SMaksim Levental print(d) 4567c850867SMaksim Levental # CHECK: TestTensorValue 4577c850867SMaksim Levental print(repr(d)) 4587c850867SMaksim Levental 459f22008edSArash Taheri-Dezfouli 460f22008edSArash Taheri-Dezfouli# CHECK-LABEL: TEST: inferReturnTypeComponents 461f22008edSArash Taheri-Dezfouli@run 462f22008edSArash Taheri-Dezfoulidef inferReturnTypeComponents(): 463f22008edSArash Taheri-Dezfouli with Context() as ctx, Location.unknown(ctx): 464f22008edSArash Taheri-Dezfouli module = Module.create() 465f22008edSArash Taheri-Dezfouli i32 = IntegerType.get_signless(32) 466f22008edSArash Taheri-Dezfouli with InsertionPoint(module.body): 467f22008edSArash Taheri-Dezfouli resultType = UnrankedTensorType.get(i32) 468f22008edSArash Taheri-Dezfouli operandTypes = [ 469f22008edSArash Taheri-Dezfouli RankedTensorType.get([1, 3, 10, 10], i32), 470f22008edSArash Taheri-Dezfouli UnrankedTensorType.get(i32), 471f22008edSArash Taheri-Dezfouli ] 472f22008edSArash Taheri-Dezfouli f = func.FuncOp( 473f22008edSArash Taheri-Dezfouli "test_inferReturnTypeComponents", (operandTypes, [resultType]) 474f22008edSArash Taheri-Dezfouli ) 475f22008edSArash Taheri-Dezfouli entry_block = Block.create_at_start(f.operation.regions[0], operandTypes) 476f22008edSArash Taheri-Dezfouli with InsertionPoint(entry_block): 477f22008edSArash Taheri-Dezfouli ranked_op = test.InferShapedTypeComponentsOp( 478f22008edSArash Taheri-Dezfouli resultType, entry_block.arguments[0] 479f22008edSArash Taheri-Dezfouli ) 480f22008edSArash Taheri-Dezfouli unranked_op = test.InferShapedTypeComponentsOp( 481f22008edSArash Taheri-Dezfouli resultType, entry_block.arguments[1] 482f22008edSArash Taheri-Dezfouli ) 483f22008edSArash Taheri-Dezfouli 484f22008edSArash Taheri-Dezfouli # CHECK: has rank: True 485f22008edSArash Taheri-Dezfouli # CHECK: rank: 4 486f22008edSArash Taheri-Dezfouli # CHECK: element type: i32 487f22008edSArash Taheri-Dezfouli # CHECK: shape: [1, 3, 10, 10] 488f22008edSArash Taheri-Dezfouli iface = InferShapedTypeOpInterface(ranked_op) 489f22008edSArash Taheri-Dezfouli shaped_type_components = iface.inferReturnTypeComponents( 490f22008edSArash Taheri-Dezfouli operands=[ranked_op.operand] 491f22008edSArash Taheri-Dezfouli )[0] 492f22008edSArash Taheri-Dezfouli print("has rank:", shaped_type_components.has_rank) 493f22008edSArash Taheri-Dezfouli print("rank:", shaped_type_components.rank) 494f22008edSArash Taheri-Dezfouli print("element type:", shaped_type_components.element_type) 495f22008edSArash Taheri-Dezfouli print("shape:", shaped_type_components.shape) 496f22008edSArash Taheri-Dezfouli 497f22008edSArash Taheri-Dezfouli # CHECK: has rank: False 498f22008edSArash Taheri-Dezfouli # CHECK: rank: None 499f22008edSArash Taheri-Dezfouli # CHECK: element type: i32 500f22008edSArash Taheri-Dezfouli # CHECK: shape: None 501f22008edSArash Taheri-Dezfouli iface = InferShapedTypeOpInterface(unranked_op) 502f22008edSArash Taheri-Dezfouli shaped_type_components = iface.inferReturnTypeComponents( 503f22008edSArash Taheri-Dezfouli operands=[unranked_op.operand] 504f22008edSArash Taheri-Dezfouli )[0] 505f22008edSArash Taheri-Dezfouli print("has rank:", shaped_type_components.has_rank) 506f22008edSArash Taheri-Dezfouli print("rank:", shaped_type_components.rank) 507f22008edSArash Taheri-Dezfouli print("element type:", shaped_type_components.element_type) 508f22008edSArash Taheri-Dezfouli print("shape:", shaped_type_components.shape) 509bfb1ba75Smax 510bfb1ba75Smax 511bfb1ba75Smax# CHECK-LABEL: TEST: testCustomTypeTypeCaster 512bfb1ba75Smax@run 513bfb1ba75Smaxdef testCustomTypeTypeCaster(): 514bfb1ba75Smax with Context() as ctx, Location.unknown(): 515*392622d0SMaksim Levental a = TestType.get() 516bfb1ba75Smax assert a.typeid is not None 517bfb1ba75Smax 518bfb1ba75Smax b = Type.parse("!python_test.test_type") 519bfb1ba75Smax # CHECK: !python_test.test_type 520bfb1ba75Smax print(b) 521bfb1ba75Smax # CHECK: TestType(!python_test.test_type) 522bfb1ba75Smax print(repr(b)) 523bfb1ba75Smax 524*392622d0SMaksim Levental c = TestIntegerRankedTensorType.get([10, 10], 5) 525bfb1ba75Smax # CHECK: tensor<10x10xi5> 526bfb1ba75Smax print(c) 527bfb1ba75Smax # CHECK: TestIntegerRankedTensorType(tensor<10x10xi5>) 528bfb1ba75Smax print(repr(c)) 529bfb1ba75Smax 530bfb1ba75Smax # CHECK: Type caster is already registered 531bfb1ba75Smax try: 532bfb1ba75Smax 5337c850867SMaksim Levental @register_type_caster(c.typeid) 534bfb1ba75Smax def type_caster(pytype): 535*392622d0SMaksim Levental return TestIntegerRankedTensorType(pytype) 536bfb1ba75Smax 537bfb1ba75Smax except RuntimeError as e: 538bfb1ba75Smax print(e) 539bfb1ba75Smax 540b0e00ca6SMaksim Levental # python_test dialect registers a caster for RankedTensorType in its extension (pybind) module. 541b0e00ca6SMaksim Levental # So this one replaces that one (successfully). And then just to be sure we restore the original caster below. 5427c850867SMaksim Levental @register_type_caster(c.typeid, replace=True) 5437c850867SMaksim Levental def type_caster(pytype): 5447c850867SMaksim Levental return RankedTensorType(pytype) 545b0e00ca6SMaksim Levental 546b0e00ca6SMaksim Levental d = tensor.EmptyOp([10, 10], IntegerType.get_signless(5)).result 547b0e00ca6SMaksim Levental # CHECK: tensor<10x10xi5> 548b0e00ca6SMaksim Levental print(d.type) 549b0e00ca6SMaksim Levental # CHECK: ranked tensor type RankedTensorType(tensor<10x10xi5>) 550b0e00ca6SMaksim Levental print("ranked tensor type", repr(d.type)) 551b0e00ca6SMaksim Levental 5527c850867SMaksim Levental @register_type_caster(c.typeid, replace=True) 553b0e00ca6SMaksim Levental def type_caster(pytype): 554*392622d0SMaksim Levental return TestIntegerRankedTensorType(pytype) 555bfb1ba75Smax 556bfb1ba75Smax d = tensor.EmptyOp([10, 10], IntegerType.get_signless(5)).result 557bfb1ba75Smax # CHECK: tensor<10x10xi5> 558bfb1ba75Smax print(d.type) 559bfb1ba75Smax # CHECK: TestIntegerRankedTensorType(tensor<10x10xi5>) 560bfb1ba75Smax print(repr(d.type)) 561e0ca7e99Smax 562e0ca7e99Smax 563e0ca7e99Smax# CHECK-LABEL: TEST: testInferTypeOpInterface 564e0ca7e99Smax@run 565e0ca7e99Smaxdef testInferTypeOpInterface(): 566e0ca7e99Smax with Context() as ctx, Location.unknown(ctx): 567e0ca7e99Smax module = Module.create() 568e0ca7e99Smax with InsertionPoint(module.body): 569e0ca7e99Smax i64 = IntegerType.get_signless(64) 570e0ca7e99Smax zero = arith.ConstantOp(i64, 0) 571e0ca7e99Smax 572e0ca7e99Smax one_operand = test.InferResultsVariadicInputsOp(single=zero, doubled=None) 573e0ca7e99Smax # CHECK: i32 574e0ca7e99Smax print(one_operand.result.type) 575e0ca7e99Smax 576e0ca7e99Smax two_operands = test.InferResultsVariadicInputsOp(single=zero, doubled=zero) 577e0ca7e99Smax # CHECK: f32 578e0ca7e99Smax print(two_operands.result.type) 5793766ba44SKasper Nielsen 5803766ba44SKasper Nielsen 5813766ba44SKasper Nielsen# CHECK-LABEL: TEST: testVariadicOperandAccess 5823766ba44SKasper Nielsen@run 5833766ba44SKasper Nielsendef testVariadicOperandAccess(): 5843766ba44SKasper Nielsen def values(lst): 5853766ba44SKasper Nielsen return [str(e) for e in lst] 5863766ba44SKasper Nielsen 5873766ba44SKasper Nielsen with Context() as ctx, Location.unknown(ctx): 5883766ba44SKasper Nielsen module = Module.create() 5893766ba44SKasper Nielsen with InsertionPoint(module.body): 5903766ba44SKasper Nielsen i32 = IntegerType.get_signless(32) 5913766ba44SKasper Nielsen zero = arith.ConstantOp(i32, 0) 5923766ba44SKasper Nielsen one = arith.ConstantOp(i32, 1) 5933766ba44SKasper Nielsen two = arith.ConstantOp(i32, 2) 5943766ba44SKasper Nielsen three = arith.ConstantOp(i32, 3) 5953766ba44SKasper Nielsen four = arith.ConstantOp(i32, 4) 5963766ba44SKasper Nielsen 5973766ba44SKasper Nielsen variadic_operands = test.SameVariadicOperandSizeOp( 5983766ba44SKasper Nielsen [zero, one], two, [three, four] 5993766ba44SKasper Nielsen ) 6003766ba44SKasper Nielsen # CHECK: Value(%{{.*}} = arith.constant 2 : i32) 6013766ba44SKasper Nielsen print(variadic_operands.non_variadic) 6023766ba44SKasper Nielsen # CHECK: ['Value(%{{.*}} = arith.constant 0 : i32)', 'Value(%{{.*}} = arith.constant 1 : i32)'] 6033766ba44SKasper Nielsen print(values(variadic_operands.variadic1)) 6043766ba44SKasper Nielsen # CHECK: ['Value(%{{.*}} = arith.constant 3 : i32)', 'Value(%{{.*}} = arith.constant 4 : i32)'] 6053766ba44SKasper Nielsen print(values(variadic_operands.variadic2)) 6063766ba44SKasper Nielsen 6073766ba44SKasper Nielsen 6083766ba44SKasper Nielsen# CHECK-LABEL: TEST: testVariadicResultAccess 6093766ba44SKasper Nielsen@run 6103766ba44SKasper Nielsendef testVariadicResultAccess(): 6113766ba44SKasper Nielsen def types(lst): 6123766ba44SKasper Nielsen return [e.type for e in lst] 6133766ba44SKasper Nielsen 6143766ba44SKasper Nielsen with Context() as ctx, Location.unknown(ctx): 6153766ba44SKasper Nielsen module = Module.create() 6163766ba44SKasper Nielsen with InsertionPoint(module.body): 6173766ba44SKasper Nielsen i = [IntegerType.get_signless(k) for k in range(7)] 6183766ba44SKasper Nielsen 6193766ba44SKasper Nielsen # Test Variadic-Fixed-Variadic 6203766ba44SKasper Nielsen op = test.SameVariadicResultSizeOpVFV([i[0], i[1]], i[2], [i[3], i[4]]) 6213766ba44SKasper Nielsen # CHECK: i2 6223766ba44SKasper Nielsen print(op.non_variadic.type) 6233766ba44SKasper Nielsen # CHECK: [IntegerType(i0), IntegerType(i1)] 6243766ba44SKasper Nielsen print(types(op.variadic1)) 6253766ba44SKasper Nielsen # CHECK: [IntegerType(i3), IntegerType(i4)] 6263766ba44SKasper Nielsen print(types(op.variadic2)) 6273766ba44SKasper Nielsen 6283766ba44SKasper Nielsen # Test Variadic-Variadic-Variadic 6293766ba44SKasper Nielsen op = test.SameVariadicResultSizeOpVVV( 6303766ba44SKasper Nielsen [i[0], i[1]], [i[2], i[3]], [i[4], i[5]] 6313766ba44SKasper Nielsen ) 6323766ba44SKasper Nielsen # CHECK: [IntegerType(i0), IntegerType(i1)] 6333766ba44SKasper Nielsen print(types(op.variadic1)) 6343766ba44SKasper Nielsen # CHECK: [IntegerType(i2), IntegerType(i3)] 6353766ba44SKasper Nielsen print(types(op.variadic2)) 6363766ba44SKasper Nielsen # CHECK: [IntegerType(i4), IntegerType(i5)] 6373766ba44SKasper Nielsen print(types(op.variadic3)) 6383766ba44SKasper Nielsen 6393766ba44SKasper Nielsen # Test Fixed-Fixed-Variadic 6403766ba44SKasper Nielsen op = test.SameVariadicResultSizeOpFFV(i[0], i[1], [i[2], i[3], i[4]]) 6413766ba44SKasper Nielsen # CHECK: i0 6423766ba44SKasper Nielsen print(op.non_variadic1.type) 6433766ba44SKasper Nielsen # CHECK: i1 6443766ba44SKasper Nielsen print(op.non_variadic2.type) 6453766ba44SKasper Nielsen # CHECK: [IntegerType(i2), IntegerType(i3), IntegerType(i4)] 6463766ba44SKasper Nielsen print(types(op.variadic)) 6473766ba44SKasper Nielsen 6483766ba44SKasper Nielsen # Test Variadic-Variadic-Fixed 6493766ba44SKasper Nielsen op = test.SameVariadicResultSizeOpVVF( 6503766ba44SKasper Nielsen [i[0], i[1], i[2]], [i[3], i[4], i[5]], i[6] 6513766ba44SKasper Nielsen ) 6523766ba44SKasper Nielsen # CHECK: [IntegerType(i0), IntegerType(i1), IntegerType(i2)] 6533766ba44SKasper Nielsen print(types(op.variadic1)) 6543766ba44SKasper Nielsen # CHECK: [IntegerType(i3), IntegerType(i4), IntegerType(i5)] 6553766ba44SKasper Nielsen print(types(op.variadic2)) 6563766ba44SKasper Nielsen # CHECK: i6 6573766ba44SKasper Nielsen print(op.non_variadic.type) 6583766ba44SKasper Nielsen 6593766ba44SKasper Nielsen # Test Fixed-Variadic-Fixed-Variadic-Fixed 6603766ba44SKasper Nielsen op = test.SameVariadicResultSizeOpFVFVF( 6613766ba44SKasper Nielsen i[0], [i[1], i[2]], i[3], [i[4], i[5]], i[6] 6623766ba44SKasper Nielsen ) 6633766ba44SKasper Nielsen # CHECK: i0 6643766ba44SKasper Nielsen print(op.non_variadic1.type) 6653766ba44SKasper Nielsen # CHECK: [IntegerType(i1), IntegerType(i2)] 6663766ba44SKasper Nielsen print(types(op.variadic1)) 6673766ba44SKasper Nielsen # CHECK: i3 6683766ba44SKasper Nielsen print(op.non_variadic2.type) 6693766ba44SKasper Nielsen # CHECK: [IntegerType(i4), IntegerType(i5)] 6703766ba44SKasper Nielsen print(types(op.variadic2)) 6713766ba44SKasper Nielsen # CHECK: i6 6723766ba44SKasper Nielsen print(op.non_variadic3.type) 6733766ba44SKasper Nielsen 6743766ba44SKasper Nielsen # Test Fixed-Variadic-Fixed-Variadic-Fixed - Variadic group size 0 6753766ba44SKasper Nielsen op = test.SameVariadicResultSizeOpFVFVF(i[0], [], i[1], [], i[2]) 6763766ba44SKasper Nielsen # CHECK: i0 6773766ba44SKasper Nielsen print(op.non_variadic1.type) 6783766ba44SKasper Nielsen # CHECK: [] 6793766ba44SKasper Nielsen print(types(op.variadic1)) 6803766ba44SKasper Nielsen # CHECK: i1 6813766ba44SKasper Nielsen print(op.non_variadic2.type) 6823766ba44SKasper Nielsen # CHECK: [] 6833766ba44SKasper Nielsen print(types(op.variadic2)) 6843766ba44SKasper Nielsen # CHECK: i2 6853766ba44SKasper Nielsen print(op.non_variadic3.type) 6863766ba44SKasper Nielsen 6873766ba44SKasper Nielsen # Test Fixed-Variadic-Fixed-Variadic-Fixed - Variadic group size 1 6883766ba44SKasper Nielsen op = test.SameVariadicResultSizeOpFVFVF(i[0], [i[1]], i[2], [i[3]], i[4]) 6893766ba44SKasper Nielsen # CHECK: i0 6903766ba44SKasper Nielsen print(op.non_variadic1.type) 6913766ba44SKasper Nielsen # CHECK: [IntegerType(i1)] 6923766ba44SKasper Nielsen print(types(op.variadic1)) 6933766ba44SKasper Nielsen # CHECK: i2 6943766ba44SKasper Nielsen print(op.non_variadic2.type) 6953766ba44SKasper Nielsen # CHECK: [IntegerType(i3)] 6963766ba44SKasper Nielsen print(types(op.variadic2)) 6973766ba44SKasper Nielsen # CHECK: i4 6983766ba44SKasper Nielsen print(op.non_variadic3.type) 699