[llvm] [Utils][SPIR-V] Adding spirv-sim to LLVM (PR #104020)

Michal Paszkowski via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 19 23:02:00 PDT 2024


Nathan =?utf-8?q?Gauër?= <brioche at google.com>,
Nathan =?utf-8?q?Gauër?= <brioche at google.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/104020 at github.com>


================
@@ -0,0 +1,387 @@
+# Base class for an instruction. To implement a basic instruction that doesn't
+# impact the control-flow, create a new class inheriting from this.
+class Instruction:
+    _result: str
+
+    def __init__(self, line: str):
+        # Contains the name of the output register, if any.
+        self._result: str = None
+        # Contains the instruction opcode.
+        self._opcode: str = None
+        # Contains all the instruction operands, except result and opcode.
+        self._operands: list[str] = []
+
+        self.line = line
+        tokens = line.split()
+        if len(tokens) > 1 and tokens[1] == "=":
+            self._result = tokens[0]
+            self._opcode = tokens[2]
+            self._operands = tokens[3:] if len(tokens) > 2 else []
+        else:
+            self._result = None
+            self._opcode = tokens[0]
+            self._operands = tokens[1:] if len(tokens) > 1 else []
+
+    def __str__(self):
+        if self._result is None:
+            return f"      {self._opcode} {self._operands}"
+        return f"{self._result:3} = {self._opcode} {self._operands}"
+
+    # Returns the instruction opcode.
+    def opcode(self) -> str:
+        return self._opcode
+
+    # Returns the instruction operands.
+    def operands(self) -> list[str]:
+        return self._operands
+
+    # Returns the instruction output register. Calling this function is
+    # only allowed if has_output_register() is true.
+    def output_register(self) -> str:
+        assert self.has_output_register()
+        return self._result
+
+    # Returns true if this function has an output register. False otherwise.
+    def has_output_register(self) -> bool:
+        return self._result is not None
+
+    # This function is used to initialize state related to this instruction
+    # before module execution begins. For example, global Input variables
+    # can use this to store the lane ID into the register.
+    def static_execution(self, lane):
+        pass
+
+    # This function is called everytime this instruction is executed by a
+    # tangle. This function should not be directly overriden, instead see
+    # _impl and _advance_ip.
+    def runtime_execution(self, module, lane):
+        self._impl(module, lane)
+        self._advance_ip(module, lane)
+
+    # This function needs to be overriden if your instruction can be executed.
+    # It implements the logic of the instruction.
+    # 'Static' instructions like OpConstant should not override this since
+    # they are not supposed to be executed at runtime.
+    def _impl(self, module, lane):
+        raise RuntimeError(f"Unimplemented instruction {self}")
+
+    # By default, IP is incremented to point to the next instruction.
+    # If the instruction modifies IP (like OpBranch), this must be overridden.
+    def _advance_ip(self, module, lane):
+        lane.set_ip(lane.ip() + 1)
+
+
+# Those are parsed, but never executed.
+class OpEntryPoint(Instruction):
+    pass
+
+
+class OpFunction(Instruction):
+    pass
+
+
+class OpFunctionEnd(Instruction):
+    pass
+
+
+class OpLabel(Instruction):
+    pass
+
+
+class OpVariable(Instruction):
+    pass
+
+
+class OpName(Instruction):
+    def name(self) -> str:
+        return self._operands[1][1:-1]
+
+    def decoratedRegister(self) -> str:
+        return self._operands[0]
+
+
+# The only decoration we use if the BuilIn one to initialize the values.
+class OpDecorate(Instruction):
+    def static_execution(self, lane):
+        if self._operands[1] == "LinkageAttributes":
+            return
+
+        assert (
+            self._operands[1] == "BuiltIn"
+            and self._operands[2] == "SubgroupLocalInvocationId"
+        )
+        lane.set_register(self._operands[0], lane.tid())
+
+
+# Constants
+class OpConstant(Instruction):
+    def static_execution(self, lane):
+        lane.set_register(self._result, int(self._operands[1]))
+
+
+class OpConstantTrue(OpConstant):
+    def static_execution(self, lane):
+        lane.set_register(self._result, True)
+
+
+class OpConstantFalse(OpConstant):
+    def static_execution(self, lane):
+        lane.set_register(self._result, False)
+
+
+class OpConstantComposite(OpConstant):
+    def static_execution(self, lane):
+        result = []
+        length = self.get_register(self._operands[0])
+        for op in self._operands[1:]:
+            result.append(self.get_register(op))
+        lane.set_register(self._result, result)
+
+
+class OpConstantComposite(OpConstant):
----------------
michalpaszkowski wrote:

`OpConstantComposite` is defined twice

https://github.com/llvm/llvm-project/pull/104020


More information about the llvm-commits mailing list