multi.isa (4310:8f9d834f19bc) | multi.isa (4323:13ca4002d2ac) |
---|---|
1// -*- mode:c++ -*- 2 3// Copyright (c) 2007 The Hewlett-Packard Development Company 4// All rights reserved. 5// 6// Redistribution and use of this software in source and binary forms, 7// with or without modification, are permitted provided that the 8// following conditions are met: --- 46 unchanged lines hidden (view full) --- 55// 56// Authors: Gabe Black 57 58//////////////////////////////////////////////////////////////////// 59// 60// Instructions that do the same thing to multiple sets of arguments. 61// 62 | 1// -*- mode:c++ -*- 2 3// Copyright (c) 2007 The Hewlett-Packard Development Company 4// All rights reserved. 5// 6// Redistribution and use of this software in source and binary forms, 7// with or without modification, are permitted provided that the 8// following conditions are met: --- 46 unchanged lines hidden (view full) --- 55// 56// Authors: Gabe Black 57 58//////////////////////////////////////////////////////////////////// 59// 60// Instructions that do the same thing to multiple sets of arguments. 61// 62 |
63output header {{ | 63let {{ 64 # This builds either a regular or macro op to implement the sequence of 65 # ops we give it. 66 def genInst(name, Name, ops): 67 # If we can implement this instruction with exactly one microop, just 68 # use that directly. 69 newStmnt = '' 70 if len(ops) == 1: 71 decode_block = "return (X86StaticInst *)(%s);" % \ 72 ops[0].getAllocator() 73 return ('', '', decode_block, '') 74 else: 75 # Build a macroop to contain the sequence of microops we've 76 # been given. 77 return genMacroOp(name, Name, ops) |
64}}; 65 | 78}}; 79 |
66output decoder {{ | 80let {{ 81 # This code builds up a decode block which decodes based on switchval. 82 # vals is a dict which matches case values with what should be decoded to. 83 # builder is called on the exploded contents of "vals" values to generate 84 # whatever code should be used. 85 def doMultiOp(name, Name, builder, switchVal, vals, default = None): 86 header_output = '' 87 decoder_output = '' 88 decode_block = 'switch(%s) {\n' % switchVal 89 exec_output = '' 90 for (val, todo) in vals.items(): 91 (new_header_output, 92 new_decoder_output, 93 new_decode_block, 94 new_exec_output) = builder(name, Name, *todo) 95 header_output += new_header_output 96 decoder_output += new_decoder_output 97 decode_block += '\tcase %s: %s\n' % (val, new_decode_block) 98 exec_output += new_exec_output 99 if default: 100 (new_header_output, 101 new_decoder_output, 102 new_decode_block, 103 new_exec_output) = builder(name, Name, *default) 104 header_output += new_header_output 105 decoder_output += new_decoder_output 106 decode_block += '\tdefault: %s\n' % new_decode_block 107 exec_output += new_exec_output 108 decode_block += '}\n' 109 return (header_output, decoder_output, decode_block, exec_output) |
67}}; 68 | 110}}; 111 |
69output exec {{ 70}}; 71 | |
72let {{ | 112let {{ |
73 multiops = {} 74}}; | |
75 | 113 |
76def format MultiOp(code, switchVal, opTags, *opt_flags) {{ 77 # These are C++ statements to create each type of static int. Since we 78 # don't know what will be microcoded and what won't, we can't assume a 79 # particular set of arguments for the constructor. 80 instNew = [] 81 orig_code = code 82 opRe = re.compile(r"%(?P<operandNum>[0-9]*)") 83 # Get all the labels out of the code and make a dict for them. We'll do 84 # this once since the position of labels shouldn't need to change at all. 85 ops = assembleMicro(code) 86 labels = buildLabelDict(ops) 87 for tagSet in opTags: 88 # A list of strings which either have the register number to use, or 89 # a piece of code for calculating it. 90 regNums = [] 91 code = orig_code 92 # Build up a name for this instructions class using the argument 93 # types. Each variation will get its own name this way. 94 postfix = '' 95 for tag in tagSet: 96 postfix += '_' + tag | 114 # This function specializes the given piece of code to use a particular 115 # set of argument types described by "opTags". These are "implemented" 116 # in reverse order. 117 def doCompOps(name, Name, code, opTags, postfix): 118 opNum = len(opTags) - 1 119 while len(opTags): 120 # print "Building a composite op with tags", opTags 121 # print "And code", code 122 opNum = len(opTags) - 1 123 # A regular expression to find the operand placeholders we're 124 # interested in. 125 opRe = re.compile("%%(?P<operandNum>%d)(?=[^0-9]|$)" % opNum) 126 tag = opTags[opNum] 127 # Build up a name for this instructions class using the argument 128 # types. Each variation will get its own name this way. 129 postfix = '_' + tag + postfix 130 tagParser = re.compile(r"(?P<tagType>[A-Z][A-Z]*)(?P<tagSize>[a-z][a-z]*)|(r(?P<tagReg>[A-Za-z0-9][A-Za-z0-9]*))") 131 tagMatch = tagParser.search(tag) 132 if tagMatch == None: 133 raise Exception, "Problem parsing operand tag %s" % tag 134 reg = tagMatch.group("tagReg") 135 tagType = tagMatch.group("tagType") 136 tagSize = tagMatch.group("tagSize") 137 if reg: 138 #Figure out what to do with fixed register operands 139 if reg in ("Ax", "Bx", "Cx", "Dx"): 140 code = opRe.sub("{INTREG_R%s}" % reg.upper(), code) 141 elif reg == "Al": 142 # We need a way to specify register width 143 code = opRe.sub("{INTREG_RAX}", code) 144 else: 145 print "Didn't know how to encode fixed register %s!" % reg 146 elif tagType == None or tagSize == None: 147 raise Exception, "Problem parsing operand tag: %s" % tag 148 elif tagType == "C" or tagType == "D" or tagType == "G" or \ 149 tagType == "P" or tagType == "S" or \ 150 tagType == "T" or tagType == "V": 151 # Use the "reg" field of the ModRM byte to select the register 152 code = opRe.sub("{(uint8_t)MODRM_REG}", code) 153 elif tagType == "E" or tagType == "Q" or tagType == "W": 154 # This might refer to memory or to a register. We need to 155 # divide it up farther. 156 regCode = opRe.sub("{(uint8_t)MODRM_RM}", code) 157 regTags = copy.copy(opTags) 158 regTags.pop(-1) 159 # This needs to refer to memory, but we'll fill in the details 160 # later. It needs to take into account unaligned memory 161 # addresses. 162 memCode = opRe.sub("0", code) 163 memTags = copy.copy(opTags) 164 memTags.pop(-1) 165 return doMultiOp(name, Name, doCompOps, "MODRM_MOD", 166 {"3" : (regCode, regTags, postfix)}, 167 (memCode, memTags, postfix)) 168 elif tagType == "I" or tagType == "J": 169 # Substitute in an immediate 170 code = opRe.sub("{IMMEDIATE}", code) 171 elif tagType == "M": 172 # This needs to refer to memory, but we'll fill in the details 173 # later. It needs to take into account unaligned memory 174 # addresses. 175 code = opRe.sub("0", code) 176 elif tagType == "PR" or tagType == "R" or tagType == "VR": 177 # There should probably be a check here to verify that mod 178 # is equal to 11b 179 code = opRe.sub("{(uint8_t)MODRM_RM}", code) 180 else: 181 raise Exception, "Unrecognized tag %s." % tag 182 opTags.pop(-1) |
97 | 183 |
98 # Figure out what register indexes to use for each operand. This 99 # is where loads/stores could be set up. I need to distinguish 100 # between inputs and outputs. 101 # For right now, the indexes are just an increasing sequence 102 counter = 0 103 for tag in tagSet: 104 regNums.append("%d" % counter) 105 counter += 1 106 107 # Replace the placeholders %0, %1, etc., with the right register 108 # indexes. 109 opMatch = opRe.search(code) 110 while opMatch: 111 opNum = opMatch.group("operandNum") 112 opNum = int(opNum) 113 if opNum > len(regNums): 114 print "No operand type specified for operand %d!" % opNum 115 print "I should bail out here too!" 116 regNum = regNums[opNum] 117 code = opRe.sub(regNum, code, 1) 118 opMatch = opRe.search(code) 119 120 # All the loads which feed this instruction 121 loads = [] 122 # All the ops that make up the instruction proper. | 184 # At this point, we've built up "code" to have all the necessary extra 185 # instructions needed to implement whatever types of operands were 186 # specified. Now we'll assemble it it into a microOp sequence. |
123 ops = assembleMicro(code) | 187 ops = assembleMicro(code) |
124 # Get all the labels out and make a dict for them 125 # All the stores for this instruction's results 126 stores = [] | |
127 | 188 |
128 # Various counts 129 numLoads = len(loads) 130 numOps = len(ops) 131 numStores = len(stores) 132 totalOps = numLoads + numOps + numStores 133 print "There are %d total ops" % totalOps | 189 # Build a macroop to contain the sequence of microops we've 190 # constructed. The decode block will be used to fill in our 191 # inner decode structure, and the rest will be concatenated and 192 # passed back. 193 return genInst(name, Name + postfix, ops) 194}}; |
134 | 195 |
135 # If we can implement this instruction with exactly one microop, just 136 # use that directly. 137 newStmnt = '' 138 if totalOps == 1: 139 newStmnt = ops[0].getAllocator(labels) 140 else: 141 # Build up a macro op. We'll punt on this for now 142 pass | 196def format TaggedOp(code, tagSet) {{ 197 (header_output, 198 decoder_output, 199 decode_block, 200 exec_output) = doCompOps(name, Name, code, tagSet, '') 201}}; |
143 | 202 |
144 instNew.append(newStmnt) 145 146 decodeBlob = 'switch(%s) {\n' % switchVal 147 counter = 0 148 for newStmnt in instNew: 149 decodeBlob += 'case %d: return (X86StaticInst *)(%s);\n' % \ 150 (counter, newStmnt) 151 counter += 1 152 decodeBlob += '}\n' 153 decode_block = decodeBlob | 203def format MultiOp(code, switchVal, opTags, *opt_flags) {{ 204 switcher = {} 205 for (count, tagSet) in zip(xrange(len(opTags) - 1), opTags): 206 switcher[count] = (code, tagSet, '') 207 (header_output, 208 decoder_output, 209 decode_block, 210 exec_output) = doMultiOp(name, Name, doCompOps, switchVal, switcher) |
154}}; | 211}}; |