func (v *Codegen) genBoundsCheck(limit llvm.Value, index llvm.Value, indexType parser.Type) { segvBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_segv") endBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_end") upperCheckBlock := llvm.AddBasicBlock(v.currentLLVMFunction(), "boundscheck_upper_block") tooLow := v.builder().CreateICmp(llvm.IntSGT, llvm.ConstInt(index.Type(), 0, false), index, "boundscheck_lower") v.builder().CreateCondBr(tooLow, segvBlock, upperCheckBlock) v.builder().SetInsertPointAtEnd(upperCheckBlock) // make sure limit and index have same width castedLimit := limit castedIndex := index if index.Type().IntTypeWidth() < limit.Type().IntTypeWidth() { if indexType.IsSigned() { castedIndex = v.builder().CreateSExt(index, limit.Type(), "") } else { castedIndex = v.builder().CreateZExt(index, limit.Type(), "") } } else if index.Type().IntTypeWidth() > limit.Type().IntTypeWidth() { castedLimit = v.builder().CreateZExt(limit, index.Type(), "") } tooHigh := v.builder().CreateICmp(llvm.IntSLE, castedLimit, castedIndex, "boundscheck_upper") v.builder().CreateCondBr(tooHigh, segvBlock, endBlock) v.builder().SetInsertPointAtEnd(segvBlock) v.genRaiseSegfault() v.builder().CreateUnreachable() v.builder().SetInsertPointAtEnd(endBlock) }
func (v *Codegen) genBinop(operator parser.BinOpType, resType, lhandType, rhandType parser.Type, lhand, rhand llvm.Value) llvm.Value { if lhand.IsNil() || rhand.IsNil() { v.err("invalid binary expr") } else { switch operator { // Arithmetic case parser.BINOP_ADD: if resType.IsFloatingType() { return v.builder().CreateFAdd(lhand, rhand, "") } else { return v.builder().CreateAdd(lhand, rhand, "") } case parser.BINOP_SUB: if resType.IsFloatingType() { return v.builder().CreateFSub(lhand, rhand, "") } else { return v.builder().CreateSub(lhand, rhand, "") } case parser.BINOP_MUL: if resType.IsFloatingType() { return v.builder().CreateFMul(lhand, rhand, "") } else { return v.builder().CreateMul(lhand, rhand, "") } case parser.BINOP_DIV: if resType.IsFloatingType() { return v.builder().CreateFDiv(lhand, rhand, "") } else { if resType.(parser.PrimitiveType).IsSigned() { return v.builder().CreateSDiv(lhand, rhand, "") } else { return v.builder().CreateUDiv(lhand, rhand, "") } } case parser.BINOP_MOD: if resType.IsFloatingType() { return v.builder().CreateFRem(lhand, rhand, "") } else { if resType.(parser.PrimitiveType).IsSigned() { return v.builder().CreateSRem(lhand, rhand, "") } else { return v.builder().CreateURem(lhand, rhand, "") } } // Comparison case parser.BINOP_GREATER, parser.BINOP_LESS, parser.BINOP_GREATER_EQ, parser.BINOP_LESS_EQ, parser.BINOP_EQ, parser.BINOP_NOT_EQ: if lhandType.IsFloatingType() { return v.builder().CreateFCmp(comparisonOpToFloatPredicate(operator), lhand, rhand, "") } else { return v.builder().CreateICmp(comparisonOpToIntPredicate(operator, lhandType.IsSigned()), lhand, rhand, "") } // Bitwise case parser.BINOP_BIT_AND: return v.builder().CreateAnd(lhand, rhand, "") case parser.BINOP_BIT_OR: return v.builder().CreateOr(lhand, rhand, "") case parser.BINOP_BIT_XOR: return v.builder().CreateXor(lhand, rhand, "") case parser.BINOP_BIT_LEFT: return v.builder().CreateShl(lhand, rhand, "") case parser.BINOP_BIT_RIGHT: // TODO make sure both operands are same type (create type cast here?) // TODO in semantic.go, make sure rhand is *unsigned* (LLVM always treats it that way) // TODO doc this if lhandType.IsSigned() { return v.builder().CreateAShr(lhand, rhand, "") } else { return v.builder().CreateLShr(lhand, rhand, "") } default: panic("umimplented binop") } } panic("unreachable") }