/* * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ssa import ( "go/token" "github.com/goplus/llvm" ) type valueKind = int type Value struct { impl llvm.Value kind valueKind } const ( mathOpBase = token.ADD mathOpLast = token.REM ) const ( vkInvalid valueKind = iota vkSigned vkUnsigned vkFloat vkComplex vkString vkBool ) var mathOpToLLVM = []llvm.Opcode{ int(token.ADD-mathOpBase)<<2 | vkSigned: llvm.Add, int(token.ADD-mathOpBase)<<2 | vkUnsigned: llvm.Add, int(token.ADD-mathOpBase)<<2 | vkFloat: llvm.FAdd, int(token.SUB-mathOpBase)<<2 | vkSigned: llvm.Sub, int(token.SUB-mathOpBase)<<2 | vkUnsigned: llvm.Sub, int(token.SUB-mathOpBase)<<2 | vkFloat: llvm.FSub, int(token.MUL-mathOpBase)<<2 | vkSigned: llvm.Mul, int(token.MUL-mathOpBase)<<2 | vkUnsigned: llvm.Mul, int(token.MUL-mathOpBase)<<2 | vkFloat: llvm.FMul, int(token.QUO-mathOpBase)<<2 | vkSigned: llvm.SDiv, int(token.QUO-mathOpBase)<<2 | vkUnsigned: llvm.UDiv, int(token.QUO-mathOpBase)<<2 | vkFloat: llvm.FDiv, int(token.REM-mathOpBase)<<2 | vkSigned: llvm.SRem, int(token.REM-mathOpBase)<<2 | vkUnsigned: llvm.URem, int(token.REM-mathOpBase)<<2 | vkFloat: llvm.FRem, } func mathOpIdx(op token.Token, x valueKind) int { return int(op-mathOpBase)<<2 | x } // ADD SUB MUL QUO REM + - * / % func isMathOp(op token.Token) bool { return op >= mathOpBase && op <= mathOpLast } const ( logicOpBase = token.AND logicOpLast = token.AND_NOT ) var logicOpToLLVM = []llvm.Opcode{ token.AND - logicOpBase: llvm.And, token.OR - logicOpBase: llvm.Or, token.XOR - logicOpBase: llvm.Xor, token.SHL - logicOpBase: llvm.Shl, token.SHR - logicOpBase: llvm.LShr, } // AND OR XOR SHL SHR AND_NOT & | ^ << >> &^ func isLogicOp(op token.Token) bool { return op >= logicOpBase && op <= logicOpLast } const ( predOpBase = token.EQL predOpLast = token.GEQ ) var intPredOpToLLVM = []llvm.IntPredicate{ token.EQL - predOpBase: llvm.IntEQ, token.NEQ - predOpBase: llvm.IntNE, token.LSS - predOpBase: llvm.IntSLT, token.LEQ - predOpBase: llvm.IntSLE, token.GTR - predOpBase: llvm.IntSGT, token.GEQ - predOpBase: llvm.IntSGE, } var uintPredOpToLLVM = []llvm.IntPredicate{ token.EQL - predOpBase: llvm.IntEQ, token.NEQ - predOpBase: llvm.IntNE, token.LSS - predOpBase: llvm.IntULT, token.LEQ - predOpBase: llvm.IntULE, token.GTR - predOpBase: llvm.IntUGT, token.GEQ - predOpBase: llvm.IntUGE, } var floatPredOpToLLVM = []llvm.FloatPredicate{ token.EQL - predOpBase: llvm.FloatOEQ, token.NEQ - predOpBase: llvm.FloatONE, token.LSS - predOpBase: llvm.FloatOLT, token.LEQ - predOpBase: llvm.FloatOLE, token.GTR - predOpBase: llvm.FloatOGT, token.GEQ - predOpBase: llvm.FloatOGE, } // EQL NEQ LSS LEQ GTR GEQ == != < <= < >= func isPredOp(op token.Token) bool { return op >= predOpBase && op <= predOpLast } // op: // ADD SUB MUL QUO REM + - * / % // AND OR XOR SHL SHR AND_NOT & | ^ << >> &^ // EQL NEQ LSS LEQ GTR GEQ == != < <= < >= func (b Builder) BinOp(op token.Token, x, y Value) (v Value) { switch { case isMathOp(op): // op: + - * / % switch x.kind { case vkString, vkComplex: panic("todo") } idx := mathOpIdx(op, x.kind) if llop := mathOpToLLVM[idx]; llop != 0 { v.impl = llvm.CreateBinOp(b.impl, llop, x.impl, y.impl) return } case isLogicOp(op): // op: & | ^ << >> &^ if op == token.AND_NOT { panic("todo") } llop := logicOpToLLVM[op-logicOpBase] if op == token.SHR && x.kind == vkUnsigned { llop = llvm.AShr } v.impl = llvm.CreateBinOp(b.impl, llop, x.impl, y.impl) return case isPredOp(op): // op: == != < <= < >= switch x.kind { case vkSigned: pred := intPredOpToLLVM[op-predOpBase] v.impl = llvm.CreateICmp(b.impl, pred, x.impl, y.impl) return case vkUnsigned: pred := uintPredOpToLLVM[op-predOpBase] v.impl = llvm.CreateICmp(b.impl, pred, x.impl, y.impl) return case vkFloat: pred := floatPredOpToLLVM[op-predOpBase] v.impl = llvm.ConstFCmp(pred, x.impl, y.impl) return case vkString, vkComplex, vkBool: panic("todo") } } return }