RValue Inst::PointerMath(int type, RValue ptr, RValue val, CodeContext& context) { if (type != ParserBase::TT_INC && type != ParserBase::TT_DEC) { context.addError("pointer arithmetic only valid using ++/-- operators"); return ptr; } auto ptrVal = GetElementPtrInst::Create(ptr, val.value(), "", context); return RValue(ptrVal, ptr.stype()); }
RValue Inst::Deref(CodeContext& context, RValue value, bool recursive) { auto retVal = RValue(value.value(), value.stype()); while (retVal.stype()->isPointer()) { retVal = RValue(new LoadInst(retVal, "", context), retVal.stype()->subType()); if (!recursive) break; } return retVal; }
bool Inst::CastMatch(CodeContext& context, RValue& lhs, RValue& rhs, bool upcast) { auto ltype = lhs.stype(); auto rtype = rhs.stype(); if (ltype == rtype) { return false; } else if (ltype->isComplex() || rtype->isComplex()) { context.addError("can not cast complex types"); return true; } else if (ltype->isPointer() || rtype->isPointer()) { // different pointer types can't be cast automatically // the operations need to handle pointers specially return false; } auto toType = SType::numericConv(context, ltype, rtype, upcast); return CastTo(context, lhs, toType, upcast) || CastTo(context, rhs, toType, upcast); }
RValue Inst::BinaryOp(int type, RValue lhs, RValue rhs, CodeContext& context) { if (!lhs || !rhs) return RValue(); if (CastMatch(context, lhs, rhs, true)) return RValue(); switch ((lhs.stype()->isPointer() << 1) | rhs.stype()->isPointer()) { default: case 0: // no pointer { auto llvmOp = getOperator(type, lhs.stype(), context); return RValue(BinaryOperator::Create(llvmOp, lhs, rhs, "", context), lhs.stype()); } case 1: // lhs != ptr, rhs == ptr swap(lhs, rhs); case 2: // lhs == ptr, rhs != ptr return PointerMath(type, lhs, rhs, context); case 3: // both ptr context.addError("can't perform operation with two pointers"); return lhs; } }
RValue Inst::Cmp(int type, RValue lhs, RValue rhs, CodeContext& context) { if (CastMatch(context, lhs, rhs)) return RValue(); auto pred = getPredicate(type, lhs.stype(), context); auto cmpType = lhs.stype()->isVec()? lhs.stype()->subType() : lhs.stype(); auto op = cmpType->isFloating()? Instruction::FCmp : Instruction::ICmp; auto cmp = CmpInst::Create(op, pred, lhs, rhs, "", context); auto retType = lhs.stype()->isVec()? SType::getVec(context, SType::getBool(context), lhs.stype()->size()) : SType::getBool(context); return RValue(cmp, retType); }
bool Inst::CastTo(CodeContext& context, RValue& value, SType* type, bool upcast) { auto valueType = value.stype(); if (type == valueType) { // non-assignment and non-comparison operations with enum types // must result in an int type to keep enum variables within range. if (upcast && valueType->isEnum()) value.castToSubtype(); return false; } else if (type->isComplex() || valueType->isComplex()) { context.addError("can not cast complex types"); return true; } else if (type->isPointer()) { if (value.isNullPtr()) { // NOTE: discard current null value and create // a new one using the right type value = RValue::getNullPtr(context, type); return false; } else if (type->subType()->isVoid()) { value = RValue(new BitCastInst(value, *type, "", context), type); return false; } context.addError("can't cast value to pointer type"); return true; } else if (type->isVec()) { // unwrap enum type if (valueType->isEnum()) valueType = value.castToSubtype(); if (valueType->isNumeric()) { CastTo(context, value, type->subType(), upcast); auto i32 = SType::getInt(context, 32); auto mask = RValue::getZero(context, SType::getVec(context, i32, type->size())); auto udef = UndefValue::get(*SType::getVec(context, type->subType(), 1)); auto instEle = InsertElementInst::Create(udef, value, RValue::getZero(context, i32), "", context); auto retVal = new ShuffleVectorInst(instEle, udef, mask, "", context); value = RValue(retVal, type); return false; } else if (valueType->isPointer()) { context.addError("can not cast pointer to vec type"); return true; } else if (type->size() != valueType->size()) { context.addError("can not cast vec types of different sizes"); return true; } else if (type->subType()->isBool()) { // cast to bool is value != 0 auto pred = getPredicate(ParserBase::TT_NEQ, valueType, context); auto op = valueType->subType()->isFloating()? Instruction::FCmp : Instruction::ICmp; auto val = CmpInst::Create(op, pred, value, RValue::getZero(context, valueType), "", context); value = RValue(val, type); return false; } else { auto op = getCastOp(valueType->subType(), type->subType()); auto val = CastInst::Create(op, value, *type, "", context); value = RValue(val, type); return false; } } else if (type->isEnum()) { // casting to enum would violate value constraints context.addError("can't cast to enum type"); return true; } else if (type->isBool()) { if (valueType->isVec()) { context.addError("can not cast vec type to bool"); return true; } else if (valueType->isEnum()) { valueType = value.castToSubtype(); } // cast to bool is value != 0 auto pred = getPredicate(ParserBase::TT_NEQ, valueType, context); auto op = valueType->isFloating()? Instruction::FCmp : Instruction::ICmp; auto val = CmpInst::Create(op, pred, value, RValue::getZero(context, valueType), "", context); value = RValue(val, type); return false; } if (valueType->isPointer()) { context.addError("can't cast pointer to numeric type"); return true; } // unwrap enum type if (valueType->isEnum()) valueType = value.castToSubtype(); auto op = getCastOp(valueType, type); auto val = op != Instruction::AddrSpaceCast? CastInst::Create(op, value, *type, "", context) : value; value = RValue(val, type); return false; }
RValue Inst::Load(CodeContext& context, RValue value) { return RValue(new LoadInst(value, "", context), value.stype()); }