def analyze_shufflevector(tokens): statement = Shufflevector() # pop potential assignment while tokens[0] != "shufflevector": tokens.pop(0) # pop the shufflevector token tokens.pop(0) # get the first vector type _, tokens = get_type(tokens) # get the first vector value value, tokens = get_value(tokens) statement.set_first_vector_value(value) # get the second vector type _, tokens = get_type(tokens) # get the second vector value value, tokens = get_value(tokens) statement.set_second_vector_value(value) # get the third vector type _, tokens = get_type(tokens) # get the third vector value value, tokens = get_value(tokens) statement.set_third_vector_value(value) return statement
def analyze_atomicrmw(tokens): statement = Atomicrmw() # pop potential assignment while tokens[0] != "atomicrmw": tokens.pop(0) # pop the atomicrmw token tokens.pop(0) # pop the potential volatile token if tokens[0] == "volatile": tokens.pop(0) # pop the operation operation = tokens.pop(0) statement.set_operation(operation) # pop the address _, tokens = get_type(tokens) address, tokens = get_value(tokens) statement.set_address(address) # pop the value _, tokens = get_type(tokens) value, tokens = get_value(tokens) statement.set_value(value) # we are not interested in ordering, we can therefore pop all remaining tokens while tokens: tokens.pop(0) return statement
def analyze_insertelement(tokens): statement = InsertElement() # pop the potential assignment while tokens[0] != "insertelement": tokens.pop(0) # pop the insertelement token tokens.pop(0) # get the vector type vector_type, tokens = get_type(tokens) statement.set_vector_type(vector_type) # pop the value token vector_value = get_value(tokens) statement.set_vector_value(vector_value) # skip the scalar element type _, tokens = get_type(tokens) # get the value element value, tokens = get_value(tokens) statement.set_scalar_value(value) # pop the type token _, tokens = get_type(tokens) # get the index statement.set_index(tokens.pop(0)) return statement
def analyze_cmp(tokens): cmp = Cmp() # pop the potential assignment instruction while tokens[0] not in ["fcmp", "icmp"]: tokens.pop(0) # pop the fcmp instruction cmp.set_op_type(tokens.pop(0)) # pop potential fast-math flags while is_fast_math_flag(tokens[0]): tokens.pop(0) # get the condition cmp.set_condition(tokens.pop(0)) # pop the type _, tokens = get_type(tokens) # get the first value value1, tokens = get_value(tokens) cmp.set_value1(value1) value2, tokens = get_value(tokens) cmp.set_value2(value2) return cmp
def analyze_extractelement(tokens): statement = ExtractElement() # pop the potential assignment while tokens[0] != "extractelement": tokens.pop(0) # pop the extractelement token tokens.pop(0) # get the vector type vector_type, tokens = get_type(tokens) statement.set_vector_type(vector_type) # pop the value token vector_value, tokens = get_value(tokens) statement.set_vector_value(vector_value) # pop the type token _, tokens = get_type(tokens) # get the index index_value, tokens = get_value(tokens) statement.set_index(index_value) return statement
def test_const_vector_op(self): result = get_value([ "extractelement", "<2 x i32>", "<i32", "42,", "i32", "11>,", "i32", "0" ]) self.assertEqual(result[0], "extractelement <2 x i32> <i32 42, i32 11>, i32 0") result = get_value([ "insertelement", "<2 x i32>", "<i32", "42,", "i32", "11>,", "i32", "1,", "i32", "0" ]) self.assertEqual( result[0], "insertelement <2 x i32> <i32 42, i32 11>, i32 1, i32 0") result = get_value([ "shufflevector", "<2", "x", "i32>", "<i32", "42,", "i32", "11>,", "<1", "x", "i32>", "<i32", "5>,", "<3", "x", "i32>", "<i32", "0,", "i32", "2,", "i32", "1>" ]) self.assertEqual( result[0], "shufflevector <2 x i32> <i32 42, i32 11>, <1 x i32> <i32 5>, " "<3 x i32> <i32 0, i32 2, i32 1>")
def test_global_var(self): self.assertEqual(get_value(["@A"])[0], "@A") self.assertEqual(get_value(["@str.1"])[0], "@str.1") self.assertEqual(get_value(["@_class_Profile"])[0], "@_class_Profile") self.assertEqual( get_value(["@_class_Profile,", "i32", "4)"])[0], "@_class_Profile") self.assertEqual(get_value(["@str.1)"])[0], "@str.1")
def analyze_insertvalue(tokens): insertvalue_instruction = Insertvalue() # pop the assignment segment while tokens[0] != "insertvalue": tokens.pop(0) # pop the insertvalue instruction tokens.pop(0) # get the object type object_type, tokens = get_type(tokens) insertvalue_instruction.set_object_type(object_type) # get the original object insertvalue_instruction.set_original(tokens[0].replace(",", "")) tokens.pop(0) # get the type and value that is to be inserted insert_type, tokens = get_type(tokens) insertvalue_instruction.set_insert_type(insert_type) value, tokens = get_value(tokens) insertvalue_instruction.set_insert_value(value) tokens.pop(0) while len(tokens) != 0: index, tokens = get_value(tokens) insertvalue_instruction.add_index(index) return insertvalue_instruction
def analyze_store(tokens): store = Store() # pop the store instruction tokens.pop(0) # check for atomic if tokens[0] == "atomic": tokens.pop(0) # check for volatile if tokens[0] == "volatile": tokens.pop(0) # skip type temp, tokens = get_type(tokens) store_value, tokens = get_value(tokens) store.set_value(store_value) # skip type _, tokens = get_type(tokens) # get the register register, tokens = get_value(tokens) store.set_register(register) return store
def analyze_bitwise_binary(tokens): statement = BitwiseBinaryStatement() # pop the potential assignment while tokens[0] not in ["shl", "lshr", "ashr", "and", "or", "xor"]: tokens.pop(0) # pop the bin instruction statement.set_statement_type(tokens.pop(0)) # pop potential nuw token if tokens[0] == "nuw": tokens.pop(0) # pop potential nsw token if tokens[0] == "nsw": tokens.pop(0) # pop potential exact token if tokens[0] == "exact": tokens.pop(0) # pop the type _, tokens = get_type(tokens) # get the first operand op1, tokens = get_value(tokens) statement.set_op1(op1) # get the second operand op2, tokens = get_value(tokens) statement.set_op2(op2) return statement
def test_const_aggregate_op(self): result = get_value([ "extractvalue", "{i32,", "float}", "{i32", "4,", "float", "17.0},", "0" ]) self.assertEqual(result[0], "extractvalue {i32, float} {i32 4, float 17.0}, 0") result = get_value([ "extractvalue", "({i32,", "float}", "{i32", "4,", "float", "17.0},", "0),", "i32", "8)" ]) self.assertEqual(result[0], "extractvalue {i32, float} {i32 4, float 17.0}, 0") self.assertEqual(result[1], ["i32", "8)"]) result = get_value([ "extractvalue", "({i32,", "float}", "{i32", "4,", "float", "17.0},", "0)(@\"foo\")" ]) self.assertEqual(result[0], "extractvalue {i32, float} {i32 4, float 17.0}, 0") self.assertEqual(result[1], ["(@\"foo\")"]) result = get_value([ "insertvalue", "{i32,", "float}", "{i32", "4,", "float", "17.0},", "i32", "4,", "0" ]) self.assertEqual( result[0], "insertvalue {i32, float} {i32 4, float 17.0}, i32 4, 0")
def analyze_select(tokens): statement = Select() # pop the potential assignment while tokens[0] != "select": tokens.pop(0) # pop the select token tokens.pop(0) # pop the potential fast-math flags while is_fast_math_flag(tokens[0]): tokens.pop(0) # get the condition _, tokens = get_type(tokens) condition, tokens = get_value(tokens) statement.set_condition(condition) # get the if true option _, tokens = get_type(tokens) val1, tokens = get_value(tokens) statement.set_val1(val1) # get the if false option _, tokens = get_type(tokens) val2, tokens = get_value(tokens) statement.set_val2(val2) return statement
def test_hex_numeric_constants(self): self.assertEqual( get_value(["0x432ff973cafa8000"])[0], "0x432ff973cafa8000") self.assertEqual( get_value(["0x432ff973cafa323,", "i1", "true"])[0], "0x432ff973cafa323") self.assertEqual( get_value(["0x432ff973cafa323)"])[0], "0x432ff973cafa323")
def test_vector_constants(self): self.assertEqual( get_value( ["<i32", "42,", "i32", "11,", "i32", "74,", "i32", "100>"])[0], "<i32 42, i32 11, i32 74, i32 100>") self.assertEqual( get_value(["<i32", "42>,", "i32", "0)"])[0], "<i32 42>") self.assertEqual(get_value(["<i32", "42>)"])[0], "<i32 42>")
def test_metadata(self): self.assertEqual( get_value(["!{!0,", "!{!2,", "!0},", "!\"test\"}"])[0], "!{!0, !{!2, !0}, !\"test\"}") self.assertEqual( get_value([ "!{!0,", "i32", "0,", "i8*", "@global,", "i64", "(i64)*", "@function,", "!\"str\"}" ])[0], "!{!0, i32 0, i8* @global, i64 (i64)* @function, !\"str\"}")
def test_const_other(self): result = get_value(["select", "i1", "true,", "i8", "17,", "i8", "42"]) self.assertEqual(result[0], "select i1 true, i8 17, i8 42") result = get_value(["icmp", "eq", "(i32", "4,", "5),", "i32", "8)"]) self.assertEqual(result[0], "icmp eq i32 4, 5") self.assertEqual(result[1], ["i32", "8)"]) result = get_value(["fcmp", "oeq", "float", "4.0,", "5.0"]) self.assertEqual(result[0], "fcmp oeq float 4.0, 5.0")
def test_structure_constants(self): self.assertEqual( get_value(["{", "i32", "4,", "float", "17.0,", "i32*", "@G", "}"])[0], "{ i32 4, float 17.0, i32* @G }") self.assertEqual( get_value(["{i32", "4,", "float", "17.0})"])[0], "{i32 4, float 17.0}") self.assertEqual( get_value(["{i32", "4,", "float", "17.0},", "i32", "5", ")"])[0], "{i32 4, float 17.0}")
def analyze_load(tokens): load = Load() # pop the assignment instruction while tokens[0] != "load": tokens.pop(0) # pop the load instruction tokens.pop(0) # check for atomic if tokens[0] == "atomic": tokens.pop(0) # check for volatile if tokens[0] == "volatile": tokens.pop(0) # skip type resulting_type, tokens = get_type(tokens) load.set_type(resulting_type) # check for , if tokens[0] == ",": tokens.pop(0) # skip type _, tokens = get_type(tokens) # get the value value, tokens = get_value(tokens) load.set_value(value) return load
def test_const_getelementptr(self): result = get_value([ "getelementptr", "inbounds", "[5", "x", "i8*],", "[5", "x", "i8*]*", "@_ZTV9Rectangle,", "i32", "0,", "i32", "2" ]) self.assertEqual( result[0], "getelementptr inbounds [5 x i8*], [5 x i8*]* @_ZTV9Rectangle, i32 0, i32 2" ) result = get_value([ "getelementptr", "inbounds", "([5", "x", "i8*],", "[5", "x", "i8*]*", "@_ZTV9Rectangle,", "i32", "0,", "i32", "2),", "i32", "5)" ]) self.assertEqual( result[0], "getelementptr inbounds [5 x i8*], [5 x i8*]* @_ZTV9Rectangle, i32 0, i32 2" )
def test_numeric_constants(self): self.assertEqual(get_value(["123"])[0], "123") self.assertEqual(get_value(["-4"])[0], "-4") self.assertEqual(get_value(["123.321"])[0], "123.321") self.assertEqual(get_value(["1.23321e+2"])[0], "1.23321e+2") self.assertEqual( get_value(["1.23321e+2,", "i1", "false"])[0], "1.23321e+2") self.assertEqual(get_value(["1.23321e+2)"])[0], "1.23321e+2")
def analyze_cmpxchg(tokens): statement = Cmpxchg() # pop a potential assignment instruction while tokens[0] != "cmpxchg": tokens.pop(0) # pop the cmpxchg token tokens.pop(0) # pop the weak token, if present if tokens[0] == "weak": tokens.pop(0) # pop the volatile token, if present if tokens[0] == "volatile": tokens.pop(0) # get the address value _, tokens = get_type(tokens) address, tokens = get_value(tokens) statement.set_address(address) # get the cmp value _, tokens = get_type(tokens) cmp, tokens = get_value(tokens) statement.set_cmp(cmp) # get the new value _, tokens = get_type(tokens) new, tokens = get_value(tokens) statement.set_new(new) # we are not interested in ordering instructions, and these can therefore be popped while tokens: tokens.pop(0) return statement
def analyze_binary_op(self, tokens: list): op = BinOp() # pop the assignment while tokens[0] not in self.operations: tokens.pop(0) # pop the operation op.set_op(self.op_symbols[tokens.pop(0)]) # pop potential nuw token if tokens[0] == "nuw": tokens.pop(0) # pop potential nsw token if tokens[0] == "nsw": tokens.pop(0) # pop potential exact token if tokens[0] == "exact": tokens.pop(0) # pop potential fastmath flags while is_fast_math_flag(tokens[0]): tokens.pop(0) # get the type _, tokens = get_type(tokens) # get the first op value1, tokens = get_value(tokens) op.set_value1(value1) # get the second op value2, tokens = get_value(tokens) op.set_value2(value2) return op
def analyze_ret(tokens: list): ret = Ret() # pop the return command tokens.pop(0) # get the return type ret_type, tokens = get_type(tokens) # if any, get the return value if ret_type != "void": ret_value, tokens = get_value(tokens) ret.set_value(ret_value) return ret
def analyze_resume(tokens): resume = Resume() # pop the resume instruction tokens.pop(0) # get the ex type ex_type, tokens = get_type(tokens) resume.set_type(ex_type) # get the value value, tokens = get_value(tokens) resume.set_value(value) return resume
def analyze_freeze(tokens): statement = Freeze() # pop the potential assignment while tokens[0] != "freeze": tokens.pop(0) # pop the freeze token tokens.pop(0) # get the value _, tokens = get_type(tokens) value, tokens = get_value(tokens) statement.set_value(value) return statement
def analyze_fneg(tokens): fneg = Fneg() # pop potential assignment while tokens[0] != "fneg": tokens.pop(0) # pop the fneg command tokens.pop(0) # pop potential fast math flags while is_fast_math_flag(tokens[0]): tokens.pop(0) # skip the type _, tokens = get_type(tokens) # get the value value, tokens = get_value(tokens) fneg.set_value(value) return fneg
def analyze_extractvalue(tokens): extractvalue = Extractvalue() # skip initial assignment part while tokens[0] != "extractvalue": tokens.pop(0) # pop the extractvalue token tokens.pop(0) # pop the type _, tokens = get_type(tokens) # get the value value, tokens = get_type(tokens) extractvalue.set_value(value) # get the indices while len(tokens) != 0: index, tokens = get_value(tokens) extractvalue.add_index(index) return extractvalue
def analyze_getelementptr(tokens: list): op = Getelementptr() # skip potential assignment tokens while tokens[0] != "getelementptr": tokens.pop(0) # pop getelementptr tokens.pop(0) # pop a potential inbounds keyword if tokens[0] == "inbounds": tokens.pop(0) # pop the type _, tokens = get_type(tokens) # pop the second type _, tokens = get_type(tokens) # get the value value, tokens = get_value(tokens) op.set_value(value) # access potential further indices while len(tokens) != 0: if tokens[0] == "inrange": tokens.pop(0) # get the index type _, tokens = get_type(tokens) # get the index value op.add_index(tokens.pop(0).replace(",", "")) return op
def analyze_callbr(tokens: list): br = CallBr() # pop the potential assignment while tokens[0] != "callbr": tokens.pop(0) # pop the callbr command tokens.pop(0) # pop the calling convention if is_calling_convention(tokens[0]): tokens.pop(0) # pop the parameter attributes while is_parameter_attribute(tokens[0]): open_brackets = tokens[0].count("(") - tokens[0].count(")") tokens.pop(0) while open_brackets != 0: open_brackets += tokens[0].count("(") - tokens[0].count(")") tokens.pop(0) # pop the address space if is_address_space(tokens[0]): tokens.pop(0) # get the return type ret_type, tokens = get_type(tokens) br.set_return_type(ret_type) # skip potential redundant tokens while tokens[0].count("(") == 0 and "bitcast" not in tokens[0]: tokens.pop(0) # get the function name if "bitcast" in tokens[0]: conversion = analyze_conversion(tokens) br.set_function(conversion.get_value()) else: temp = tokens[0].split("(", 1) br.set_function(temp[0]) tokens[0] = temp[1] # read the argument list while tokens and \ not is_group_attribute(tokens[0]) and \ not is_function_attribute(tokens[0]) and \ ("(" in tokens[0] or ")" not in tokens[0]): argument = Argument() # read argument type parameter_type, tokens = get_type(tokens) argument.set_parameter_type(parameter_type) # read potential parameter attributes while is_parameter_attribute(tokens[0]): open_brackets = tokens[0].count("(") - tokens[0].count(")") attribute = tokens.pop(0) while open_brackets != 0 or attribute == "align": open_brackets += tokens[0].count("(") - tokens[0].count(")") attribute += tokens.pop(0) argument.add_parameter_attribute(attribute) # read register value, tokens = get_value(tokens) argument.set_register(value) br.add_function_argument(argument) # pop potential function attributes while is_function_attribute(tokens[0]): tokens.pop(0) # pop operand bundles while tokens[0] != "to": tokens.pop(0) tokens.pop(0) tokens.pop(0) # pop the fallthrough label br.set_fallthrough_label(tokens.pop(0)) while tokens: # pop the label token tokens.pop(0) # pop the label specification br.add_indirect_label(tokens.pop(0).replace("]", "")) return br
def test_const_conversion(self): result = get_value(["trunc", "i32", "257", "to", "i8"]) self.assertEqual(result[0], "trunc i32 257 to i8") result = get_value([ "zext", "(<2", "x", "i16>", "<i16", "8,", "i16", "7>", "to", "<2", "x", "i32>)" ]) self.assertEqual(result[0], "zext <2 x i16> <i16 8, i16 7> to <2 x i32>") result = get_value(["sext", "(i8", "-1", "to", "i16),", "i32", "5)"]) self.assertEqual(result[0], "sext i8 -1 to i16") self.assertEqual(result[1], ["i32", "5)"]) result = get_value(["fptrunc", "double", "16777217.0", "to", "float"]) self.assertEqual(result[0], "fptrunc double 16777217.0 to float") result = get_value(["fpext", "double", "%X", "to", "fp128"]) self.assertEqual(result[0], "fpext double %X to fp128") result = get_value(["fptoui", "float", "1.04E+17", "to", "i8"]) self.assertEqual(result[0], "fptoui float 1.04E+17 to i8") result = get_value(["fptosi", "float", "1.0E-247", "to", "i1"]) self.assertEqual(result[0], "fptosi float 1.0E-247 to i1") result = get_value(["uitofp", "i8", "-1", "to", "double"]) self.assertEqual(result[0], "uitofp i8 -1 to double") result = get_value(["sitofp", "i8", "-1", "to", "double"]) self.assertEqual(result[0], "sitofp i8 -1 to double") result = get_value( ["ptrtoint", "<4", "x", "i32*>", "%P", "to", "<4", "x", "i64>"]) self.assertEqual(result[0], "ptrtoint <4 x i32*> %P to <4 x i64>") result = get_value( ["inttoptr", "<4", "x", "i32>", "%G", "to", "<4", "x", "i8*>"]) self.assertEqual(result[0], "inttoptr <4 x i32> %G to <4 x i8*>") result = get_value( ["bitcast", "(<2", "x", "i32*>", "%V", "to", "<2", "x", "i64*>)"]) self.assertEqual(result[0], "bitcast <2 x i32*> %V to <2 x i64*>") result = get_value([ "addrspacecast", "<4 x i32*>", "%z", "to", "<4", "x", "float", "addrspace(3)*>" ]) self.assertEqual( result[0], "addrspacecast <4 x i32*> %z to <4 x float addrspace(3)*>")