diff options
| author | Yong He <yonghe@outlook.com> | 2022-08-03 12:08:37 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-03 12:08:37 -0700 |
| commit | e81a5fe56f3177fc3c7040e2320ae083e3746eb7 (patch) | |
| tree | 884c15287bc10050e7883897dd266b27e62bff66 | |
| parent | 260fc5fbe58f2cf976d64993054c638769bc280f (diff) | |
Basic pointer usages. (#2342)
| -rw-r--r-- | build/visual-studio/slang/slang.vcxproj | 1 | ||||
| -rw-r--r-- | build/visual-studio/slang/slang.vcxproj.filters | 3 | ||||
| -rw-r--r-- | examples/heterogeneous-hello-world/main.slang | 9 | ||||
| -rw-r--r-- | source/slang/core.meta.slang | 115 | ||||
| -rw-r--r-- | source/slang/slang-ast-expr.h | 15 | ||||
| -rw-r--r-- | source/slang/slang-ast-support-types.cpp | 13 | ||||
| -rw-r--r-- | source/slang/slang-ast-support-types.h | 8 | ||||
| -rw-r--r-- | source/slang/slang-check-conversion.cpp | 5 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 29 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 7 | ||||
| -rw-r--r-- | source/slang/slang-check-overload.cpp | 5 | ||||
| -rw-r--r-- | source/slang/slang-emit-c-like.cpp | 6 | ||||
| -rw-r--r-- | source/slang/slang-ir-inst-defs.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir-peephole.cpp | 11 | ||||
| -rw-r--r-- | source/slang/slang-ir-util.cpp | 5 | ||||
| -rw-r--r-- | source/slang/slang-ir-util.h | 2 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 38 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 91 | ||||
| -rw-r--r-- | tests/cpu-program/pointer-basics.slang | 26 | ||||
| -rw-r--r-- | tests/cpu-program/pointer-basics.slang.expected | 6 |
20 files changed, 363 insertions, 34 deletions
diff --git a/build/visual-studio/slang/slang.vcxproj b/build/visual-studio/slang/slang.vcxproj index 534effb16..f0cccb341 100644 --- a/build/visual-studio/slang/slang.vcxproj +++ b/build/visual-studio/slang/slang.vcxproj @@ -471,6 +471,7 @@ IF EXIST ..\..\..\external\slang-glslang\bin\windows-aarch64\release\slang-glsla <ClCompile Include="..\..\..\source\slang\slang-ast-print.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-reflect.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-substitutions.cpp" />
+ <ClCompile Include="..\..\..\source\slang\slang-ast-support-types.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-type.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ast-val.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-capability.cpp" />
diff --git a/build/visual-studio/slang/slang.vcxproj.filters b/build/visual-studio/slang/slang.vcxproj.filters index afbd5ff8e..ea1fd80ea 100644 --- a/build/visual-studio/slang/slang.vcxproj.filters +++ b/build/visual-studio/slang/slang.vcxproj.filters @@ -506,6 +506,9 @@ <ClCompile Include="..\..\..\source\slang\slang-ast-substitutions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\source\slang\slang-ast-support-types.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\source\slang\slang-ast-type.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/examples/heterogeneous-hello-world/main.slang b/examples/heterogeneous-hello-world/main.slang index 2a9c1eaf1..b852ca1a1 100644 --- a/examples/heterogeneous-hello-world/main.slang +++ b/examples/heterogeneous-hello-world/main.slang @@ -4,9 +4,9 @@ __target_intrinsic(cpp, "printf(\"%s\", ($0).getBuffer())") public void writeln(String text); [DllImport("User32")] -int MessageBoxA(Ptr<void> hwnd, String text, String caption, uint flags); +int MessageBoxA(void* hwnd, String text, String caption, uint flags); -[COM] +[COM("111702C2-2FD7-46F9-A318-DCCEEC96357E")] interface IObject { int getValue(int value) throws int; @@ -17,9 +17,8 @@ IObject createObject(); public __extern_cpp void main() throws int { - //writeln("hello world"); - //MessageBoxA(nullptr, "hello world!", "example", 0); - + writeln("hello world"); + MessageBoxA(nullptr, "hello world!", "example", 0); IObject object = createObject(); int rs = try object.getValue(2); diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang index fb39b43f2..1991eb583 100644 --- a/source/slang/core.meta.slang +++ b/source/slang/core.meta.slang @@ -358,9 +358,99 @@ __magic_type(PtrType) __intrinsic_type($(kIROp_PtrType)) struct Ptr { + __intrinsic_op($(kIROp_Load)) + static T __load(Ptr<T> ptr); + + __intrinsic_op($(kIROp_Store)) + static void __store(Ptr<T> ptr, T val); + + __intrinsic_op($(kIROp_getElementPtr)) + static Ptr<T> __getElementPtr(Ptr<T> ptr, int index); + + __intrinsic_op($(kIROp_Neq)) + __generic<U:__BuiltinArithmeticType> + static bool __neq(Ptr<T> ptr, U val); + + __intrinsic_op($(kIROp_Eql)) + __generic<U:__BuiltinArithmeticType> + static bool __eql(Ptr<T> ptr, U val); + + __generic<U> + __intrinsic_op($(kIROp_BitCast)) + __init(Ptr<U> ptr); + + __intrinsic_op($(kIROp_BitCast)) + __init(uint64_t val); + + __intrinsic_op($(kIROp_BitCast)) + __init(int64_t val); + + __subscript(int index) -> T + { + [__unsafeForceInlineEarly] + get + { + return __load(__getElementPtr(this, index)); + } + + [__unsafeForceInlineEarly] + set(T newValue) + { + __store(__getElementPtr(this, index), newValue); + } + + __intrinsic_op($(kIROp_getElementPtr)) + ref; + } }; __generic<T> +__intrinsic_op($(kIROp_Less)) +bool operator<(Ptr<T> p1, Ptr<T> p2); + +__generic<T> +__intrinsic_op($(kIROp_Leq)) +bool operator<=(Ptr<T> p1, Ptr<T> p2); + +__generic<T> +__intrinsic_op($(kIROp_Greater)) +bool operator>(Ptr<T> p1, Ptr<T> p2); + +__generic<T> +__intrinsic_op($(kIROp_Geq)) +bool operator>=(Ptr<T> p1, Ptr<T> p2); + +__generic<T> +__intrinsic_op($(kIROp_Neq)) +bool operator!=(Ptr<T> p1, Ptr<T> p2); + +__generic<T> +__intrinsic_op($(kIROp_Eql)) +bool operator==(Ptr<T> p1, Ptr<T> p2); + +extension bool +{ + __generic<T> + __implicit_conversion($(kConversionCost_PtrToBool)) + __intrinsic_op($(kIROp_CastPtrToBool)) + __init(Ptr<T> ptr); +} + +extension uint64_t +{ + __generic<T> + __intrinsic_op($(kIROp_Construct)) + __init(Ptr<T> ptr); +} + +extension int64_t +{ + __generic<T> + __intrinsic_op($(kIROp_Construct)) + __init(Ptr<T> ptr); +} + +__generic<T> __magic_type(OutType) __intrinsic_type($(kIROp_OutType)) struct Out @@ -1620,6 +1710,25 @@ for (auto op : intrinsicUnaryOps) }}}} +__generic<T> +__intrinsic_op(0) +__prefix Ref<T> operator*(Ptr<T> value); + +__generic<T> +__intrinsic_op(0) +__prefix Ptr<T> operator&(__ref T value); + +__generic<T> +__intrinsic_op($(kIROp_getElementPtr)) +Ptr<T> operator+(Ptr<T> value, int64_t offset); + +__generic<T> +[__unsafeForceInlineEarly] +Ptr<T> operator-(Ptr<T> value, int64_t offset) +{ + return Ptr<T>.__getElementPtr(value, -offset); +} + __generic<T : __BuiltinArithmeticType> [__unsafeForceInlineEarly] __prefix T operator+(T value) @@ -1679,6 +1788,12 @@ __generic<T : __BuiltinArithmeticType, let R : int, let C : int> matrix<T,R,C> operator$(op.name)(in out matrix<T,R,C> value) {$(fixity.bodyPrefix) value = value $(op.binOp) T(1); return $(fixity.returnVal); } +$(fixity.qual) +__generic<T> +[__unsafeForceInlineEarly] +Ptr<T> operator$(op.name)(in out Ptr<T> value) +{$(fixity.bodyPrefix) value = value $(op.binOp) 1; return $(fixity.returnVal); } + ${{{{ } diff --git a/source/slang/slang-ast-expr.h b/source/slang/slang-ast-expr.h index 3fbbe05ea..4a9cc475d 100644 --- a/source/slang/slang-ast-expr.h +++ b/source/slang/slang-ast-expr.h @@ -374,6 +374,13 @@ class ExtractExistentialValueExpr: public Expr DeclRef<VarDeclBase> declRef; }; +class OpenRefExpr : public Expr +{ + SLANG_AST_CLASS(OpenRefExpr) + + Expr* innerExpr = nullptr; +}; + /// An expression of the form `__jvp(fn)` to access the /// forward-mode derivative version of the function `fn` /// @@ -424,4 +431,12 @@ class ModifiedTypeExpr : public Expr TypeExp base; }; + /// A type expression that rrepresents a pointer type, e.g. T* +class PointerTypeExpr : public Expr +{ + SLANG_AST_CLASS(PointerTypeExpr) + + TypeExp base; +}; + } // namespace Slang diff --git a/source/slang/slang-ast-support-types.cpp b/source/slang/slang-ast-support-types.cpp new file mode 100644 index 000000000..badb524bb --- /dev/null +++ b/source/slang/slang-ast-support-types.cpp @@ -0,0 +1,13 @@ +#include "slang-ast-support-types.h" +#include "slang-ast-base.h" +#include "slang-ast-type.h" + +Slang::QualType::QualType(Type* type) + : type(type) + , isLeftValue(false) +{ + if (as<RefType>(type)) + { + isLeftValue = true; + } +} diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index e8ab51fbd..3c161877c 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -98,6 +98,9 @@ namespace Slang // Cost of converting an integer to a floating-point type kConversionCost_IntegerToFloatConversion = 400, + // Cost of converting a pointer to bool + kConversionCost_PtrToBool = 400, + // Default case (usable for user-defined conversions) kConversionCost_Default = 500, @@ -472,10 +475,7 @@ namespace Slang : isLeftValue(false) {} - QualType(Type* type) - : type(type) - , isLeftValue(false) - {} + QualType(Type* type); Type* Ptr() { return type; } diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index b4c5ebb4a..6290acbd9 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -639,6 +639,11 @@ namespace Slang return true; } + if (auto refType = as<RefType>(toType)) + { + return _coerce(refType->getValueType(), outToExpr, fromType, fromExpr, outCost); + } + // If both are string types we assume they are convertable in both directions if (as<StringTypeBase>(fromType) && as<StringTypeBase>(toType)) { diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 1895da70b..addd3a5c4 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -231,6 +231,21 @@ namespace Slang return expr; } + Expr* SemanticsVisitor::maybeOpenRef(Expr* expr) + { + auto exprType = expr->type.type; + + if (auto refType = as<RefType>(exprType)) + { + auto openRef = m_astBuilder->create<OpenRefExpr>(); + openRef->innerExpr = expr; + openRef->type.isLeftValue = true; + openRef->type.type = refType->getValueType(); + return openRef; + } + return expr; + } + static SourceLoc _getMemberOpLoc(Expr* expr) { if (auto m = as<MemberExpr>(expr)) @@ -1329,8 +1344,8 @@ namespace Slang Expr* SemanticsVisitor::checkAssignWithCheckedOperands(AssignExpr* expr) { auto type = expr->left->type; - - expr->right = coerce(type, expr->right); + auto right = maybeOpenRef(expr->right); + expr->right = coerce(type, right); if (!type.isLeftValue) { @@ -2514,6 +2529,16 @@ namespace Slang return expr; } + Expr* SemanticsExprVisitor::visitPointerTypeExpr(PointerTypeExpr* expr) + { + expr->base = CheckProperType(expr->base); + if (as<ErrorType>(expr->base.type)) + expr->type = expr->base.type; + auto ptrType = m_astBuilder->getPtrType(expr->base.type); + expr->type = m_astBuilder->getTypeType(ptrType); + return expr; + } + Expr* SemanticsExprVisitor::visitModifiedTypeExpr(ModifiedTypeExpr* expr) { // The base type should be a proper type (not an expression, generic, etc.) diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index ce1093d09..c7b3f432a 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -499,6 +499,10 @@ namespace Slang /// Expr* maybeOpenExistential(Expr* expr); + /// If `expr` has Ref<T> Type, convert it into an l-value expr that has T type. + Expr* maybeOpenRef(Expr* expr); + + Expr* ConstructDeclRefExpr( DeclRef<Decl> declRef, Expr* baseExpr, @@ -1722,6 +1726,7 @@ namespace Slang CASE(ModifierCastExpr) CASE(LetExpr) CASE(ExtractExistentialValueExpr) + CASE(OpenRefExpr) #undef CASE @@ -1734,12 +1739,14 @@ namespace Slang Expr* visitThisExpr(ThisExpr* expr); Expr* visitThisTypeExpr(ThisTypeExpr* expr); Expr* visitAndTypeExpr(AndTypeExpr* expr); + Expr* visitPointerTypeExpr(PointerTypeExpr* expr); Expr* visitModifiedTypeExpr(ModifiedTypeExpr* expr); Expr* visitJVPDifferentiateExpr(JVPDifferentiateExpr* expr); /// Perform semantic checking on a `modifier` that is being applied to the given `type` Val* checkTypeModifier(Modifier* modifier, Type* type); + }; struct SemanticsStmtVisitor diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 7f2386eb4..abb049a84 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -1438,6 +1438,11 @@ namespace Slang for (auto& arg : expr->arguments) { + arg = maybeOpenRef(arg); + } + + for (auto& arg : expr->arguments) + { arg = maybeOpenExistential(arg); } diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index c3ae31894..b6540b5f1 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -1943,7 +1943,10 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO auto rightSidePrec = rightSide(outerPrec, info); auto postfixInfo = getInfo(EmitOp::Postfix); bool rightSideNeedClose = maybeEmitParens(rightSidePrec, postfixInfo); - emitDereferenceOperand(inst->getOperand(0), leftSide(rightSidePrec, postfixInfo)); + if (isPtrToArrayType(inst->getOperand(0)->getDataType())) + emitDereferenceOperand(inst->getOperand(0), leftSide(rightSidePrec, postfixInfo)); + else + emitOperand(inst->getOperand(0), leftSide(rightSidePrec, postfixInfo)); m_writer->emit("["); emitOperand(inst->getOperand(1), getInfo(EmitOp::General)); m_writer->emit("]"); @@ -2061,7 +2064,6 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO m_writer->emit(")"); } break; - case kIROp_GlobalConstant: case kIROp_GetValueFromBoundInterface: emitOperand(inst->getOperand(0), outerPrec); diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index 8a62e34d4..afb132af7 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -738,7 +738,7 @@ INST(ExtractTaggedUnionPayload, extractTaggedUnionPayload, 1, 0) INST(BitCast, bitCast, 1, 0) INST(Reinterpret, reinterpret, 1, 0) - +INST(CastPtrToBool, CastPtrToBool, 1, 0) INST(JVPDifferentiate, jvpDifferentiate, 1, 0) // Converts other resources (such as ByteAddressBuffer) to the equivalent StructuredBuffer diff --git a/source/slang/slang-ir-peephole.cpp b/source/slang/slang-ir-peephole.cpp index 6cb5d2971..ffdb84c4a 100644 --- a/source/slang/slang-ir-peephole.cpp +++ b/source/slang/slang-ir-peephole.cpp @@ -85,6 +85,17 @@ struct PeepholeContext : InstPassBase } } break; + case kIROp_CastPtrToBool: + { + auto ptr = inst->getOperand(0); + IRBuilder builder(&sharedBuilderStorage); + builder.setInsertBefore(inst); + auto neq = builder.emitNeq(ptr, builder.getPtrValue(nullptr)); + inst->replaceUsesWith(neq); + inst->removeAndDeallocate(); + changed = true; + } + break; default: break; } diff --git a/source/slang/slang-ir-util.cpp b/source/slang/slang-ir-util.cpp index a515217d9..d91252fcc 100644 --- a/source/slang/slang-ir-util.cpp +++ b/source/slang/slang-ir-util.cpp @@ -38,4 +38,9 @@ bool isPtrToClassType(IRInst* type) return isPointerOfType(type, kIROp_ClassType); } +bool isPtrToArrayType(IRInst* type) +{ + return isPointerOfType(type, kIROp_ArrayType) || isPointerOfType(type, kIROp_UnsizedArrayType); +} + } diff --git a/source/slang/slang-ir-util.h b/source/slang/slang-ir-util.h index 2c11374e3..5a09638d4 100644 --- a/source/slang/slang-ir-util.h +++ b/source/slang/slang-ir-util.h @@ -11,6 +11,8 @@ namespace Slang bool isPtrToClassType(IRInst* type); +bool isPtrToArrayType(IRInst* type); + // True if ptrType is a pointer type to elementType bool isPointerOfType(IRInst* ptrType, IRInst* elementType); diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 66f314d06..be7373d40 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -704,6 +704,11 @@ LoweredValInfo emitCallToDeclRef( // so we will emit an instruction with the chosen // opcode, and the arguments to the call as its operands. // + if (intrinsicOpModifier->op == 0) // Identity, just pass operand 0 through. + { + SLANG_RELEASE_ASSERT(argCount == 1); + return LoweredValInfo::simple(args[0]); + } auto intrinsicOp = getIntrinsicOp(funcDecl, intrinsicOpModifier); return LoweredValInfo::simple(builder->emitIntrinsicInst( type, @@ -4002,6 +4007,12 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> UNREACHABLE_RETURN(LoweredValInfo()); } + LoweredValInfo visitPointerTypeExpr(PointerTypeExpr* /*expr*/) + { + SLANG_UNIMPLEMENTED_X("'*' type expression during code generation"); + UNREACHABLE_RETURN(LoweredValInfo()); + } + LoweredValInfo visitAssocTypeDecl(AssocTypeDecl* decl) { SLANG_UNIMPLEMENTED_X("associatedtype expression during code generation"); @@ -4105,6 +4116,11 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> context->shared->extValues.add(info); return LoweredValInfo::extractedExistential(info); } + + LoweredValInfo visitOpenRefExpr(OpenRefExpr* expr) + { + return lowerLValueExpr(context, expr->innerExpr); + } }; struct LValueExprLoweringVisitor : ExprLoweringVisitorBase<LValueExprLoweringVisitor> @@ -4264,6 +4280,14 @@ struct RValueExprLoweringVisitor : ExprLoweringVisitorBase<RValueExprLoweringVis return LoweredValInfo::simple(irSwizzle); } + + LoweredValInfo visitOpenRefExpr(OpenRefExpr* expr) + { + auto inner = lowerLValueExpr(context, expr->innerExpr); + auto builder = getBuilder(); + auto irLoad = builder->emitLoad(inner.val); + return LoweredValInfo::simple(irLoad); + } }; LoweredValInfo lowerLValueExpr( @@ -4274,7 +4298,12 @@ LoweredValInfo lowerLValueExpr( LValueExprLoweringVisitor visitor; visitor.context = context; - return visitor.dispatch(expr); + auto info = visitor.dispatch(expr); + if (as<RefType>(expr->type)) + { + info.flavor = LoweredValInfo::Flavor::Ptr; + } + return info; } LoweredValInfo lowerRValueExpr( @@ -4285,7 +4314,12 @@ LoweredValInfo lowerRValueExpr( RValueExprLoweringVisitor visitor; visitor.context = context; - return visitor.dispatch(expr); + auto info = visitor.dispatch(expr); + if (as<RefType>(expr->type)) + { + info.val = context->irBuilder->emitLoad(info.val); + } + return info; } struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index dbf329e9a..cdf418d3d 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -1807,9 +1807,10 @@ namespace Slang case Declarator::Flavor::Pointer: { auto ptrDeclarator = (PointerDeclarator*) declarator.Ptr(); - - // TODO(tfoley): we don't support pointers for now - // ioInfo->typeSpec = new PointerTypeExpr(ioInfo->typeSpec); + auto ptrTypeExpr = astBuilder->create<PointerTypeExpr>(); + ptrTypeExpr->loc = ptrDeclarator->starLoc; + ptrTypeExpr->base.exp = ioInfo->typeSpec; + ioInfo->typeSpec = ptrTypeExpr; declarator = ptrDeclarator->inner; } @@ -2014,6 +2015,17 @@ namespace Slang memberExpr->name = expectIdentifier(parser).name; return memberExpr; } + static Expr* parseStaticMemberType(Parser* parser, Expr* base, SourceLoc opLoc) + { + // When called the :: or . have been consumed, so don't need to consume here. + + StaticMemberExpr* memberExpr = parser->astBuilder->create<StaticMemberExpr>(); + memberExpr->memberOperatorLoc = opLoc; + parser->FillPosition(memberExpr); + memberExpr->baseExpression = base; + memberExpr->name = expectIdentifier(parser).name; + return memberExpr; + } // Parse option `[]` braces after a type expression, that indicate an array type static Expr* parsePostfixTypeSuffix( @@ -2021,18 +2033,31 @@ namespace Slang Expr* inTypeExpr) { auto typeExpr = inTypeExpr; - while (parser->LookAheadToken(TokenType::LBracket)) + for (;;) { - IndexExpr* arrType = parser->astBuilder->create<IndexExpr>(); - arrType->loc = typeExpr->loc; - arrType->baseExpression = typeExpr; - parser->ReadToken(TokenType::LBracket); - if (!parser->LookAheadToken(TokenType::RBracket)) + Token token; + if (parser->LookAheadToken(TokenType::LBracket)) { - arrType->indexExpression = parser->ParseExpression(); + IndexExpr* arrType = parser->astBuilder->create<IndexExpr>(); + arrType->loc = typeExpr->loc; + arrType->baseExpression = typeExpr; + parser->ReadToken(TokenType::LBracket); + if (!parser->LookAheadToken(TokenType::RBracket)) + { + arrType->indexExpression = parser->ParseExpression(); + } + parser->ReadToken(TokenType::RBracket); + typeExpr = arrType; } - parser->ReadToken(TokenType::RBracket); - typeExpr = arrType; + else if (AdvanceIf(parser, TokenType::OpMul, &token)) + { + PointerTypeExpr* ptrType = parser->astBuilder->create<PointerTypeExpr>(); + ptrType->loc = token.loc; + ptrType->base.exp = typeExpr; + typeExpr = ptrType; + } + else + break; } return typeExpr; } @@ -2309,7 +2334,7 @@ namespace Slang case TokenType::Scope: { auto opToken = parser->ReadToken(TokenType::Scope); - typeExpr = parseMemberType(parser, typeExpr, opToken.loc); + typeExpr = parseStaticMemberType(parser, typeExpr, opToken.loc); break; } case TokenType::Dot: @@ -4368,7 +4393,7 @@ namespace Slang // with any side effects. // // - if (LookAheadToken(TokenType::Identifier)) + if (LookAheadToken(TokenType::Identifier) || LookAheadToken(TokenType::OpMul)) { // Reset the cursor and try to parse a declaration now. // Note: the declaration will consume any modifiers @@ -5171,6 +5196,10 @@ namespace Slang static bool _isCast(Parser* parser, Expr* expr) { + if (as<PointerTypeExpr>(expr)) + { + return true; + } // We can't just look at expr and look up if it's a type, because we allow // out-of-order declarations. So to a first approximation we'll try and @@ -5231,6 +5260,8 @@ namespace Slang } case TokenType::OpAdd: case TokenType::OpSub: + case TokenType::OpMul: + case TokenType::OpBitAnd: { // + - are ambiguous, it could be a binary + or - so -> expression, or unary -> cast // @@ -5300,6 +5331,24 @@ namespace Slang return false; } + static bool tryParseExpression(Parser* parser, Expr* &outExpr, TokenType tokenTypeAfter) + { + auto cursor = parser->tokenReader.getCursor(); + auto isRecovering = parser->isRecovering; + auto oldSink = parser->sink; + DiagnosticSink newSink(parser->sink->getSourceManager(), nullptr); + parser->sink = &newSink; + outExpr = parser->ParseExpression(); + parser->sink = oldSink; + parser->isRecovering = isRecovering; + if (outExpr && newSink.getErrorCount() == 0 && parser->LookAheadToken(tokenTypeAfter)) + { + return true; + } + parser->tokenReader.setCursor(cursor); + return false; + } + static Expr* parseAtomicExpr(Parser* parser) { switch( peekTokenType(parser) ) @@ -5319,12 +5368,12 @@ namespace Slang case TokenType::LParent: { Token openParen = parser->ReadToken(TokenType::LParent); - - if (peekTypeName(parser) && parser->LookAheadToken(TokenType::RParent, 1)) + Expr* typeExpr = nullptr; + if (peekTypeName(parser) && parser->LookAheadToken(TokenType::RParent)) { TypeCastExpr* tcexpr = parser->astBuilder->create<ExplicitCastExpr>(); parser->FillPosition(tcexpr); - tcexpr->functionExpr = parser->ParseType(); + tcexpr->functionExpr = typeExpr; parser->ReadToken(TokenType::RParent); auto arg = parsePrefixExpr(parser); @@ -5339,7 +5388,11 @@ namespace Slang // branch will be taken. This is okay in so far as SomeScope::Thing will parse // as an expression. - Expr* base = parser->ParseExpression(); + Expr* base = nullptr; + if (!tryParseExpression(parser, base, TokenType::RParent)) + { + base = parser->ParseType(); + } parser->ReadToken(TokenType::RParent); @@ -5853,6 +5906,8 @@ namespace Slang case TokenType::OpNot: case TokenType::OpInc: case TokenType::OpDec: + case TokenType::OpMul: + case TokenType::OpBitAnd: { PrefixExpr* prefixExpr = parser->astBuilder->create<PrefixExpr>(); parser->FillPosition(prefixExpr); diff --git a/tests/cpu-program/pointer-basics.slang b/tests/cpu-program/pointer-basics.slang new file mode 100644 index 000000000..3054cda1c --- /dev/null +++ b/tests/cpu-program/pointer-basics.slang @@ -0,0 +1,26 @@ +//TEST:EXECUTABLE: +__target_intrinsic(cpp, "printf(\"%s\\n\", ($0).getBuffer())") +void writeln(String text); + +public __extern_cpp int main() +{ + uint2 value; + int *pValue = (int*)&value; + *pValue = 1; + (*pValue)++; + ++pValue[0]; + ++pValue; + *pValue = 1; + pValue = (int *)&value; + int64_t ptrVal = int64_t(pValue); + pValue = (int *)ptrVal; + if (pValue + && pValue != nullptr + && ptrVal != 0 + && value[0] == 3 + && pValue[1] == 1) + writeln("Success"); + else + writeln("Fail"); + return 0; +}
\ No newline at end of file diff --git a/tests/cpu-program/pointer-basics.slang.expected b/tests/cpu-program/pointer-basics.slang.expected new file mode 100644 index 000000000..9e97ae031 --- /dev/null +++ b/tests/cpu-program/pointer-basics.slang.expected @@ -0,0 +1,6 @@ +result code = 0 +standard error = { +} +standard output = { +Success +} |
