def ToFPCore(expr, ofname="fpcore.fpcore"): vs = expr.vars() vs = [v for v in vs if (not tft_expr.isConstVar(v))] assert (all([(v.hasLB() and v.hasUB()) for v in vs])) ofile = open(ofname, "w") str_paras = "(" for v in vs: str_paras += v.label() + " " str_paras = str_paras.strip() str_paras += ")" str_pre = ":pre (and" for v in vs: str_pre += " (>= " + v.label() + " " + str(float(v.lb().value())) + ")" str_pre += " (>= " + str(float(v.ub().value())) + " " + v.label() + ")" str_pre += ")" ofile.write("(FPCore " + str_paras + "\n") ofile.write(" " + str_pre + "\n") ofile.write(" " + expr.toFPCoreString() + ")") ofile.close()
def ExportCppInsts(alloc, ifname): assert ((type(N_CPP_REPEATS) is int) and (1 <= N_CPP_REPEATS)) assert (isinstance(alloc, tft_alloc.Alloc)) assert (all( [isinstance(expr, tft_expr.Expr) for expr in tft_ir_api.CPP_INSTS])) type_def_map = {} for gid, eps in alloc.gid2eps.items(): assert (TypeExpr(gid) not in type_def_map.keys()) type_def_map[TypeExpr(gid)] = Eps2CtypeString(eps) # -- write .cpp file -- ifile = open(ifname, "w") ifile.write("#include <iostream>\n") ifile.write("#include <math.h>\n") if (Eps2CtypeString(tft_alloc.EPSILON_128) in type_def_map.values()): ifile.write("extern \"C\" { \n#include \"quadmath.h\"\n}\n") ifile.write("\n") ifile.write("using namespace std;\n") ifile.write("\n") for tr, tv in type_def_map.items(): ifile.write("#define " + tr + " " + tv + "\n") ifile.write("\n") # ifile.write("void computation () {\n") # # for expr in tft_ir_api.CPP_INSTS: # if (isinstance(expr, tft_expr.VariableExpr) and # tft_expr.isConstVar(expr)): # continue # # ifile.write("\t" + Expr2CStatement(expr, alloc) + "\n") # # ifile.write("}\n") # # ifile.write("\n") ifile.write("int main (int argc, char **argv) {\n") ifile.write("\n\tfor(int __r = 0 ; __r < " + str(N_CPP_REPEATS) + " ; __r++) {\n") # ifile.write("\t\tcomputation();\n") for expr in tft_ir_api.CPP_INSTS: if (isinstance(expr, tft_expr.VariableExpr) and tft_expr.isConstVar(expr)): continue ifile.write("\t\t" + Expr2CStatement(expr, alloc) + "\n") ifile.write("\t}\n") ifile.write("\n\treturn 0;\n}")
def ExportExpr4FPTaylorSanitation(expr, alloc, qfname): assert (isinstance(expr, tft_expr.Expr)) assert (isinstance(alloc, tft_alloc.Alloc)) vs_all = expr.vars() vs = [v for v in vs_all if (not tft_expr.isConstVar(v))] qfile = open(qfname, "w") # write variables qfile.write("Variables\n") for i in range(0, len(vs)): v = vs[i] qfile.write(" " + v.label() + " in [" + v.lb().toCString() + ", " + v.ub().toCString() + "]") if (i < (len(vs) - 1)): qfile.write(",") qfile.write("\n") qfile.write(";\n\n") # write expressions qfile.write("Expressions\n") qfile.write(" __final_result = " + FPTaylorExpr(expr, alloc) + "\n") qfile.write(";\n\n") qfile.close()
def _ColorExpr(expr, alloc): assert (isinstance(expr, tft_expr.Expr)) assert (isinstance(alloc, tft_alloc.Alloc)) if (isinstance(expr, tft_expr.ConstantExpr)): return color(plain, tft_alloc.EPSILON_128, str(float(expr.value()))) bw_mine = alloc[expr.getGid()] if (isinstance(expr, tft_expr.VariableExpr)): if (tft_expr.isConstVar(expr)): assert (expr.lb() == expr.ub()) return color(plain, bw_mine, expr.ub().toCString()) else: return color(plain, bw_mine, expr.label()) if (isinstance(expr, tft_expr.UnaryExpr)): str_opd = _ColorExpr(expr.opd(), alloc) str_opd = color(plain, bw_mine, "(") + str_opd + color( plain, bw_mine, ")") return color(plain, bw_mine, expr.operator.label + " ") + str_opd if (isinstance(expr, tft_expr.BinaryExpr)): str_lhs = _ColorExpr(expr.lhs(), alloc) str_rhs = _ColorExpr(expr.rhs(), alloc) str_lhs = color(plain, bw_mine, "(") + str_lhs + color( plain, bw_mine, ")") str_rhs = color(plain, bw_mine, "(") + str_rhs + color( plain, bw_mine, ")") return color(plain, bw_mine, expr.operator.label + " ") + str_lhs + " \n" + str_rhs sys.exit("Error: not supported expr 4 ColorExpr...")
def Expr2Ref(expr, alloc): global NEW_EREF global EREF_LIST assert (isinstance(alloc, tft_alloc.Alloc)) if (isinstance(expr, tft_expr.ConstantExpr)): return expr.toCString() elif (isinstance(expr, tft_expr.VariableExpr) and tft_expr.isConstVar(expr)): assert (expr.lb().value() == expr.ub().value()) vstr = str(float(expr.lb().value())) my_bw = alloc[expr.getGid()] if (my_bw == tft_alloc.EPSILON_32): vstr = vstr + "f" elif (my_bw == tft_alloc.EPSILON_64 or my_bw == tft_alloc.EPSILON_128): vstr = vstr else: sys.exit("Error: unsupported constant bit-width: " + str(my_bw)) return vstr elif (isinstance(expr, tft_expr.VariableExpr) or isinstance(expr, tft_expr.UnaryExpr) or isinstance(expr, tft_expr.BinaryExpr)): for e_eref in EREF_LIST: assert (len(e_eref) == 2) e = e_eref[0] eref = e_eref[1] if (e == expr): return ExprRef(eref) eref = NEW_EREF NEW_EREF = NEW_EREF + 1 EREF_LIST.append([expr, eref]) return ExprRef(eref)
def MakeBinaryExpr(op_label, op_gid, opd0, opd1, internal=False): global EXTERNAL_GIDS if ((not internal) and (TUNE_FOR_ALL)): op_gid = 0 assert (type(op_label) is str) assert (type(op_gid) is int) assert (isinstance(opd0, tft_expr.Expr)) assert (isinstance(opd1, tft_expr.Expr)) if (COALESCE_CONST): # if (isinstance(opd0, tft_expr.ConstantExpr) and isinstance(opd1, tft_expr.ConstantExpr)): if (isinstance(opd0, tft_expr.ConstantExpr) and isinstance(opd1, tft_expr.ConstantExpr) and tft_expr.isPreciseConstantExpr(opd0) and tft_expr.isPreciseConstantExpr(opd1)): v0 = opd0.value() v1 = opd1.value() if (op_label == "+"): eret = tft_expr.ConstantExpr(v0 + v1) AppendCppInst(eret) return eret elif (op_label == "-"): eret = tft_expr.ConstantExpr(v0 - v1) AppendCppInst(eret) return eret elif (op_label == "*"): eret = tft_expr.ConstantExpr(v0 * v1) AppendCppInst(eret) return eret elif (op_label == "/"): eret = tft_expr.ConstantExpr(v0 / v1) AppendCppInst(eret) return eret else: sys.exit("ERROR: unknown Binary Operator: " + op_label) # possibly bind the constant type if ((not tft_utils.FIX_CONST_TYPE) and tft_expr.isConstVar(opd0)): if (opd0.getGid() == tft_expr.PRESERVED_CONST_GID): CountGID(tft_expr.PRESERVED_CONST_GID, -1) opd0.gid = op_gid else: if (opd0.getGid() != op_gid): print("Warning: conflicting constant type...") if ((not tft_utils.FIX_CONST_TYPE) and tft_expr.isConstVar(opd1)): if (opd1.getGid() == tft_expr.PRESERVED_CONST_GID): CountGID(tft_expr.PRESERVED_CONST_GID, -1) opd1.gid = op_gid else: if (opd1.getGid() != op_gid): print("Warning: conflicting constant type...") if (not internal): CountGID(op_gid) CountCasting(opd0, op_gid) CountCasting(opd1, op_gid) if (internal): assert (-1 == op_gid) else: assert (0 <= op_gid) if (op_gid not in EXTERNAL_GIDS): EXTERNAL_GIDS.append(op_gid) ret_expr = tft_expr.BinaryExpr(tft_expr.BinaryOp(op_gid, op_label), opd0.copy((not internal)), opd1.copy((not internal))) AppendCppInst(ret_expr) return ret_expr
def MakeUnaryExpr(op_label, op_gid, opd0, internal=False): global EXTERNAL_GIDS if ((not internal) and (TUNE_FOR_ALL)): op_gid = 0 assert (type(op_label) is str) assert (type(op_gid) is int) assert (isinstance(opd0, tft_expr.Expr)) if (COALESCE_CONST): if (isinstance(opd0, tft_expr.ConstantExpr)): if (op_label == "abs"): eret = tft_expr.ConstantExpr(abs(opd0.value())) AppendCppInst(eret) return eret elif (op_label == "-"): eret = tft_expr.ConstantExpr(-1.0 * opd0.value()) AppendCppInst(eret) return eret elif (op_label == "sqrt"): cv = opd0.value() assert (cv >= 0.0) eret = tft_expr.ConstantExpr(math.sqrt(cv)) AppendCppInst(eret) return eret else: sys.exit("ERROR: unknown Unary Operator: " + op_label) # possibly bind the constant type if ((not tft_utils.FIX_CONST_TYPE) and tft_expr.isConstVar(opd0)): if (opd0.getGid() == tft_expr.PRESERVED_CONST_GID): CountGID(tft_expr.PRESERVED_CONST_GID, -1) opd0.gid = op_gid else: if (opd0.getGId() != op_gid): print("Warning: conflicting constant type...") if (not internal): CountGID(op_gid) CountCasting(opd0, op_gid) if (internal): assert (-1 == op_gid) else: assert (0 <= op_gid) if (op_gid not in EXTERNAL_GIDS): EXTERNAL_GIDS.append(op_gid) ret_expr = None if (op_label == "-"): ret_expr = BE("*", op_gid, FConst(-1.0), opd0) else: ret_expr = tft_expr.UnaryExpr(tft_expr.UnaryOp(op_gid, op_label), opd0.copy((not internal))) AppendCppInst(ret_expr) return ret_expr
def maxObj(self, expr_optobj, id_query=None, id_retry=None): assert (isinstance(expr_optobj, tft_expr.Expr)) assert (self.tolerance is not None) assert ((id_query is None) or (type(id_query) is int)) assert ((id_retry is None) or (type(id_retry) is int)) tft_utils.checkGelpiaInstallation("master") if ((id_retry is not None) and (id_retry >= MAX_RETRIES)): print("WARNING: Gelpia reached the max. # of retries...") self.cached_result = None fname_query = os.path.abspath(FNAME_GELPIA_QUERY) fname_log = os.path.abspath(FNAME_GELPIA_LOG) if (id_query is not None): fname_query = fname_query + "." + str(id_query) fname_log = fname_log + "." + str(id_query) if (tft_utils.FPTUNER_DEBUG): if (os.path.isfile(fname_query)): print( "WARNING: automatically overwrite Gelpia's query file: " + fname_query) return None if (os.path.isfile(fname_log)): print("WARNING: automatically overwrite Gelpia's log file: " + fname_log) return None # ---- write query file ---- qfile = open(fname_query, "w") # write input and output tolerances qfile.write("-ie .0000000001\n") qfile.write("-oe " + str(float(self.tolerance)) + "\n") # maximization objective qfile.write("-f \"" + expr_optobj.toCString(True) + "\"\n") # specify the timeout qfile.write("-t " + str(tft_utils.GOPT_TIMEOUT) + "\n") # turn off divide-by-zero analysis qfile.write("-z\n") # redirect temporal results to stderr qfile.write("-L " + fname_log + "\n") # variables and their ranges non_const_vars = [ v for v in expr_optobj.vars() if (not tft_expr.isConstVar(v)) ] str_vars = "-i \"{" if (len(non_const_vars) == 0): str_vars = str_vars + "}\"\n" else: for var in non_const_vars: assert (isinstance(var, tft_expr.VariableExpr)) assert (var.hasBounds()) if (var.type() is Fraction): str_vars = str_vars + "\'" + var.label( ) + "\' : (" + var.lb().toCString() + "," + var.ub( ).toCString() + "), " elif (var.type() is int): vlb = var.lb().value() vub = var.ub().value() assert ((vlb == int(vlb)) and (vub == int(vub))) vlb = int(vlb) vub = int(vub) str_vars = str_vars + "\'" + var.label() + "\' : (" + str( vlb) + "," + str(vub) + "), " else: sys.exit("ERROR: Gelpia doesn't support variable type: " + str(var.type())) assert (str_vars.endswith(", ")) str_vars = str_vars[0:len(str_vars) - 2] + "}\"\n" qfile.write(str_vars) qfile.close() # ---- save the query file ---- if (SAVE_QUERY): qi = 0 if (not os.path.isdir(DIR_SAVED_QUERIES)): os.system("mkdir " + DIR_SAVED_QUERIES) assert (os.path.isdir(DIR_SAVED_QUERIES)) assert (os.path.isfile(FNAME_GELPIA_QUERY)) while (True): qname = DIR_SAVED_QUERIES + "/" + NAME_QUERY + "_" + str(qi) if (not os.path.isfile(qname)): os.system("cp " + FNAME_GELPIA_QUERY + " " + qname) break else: qi = qi + 1 # ---- run gelpia ---- assert (tft_utils.GOPT_TIMEOUT > 0) assert ((0 < POLL_INTERVAL) and (POLL_INTERVAL <= tft_utils.GOPT_TIMEOUT)) now_dir = os.path.abspath(os.getcwd()) os.chdir(os.environ["GELPIA_PATH"]) exe_gelpia = subp.Popen([os.environ["GELPIA"], "@" + fname_query], shell=False, stdout=subp.PIPE, stderr=subp.PIPE, bufsize=0) finished = False wait_time = 0 while (True): time.sleep(POLL_INTERVAL) wait_time = wait_time + POLL_INTERVAL if (exe_gelpia.poll() is not None): finished = True break if (wait_time >= (tft_utils.GOPT_TIMEOUT + 15)): break os.chdir(now_dir) if (not finished): print( "WARNING: Manually timeout Gelpia... Gelpia's timeout facility may failed..." ) return None # ---- read result ---- not_certain = False value_bound = None if (finished): # Gelpia terminated itself for aline in exe_gelpia.stdout: aline = aline.decode(encoding='UTF-8').strip() if (aline == "error"): print("Warning : Gelpia returned \"error\"") if (aline == "ERROR: Division by zero"): print("Warning : Gelpia encounter division by zero") str_val = None if (aline.startswith("[[")): i_first_end = aline.find("]") if (i_first_end >= 5): aline = aline[2:i_first_end] i_coma = aline.find(",") if (i_coma >= 1): str_val = aline[i_coma + 1:] elif (aline.startswith("[") and aline.endswith(", {")): str_val = aline[1:len(aline) - 3] elif (aline.startswith("[") and aline.endswith(", {}]")): str_val = aline[1:len(aline) - 5] else: pass if (str_val is not None): if (str_val == "inf" or str_val == "nan"): print("WARNING: pessimistic bound: " + str_val) print(" expr: " + str(expr_optobj.toCString())) print("Gelpia retry...") if (id_retry is None): return self.maxObj(expr_optobj, id_query, 1) else: assert (type(id_retry) is int) return self.maxObj(expr_optobj, id_query, (id_retry + 1)) if (str_val == "inf"): raise InfValueException() try: value_bound = Fraction(float(str_val)) except: print("WARNING: cannot convert " + str_val + " to float...") return None if (value_bound is None): not_certain = True print("WARNING: Gelpia didn't return a certain answer...") # assert(value_bound is not None) if ( not finished or not_certain ): # 1) Gelpia didn't terminate itself OR 2) Gelpia didn't return a certain answer... if (not finished): exe_gelpia.terminate() exe_gelpia.kill() assert (os.path.isfile(fname_log)) flog = open(fname_log, "r") target_token = "guaranteed ub:" for aline in flog: if (type(aline) is not str): aline = aline.decode(encoding='UTF-8').strip() if (VERBOSE): print("Gelpia (stderr) >> " + aline) target_id = aline.find(target_token) if (target_id >= 0): aline = aline[target_id + len(target_token):].strip() try: value_bound = Fraction(float(aline)) except: print("WARNING: cannot convert " + aline + " to float...") sys.exit(1) flog.close() if (value_bound is None): print("WARNING: Gelpia terminated prematurely... retry...") if (id_retry is None): return self.maxObj(expr_optobj, id_query, 1) else: assert (type(id_retry) is int) return self.maxObj(expr_optobj, id_query, (id_retry + 1)) if (value_bound is None): print("EXIT: Gelpia abort with value_bound = None...") print(":: " + str(expr_optobj)) sys.exit(1) # ---- finalize ---- self.cached_result = value_bound return value_bound
def LoadExprsFile(fname): global FNAME_EXPRS global FILE_PREFIX global FILE_GID2EPSS global FILE_POSTFIX assert (fname.endswith(".exprs")) FNAME_EXPRS = fname f_stage = "prefix" efile = open(fname, "r") for aline in efile: # decide loading stage if (aline.strip() == "var-ranges:"): assert (f_stage == "prefix") f_stage = "var-ranges" continue elif (aline.strip() == "group-epsilons:"): assert (f_stage == "var-ranges") f_stage = "group-epsilons" continue elif (aline.strip() == "eq-gids:"): assert (f_stage == "group-epsilons") f_stage = "postfix" FILE_POSTFIX.append("\n") else: pass # handle based on stage if (f_stage == "prefix"): FILE_PREFIX.append(aline) elif (f_stage == "var-ranges"): if (aline.strip() != ""): ve = tft_parser.String2BoundedVariableExpr(aline.strip()) assert (ve.label() not in DEF.VNames) if (not tft_expr.isConstVar(ve)): DEF.VarExprs.append(ve) DEF.VNames.append(ve.label()) DEF.VRanges.append( (float(ve.lb().value()), float(ve.ub().value()))) elif (f_stage == "group-epsilons"): if (aline.strip() != ""): tokens = tft_utils.String2Tokens(aline.strip(), ":") assert (len(tokens) == 2) gid = int(tokens[0]) epss = tokens[1] assert (gid not in FILE_GID2EPSS.keys()) FILE_GID2EPSS[gid] = epss elif (f_stage == "postfix"): FILE_POSTFIX.append(aline) else: assert (False) efile.close() # generate N_Var_Intervals DEF.assert_VNames() DEF.assert_VRanges() DEF.N_Var_Intervals = [DEF.N_Partitions for i in range(0, len(DEF.VNames))]
def FPTaylorExpr(expr, alloc): assert (isinstance(expr, tft_expr.Expr)) assert (isinstance(alloc, tft_alloc.Alloc)) if (isinstance(expr, tft_expr.ConstantExpr)): return "rnd128(" + str(float(expr.value())) + ")" if (isinstance(expr, tft_expr.VariableExpr)): bw_mine = alloc[expr.getGid()] if (tft_expr.isConstVar(expr)): assert (expr.lb() == expr.ub()) return FPTaylorTypeCastWrap(bw_mine, expr.ub().toCString()) else: return FPTaylorTypeCastWrap(bw_mine, expr.label()) if (isinstance(expr, tft_expr.UnaryExpr)): go_cast = False bw_mine = alloc[expr.getGid()] if (isinstance(expr.opd(), tft_expr.ConstantExpr)): go_cast = True else: bw_opd = alloc[expr.opd().getGid()] if (bw_opd != bw_mine): go_cast = True str_opd = FPTaylorExpr(expr.opd(), alloc) if (go_cast): if (bw_mine == tft_alloc.EPSILON_32): str_opd = "rnd32(" + str_opd + ")" elif (bw_mine == tft_alloc.EPSILON_64): str_opd = "rnd64(" + str_opd + ")" elif (bw_mine == tft_alloc.EPSILON_128): str_opd = "rnd128(" + str_opd + ")" else: assert (False) return FPTaylorTypeCastWrap(bw_mine, expr.operator.label + "(" + str_opd + ")") if (isinstance(expr, tft_expr.BinaryExpr)): cast_lhs = False cast_rhs = False bw_mine = alloc[expr.getGid()] if (isinstance(expr.lhs(), tft_expr.ConstantExpr)): cast_lhs = True else: bw_lhs = alloc[expr.lhs().getGid()] if (bw_lhs != bw_mine): cast_lhs = True if (isinstance(expr.rhs(), tft_expr.ConstantExpr)): cast_rhs = True else: bw_rhs = alloc[expr.rhs().getGid()] if (bw_rhs != bw_mine): cast_rhs = True str_lhs = FPTaylorExpr(expr.lhs(), alloc) str_rhs = FPTaylorExpr(expr.rhs(), alloc) if (cast_lhs): if (bw_mine == tft_alloc.EPSILON_32): str_lhs = "rnd32(" + str_lhs + ")" elif (bw_mine == tft_alloc.EPSILON_64): str_lhs = "rnd64(" + str_lhs + ")" elif (bw_mine == tft_alloc.EPSILON_128): str_lhs = "rnd128(" + str_lhs + ")" else: assert (False) if (cast_rhs): if (bw_mine == tft_alloc.EPSILON_32): str_rhs = "rnd32(" + str_rhs + ")" elif (bw_mine == tft_alloc.EPSILON_64): str_rhs = "rnd64(" + str_rhs + ")" elif (bw_mine == tft_alloc.EPSILON_128): str_rhs = "rnd128(" + str_rhs + ")" else: assert (False) return FPTaylorTypeCastWrap( bw_mine, "(" + str_lhs + " " + expr.operator.label + " " + str_rhs + ")") sys.exit("Error: not supported expr 4 FPTaylorExpr...")