diff --git a/llvm/projects/hpvm-tensor-rt/code_autogenerators/online_benchmark_testing_automator.py b/llvm/projects/hpvm-tensor-rt/code_autogenerators/benchmark_different_clock_frequencies_testing_automator.py
similarity index 100%
rename from llvm/projects/hpvm-tensor-rt/code_autogenerators/online_benchmark_testing_automator.py
rename to llvm/projects/hpvm-tensor-rt/code_autogenerators/benchmark_different_clock_frequencies_testing_automator.py
diff --git a/llvm/projects/hpvm-tensor-rt/code_autogenerators/source_code_autogenerator.py b/llvm/projects/hpvm-tensor-rt/code_autogenerators/source_code_autogenerator.py
index 0ee30bf36d170f403a645914486e500ff3bda546..d587a3b7b57b96c8eb61b2e3e63709c7745ed466 100644
--- a/llvm/projects/hpvm-tensor-rt/code_autogenerators/source_code_autogenerator.py
+++ b/llvm/projects/hpvm-tensor-rt/code_autogenerators/source_code_autogenerator.py
@@ -10,6 +10,12 @@ import sys
 import os
 import re
 
+class Approx:
+    FP32 = 0
+    FP16 = 1
+    PERF = 2
+    SAMP = 3
+
 class KnobConfiguration:
     '''
     Stores the configurations as well as other useful information for each knob configuration
@@ -24,12 +30,45 @@ class KnobConfiguration:
         Args: raw_config = line of configuration file to parse
         '''
         line_as_lst = raw_config.strip().split()
+        # approx,<id> knob1,knob2,etc IGNORE old_fun_name new_fun_name
+
+        approx_id_lst = line_as_lst[0].split(',')
+        assert len(approx_id_lst) == 2
+
+        self.id = int(approx_id_lst[1])
+
+        if approx_id_lst[0] == "fp32":
+            self.approx = Approx.FP32
+            return # special case 
+        elif approx_id_lst[0] == "fp16":
+            self.approx = Approx.FP16
+            return # special case
+        elif approx_id_lst[0] == "perf":
+            self.approx = Approx.PERF
+        elif approx_id_lst[0] == "samp":
+            self.approx = Approx.SAMP
+
+        self.orig_func_name = line_as_lst[-2] # Second to last element
+        self.modified_func_name = line_as_lst[-1] # Last element  
+        self.params = line_as_lst[1].split(",") # First element = knob configuration 
+ 
+
+    # DEBUG
+    def __repr__(self):
+        if self.approx == Approx.FP32:
+            return "FP32"
+        elif self.approx == Approx.FP16:
+            return "FP16"
+
+        approx_type = None
+        if self.approx == Approx.PERF:
+            approx_type = "PERF"
+        elif self.approx == Approx.SAMP:
+            approx_type = "SAMP"
+        return "Approx: %s, ID: %d, Orig func nane: %s, Modified func nane: %s, Params: %s" \
+                % (approx_type, self.id, self.orig_func_name, self.modified_func_name, \
+                   ', '.join(self.params))
 
-        self.id = int(line_as_lst[0])
-        self.orig_func_name = line_as_lst[-2]
-        self.modified_func_name = line_as_lst[-1]
-        self.params = line_as_lst[1:-2]
-   
 
 def get_new_path(old_path, orig_source_code_dir):
     '''
@@ -71,10 +110,96 @@ def get_new_function_calls(complete_line, knob_config):
         new_line.append("%s%s, %s)" % (knob_config.modified_func_name, old_func_call[:-1], ', '.join(knob_config.params)))
         orig_func_ind = complete_line.find(knob_config.orig_func_name, line_start_ind)
 	new_line.append(complete_line[line_start_ind : ])
-    #print(new_line)
     return ''.join(new_line)
 
 
+def convert_local_paths(file_contents, orig_source_dir): 
+    '''
+    Converts all local paths wrt the original source file's directory to paths compatible
+    with the current source code directory
+
+    Args:
+        file_contents: String containing source code read from file
+        orig_source_dir: Path of original source code dir wrt the current directory 
+    '''
+    last_include_ind = file_contents.rfind("#include")
+    last_include_newline_ind = file_contents.find("\n", last_include_ind)
+    include_lines = file_contents[ : last_include_newline_ind].split("\n")
+    
+    new_file_contents = []
+    for line in include_lines:
+        if line.startswith("#"):
+            include_file = line.split()[1]
+            if include_file.startswith("\""):
+                new_include_path = get_new_path(include_file.replace("\"", ""), orig_source_dir.replace("\"", ""))
+                new_file_contents.append("#include \"%s\"\n" % new_include_path)
+            else:
+                new_file_contents.append(line)
+    new_file_contents.append(file_contents[last_include_newline_ind : ])
+    return '\n'.join(new_file_contents)
+
+
+def generate_fp32_source(new_file, source_file, orig_source_dir):
+    # Copy the source code over 
+    new_file_contents = convert_local_paths(source_file.read(), orig_source_dir)
+    new_file.write(new_file_contents)
+
+
+def generate_fp16_source(knob_config, new_file, source_file, orig_source_dir):
+    file_contents = source_file.read()
+
+    new_file_contents = convert_local_paths(file_contents, orig_source_dir)
+
+    # Replace all tensorOperation calls with tensorHalfOperation calls
+    # Derived from ../bin/replace_half_calls.py 
+    # NOTE: Not very portable but I don't see another way of ONLY replacing tensorOperation FUNCTION calls
+    new_file_contents = new_file_contents.replace("tensorConvolution", "tensorHalfConvolution")
+    new_file_contents = new_file_contents.replace("tensorAdd", "tensorHalfAdd")
+    new_file_contents = new_file_contents.replace("tensorRelu", "tensorHalfRelu")
+    new_file_contents = new_file_contents.replace("tensorRelu2", "tensorHalfRelu2")
+    new_file_contents = new_file_contents.replace("tensorTanh", "tensorHalfTanh")
+    new_file_contents = new_file_contents.replace("tensorPooling", "tensorHalfPooling")
+    new_file_contents = new_file_contents.replace("tensorGemmGPU", "tensorHalfGemmGPU")
+   
+    new_file.write(new_file_contents)
+
+
+def generate_approx_source(knob_config, new_file, source_file, orig_source_dir):
+	new_file_contents = []
+
+	# Store complete line to handle cases where one line of code is split into two lines
+	complete_line = ""
+	for line in source_file:
+		# Replace the current path of the local include with a path that's compatible 
+		# with the location of the generated source code 
+		if line.startswith("#"):
+			include_file = line.split()[1]
+			if include_file.startswith("\""):
+				new_include_path = get_new_path(include_file.replace("\"", ""), orig_source_dir.replace("\"", ""))
+				new_file_contents.append("#include \"%s\"\n" % new_include_path)
+			else:
+				new_file_contents.append(line)
+			continue
+		# Handles case where 1 actual line of code is split into 2 lines 
+		elif line.find("}") != -1 or line.find("{") != -1:
+			complete_line += line
+			new_file_contents.append(complete_line)
+			complete_line = ""
+			continue
+		elif line.find(";") == -1: # Last char is always \n
+			complete_line += line
+			continue
+
+		complete_line += line
+		orig_func_ind = complete_line.find(knob_config.orig_func_name)
+		if orig_func_ind != -1:
+			new_file_contents.append(get_new_function_calls(complete_line, knob_config))
+		else:
+			new_file_contents.append(complete_line)
+		complete_line = ""
+	new_file.write(''.join(new_file_contents))
+
+
 def generate_source_code(table, dir_name, filename, source_name):
     '''
     Generates source code for all configurations in the table for one original source 
@@ -84,50 +209,20 @@ def generate_source_code(table, dir_name, filename, source_name):
         filename: Filename of original source
         source_name: Filename without the file extension (ex: foo/blah.cc --> blah)
     '''
-    file_comment = "// AUTO-GENERATED SOURCE CODE. REPLACED ALL INSTANCES OF %s WITH %s\n"
-
     source_file = open(filename, "r") 
-    filename_dir = os.path.dirname(filename)
+    orig_source_dir = os.path.dirname(filename)
 
     for knob_config in table:
         source_file.seek(0, 0)
-       
-        new_file_contents = [file_comment % (knob_config.orig_func_name, knob_config.modified_func_name)]
-
-        # Store complete line to handle cases where one line of code is split into two lines
-        complete_line = ""
-        for line in source_file:
-            # Replace the current path of the local include with a path that's compatible 
-            # with the location of the generated source code 
-            if line.startswith("#"):
-                include_file = line.split()[1]
-                if include_file.startswith("\""):
-                    new_include_path = get_new_path(include_file.replace("\"", ""), filename_dir.replace("\"", ""))
-                    new_file_contents.append("#include \"%s\"\n" % new_include_path)
-                else:
-                    new_file_contents.append(line)
-                continue
-            # Handles case where 1 actual line of code is split into 2 lines 
-            elif line.find("}") != -1 or line.find("{") != -1:
-                complete_line += line
-                new_file_contents.append(complete_line)
-                complete_line = ""
-                continue
-            elif line.find(";") == -1: # Last char is always \n
-                complete_line += line
-                continue
-
-            complete_line += line
-            orig_func_ind = complete_line.find(knob_config.orig_func_name)
-            if orig_func_ind != -1:
-				new_file_contents.append(get_new_function_calls(complete_line, knob_config))
-            else:
-                new_file_contents.append(complete_line)
-            complete_line = ""
-
         new_filename = os.path.join(dir_name, "%s_%s.cc" % (source_name, knob_config.id))
         new_file = open(new_filename, "w")
-        new_file.write(''.join(new_file_contents))
+        if knob_config.approx == Approx.FP16:
+            generate_fp16_source(knob_config, new_file, source_file, orig_source_dir)
+        elif knob_config.approx == Approx.FP32:
+            generate_fp32_source(new_file, source_file, orig_source_dir)
+        else:
+			generate_approx_source(knob_config, new_file, source_file, orig_source_dir)
+
         new_file.close()
         print("Generated source code as %s" % new_filename)
     source_file.close()